xhci: check xhci hardware for USB 3.1 support
authorMathias Nyman <mathias.nyman@linux.intel.com>
Thu, 1 Oct 2015 15:40:38 +0000 (18:40 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 4 Oct 2015 09:34:17 +0000 (10:34 +0100)
Set the controller speed to HCD_USB31 to if host hardware supports USB 3.1

For PCI xhci controllers the USB 3.1 support is checked from SBRN bits in
pci config space. Platform controllers will need to set xhci->sbrn == 0x31
to indicate USB 3.1 support before calling xhci_gen_setup().

Also make sure xhci driver works correctly with speed set to HCD_USB31

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c

index 483b5f8..a4d429c 100644 (file)
@@ -262,7 +262,7 @@ static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
                struct usb_hub_descriptor *desc)
 {
 
-       if (hcd->speed == HCD_USB3)
+       if (hcd->speed >= HCD_USB3)
                xhci_usb3_hub_descriptor(hcd, xhci, desc);
        else
                xhci_usb2_hub_descriptor(hcd, xhci, desc);
@@ -351,7 +351,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
                if (!xhci->devs[i])
                        continue;
                speed = xhci->devs[i]->udev->speed;
-               if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3))
+               if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3))
                                && xhci->devs[i]->fake_port == port) {
                        slot_id = i;
                        break;
@@ -440,7 +440,7 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
                u16 wIndex, __le32 __iomem *addr, u32 port_status)
 {
        /* Don't allow the USB core to disable SuperSpeed ports. */
-       if (hcd->speed == HCD_USB3) {
+       if (hcd->speed >= HCD_USB3) {
                xhci_dbg(xhci, "Ignoring request to disable "
                                "SuperSpeed port.\n");
                return;
@@ -508,7 +508,7 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
        int max_ports;
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
-       if (hcd->speed == HCD_USB3) {
+       if (hcd->speed >= HCD_USB3) {
                max_ports = xhci->num_usb3_ports;
                *port_array = xhci->usb3_ports;
        } else {
@@ -691,7 +691,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
        if ((raw_port_status & PORT_RC))
                status |= USB_PORT_STAT_C_RESET << 16;
        /* USB3.0 only */
-       if (hcd->speed == HCD_USB3) {
+       if (hcd->speed >= HCD_USB3) {
                /* Port link change with port in resume state should not be
                 * reported to usbcore, as this is an internal state to be
                 * handled by xhci driver. Reporting PLC to usbcore may
@@ -707,7 +707,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                        status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
        }
 
-       if (hcd->speed != HCD_USB3) {
+       if (hcd->speed < HCD_USB3) {
                if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3
                                && (raw_port_status & PORT_POWER))
                        status |= USB_PORT_STAT_SUSPEND;
@@ -770,7 +770,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                        && (raw_port_status & PORT_POWER)
                        && (bus_state->suspended_ports & (1 << wIndex))) {
                bus_state->suspended_ports &= ~(1 << wIndex);
-               if (hcd->speed != HCD_USB3)
+               if (hcd->speed < HCD_USB3)
                        bus_state->port_c_suspend |= 1 << wIndex;
        }
        if (raw_port_status & PORT_CONNECT) {
@@ -784,13 +784,13 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
        if (raw_port_status & PORT_RESET)
                status |= USB_PORT_STAT_RESET;
        if (raw_port_status & PORT_POWER) {
-               if (hcd->speed == HCD_USB3)
+               if (hcd->speed >= HCD_USB3)
                        status |= USB_SS_PORT_STAT_POWER;
                else
                        status |= USB_PORT_STAT_POWER;
        }
        /* Update Port Link State */
-       if (hcd->speed == HCD_USB3) {
+       if (hcd->speed >= HCD_USB3) {
                xhci_hub_report_usb3_link_state(xhci, &status, raw_port_status);
                /*
                 * Verify if all USB3 Ports Have entered U0 already.
@@ -835,7 +835,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                 * descriptor for the USB 3.0 roothub.  If not, we stall the
                 * endpoint, like external hubs do.
                 */
-               if (hcd->speed == HCD_USB3 &&
+               if (hcd->speed >= HCD_USB3 &&
                                (wLength < USB_DT_SS_HUB_SIZE ||
                                 wValue != (USB_DT_SS_HUB << 8))) {
                        xhci_dbg(xhci, "Wrong hub descriptor type for "
@@ -1040,7 +1040,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        temp = readl(port_array[wIndex]);
                        break;
                case USB_PORT_FEAT_U1_TIMEOUT:
-                       if (hcd->speed != HCD_USB3)
+                       if (hcd->speed < HCD_USB3)
                                goto error;
                        temp = readl(port_array[wIndex] + PORTPMSC);
                        temp &= ~PORT_U1_TIMEOUT_MASK;
@@ -1048,7 +1048,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        writel(temp, port_array[wIndex] + PORTPMSC);
                        break;
                case USB_PORT_FEAT_U2_TIMEOUT:
-                       if (hcd->speed != HCD_USB3)
+                       if (hcd->speed < HCD_USB3)
                                goto error;
                        temp = readl(port_array[wIndex] + PORTPMSC);
                        temp &= ~PORT_U2_TIMEOUT_MASK;
index c79d336..012d7f4 100644 (file)
@@ -200,15 +200,17 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
        int                     retval;
 
+       xhci = hcd_to_xhci(hcd);
+       if (!xhci->sbrn)
+               pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
+
        retval = xhci_gen_setup(hcd, xhci_pci_quirks);
        if (retval)
                return retval;
 
-       xhci = hcd_to_xhci(hcd);
        if (!usb_hcd_is_primary_hcd(hcd))
                return 0;
 
-       pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
        xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
 
        /* Find any debug ports */
index 0e5aa87..48d2d40 100644 (file)
@@ -1453,7 +1453,7 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
                 * 1.1 ports are under the USB 2.0 hub.  If the port speed
                 * matches the device speed, it's a similar speed port.
                 */
-               if ((port_speed == 0x03) == (hcd->speed == HCD_USB3))
+               if ((port_speed == 0x03) == (hcd->speed >= HCD_USB3))
                        num_similar_speed_ports++;
        }
        return num_similar_speed_ports;
@@ -1515,7 +1515,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
 
        /* Find the right roothub. */
        hcd = xhci_to_hcd(xhci);
-       if ((major_revision == 0x03) != (hcd->speed == HCD_USB3))
+       if ((major_revision == 0x03) != (hcd->speed >= HCD_USB3))
                hcd = xhci->shared_hcd;
 
        if (major_revision == 0) {
@@ -1541,7 +1541,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
         * correct bus_state structure.
         */
        bus_state = &xhci->bus_state[hcd_index(hcd)];
-       if (hcd->speed == HCD_USB3)
+       if (hcd->speed >= HCD_USB3)
                port_array = xhci->usb3_ports;
        else
                port_array = xhci->usb2_ports;
@@ -1555,7 +1555,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
                usb_hcd_resume_root_hub(hcd);
        }
 
-       if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
+       if (hcd->speed >= HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
                bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
 
        if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
@@ -1633,7 +1633,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
                goto cleanup;
        }
 
-       if (hcd->speed != HCD_USB3)
+       if (hcd->speed < HCD_USB3)
                xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
                                        PORT_PLC);
 
index 0ba6c1c..49a41c7 100644 (file)
@@ -3973,7 +3973,7 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
        __le32 __iomem *addr;
        int raw_port;
 
-       if (hcd->speed != HCD_USB3)
+       if (hcd->speed < HCD_USB3)
                addr = xhci->usb2_ports[port1 - 1];
        else
                addr = xhci->usb3_ports[port1 - 1];
@@ -4124,7 +4124,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
        int             hird, exit_latency;
        int             ret;
 
-       if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
+       if (hcd->speed >= HCD_USB3 || !xhci->hw_lpm_support ||
                        !udev->lpm_capable)
                return -EPERM;
 
@@ -4241,7 +4241,7 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        int             portnum = udev->portnum - 1;
 
-       if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
+       if (hcd->speed >= HCD_USB3 || !xhci->sw_lpm_support ||
                        !udev->lpm_capable)
                return 0;
 
@@ -4841,8 +4841,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        /* XHCI controllers don't stop the ep queue on short packets :| */
        hcd->self.no_stop_on_short = 1;
 
+       xhci = hcd_to_xhci(hcd);
+
        if (usb_hcd_is_primary_hcd(hcd)) {
-               xhci = hcd_to_xhci(hcd);
                xhci->main_hcd = hcd;
                /* Mark the first roothub as being USB 2.0.
                 * The xHCI driver will register the USB 3.0 roothub.
@@ -4856,6 +4857,10 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                 */
                hcd->has_tt = 1;
        } else {
+               if (xhci->sbrn == 0x31) {
+                       xhci_info(xhci, "Host supports USB 3.1 Enhanced SuperSpeed\n");
+                       hcd->speed = HCD_USB31;
+               }
                /* xHCI private pointer was set in xhci_pci_probe for the second
                 * registered roothub.
                 */