xHCI: cancel command after command timeout
The patch is used to cancel command when the command isn't
acknowledged and a timeout occurs.
This patch should be backported to kernels as old as 3.0, that contain
the commit 7ed603ecf8
"xhci: Add an
assertion to check for virt_dev=0 bug." That commit papers over a NULL
pointer dereference, and this patch fixes the underlying issue that
caused the NULL pointer dereference.
Signed-off-by: Elric Fu <elricfu1@gmail.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Tested-by: Miroslav Sabljic <miroslav.sabljic@avl.com>
Cc: stable@vger.kernel.org
This commit is contained in:
parent
b92cc66c04
commit
6e4468b9a0
2 changed files with 22 additions and 7 deletions
|
@ -2402,6 +2402,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
|||
struct completion *cmd_completion;
|
||||
u32 *cmd_status;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
union xhci_trb *cmd_trb;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
|
@ -2447,6 +2448,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
|||
}
|
||||
init_completion(cmd_completion);
|
||||
|
||||
cmd_trb = xhci->cmd_ring->dequeue;
|
||||
if (!ctx_change)
|
||||
ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
|
||||
udev->slot_id, must_succeed);
|
||||
|
@ -2468,14 +2470,17 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
|||
/* Wait for the configure endpoint command to complete */
|
||||
timeleft = wait_for_completion_interruptible_timeout(
|
||||
cmd_completion,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
if (timeleft <= 0) {
|
||||
xhci_warn(xhci, "%s while waiting for %s command\n",
|
||||
timeleft == 0 ? "Timeout" : "Signal",
|
||||
ctx_change == 0 ?
|
||||
"configure endpoint" :
|
||||
"evaluate context");
|
||||
/* FIXME cancel the configure endpoint command */
|
||||
/* cancel the configure endpoint command */
|
||||
ret = xhci_cancel_cmd(xhci, command, cmd_trb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
|
@ -3424,8 +3429,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
unsigned long flags;
|
||||
int timeleft;
|
||||
int ret;
|
||||
union xhci_trb *cmd_trb;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
cmd_trb = xhci->cmd_ring->dequeue;
|
||||
ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
@ -3437,12 +3444,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
|
||||
/* XXX: how much time for xHC slot assignment? */
|
||||
timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
if (timeleft <= 0) {
|
||||
xhci_warn(xhci, "%s while waiting for a slot\n",
|
||||
timeleft == 0 ? "Timeout" : "Signal");
|
||||
/* FIXME cancel the enable slot request */
|
||||
return 0;
|
||||
/* cancel the enable slot request */
|
||||
return xhci_cancel_cmd(xhci, NULL, cmd_trb);
|
||||
}
|
||||
|
||||
if (!xhci->slot_id) {
|
||||
|
@ -3503,6 +3510,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
struct xhci_slot_ctx *slot_ctx;
|
||||
struct xhci_input_control_ctx *ctrl_ctx;
|
||||
u64 temp_64;
|
||||
union xhci_trb *cmd_trb;
|
||||
|
||||
if (!udev->slot_id) {
|
||||
xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
|
||||
|
@ -3541,6 +3549,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
cmd_trb = xhci->cmd_ring->dequeue;
|
||||
ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
|
||||
udev->slot_id);
|
||||
if (ret) {
|
||||
|
@ -3553,7 +3562,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
|
||||
/* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */
|
||||
timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
/* FIXME: From section 4.3.4: "Software shall be responsible for timing
|
||||
* the SetAddress() "recovery interval" required by USB and aborting the
|
||||
* command on a timeout.
|
||||
|
@ -3561,7 +3570,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
if (timeleft <= 0) {
|
||||
xhci_warn(xhci, "%s while waiting for address device command\n",
|
||||
timeleft == 0 ? "Timeout" : "Signal");
|
||||
/* FIXME cancel the address device command */
|
||||
/* cancel the address device command */
|
||||
ret = xhci_cancel_cmd(xhci, NULL, cmd_trb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
|
|
|
@ -1256,6 +1256,9 @@ struct xhci_td {
|
|||
union xhci_trb *last_trb;
|
||||
};
|
||||
|
||||
/* xHCI command default timeout value */
|
||||
#define XHCI_CMD_DEFAULT_TIMEOUT (5 * HZ)
|
||||
|
||||
/* command descriptor */
|
||||
struct xhci_cd {
|
||||
struct list_head cancel_cmd_list;
|
||||
|
|
Loading…
Reference in a new issue