From 678539cfaa090093a9aef185f545f6b17acc445c Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 27 Oct 2009 10:55:52 -0700 Subject: USB: xhci: Handle URB cancel, complete and resubmit race. In the old code, there was a race condition between the stop endpoint command and the URB submission process. When the stop endpoint command is handled by the event handler, the endpoint ring is assumed to be stopped. When a stop endpoint command is queued, URB submissions are to not ring the doorbell. The old code would check the number of pending URBs to be canceled, and would not ring the doorbell if it was non-zero. However, the following race condition could occur with the old code: 1. Cancel an URB, add it to the list of URBs to be canceled, queue the stop endpoint command, and increment ep->cancels_pending to 1. 2. The URB finishes on the HW, and an event is enqueued to the event ring (at the same time as 1). 3. The stop endpoint command finishes, and the endpoint is halted. An event is queued to the event ring. 4. The event handler sees the finished URB, notices it was to be canceled, decrements ep->cancels_pending to 0, and removes it from the to be canceled list. 5. The event handler drops the lock and gives back the URB. The completion handler requeues the URB (or a different driver enqueues a new URB). This causes the endpoint's doorbell to be rung, since ep->cancels_pending == 0. The endpoint is now running. 6. A second URB is canceled, and it's added to the canceled list. Since ep->cancels_pending == 0, a new stop endpoint command is queued, and ep->cancels_pending is incremented to 1. 7. The event handler then sees the completed stop endpoint command. The handler assumes the endpoint is stopped, but it isn't. It attempts to move the dequeue pointer or change TDs to cancel the second URB, while the hardware is actively accessing the endpoint ring. To eliminate this race condition, a new endpoint state bit is introduced, EP_HALT_PENDING. When this bit is set, a stop endpoint command has been queued, and the command handler has not begun to process the URB cancellation list yet. The endpoint doorbell should not be rung when this is set. Set this when a stop endpoint command is queued, clear it when the handler for that command runs, and check if it's set before ringing a doorbell. ep->cancels_pending is eliminated, because it is no longer used. Make sure to ring the doorbell for an endpoint when the stop endpoint command handler runs, even if the canceled URB list is empty. All canceled URBs could have completed and new URBs could have been enqueued without the doorbell being rung before the command was handled. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 821b7b4709d..184e8b6f30b 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -306,7 +306,7 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci, /* Don't ring the doorbell for this endpoint if there are pending * cancellations because the we don't want to interrupt processing. */ - if (!ep->cancels_pending && !(ep_state & SET_DEQ_PENDING) + if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING) && !(ep_state & EP_HALTED)) { field = xhci_readl(xhci, db_addr) & DB_MASK; xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr); @@ -507,8 +507,11 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, ep = &xhci->devs[slot_id]->eps[ep_index]; ep_ring = ep->ring; - if (list_empty(&ep->cancelled_td_list)) + if (list_empty(&ep->cancelled_td_list)) { + ep->ep_state &= ~EP_HALT_PENDING; + ring_ep_doorbell(xhci, slot_id, ep_index); return; + } /* Fix up the ep ring first, so HW stops executing cancelled TDs. * We have the xHCI lock, so nothing can modify this list until we drop @@ -535,9 +538,9 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, * the cancelled TD list for URB completion later. */ list_del(&cur_td->td_list); - ep->cancels_pending--; } last_unlinked_td = cur_td; + ep->ep_state &= ~EP_HALT_PENDING; /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { @@ -1249,10 +1252,9 @@ td_cleanup: } list_del(&td->td_list); /* Was this TD slated to be cancelled but completed anyway? */ - if (!list_empty(&td->cancelled_td_list)) { + if (!list_empty(&td->cancelled_td_list)) list_del(&td->cancelled_td_list); - ep->cancels_pending--; - } + /* Leave the TD around for the reset endpoint function to use * (but only if it's not a control endpoint, since we already * queued the Set TR dequeue pointer command for stalled -- cgit v1.2.3-70-g09d2 From 6f5165cf989387e84ef23122330b27cca1cbe831 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 27 Oct 2009 10:57:01 -0700 Subject: USB: xhci: Add watchdog timer for URB cancellation. In order to giveback a canceled URB, we must ensure that the xHCI hardware will not access the buffer in an URB. We can't modify the buffer pointers on endpoint rings without issuing and waiting for a stop endpoint command. Since URBs can be canceled in interrupt context, we can't wait on that command. The old code trusted that the host controller would respond to the command, and would giveback the URBs in the event handler. If the hardware never responds to the stop endpoint command, the URBs will never be completed, and we might hang the USB subsystem. Implement a watchdog timer that is spawned whenever a stop endpoint command is queued. If a stop endpoint command event is found on the event ring during an interrupt, we need to stop the watchdog timer with del_timer(). Since del_timer() can fail if the timer is running and waiting on the xHCI lock, we need a way to signal to the timer that everything is fine and it should exit. If we simply clear EP_HALT_PENDING, a new stop endpoint command could sneak in and set it before the watchdog timer can grab the lock. Instead we use a combination of the EP_HALT_PENDING flag and a counter for the number of pending stop endpoint commands (xhci_virt_ep->stop_cmds_pending). If we need to cancel the watchdog timer and del_timer() succeeds, we decrement the number of pending stop endpoint commands. If del_timer() fails, we leave the number of pending stop endpoint commands alone. In either case, we clear the EP_HALT_PENDING flag. The timer will decrement the number of pending stop endpoint commands once it obtains the lock. If the timer is the tail end of the last stop endpoint command (xhci_virt_ep->stop_cmds_pending == 0), and the endpoint's command is still pending (EP_HALT_PENDING is set), we assume the host is dying. The watchdog timer will set XHCI_STATE_DYING, try to halt the xHCI host, and give back all pending URBs. Various other places in the driver need to check whether the xHCI host is dying. If the interrupt handler ever notices, it should immediately stop processing events. The URB enqueue function should also return -ESHUTDOWN. The URB dequeue function should simply return the value of usb_hcd_check_unlink_urb() and the watchdog timer will take care of giving the URB back. When a device is disconnected, the xHCI hardware structures should be freed without issuing a disable slot command (since the hardware probably won't respond to it anyway). The debugging polling loop should stop polling if the host is dying. When a device is disconnected, any pending watchdog timers are killed with del_timer_sync(). It must be synchronous so that the watchdog timer doesn't attempt to access the freed endpoint structures. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 52 ++++++++++++- drivers/usb/host/xhci-mem.c | 15 +++- drivers/usb/host/xhci-ring.c | 170 ++++++++++++++++++++++++++++++++++++++++--- drivers/usb/host/xhci.h | 22 ++++++ 4 files changed, 243 insertions(+), 16 deletions(-) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 5839453d342..0d5a8564ed1 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -246,8 +246,14 @@ static void xhci_work(struct xhci_hcd *xhci) /* Flush posted writes */ xhci_readl(xhci, &xhci->ir_set->irq_pending); - /* FIXME this should be a delayed service routine that clears the EHB */ - xhci_handle_event(xhci); + if (xhci->xhc_state & XHCI_STATE_DYING) + xhci_dbg(xhci, "xHCI dying, ignoring interrupt. " + "Shouldn't IRQs be disabled?\n"); + else + /* FIXME this should be a delayed service routine + * that clears the EHB. + */ + xhci_handle_event(xhci); /* Clear the event handler busy flag (RW1C); the event ring should be empty. */ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); @@ -320,7 +326,7 @@ void xhci_event_ring_work(unsigned long arg) spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, &xhci->op_regs->status); xhci_dbg(xhci, "op reg status = 0x%x\n", temp); - if (temp == 0xffffffff) { + if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING)) { xhci_dbg(xhci, "HW died, polling stopped.\n"); spin_unlock_irqrestore(&xhci->lock, flags); return; @@ -710,16 +716,22 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) * atomic context to this function, which may allocate memory. */ spin_lock_irqsave(&xhci->lock, flags); + if (xhci->xhc_state & XHCI_STATE_DYING) + goto dying; ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); spin_unlock_irqrestore(&xhci->lock, flags); } else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) { spin_lock_irqsave(&xhci->lock, flags); + if (xhci->xhc_state & XHCI_STATE_DYING) + goto dying; ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); spin_unlock_irqrestore(&xhci->lock, flags); } else if (usb_endpoint_xfer_int(&urb->ep->desc)) { spin_lock_irqsave(&xhci->lock, flags); + if (xhci->xhc_state & XHCI_STATE_DYING) + goto dying; ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); spin_unlock_irqrestore(&xhci->lock, flags); @@ -728,6 +740,12 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) } exit: return ret; +dying: + xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for " + "non-responsive xHCI host.\n", + urb->ep->desc.bEndpointAddress, urb); + spin_unlock_irqrestore(&xhci->lock, flags); + return -ESHUTDOWN; } /* @@ -789,6 +807,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) kfree(td); return ret; } + if (xhci->xhc_state & XHCI_STATE_DYING) { + xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on " + "non-responsive xHCI host.\n", + urb->ep->desc.bEndpointAddress, urb); + /* Let the stop endpoint command watchdog timer (which set this + * state) finish cleaning up the endpoint TD lists. We must + * have caught it in the middle of dropping a lock and giving + * back an URB. + */ + goto done; + } xhci_dbg(xhci, "Cancel URB %p\n", urb); xhci_dbg(xhci, "Event ring:\n"); @@ -806,6 +835,10 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) */ if (!(ep->ep_state & EP_HALT_PENDING)) { ep->ep_state |= EP_HALT_PENDING; + ep->stop_cmds_pending++; + ep->stop_cmd_timer.expires = jiffies + + XHCI_STOP_EP_CMD_TIMEOUT * HZ; + add_timer(&ep->stop_cmd_timer); xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index); xhci_ring_cmd_db(xhci); } @@ -1410,16 +1443,27 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct xhci_virt_device *virt_dev; unsigned long flags; u32 state; + int i; if (udev->slot_id == 0) return; + virt_dev = xhci->devs[udev->slot_id]; + if (!virt_dev) + return; + + /* Stop any wayward timer functions (which may grab the lock) */ + for (i = 0; i < 31; ++i) { + virt_dev->eps[i].ep_state &= ~EP_HALT_PENDING; + del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); + } spin_lock_irqsave(&xhci->lock, flags); /* Don't disable the slot if the host controller is dead. */ state = xhci_readl(xhci, &xhci->op_regs->status); - if (state == 0xffffffff) { + if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING)) { xhci_free_virt_device(xhci, udev->slot_id); spin_unlock_irqrestore(&xhci->lock, flags); return; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index b8fd270a8b0..fd05247b7bb 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -248,6 +248,15 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params))); } +static void xhci_init_endpoint_timer(struct xhci_hcd *xhci, + struct xhci_virt_ep *ep) +{ + init_timer(&ep->stop_cmd_timer); + ep->stop_cmd_timer.data = (unsigned long) ep; + ep->stop_cmd_timer.function = xhci_stop_endpoint_command_watchdog; + ep->xhci = xhci; +} + /* All the xhci_tds in the ring's TD list should be freed at this point */ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) { @@ -309,9 +318,11 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, (unsigned long long)dev->in_ctx->dma); - /* Initialize the cancellation list for each endpoint */ - for (i = 0; i < 31; i++) + /* Initialize the cancellation list and watchdog timers for each ep */ + for (i = 0; i < 31; i++) { + xhci_init_endpoint_timer(xhci, &dev->eps[i]); INIT_LIST_HEAD(&dev->eps[i].cancelled_td_list); + } /* Allocate endpoint 0 ring */ dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, flags); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 184e8b6f30b..9541e88df68 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -475,6 +475,35 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, ep->ep_state |= SET_DEQ_PENDING; } +static inline void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, + struct xhci_virt_ep *ep) +{ + ep->ep_state &= ~EP_HALT_PENDING; + /* Can't del_timer_sync in interrupt, so we attempt to cancel. If the + * timer is running on another CPU, we don't decrement stop_cmds_pending + * (since we didn't successfully stop the watchdog timer). + */ + if (del_timer(&ep->stop_cmd_timer)) + ep->stop_cmds_pending--; +} + +/* Must be called with xhci->lock held in interrupt context */ +static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, + struct xhci_td *cur_td, int status, char *adjective) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + + cur_td->urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(hcd, cur_td->urb); + xhci_dbg(xhci, "Giveback %s URB %p\n", adjective, cur_td->urb); + + spin_unlock(&xhci->lock); + usb_hcd_giveback_urb(hcd, cur_td->urb, status); + kfree(cur_td); + spin_lock(&xhci->lock); + xhci_dbg(xhci, "%s URB given back\n", adjective); +} + /* * When we get a command completion for a Stop Endpoint Command, we need to * unlink any cancelled TDs from the ring. There are two ways to do that: @@ -508,7 +537,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, ep_ring = ep->ring; if (list_empty(&ep->cancelled_td_list)) { - ep->ep_state &= ~EP_HALT_PENDING; + xhci_stop_watchdog_timer_in_irq(xhci, ep); ring_ep_doorbell(xhci, slot_id, ep_index); return; } @@ -540,7 +569,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, list_del(&cur_td->td_list); } last_unlinked_td = cur_td; - ep->ep_state &= ~EP_HALT_PENDING; + xhci_stop_watchdog_timer_in_irq(xhci, ep); /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { @@ -568,23 +597,136 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, hcd_stat_update(xhci->tp_stat, cur_td->urb->actual_length, ktime_sub(stop_time, cur_td->start_time)); #endif - cur_td->urb->hcpriv = NULL; - usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), cur_td->urb); - - xhci_dbg(xhci, "Giveback cancelled URB %p\n", cur_td->urb); - spin_unlock(&xhci->lock); /* Doesn't matter what we pass for status, since the core will * just overwrite it (because the URB has been unlinked). */ - usb_hcd_giveback_urb(xhci_to_hcd(xhci), cur_td->urb, 0); - kfree(cur_td); + xhci_giveback_urb_in_irq(xhci, cur_td, 0, "cancelled"); - spin_lock(&xhci->lock); + /* Stop processing the cancelled list if the watchdog timer is + * running. + */ + if (xhci->xhc_state & XHCI_STATE_DYING) + return; } while (cur_td != last_unlinked_td); /* Return to the event handler with xhci->lock re-acquired */ } +/* Watchdog timer function for when a stop endpoint command fails to complete. + * In this case, we assume the host controller is broken or dying or dead. The + * host may still be completing some other events, so we have to be careful to + * let the event ring handler and the URB dequeueing/enqueueing functions know + * through xhci->state. + * + * The timer may also fire if the host takes a very long time to respond to the + * command, and the stop endpoint command completion handler cannot delete the + * timer before the timer function is called. Another endpoint cancellation may + * sneak in before the timer function can grab the lock, and that may queue + * another stop endpoint command and add the timer back. So we cannot use a + * simple flag to say whether there is a pending stop endpoint command for a + * particular endpoint. + * + * Instead we use a combination of that flag and a counter for the number of + * pending stop endpoint commands. If the timer is the tail end of the last + * stop endpoint command, and the endpoint's command is still pending, we assume + * the host is dying. + */ +void xhci_stop_endpoint_command_watchdog(unsigned long arg) +{ + struct xhci_hcd *xhci; + struct xhci_virt_ep *ep; + struct xhci_virt_ep *temp_ep; + struct xhci_ring *ring; + struct xhci_td *cur_td; + int ret, i, j; + + ep = (struct xhci_virt_ep *) arg; + xhci = ep->xhci; + + spin_lock(&xhci->lock); + + ep->stop_cmds_pending--; + if (xhci->xhc_state & XHCI_STATE_DYING) { + xhci_dbg(xhci, "Stop EP timer ran, but another timer marked " + "xHCI as DYING, exiting.\n"); + spin_unlock(&xhci->lock); + return; + } + if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { + xhci_dbg(xhci, "Stop EP timer ran, but no command pending, " + "exiting.\n"); + spin_unlock(&xhci->lock); + return; + } + + xhci_warn(xhci, "xHCI host not responding to stop endpoint command.\n"); + xhci_warn(xhci, "Assuming host is dying, halting host.\n"); + /* Oops, HC is dead or dying or at least not responding to the stop + * endpoint command. + */ + xhci->xhc_state |= XHCI_STATE_DYING; + /* Disable interrupts from the host controller and start halting it */ + xhci_quiesce(xhci); + spin_unlock(&xhci->lock); + + ret = xhci_halt(xhci); + + spin_lock(&xhci->lock); + if (ret < 0) { + /* This is bad; the host is not responding to commands and it's + * not allowing itself to be halted. At least interrupts are + * disabled, so we can set HC_STATE_HALT and notify the + * USB core. But if we call usb_hc_died(), it will attempt to + * disconnect all device drivers under this host. Those + * disconnect() methods will wait for all URBs to be unlinked, + * so we must complete them. + */ + xhci_warn(xhci, "Non-responsive xHCI host is not halting.\n"); + xhci_warn(xhci, "Completing active URBs anyway.\n"); + /* We could turn all TDs on the rings to no-ops. This won't + * help if the host has cached part of the ring, and is slow if + * we want to preserve the cycle bit. Skip it and hope the host + * doesn't touch the memory. + */ + } + for (i = 0; i < MAX_HC_SLOTS; i++) { + if (!xhci->devs[i]) + continue; + for (j = 0; j < 31; j++) { + temp_ep = &xhci->devs[i]->eps[j]; + ring = temp_ep->ring; + if (!ring) + continue; + xhci_dbg(xhci, "Killing URBs for slot ID %u, " + "ep index %u\n", i, j); + while (!list_empty(&ring->td_list)) { + cur_td = list_first_entry(&ring->td_list, + struct xhci_td, + td_list); + list_del(&cur_td->td_list); + if (!list_empty(&cur_td->cancelled_td_list)) + list_del(&cur_td->cancelled_td_list); + xhci_giveback_urb_in_irq(xhci, cur_td, + -ESHUTDOWN, "killed"); + } + while (!list_empty(&temp_ep->cancelled_td_list)) { + cur_td = list_first_entry( + &temp_ep->cancelled_td_list, + struct xhci_td, + cancelled_td_list); + list_del(&cur_td->cancelled_td_list); + xhci_giveback_urb_in_irq(xhci, cur_td, + -ESHUTDOWN, "killed"); + } + } + } + spin_unlock(&xhci->lock); + xhci_to_hcd(xhci)->state = HC_STATE_HALT; + xhci_dbg(xhci, "Calling usb_hc_died()\n"); + usb_hc_died(xhci_to_hcd(xhci)); + xhci_dbg(xhci, "xHCI host controller is dead.\n"); +} + /* * When we get a completion for a Set Transfer Ring Dequeue Pointer command, * we need to clear the set deq pending flag in the endpoint ring state, so that @@ -1333,6 +1475,14 @@ void xhci_handle_event(struct xhci_hcd *xhci) default: xhci->error_bitmask |= 1 << 3; } + /* Any of the above functions may drop and re-acquire the lock, so check + * to make sure a watchdog timer didn't mark the host as non-responsive. + */ + if (xhci->xhc_state & XHCI_STATE_DYING) { + xhci_dbg(xhci, "xHCI host dying, returning from " + "event handler.\n"); + return; + } if (update_ptrs) { /* Update SW and HC event ring dequeue pointer */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index af3c5638526..c92f84154fb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -659,6 +659,10 @@ struct xhci_virt_ep { /* The TRB that was last reported in a stopped endpoint ring */ union xhci_trb *stopped_trb; struct xhci_td *stopped_td; + /* Watchdog timer for stop endpoint command to cancel URBs */ + struct timer_list stop_cmd_timer; + int stop_cmds_pending; + struct xhci_hcd *xhci; }; struct xhci_virt_device { @@ -1022,6 +1026,8 @@ struct xhci_scratchpad { #define ERST_ENTRIES 1 /* Poll every 60 seconds */ #define POLL_TIMEOUT 60 +/* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */ +#define XHCI_STOP_EP_CMD_TIMEOUT 5 /* XXX: Make these module parameters */ @@ -1083,6 +1089,21 @@ struct xhci_hcd { struct timer_list event_ring_timer; int zombie; #endif + /* Host controller watchdog timer structures */ + unsigned int xhc_state; +/* Host controller is dying - not responding to commands. "I'm not dead yet!" + * + * xHC interrupts have been disabled and a watchdog timer will (or has already) + * halt the xHCI host, and complete all URBs with an -ESHUTDOWN code. Any code + * that sees this status (other than the timer that set it) should stop touching + * hardware immediately. Interrupt handlers should return immediately when + * they see this status (any time they drop and re-acquire xhci->lock). + * xhci_urb_dequeue() should call usb_hcd_check_unlink_urb() and return without + * putting the TD on the canceled list, etc. + * + * There are no reports of xHCI host controllers that display this issue. + */ +#define XHCI_STATE_DYING (1 << 0) /* Statistics */ int noops_submitted; int noops_handled; @@ -1279,6 +1300,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state); +void xhci_stop_endpoint_command_watchdog(unsigned long arg); /* xHCI roothub code */ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, -- cgit v1.2.3-70-g09d2 From 3c67d899cde32099bfc484f6ccc9b90c2e0c9fc8 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 3 Nov 2009 13:06:40 -0800 Subject: USB: xhci: Remove unused HCD statistics code. CONFIG_USB_HCD_STAT was used in an abandoned patch to track host controller throughput statistics. Since CONFIG_USB_HCD_STAT will never be defined, remove code that can never run. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9541e88df68..aaed076bae3 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -526,9 +526,6 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, struct xhci_td *last_unlinked_td; struct xhci_dequeue_state deq_state; -#ifdef CONFIG_USB_HCD_STAT - ktime_t stop_time = ktime_get(); -#endif memset(&deq_state, 0, sizeof(deq_state)); slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); @@ -593,10 +590,6 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, list_del(&cur_td->cancelled_td_list); /* Clean up the cancelled URB */ -#ifdef CONFIG_USB_HCD_STAT - hcd_stat_update(xhci->tp_stat, cur_td->urb->actual_length, - ktime_sub(stop_time, cur_td->start_time)); -#endif /* Doesn't matter what we pass for status, since the core will * just overwrite it (because the URB has been unlinked). */ -- cgit v1.2.3-70-g09d2 From 6648f29d3be2972a74ef8e29aa5d425ab4f1fc48 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 9 Nov 2009 13:35:23 -0800 Subject: USB: xhci: Add tests for TRB address translation. It's not surprising that the transfer request buffer (TRB) physical to virtual address translation function has bugs in it, since I wrote most of it at 4am last October. Add a test suite to check the TRB math. This runs at memory initialization time, and causes the driver to fail to load if the TRB math fails. Please excuse the excessively long lines in the test vectors; they can't really be made shorter and still be readable. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 159 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci-ring.c | 3 +- drivers/usb/host/xhci.h | 3 + 3 files changed, 163 insertions(+), 2 deletions(-) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fd05247b7bb..711dc554e71 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -859,6 +859,163 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->page_shift = 0; } +static int xhci_test_trb_in_td(struct xhci_hcd *xhci, + struct xhci_segment *input_seg, + union xhci_trb *start_trb, + union xhci_trb *end_trb, + dma_addr_t input_dma, + struct xhci_segment *result_seg, + char *test_name, int test_number) +{ + unsigned long long start_dma; + unsigned long long end_dma; + struct xhci_segment *seg; + + start_dma = xhci_trb_virt_to_dma(input_seg, start_trb); + end_dma = xhci_trb_virt_to_dma(input_seg, end_trb); + + seg = trb_in_td(input_seg, start_trb, end_trb, input_dma); + if (seg != result_seg) { + xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n", + test_name, test_number); + xhci_warn(xhci, "Tested TRB math w/ seg %p and " + "input DMA 0x%llx\n", + input_seg, + (unsigned long long) input_dma); + xhci_warn(xhci, "starting TRB %p (0x%llx DMA), " + "ending TRB %p (0x%llx DMA)\n", + start_trb, start_dma, + end_trb, end_dma); + xhci_warn(xhci, "Expected seg %p, got seg %p\n", + result_seg, seg); + return -1; + } + return 0; +} + +/* TRB math checks for xhci_trb_in_td(), using the command and event rings. */ +static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci, gfp_t mem_flags) +{ + struct { + dma_addr_t input_dma; + struct xhci_segment *result_seg; + } simple_test_vector [] = { + /* A zeroed DMA field should fail */ + { 0, NULL }, + /* One TRB before the ring start should fail */ + { xhci->event_ring->first_seg->dma - 16, NULL }, + /* One byte before the ring start should fail */ + { xhci->event_ring->first_seg->dma - 1, NULL }, + /* Starting TRB should succeed */ + { xhci->event_ring->first_seg->dma, xhci->event_ring->first_seg }, + /* Ending TRB should succeed */ + { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16, + xhci->event_ring->first_seg }, + /* One byte after the ring end should fail */ + { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16 + 1, NULL }, + /* One TRB after the ring end should fail */ + { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT)*16, NULL }, + /* An address of all ones should fail */ + { (dma_addr_t) (~0), NULL }, + }; + struct { + struct xhci_segment *input_seg; + union xhci_trb *start_trb; + union xhci_trb *end_trb; + dma_addr_t input_dma; + struct xhci_segment *result_seg; + } complex_test_vector [] = { + /* Test feeding a valid DMA address from a different ring */ + { .input_seg = xhci->event_ring->first_seg, + .start_trb = xhci->event_ring->first_seg->trbs, + .end_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1], + .input_dma = xhci->cmd_ring->first_seg->dma, + .result_seg = NULL, + }, + /* Test feeding a valid end TRB from a different ring */ + { .input_seg = xhci->event_ring->first_seg, + .start_trb = xhci->event_ring->first_seg->trbs, + .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1], + .input_dma = xhci->cmd_ring->first_seg->dma, + .result_seg = NULL, + }, + /* Test feeding a valid start and end TRB from a different ring */ + { .input_seg = xhci->event_ring->first_seg, + .start_trb = xhci->cmd_ring->first_seg->trbs, + .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1], + .input_dma = xhci->cmd_ring->first_seg->dma, + .result_seg = NULL, + }, + /* TRB in this ring, but after this TD */ + { .input_seg = xhci->event_ring->first_seg, + .start_trb = &xhci->event_ring->first_seg->trbs[0], + .end_trb = &xhci->event_ring->first_seg->trbs[3], + .input_dma = xhci->event_ring->first_seg->dma + 4*16, + .result_seg = NULL, + }, + /* TRB in this ring, but before this TD */ + { .input_seg = xhci->event_ring->first_seg, + .start_trb = &xhci->event_ring->first_seg->trbs[3], + .end_trb = &xhci->event_ring->first_seg->trbs[6], + .input_dma = xhci->event_ring->first_seg->dma + 2*16, + .result_seg = NULL, + }, + /* TRB in this ring, but after this wrapped TD */ + { .input_seg = xhci->event_ring->first_seg, + .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3], + .end_trb = &xhci->event_ring->first_seg->trbs[1], + .input_dma = xhci->event_ring->first_seg->dma + 2*16, + .result_seg = NULL, + }, + /* TRB in this ring, but before this wrapped TD */ + { .input_seg = xhci->event_ring->first_seg, + .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3], + .end_trb = &xhci->event_ring->first_seg->trbs[1], + .input_dma = xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 4)*16, + .result_seg = NULL, + }, + /* TRB not in this ring, and we have a wrapped TD */ + { .input_seg = xhci->event_ring->first_seg, + .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3], + .end_trb = &xhci->event_ring->first_seg->trbs[1], + .input_dma = xhci->cmd_ring->first_seg->dma + 2*16, + .result_seg = NULL, + }, + }; + + unsigned int num_tests; + int i, ret; + + num_tests = sizeof(simple_test_vector) / sizeof(simple_test_vector[0]); + for (i = 0; i < num_tests; i++) { + ret = xhci_test_trb_in_td(xhci, + xhci->event_ring->first_seg, + xhci->event_ring->first_seg->trbs, + &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1], + simple_test_vector[i].input_dma, + simple_test_vector[i].result_seg, + "Simple", i); + if (ret < 0) + return ret; + } + + num_tests = sizeof(complex_test_vector) / sizeof(complex_test_vector[0]); + for (i = 0; i < num_tests; i++) { + ret = xhci_test_trb_in_td(xhci, + complex_test_vector[i].input_seg, + complex_test_vector[i].start_trb, + complex_test_vector[i].end_trb, + complex_test_vector[i].input_dma, + complex_test_vector[i].result_seg, + "Complex", i); + if (ret < 0) + return ret; + } + xhci_dbg(xhci, "TRB math tests passed.\n"); + return 0; +} + + int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) { dma_addr_t dma; @@ -962,6 +1119,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags); if (!xhci->event_ring) goto fail; + if (xhci_check_trb_in_td_math(xhci, flags) < 0) + goto fail; xhci->erst.entries = pci_alloc_consistent(to_pci_dev(dev), sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS, &dma); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index aaed076bae3..371ba4297d9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -987,8 +987,7 @@ static void handle_port_status(struct xhci_hcd *xhci, * TRB in this TD, this function returns that TRB's segment. Otherwise it * returns 0. */ -static struct xhci_segment *trb_in_td( - struct xhci_segment *start_seg, +struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, union xhci_trb *start_trb, union xhci_trb *end_trb, dma_addr_t suspect_dma) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c92f84154fb..3989aadcf67 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1268,6 +1268,9 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); /* xHCI ring, segment, TRB, and TD functions */ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); +struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, + union xhci_trb *start_trb, union xhci_trb *end_trb, + dma_addr_t suspect_dma); void xhci_ring_cmd_db(struct xhci_hcd *xhci); void *xhci_setup_one_noop(struct xhci_hcd *xhci); void xhci_handle_event(struct xhci_hcd *xhci); -- cgit v1.2.3-70-g09d2 From 04dd950d92f41155ed0cdf39b6bfbeea22eadb34 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 11 Nov 2009 10:28:30 -0800 Subject: USB: xhci: Set transfer descriptor size field correctly. The transfer descriptor (TD) is a series of transfer request buffers (TRBs) that describe the buffer pointer, length, and other characteristics. The xHCI controllers want to know an estimate of how long the TD is, for caching reasons. In each TRB, there is a "TD size" field that provides a rough estimate of the remaining buffers to be transmitted, including the buffer pointed to by that TRB. The TD size is 5 bits long, and contains the remaining size in bytes, right shifted by 10 bits. So a remaining TD size less than 1024 would get a zero in the TD size field, and a remaining size greater than 32767 would get 31 in the field. This patches fixes a bug in the TD_REMAINDER macro that is triggered when the URB has a scatter gather list with a size bigger than 32767 bytes. Not all host controllers pay attention to the TD size field, so the bug will not appear on all USB 3.0 hosts. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 27 ++++++++++++++++++++++++--- drivers/usb/host/xhci.h | 3 --- 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 371ba4297d9..d7e10ea8f08 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1699,6 +1699,21 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); } +/* + * The TD size is the number of bytes remaining in the TD (including this TRB), + * right shifted by 10. + * It must fit in bits 21:17, so it can't be bigger than 31. + */ +static u32 xhci_td_remainder(unsigned int remainder) +{ + u32 max = (1 << (21 - 17 + 1)) - 1; + + if ((remainder >> 10) >= max) + return max << 17; + else + return (remainder >> 10) << 17; +} + static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) { @@ -1756,6 +1771,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, do { u32 field = 0; u32 length_field = 0; + u32 remainder = 0; /* Don't change the cycle bit of the first TRB until later */ if (first_trb) @@ -1785,8 +1801,10 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), (unsigned int) addr + trb_buff_len); } + remainder = xhci_td_remainder(urb->transfer_buffer_length - + running_total) ; length_field = TRB_LEN(trb_buff_len) | - TD_REMAINDER(urb->transfer_buffer_length - running_total) | + remainder | TRB_INTR_TARGET(0); queue_trb(xhci, ep_ring, false, lower_32_bits(addr), @@ -1899,6 +1917,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Queue the first TRB, even if it's zero-length */ do { + u32 remainder = 0; field = 0; /* Don't change the cycle bit of the first TRB until later */ @@ -1917,8 +1936,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, td->last_trb = ep_ring->enqueue; field |= TRB_IOC; } + remainder = xhci_td_remainder(urb->transfer_buffer_length - + running_total); length_field = TRB_LEN(trb_buff_len) | - TD_REMAINDER(urb->transfer_buffer_length - running_total) | + remainder | TRB_INTR_TARGET(0); queue_trb(xhci, ep_ring, false, lower_32_bits(addr), @@ -2006,7 +2027,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* If there's data, queue data TRBs */ field = 0; length_field = TRB_LEN(urb->transfer_buffer_length) | - TD_REMAINDER(urb->transfer_buffer_length) | + xhci_td_remainder(urb->transfer_buffer_length) | TRB_INTR_TARGET(0); if (urb->transfer_buffer_length > 0) { if (setup->bRequestType & USB_DIR_IN) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3989aadcf67..bb8e6656cca 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -828,9 +828,6 @@ struct xhci_event_cmd { /* Normal TRB fields */ /* transfer_len bitmasks - bits 0:16 */ #define TRB_LEN(p) ((p) & 0x1ffff) -/* TD size - number of bytes remaining in the TD (including this TRB): - * bits 17 - 21. Shift the number of bytes by 10. */ -#define TD_REMAINDER(p) ((((p) >> 10) & 0x1f) << 17) /* Interrupter Target - which MSI-X vector to target the completion event at */ #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) -- cgit v1.2.3-70-g09d2 From ec74e4035a660013379882ec243de98dd6717b61 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 11 Nov 2009 10:28:36 -0800 Subject: USB: xhci: Return -EPROTO on a split transaction error. When the xHCI hardware says a transfer completed with a split transaction error, set the URB status to -EPROTO. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d7e10ea8f08..98437ffb065 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1139,6 +1139,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, xhci_warn(xhci, "WARN: TRB error on endpoint\n"); status = -EILSEQ; break; + case COMP_SPLIT_ERR: case COMP_TX_ERR: xhci_warn(xhci, "WARN: transfer error on endpoint\n"); status = -EPROTO; -- cgit v1.2.3-70-g09d2 From 5ad6a529c28db36010ec56c5ee8120addc712b51 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 11 Nov 2009 10:28:40 -0800 Subject: USB: xhci: Return success for vendor-specific info codes. An xHCI host controller manufacturer can choose to implement several vendor-specific informational completion codes. These are all to be treated like a successful transfer completion. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 98437ffb065..1549b9ceb91 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1153,6 +1153,16 @@ static int handle_tx_event(struct xhci_hcd *xhci, status = -ENOSR; break; default: + if (trb_comp_code >= 224 && trb_comp_code <= 255) { + /* Vendor defined "informational" completion code, + * treat as not-an-error. + */ + xhci_dbg(xhci, "Vendor defined info completion code %u\n", + trb_comp_code); + xhci_dbg(xhci, "Treating code as success.\n"); + status = 0; + break; + } xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n"); urb = NULL; goto cleanup; -- cgit v1.2.3-70-g09d2 From bcef3fd57019e5fc0c8df402b040a52826422a4b Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 11 Nov 2009 10:28:44 -0800 Subject: USB: xhci: Handle errors that cause endpoint halts. The xHCI 0.95 and 0.96 specification defines several transfer buffer request completion codes that indicate a USB transaction error occurred. When a stall, babble, transaction, or split transaction error completion code is set, the xHCI has halted that endpoint ring. Software must issue a Reset Endpoint command and a Set Transfer Ring Dequeue Pointer command to clean up the halted ring. The USB device driver is supposed to call into usb_reset_endpoint() when an endpoint stalls. That calls into the xHCI driver to issue the proper commands. However, drivers don't call that function for the other errors that cause the xHC to halt the endpoint ring. If a babble, transaction, or split transaction error occurs, check if the endpoint context reports a halted condition, and clean up the endpoint ring if it does. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 79 +++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 19 deletions(-) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 1549b9ceb91..2e346334a36 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1037,6 +1037,45 @@ struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, return 0; } +static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + struct xhci_td *td, union xhci_trb *event_trb) +{ + struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; + ep->ep_state |= EP_HALTED; + ep->stopped_td = td; + ep->stopped_trb = event_trb; + xhci_queue_reset_ep(xhci, slot_id, ep_index); + xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index); + xhci_ring_cmd_db(xhci); +} + +/* Check if an error has halted the endpoint ring. The class driver will + * cleanup the halt for a non-default control endpoint if we indicate a stall. + * However, a babble and other errors also halt the endpoint ring, and the class + * driver won't clear the halt in that case, so we need to issue a Set Transfer + * Ring Dequeue Pointer command manually. + */ +static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci, + struct xhci_ep_ctx *ep_ctx, + unsigned int trb_comp_code) +{ + /* TRB completion codes that may require a manual halt cleanup */ + if (trb_comp_code == COMP_TX_ERR || + trb_comp_code == COMP_BABBLE || + trb_comp_code == COMP_SPLIT_ERR) + /* The 0.96 spec says a babbling control endpoint + * is not halted. The 0.96 spec says it is. Some HW + * claims to be 0.95 compliant, but it halts the control + * endpoint anyway. Check if a babble halted the + * endpoint. + */ + if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_HALTED) + return 1; + + return 0; +} + /* * If this function returns an error condition, it means it got a Transfer * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address. @@ -1191,15 +1230,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, else status = 0; break; - case COMP_BABBLE: - /* The 0.96 spec says a babbling control endpoint - * is not halted. The 0.96 spec says it is. Some HW - * claims to be 0.95 compliant, but it halts the control - * endpoint anyway. Check if a babble halted the - * endpoint. - */ - if (ep_ctx->ep_info != EP_STATE_HALTED) + + default: + if (!xhci_requires_manual_halt_cleanup(xhci, + ep_ctx, trb_comp_code)) break; + xhci_dbg(xhci, "TRB error code %u, " + "halted endpoint index = %u\n", + trb_comp_code, ep_index); /* else fall through */ case COMP_STALL: /* Did we transfer part of the data (middle) phase? */ @@ -1211,15 +1249,9 @@ static int handle_tx_event(struct xhci_hcd *xhci, else td->urb->actual_length = 0; - ep->stopped_td = td; - ep->stopped_trb = event_trb; - xhci_queue_reset_ep(xhci, slot_id, ep_index); - xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index); - xhci_ring_cmd_db(xhci); + xhci_cleanup_halted_endpoint(xhci, + slot_id, ep_index, td, event_trb); goto td_cleanup; - default: - /* Others already handled above */ - break; } /* * Did we transfer any data, despite the errors that might have @@ -1357,16 +1389,25 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep->stopped_td = td; ep->stopped_trb = event_trb; } else { - if (trb_comp_code == COMP_STALL || - trb_comp_code == COMP_BABBLE) { + if (trb_comp_code == COMP_STALL) { /* The transfer is completed from the driver's * perspective, but we need to issue a set dequeue * command for this stalled endpoint to move the dequeue * pointer past the TD. We can't do that here because - * the halt condition must be cleared first. + * the halt condition must be cleared first. Let the + * USB class driver clear the stall later. */ ep->stopped_td = td; ep->stopped_trb = event_trb; + } else if (xhci_requires_manual_halt_cleanup(xhci, + ep_ctx, trb_comp_code)) { + /* Other types of errors halt the endpoint, but the + * class driver doesn't call usb_reset_endpoint() unless + * the error is -EPIPE. Clear the halted status in the + * xHCI hardware manually. + */ + xhci_cleanup_halted_endpoint(xhci, + slot_id, ep_index, td, event_trb); } else { /* Update ring dequeue pointer */ while (ep_ring->dequeue != td->last_trb) -- cgit v1.2.3-70-g09d2 From 06df572909080786e128eabdb2e39a12bce239de Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 3 Dec 2009 09:44:31 -0800 Subject: USB: xhci: Fix command completion after a drop endpoint. The xHCI driver issues a Configure Endpoint command for two reasons: - a new configuration or alternate interface setting is selected - a quirky Fresco Logic prototype requires the command after a Reset Endpoint command. The xHCI driver only waits on the command in the first case. When a configure endpoint command completes, the driver needs to know why the command was generated. When the driver only supported selecting an initial configuration, the check was simple. Unfortunately that check doesn't work now that the driver supports alternate interfaces. If an endpoint must be dropped (because it's not in the new alternate setting) and no new endpoints are added, the math involving xhci_last_valid_endpoint() will assign -1 to an unsigned integer and cause an out-of-bounds array access. Move the check for the quirky hardware sooner and avoid the bad array access. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers/usb/host/xhci-ring.c') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 2e346334a36..ee7bc7ecbc5 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -903,28 +903,32 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, virt_dev->in_ctx); /* Input ctx add_flags are the endpoint index plus one */ ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1; - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; - if (!ep_ring) { - /* This must have been an initial configure endpoint */ - xhci->devs[slot_id]->cmd_status = - GET_COMP_CODE(event->status); - complete(&xhci->devs[slot_id]->cmd_completion); - break; - } - ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; - xhci_dbg(xhci, "Completed config ep cmd - last ep index = %d, " - "state = %d\n", ep_index, ep_state); + /* A usb_set_interface() call directly after clearing a halted + * condition may race on this quirky hardware. + * Not worth worrying about, since this is prototype hardware. + */ if (xhci->quirks & XHCI_RESET_EP_QUIRK && - ep_state & EP_HALTED) { + ep_index != (unsigned int) -1 && + ctrl_ctx->add_flags - SLOT_FLAG == + ctrl_ctx->drop_flags) { + ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; + ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; + if (!(ep_state & EP_HALTED)) + goto bandwidth_change; + xhci_dbg(xhci, "Completed config ep cmd - " + "last ep index = %d, state = %d\n", + ep_index, ep_state); /* Clear our internal halted state and restart ring */ xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; ring_ep_doorbell(xhci, slot_id, ep_index); - } else { - xhci->devs[slot_id]->cmd_status = - GET_COMP_CODE(event->status); - complete(&xhci->devs[slot_id]->cmd_completion); + break; } +bandwidth_change: + xhci_dbg(xhci, "Completed config ep cmd\n"); + xhci->devs[slot_id]->cmd_status = + GET_COMP_CODE(event->status); + complete(&xhci->devs[slot_id]->cmd_completion); break; case TRB_TYPE(TRB_EVAL_CONTEXT): virt_dev = xhci->devs[slot_id]; -- cgit v1.2.3-70-g09d2