xhci: check xhci hardware for USB 3.1 support

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>
This commit is contained in:
Mathias Nyman 2015-10-01 18:40:38 +03:00 committed by Greg Kroah-Hartman
parent 7117522520
commit b50107bb83
4 changed files with 30 additions and 23 deletions

View File

@ -262,7 +262,7 @@ static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
struct usb_hub_descriptor *desc) struct usb_hub_descriptor *desc)
{ {
if (hcd->speed == HCD_USB3) if (hcd->speed >= HCD_USB3)
xhci_usb3_hub_descriptor(hcd, xhci, desc); xhci_usb3_hub_descriptor(hcd, xhci, desc);
else else
xhci_usb2_hub_descriptor(hcd, xhci, desc); 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]) if (!xhci->devs[i])
continue; continue;
speed = xhci->devs[i]->udev->speed; 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) { && xhci->devs[i]->fake_port == port) {
slot_id = i; slot_id = i;
break; 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) u16 wIndex, __le32 __iomem *addr, u32 port_status)
{ {
/* Don't allow the USB core to disable SuperSpeed ports. */ /* 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 " xhci_dbg(xhci, "Ignoring request to disable "
"SuperSpeed port.\n"); "SuperSpeed port.\n");
return; return;
@ -508,7 +508,7 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
int max_ports; int max_ports;
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
if (hcd->speed == HCD_USB3) { if (hcd->speed >= HCD_USB3) {
max_ports = xhci->num_usb3_ports; max_ports = xhci->num_usb3_ports;
*port_array = xhci->usb3_ports; *port_array = xhci->usb3_ports;
} else { } else {
@ -691,7 +691,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
if ((raw_port_status & PORT_RC)) if ((raw_port_status & PORT_RC))
status |= USB_PORT_STAT_C_RESET << 16; status |= USB_PORT_STAT_C_RESET << 16;
/* USB3.0 only */ /* USB3.0 only */
if (hcd->speed == HCD_USB3) { if (hcd->speed >= HCD_USB3) {
/* Port link change with port in resume state should not be /* Port link change with port in resume state should not be
* reported to usbcore, as this is an internal state to be * reported to usbcore, as this is an internal state to be
* handled by xhci driver. Reporting PLC to usbcore may * 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; 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 if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3
&& (raw_port_status & PORT_POWER)) && (raw_port_status & PORT_POWER))
status |= USB_PORT_STAT_SUSPEND; status |= USB_PORT_STAT_SUSPEND;
@ -770,7 +770,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
&& (raw_port_status & PORT_POWER) && (raw_port_status & PORT_POWER)
&& (bus_state->suspended_ports & (1 << wIndex))) { && (bus_state->suspended_ports & (1 << wIndex))) {
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; bus_state->port_c_suspend |= 1 << wIndex;
} }
if (raw_port_status & PORT_CONNECT) { 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) if (raw_port_status & PORT_RESET)
status |= USB_PORT_STAT_RESET; status |= USB_PORT_STAT_RESET;
if (raw_port_status & PORT_POWER) { if (raw_port_status & PORT_POWER) {
if (hcd->speed == HCD_USB3) if (hcd->speed >= HCD_USB3)
status |= USB_SS_PORT_STAT_POWER; status |= USB_SS_PORT_STAT_POWER;
else else
status |= USB_PORT_STAT_POWER; status |= USB_PORT_STAT_POWER;
} }
/* Update Port Link State */ /* 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); xhci_hub_report_usb3_link_state(xhci, &status, raw_port_status);
/* /*
* Verify if all USB3 Ports Have entered U0 already. * 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 * descriptor for the USB 3.0 roothub. If not, we stall the
* endpoint, like external hubs do. * endpoint, like external hubs do.
*/ */
if (hcd->speed == HCD_USB3 && if (hcd->speed >= HCD_USB3 &&
(wLength < USB_DT_SS_HUB_SIZE || (wLength < USB_DT_SS_HUB_SIZE ||
wValue != (USB_DT_SS_HUB << 8))) { wValue != (USB_DT_SS_HUB << 8))) {
xhci_dbg(xhci, "Wrong hub descriptor type for " 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]); temp = readl(port_array[wIndex]);
break; break;
case USB_PORT_FEAT_U1_TIMEOUT: case USB_PORT_FEAT_U1_TIMEOUT:
if (hcd->speed != HCD_USB3) if (hcd->speed < HCD_USB3)
goto error; goto error;
temp = readl(port_array[wIndex] + PORTPMSC); temp = readl(port_array[wIndex] + PORTPMSC);
temp &= ~PORT_U1_TIMEOUT_MASK; 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); writel(temp, port_array[wIndex] + PORTPMSC);
break; break;
case USB_PORT_FEAT_U2_TIMEOUT: case USB_PORT_FEAT_U2_TIMEOUT:
if (hcd->speed != HCD_USB3) if (hcd->speed < HCD_USB3)
goto error; goto error;
temp = readl(port_array[wIndex] + PORTPMSC); temp = readl(port_array[wIndex] + PORTPMSC);
temp &= ~PORT_U2_TIMEOUT_MASK; temp &= ~PORT_U2_TIMEOUT_MASK;

View File

@ -200,15 +200,17 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
struct pci_dev *pdev = to_pci_dev(hcd->self.controller); struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
int retval; 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); retval = xhci_gen_setup(hcd, xhci_pci_quirks);
if (retval) if (retval)
return retval; return retval;
xhci = hcd_to_xhci(hcd);
if (!usb_hcd_is_primary_hcd(hcd)) if (!usb_hcd_is_primary_hcd(hcd))
return 0; return 0;
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
/* Find any debug ports */ /* Find any debug ports */

View 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 * 1.1 ports are under the USB 2.0 hub. If the port speed
* matches the device speed, it's a similar speed port. * 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++; num_similar_speed_ports++;
} }
return 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. */ /* Find the right roothub. */
hcd = xhci_to_hcd(xhci); 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; hcd = xhci->shared_hcd;
if (major_revision == 0) { if (major_revision == 0) {
@ -1541,7 +1541,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
* correct bus_state structure. * correct bus_state structure.
*/ */
bus_state = &xhci->bus_state[hcd_index(hcd)]; bus_state = &xhci->bus_state[hcd_index(hcd)];
if (hcd->speed == HCD_USB3) if (hcd->speed >= HCD_USB3)
port_array = xhci->usb3_ports; port_array = xhci->usb3_ports;
else else
port_array = xhci->usb2_ports; port_array = xhci->usb2_ports;
@ -1555,7 +1555,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
usb_hcd_resume_root_hub(hcd); 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); bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) { 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; goto cleanup;
} }
if (hcd->speed != HCD_USB3) if (hcd->speed < HCD_USB3)
xhci_test_and_clear_bit(xhci, port_array, faked_port_index, xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
PORT_PLC); PORT_PLC);

