usb: ehci: add rockchip relinquishing port quirk support
[firefly-linux-kernel-4.4.55.git] / drivers / usb / host / xhci.c
index a8b3c0fc11fb5fcf05688bb0382ae27676d79f7e..6ae47f7927a2dd8061e447a852fe45e7f23bce98 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/dmi.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/quirks.h>
 
 #include "xhci.h"
 #include "xhci-trace.h"
@@ -741,6 +742,15 @@ void xhci_shutdown(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
+       if (!hcd->rh_registered)
+               return;
+
+       /* Don't poll the roothubs on shutdown */
+       clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+       del_timer_sync(&hcd->rh_timer);
+       clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+       del_timer_sync(&xhci->shared_hcd->rh_timer);
+
        if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
                usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
 
@@ -1549,7 +1559,8 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        if (ret || !urb->hcpriv)
                goto done;
        temp = readl(&xhci->op_regs->status);
-       if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
+       if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED) ||
+           (xhci->xhc_state & XHCI_STATE_REMOVING)) {
                xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
                                "HW died, freeing TD.");
                urb_priv = urb->hcpriv;
@@ -1569,19 +1580,6 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                xhci_urb_free_priv(urb_priv);
                return ret;
        }
-       if ((xhci->xhc_state & XHCI_STATE_DYING) ||
-                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
-               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
-                               "Ep 0x%x: URB %p to be canceled on "
-                               "non-responsive xHCI host.",
-                               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;
-       }
 
        ep_index = xhci_get_endpoint_index(&urb->ep->desc);
        ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
@@ -3652,7 +3650,8 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
        /* Don't disable the slot if the host controller is dead. */
        state = readl(&xhci->op_regs->status);
        if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
-                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
+                       (xhci->xhc_state & XHCI_STATE_HALTED) ||
+                       (xhci->xhc_state & XHCI_STATE_REMOVING)) {
                xhci_free_virt_device(xhci, udev->slot_id);
                spin_unlock_irqrestore(&xhci->lock, flags);
                kfree(command);
@@ -4894,6 +4893,10 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                /* xHCI private pointer was set in xhci_pci_probe for the second
                 * registered roothub.
                 */
+               if (xhci->quirks & XHCI_DIS_AUTOSUSPEND)
+                       xhci->shared_hcd->self.root_hub->quirks |=
+                               USB_QUIRK_AUTO_SUSPEND;
+
                return 0;
        }
 
@@ -4914,7 +4917,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
        xhci_print_registers(xhci);
 
-       xhci->quirks = quirks;
+       xhci->quirks |= quirks;
 
        get_quirks(dev, xhci);