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 483b5f8cb9510efc437379d4c9c0f2cd6d881b79..a4d429ce02a221422500b67b3ade616cf8bac9cb 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 c79d33676672daca6047ebead9d8afb70a49007d..012d7f4c29015eec1c7ba071e17d2ebfdd06c566 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 0e5aa8751c0547cdba1a89752f3cfd81f957ca67..48d2d40a53bda8e060b577a15c18a587db46ef33 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 0ba6c1cc90b4b6e511c49c50b51580cab4321cc8..49a41c7890c8aacb4f6e91e1d29a75a25ededfb0 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.
                 */