View File

@ -3973,7 +3973,7 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
__le32 __iomem *addr; __le32 __iomem *addr;
int raw_port; int raw_port;
if (hcd->speed != HCD_USB3) if (hcd->speed < HCD_USB3)
addr = xhci->usb2_ports[port1 - 1]; addr = xhci->usb2_ports[port1 - 1];
else else
addr = xhci->usb3_ports[port1 - 1]; 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 hird, exit_latency;
int ret; int ret;
if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support || if (hcd->speed >= HCD_USB3 || !xhci->hw_lpm_support ||
!udev->lpm_capable) !udev->lpm_capable)
return -EPERM; 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); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int portnum = udev->portnum - 1; 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) !udev->lpm_capable)
return 0; 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 :| */ /* XHCI controllers don't stop the ep queue on short packets :| */
hcd->self.no_stop_on_short = 1; hcd->self.no_stop_on_short = 1;
xhci = hcd_to_xhci(hcd);
if (usb_hcd_is_primary_hcd(hcd)) { if (usb_hcd_is_primary_hcd(hcd)) {
xhci = hcd_to_xhci(hcd);
xhci->main_hcd = hcd; xhci->main_hcd = hcd;
/* Mark the first roothub as being USB 2.0. /* Mark the first roothub as being USB 2.0.
* The xHCI driver will register the USB 3.0 roothub. * 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; hcd->has_tt = 1;
} else { } 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 /* xHCI private pointer was set in xhci_pci_probe for the second
* registered roothub. * registered roothub.
*/ */