diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r-- | drivers/usb/host/xhci.c | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c502c2277aeb..1e6d7579709e 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -146,7 +146,8 @@ static int xhci_start(struct xhci_hcd *xhci) "waited %u microseconds.\n", XHCI_MAX_HALT_USEC); if (!ret) - xhci->xhc_state &= ~XHCI_STATE_HALTED; + xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING); + return ret; } @@ -174,6 +175,16 @@ int xhci_reset(struct xhci_hcd *xhci) command |= CMD_RESET; writel(command, &xhci->op_regs->command); + /* Existing Intel xHCI controllers require a delay of 1 mS, + * after setting the CMD_RESET bit, and before accessing any + * HC registers. This allows the HC to complete the + * reset operation and be ready for HC register access. + * Without this delay, the subsequent HC register access, + * may result in a system hang very rarely. + */ + if (xhci->quirks & XHCI_INTEL_HOST) + udelay(1000); + ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, 10 * 1000 * 1000); if (ret) @@ -683,8 +694,11 @@ void xhci_stop(struct usb_hcd *hcd) u32 temp; struct xhci_hcd *xhci = hcd_to_xhci(hcd); + mutex_lock(&xhci->mutex); + if (!usb_hcd_is_primary_hcd(hcd)) { xhci_only_stop_hcd(xhci->shared_hcd); + mutex_unlock(&xhci->mutex); return; } @@ -723,6 +737,7 @@ void xhci_stop(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_stop completed - status = %x", readl(&xhci->op_regs->status)); + mutex_unlock(&xhci->mutex); } /* @@ -1340,6 +1355,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) if (usb_endpoint_xfer_isoc(&urb->ep->desc)) size = urb->number_of_packets; + else if (usb_endpoint_is_bulk_out(&urb->ep->desc) && + urb->transfer_buffer_length > 0 && + urb->transfer_flags & URB_ZERO_PACKET && + !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc))) + size = 2; else size = 1; @@ -3790,6 +3810,9 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, mutex_lock(&xhci->mutex); + if (xhci->xhc_state) /* dying or halted */ + goto out; + if (!udev->slot_id) { xhci_dbg_trace(xhci, trace_xhci_dbg_address, "Bad Slot ID %d", udev->slot_id); |