diff options
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 304 |
1 files changed, 151 insertions, 153 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 0054d02239e2..04cc3d681495 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -10,8 +10,9 @@ #include <linux/slab.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/bitfield.h> +#include <linux/pci.h> #include "xhci.h" #include "xhci-trace.h" @@ -109,7 +110,7 @@ static int xhci_create_usb3x_bos_desc(struct xhci_hcd *xhci, char *buf, ss_cap->bU2DevExitLat = 0; /* set later */ reg = readl(&xhci->cap_regs->hcc_params); - if (HCC_LTC(reg)) + if (reg & HCC_LTC) ss_cap->bmAttributes |= USB_LTM_SUPPORT; if ((xhci->quirks & XHCI_LPM_SUPPORT)) { @@ -262,7 +263,7 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, desc->bNbrPorts = ports; temp = 0; /* Bits 1:0 - support per-port power switching, or power always on */ - if (HCC_PPC(xhci->hcc_params)) + if (xhci->hcc_params & HCC_PPC) temp |= HUB_CHAR_INDV_PORT_LPSM; else temp |= HUB_CHAR_NO_LPSM; @@ -298,7 +299,7 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, */ memset(port_removable, 0, sizeof(port_removable)); for (i = 0; i < ports; i++) { - portsc = readl(rhub->ports[i]->addr); + portsc = xhci_portsc_readl(rhub->ports[i]); /* If a device is removable, PORTSC reports a 0, same as in the * hub descriptor DeviceRemovable bits. */ @@ -355,7 +356,7 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, port_removable = 0; /* bit 0 is reserved, bit 1 is for port 1, etc. */ for (i = 0; i < ports; i++) { - portsc = readl(rhub->ports[i]->addr); + portsc = xhci_portsc_readl(rhub->ports[i]); if (portsc & PORT_DEV_REMOVE) port_removable |= 1 << (i + 1); } @@ -448,38 +449,6 @@ u32 xhci_port_state_to_neutral(u32 state) } EXPORT_SYMBOL_GPL(xhci_port_state_to_neutral); -/** - * xhci_find_slot_id_by_port() - Find slot id of a usb device on a roothub port - * @hcd: pointer to hcd of the roothub - * @xhci: pointer to xhci structure - * @port: one-based port number of the port in this roothub. - * - * Return: Slot id of the usb device connected to the root port, 0 if not found - */ - -int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, - u16 port) -{ - int slot_id; - int i; - enum usb_device_speed speed; - - slot_id = 0; - for (i = 0; i < MAX_HC_SLOTS; i++) { - if (!xhci->devs[i] || !xhci->devs[i]->udev) - continue; - speed = xhci->devs[i]->udev->speed; - if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3)) - && xhci->devs[i]->fake_port == port) { - slot_id = i; - break; - } - } - - return slot_id; -} -EXPORT_SYMBOL_GPL(xhci_find_slot_id_by_port); - /* * Stop device * It issues stop endpoint command for EP 0 to 30. And wait the last command @@ -597,19 +566,19 @@ static void xhci_disable_port(struct xhci_hcd *xhci, struct xhci_port *port) return; } - portsc = readl(port->addr); + portsc = xhci_portsc_readl(port); portsc = xhci_port_state_to_neutral(portsc); /* Write 1 to disable the port */ - writel(portsc | PORT_PE, port->addr); + xhci_portsc_writel(port, portsc | PORT_PE); - portsc = readl(port->addr); + portsc = xhci_portsc_readl(port); xhci_dbg(xhci, "disable port %d-%d, portsc: 0x%x\n", hcd->self.busnum, port->hcd_portnum + 1, portsc); } static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, - u16 wIndex, __le32 __iomem *addr, u32 port_status) + u16 wIndex, struct xhci_port *port, u32 port_status) { char *port_change_bit; u32 status; @@ -652,8 +621,8 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, return; } /* Change bits are all write 1 to clear */ - writel(port_status | status, addr); - port_status = readl(addr); + xhci_portsc_writel(port, port_status | status); + port_status = xhci_portsc_readl(port); xhci_dbg(xhci, "clear port%d %s change, portsc: 0x%x\n", wIndex + 1, port_change_bit, port_status); @@ -681,7 +650,7 @@ static void xhci_set_port_power(struct xhci_hcd *xhci, struct xhci_port *port, u32 temp; hcd = port->rhub->hcd; - temp = readl(port->addr); + temp = xhci_portsc_readl(port); xhci_dbg(xhci, "set port power %d-%d %s, portsc: 0x%x\n", hcd->self.busnum, port->hcd_portnum + 1, on ? "ON" : "OFF", temp); @@ -690,11 +659,11 @@ static void xhci_set_port_power(struct xhci_hcd *xhci, struct xhci_port *port, if (on) { /* Power on */ - writel(temp | PORT_POWER, port->addr); - readl(port->addr); + xhci_portsc_writel(port, temp | PORT_POWER); + xhci_portsc_readl(port); } else { /* Power off */ - writel(temp & ~PORT_POWER, port->addr); + xhci_portsc_writel(port, temp & ~PORT_POWER); } spin_unlock_irqrestore(&xhci->lock, *flags); @@ -714,9 +683,9 @@ static void xhci_port_set_test_mode(struct xhci_hcd *xhci, /* xhci only supports test mode for usb2 ports */ port = xhci->usb2_rhub.ports[wIndex]; - temp = readl(port->addr + PORTPMSC); + temp = readl(&port->port_reg->portpmsc); temp |= test_mode << PORT_TEST_MODE_SHIFT; - writel(temp, port->addr + PORTPMSC); + writel(temp, &port->port_reg->portpmsc); xhci->test_mode = test_mode; if (test_mode == USB_TEST_FORCE_ENABLE) xhci_start(xhci); @@ -731,12 +700,11 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci, /* Disable all Device Slots */ xhci_dbg(xhci, "Disable all slots\n"); spin_unlock_irqrestore(&xhci->lock, *flags); - for (i = 1; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) { + for (i = 1; i <= xhci->max_slots; i++) { if (!xhci->devs[i]) continue; - retval = xhci_disable_slot(xhci, i); - xhci_free_virt_device(xhci, i); + retval = xhci_disable_and_free_slot(xhci, i); if (retval) xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n", i, retval); @@ -784,17 +752,60 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci) return xhci_reset(xhci, XHCI_RESET_SHORT_USEC); } +/** + * xhci_port_is_tunneled() - Check if USB3 connection is tunneled over USB4 + * @xhci: xhci host controller + * @port: USB3 port to be checked. + * + * Some hosts can detect if a USB3 connection is native USB3 or tunneled over + * USB4. Intel hosts expose this via vendor specific extended capability 206 + * eSS PORT registers TUNEN (tunnel enabled) bit. + * + * A USB3 device must be connected to the port to detect the tunnel. + * + * Return: link tunnel mode enum, USB_LINK_UNKNOWN if host is incapable of + * detecting USB3 over USB4 tunnels. USB_LINK_NATIVE or USB_LINK_TUNNELED + * otherwise. + */ +enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci, + struct xhci_port *port) +{ + struct usb_hcd *hcd; + void __iomem *base; + u32 offset; + + /* Don't try and probe this capability for non-Intel hosts */ + hcd = xhci_to_hcd(xhci); + if (!dev_is_pci(hcd->self.controller) || + to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL) + return USB_LINK_UNKNOWN; + + base = &xhci->cap_regs->hc_capbase; + offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW); + + if (offset && offset <= XHCI_INTEL_SPR_ESS_PORT_OFFSET) { + offset = XHCI_INTEL_SPR_ESS_PORT_OFFSET + port->hcd_portnum * 0x20; + + if (readl(base + offset) & XHCI_INTEL_SPR_TUNEN) + return USB_LINK_TUNNELED; + else + return USB_LINK_NATIVE; + } + + return USB_LINK_UNKNOWN; +} + void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, u32 link_state) { u32 temp; u32 portsc; - portsc = readl(port->addr); + portsc = xhci_portsc_readl(port); temp = xhci_port_state_to_neutral(portsc); temp &= ~PORT_PLS_MASK; temp |= PORT_LINK_STROBE | link_state; - writel(temp, port->addr); + xhci_portsc_writel(port, temp); xhci_dbg(xhci, "Set port %d-%d link state, portsc: 0x%x, write 0x%x", port->rhub->hcd->self.busnum, port->hcd_portnum + 1, @@ -806,7 +817,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, { u32 temp; - temp = readl(port->addr); + temp = xhci_portsc_readl(port); temp = xhci_port_state_to_neutral(temp); if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT) @@ -824,7 +835,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, else temp &= ~PORT_WKOC_E; - writel(temp, port->addr); + xhci_portsc_writel(port, temp); } /* Test and clear port RWC bit */ @@ -833,11 +844,11 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, struct xhci_port *port, { u32 temp; - temp = readl(port->addr); + temp = xhci_portsc_readl(port); if (temp & port_bit) { temp = xhci_port_state_to_neutral(temp); temp |= port_bit; - writel(temp, port->addr); + xhci_portsc_writel(port, temp); } } @@ -914,7 +925,7 @@ static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, if ((xhci->port_status_u0 != all_ports_seen_u0) && port_in_u0) { xhci->port_status_u0 |= 1 << wIndex; if (xhci->port_status_u0 == all_ports_seen_u0) { - del_timer_sync(&xhci->comp_mode_recovery_timer); + timer_delete_sync(&xhci->comp_mode_recovery_timer); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "All USB3 ports have entered U0 already!"); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, @@ -930,7 +941,6 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, struct xhci_bus_state *bus_state; struct xhci_hcd *xhci; struct usb_hcd *hcd; - int slot_id; u32 wIndex; hcd = port->rhub->hcd; @@ -943,9 +953,9 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, } /* did port event handler already start resume timing? */ if (!port->resume_timestamp) { - /* If not, maybe we are in a host initated resume? */ + /* If not, maybe we are in a host initiated resume? */ if (test_bit(wIndex, &bus_state->resuming_ports)) { - /* Host initated resume doesn't time the resume + /* Host initiated resume doesn't time the resume * signalling using resume_done[]. * It manually sets RESUME state, sleeps 20ms * and sets U0 state. This should probably be @@ -986,15 +996,13 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, spin_lock_irqsave(&xhci->lock, *flags); if (time_left) { - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - wIndex + 1); - if (!slot_id) { + if (!port->slot_id) { xhci_dbg(xhci, "slot_id is zero\n"); return -ENODEV; } - xhci_ring_device(xhci, slot_id); + xhci_ring_device(xhci, port->slot_id); } else { - int port_status = readl(port->addr); + int port_status = xhci_portsc_readl(port); xhci_warn(xhci, "Port resume timed out, port %d-%d: 0x%x\n", hcd->self.busnum, wIndex + 1, port_status); @@ -1062,19 +1070,19 @@ static void xhci_get_usb3_port_status(struct xhci_port *port, u32 *status, *status |= USB_PORT_STAT_C_CONFIG_ERROR << 16; /* USB3 specific wPortStatus bits */ - if (portsc & PORT_POWER) { + if (portsc & PORT_POWER) *status |= USB_SS_PORT_STAT_POWER; - /* link state handling */ - if (link_state == XDEV_U0) - bus_state->suspended_ports &= ~(1 << portnum); - } - /* remote wake resume signaling complete */ - if (bus_state->port_remote_wakeup & (1 << portnum) && + /* no longer suspended or resuming */ + if (link_state != XDEV_U3 && link_state != XDEV_RESUME && link_state != XDEV_RECOVERY) { - bus_state->port_remote_wakeup &= ~(1 << portnum); - usb_hcd_end_port_resume(&hcd->self, portnum); + /* remote wake resume signaling complete */ + if (bus_state->port_remote_wakeup & (1 << portnum)) { + bus_state->port_remote_wakeup &= ~(1 << portnum); + usb_hcd_end_port_resume(&hcd->self, portnum); + } + bus_state->suspended_ports &= ~(1 << portnum); } xhci_hub_report_usb3_link_state(xhci, status, portsc); @@ -1131,6 +1139,7 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status, usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum); } port->rexit_active = 0; + bus_state->suspended_ports &= ~(1 << portnum); } } @@ -1201,7 +1210,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, unsigned long flags; u32 temp, status; int retval = 0; - int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; @@ -1255,13 +1263,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wIndex--; port = ports[portnum1 - 1]; - temp = readl(port->addr); + temp = xhci_portsc_readl(port); if (temp == ~(u32)0) { xhci_hc_died(xhci); retval = -ENODEV; break; } - trace_xhci_get_port_status(wIndex, temp); + trace_xhci_get_port_status(port, temp); status = xhci_get_port_status(hcd, bus_state, wIndex, temp, &flags); if (status == 0xffffffff) @@ -1280,7 +1288,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, retval = -EINVAL; break; } - port_li = readl(port->addr + PORTLI); + port_li = readl(&port->port_reg->portli); status = xhci_get_ext_port_status(temp, port_li); put_unaligned_le32(status, &buf[4]); } @@ -1301,7 +1309,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, port = ports[portnum1 - 1]; wIndex--; - temp = readl(port->addr); + temp = xhci_portsc_readl(port); if (temp == ~(u32)0) { xhci_hc_died(xhci); retval = -ENODEV; @@ -1311,7 +1319,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* FIXME: What new port features do we need to support? */ switch (wValue) { case USB_PORT_FEAT_SUSPEND: - temp = readl(port->addr); + temp = xhci_portsc_readl(port); if ((temp & PORT_PLS_MASK) != XDEV_U0) { /* Resume the port to U0 first */ xhci_set_link_state(xhci, port, XDEV_U0); @@ -1323,7 +1331,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, * a port unless the port reports that it is in the * enabled (PED = ‘1’,PLS < ‘3’) state. */ - temp = readl(port->addr); + temp = xhci_portsc_readl(port); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) || (temp & PORT_PLS_MASK) >= XDEV_U3) { xhci_warn(xhci, "USB core suspending port %d-%d not in U0/U1/U2\n", @@ -1331,15 +1339,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; } - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - portnum1); - if (!slot_id) { + if (!port->slot_id) { xhci_warn(xhci, "slot_id is zero\n"); goto error; } /* unlock to execute stop endpoint commands */ spin_unlock_irqrestore(&xhci->lock, flags); - xhci_stop_device(xhci, slot_id, 1); + xhci_stop_device(xhci, port->slot_id, 1); spin_lock_irqsave(&xhci->lock, flags); xhci_set_link_state(xhci, port, XDEV_U3); @@ -1348,11 +1354,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, msleep(10); /* wait device to enter */ spin_lock_irqsave(&xhci->lock, flags); - temp = readl(port->addr); + temp = xhci_portsc_readl(port); bus_state->suspended_ports |= 1 << wIndex; break; case USB_PORT_FEAT_LINK_STATE: - temp = readl(port->addr); + temp = xhci_portsc_readl(port); /* Disable port */ if (link_state == USB_SS_PORT_LS_SS_DISABLED) { xhci_dbg(xhci, "Disable port %d-%d\n", @@ -1365,8 +1371,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp |= PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | PORT_RC | PORT_PLC | PORT_CEC; - writel(temp | PORT_PE, port->addr); - temp = readl(port->addr); + xhci_portsc_writel(port, temp | PORT_PE); + temp = xhci_portsc_readl(port); break; } @@ -1375,7 +1381,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_dbg(xhci, "Enable port %d-%d\n", hcd->self.busnum, portnum1); xhci_set_link_state(xhci, port, link_state); - temp = readl(port->addr); + temp = xhci_portsc_readl(port); break; } @@ -1394,7 +1400,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, * automatically entered as on 1.0 and prior. */ if (link_state == USB_SS_PORT_LS_COMP_MOD) { - if (!HCC2_CTC(xhci->hcc_params2)) { + if (!(xhci->hcc_params2 & HCC2_CTC)) { xhci_dbg(xhci, "CTC flag is 0, port already supports entering compliance mode\n"); break; } @@ -1408,7 +1414,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, hcd->self.busnum, portnum1); xhci_set_link_state(xhci, port, link_state); - temp = readl(port->addr); + temp = xhci_portsc_readl(port); break; } /* Port must be enabled */ @@ -1456,32 +1462,30 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_dbg(xhci, "missing U0 port change event for port %d-%d\n", hcd->self.busnum, portnum1); spin_lock_irqsave(&xhci->lock, flags); - temp = readl(port->addr); + temp = xhci_portsc_readl(port); break; } if (link_state == USB_SS_PORT_LS_U3) { int retries = 16; - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - portnum1); - if (slot_id) { + if (port->slot_id) { /* unlock to execute stop endpoint * commands */ spin_unlock_irqrestore(&xhci->lock, flags); - xhci_stop_device(xhci, slot_id, 1); + xhci_stop_device(xhci, port->slot_id, 1); spin_lock_irqsave(&xhci->lock, flags); } xhci_set_link_state(xhci, port, USB_SS_PORT_LS_U3); spin_unlock_irqrestore(&xhci->lock, flags); while (retries--) { usleep_range(4000, 8000); - temp = readl(port->addr); + temp = xhci_portsc_readl(port); if ((temp & PORT_PLS_MASK) == XDEV_U3) break; } spin_lock_irqsave(&xhci->lock, flags); - temp = readl(port->addr); + temp = xhci_portsc_readl(port); bus_state->suspended_ports |= 1 << wIndex; } break; @@ -1496,38 +1500,38 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case USB_PORT_FEAT_RESET: temp = (temp | PORT_RESET); - writel(temp, port->addr); + xhci_portsc_writel(port, temp); - temp = readl(port->addr); + temp = xhci_portsc_readl(port); xhci_dbg(xhci, "set port reset, actual port %d-%d status = 0x%x\n", hcd->self.busnum, portnum1, temp); break; case USB_PORT_FEAT_REMOTE_WAKE_MASK: xhci_set_remote_wake_mask(xhci, port, wake_mask); - temp = readl(port->addr); + temp = xhci_portsc_readl(port); xhci_dbg(xhci, "set port remote wake mask, actual port %d-%d status = 0x%x\n", hcd->self.busnum, portnum1, temp); break; case USB_PORT_FEAT_BH_PORT_RESET: temp |= PORT_WR; - writel(temp, port->addr); - temp = readl(port->addr); + xhci_portsc_writel(port, temp); + temp = xhci_portsc_readl(port); break; case USB_PORT_FEAT_U1_TIMEOUT: if (hcd->speed < HCD_USB3) goto error; - temp = readl(port->addr + PORTPMSC); + temp = readl(&port->port_reg->portpmsc); temp &= ~PORT_U1_TIMEOUT_MASK; temp |= PORT_U1_TIMEOUT(timeout); - writel(temp, port->addr + PORTPMSC); + writel(temp, &port->port_reg->portpmsc); break; case USB_PORT_FEAT_U2_TIMEOUT: if (hcd->speed < HCD_USB3) goto error; - temp = readl(port->addr + PORTPMSC); + temp = readl(&port->port_reg->portpmsc); temp &= ~PORT_U2_TIMEOUT_MASK; temp |= PORT_U2_TIMEOUT(timeout); - writel(temp, port->addr + PORTPMSC); + writel(temp, &port->port_reg->portpmsc); break; case USB_PORT_FEAT_TEST: /* 4.19.6 Port Test Modes (USB2 Test Mode) */ @@ -1543,7 +1547,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; } /* unblock any posted writes */ - temp = readl(port->addr); + temp = xhci_portsc_readl(port); break; case ClearPortFeature: if (!portnum1 || portnum1 > max_ports) @@ -1552,7 +1556,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, port = ports[portnum1 - 1]; wIndex--; - temp = readl(port->addr); + temp = xhci_portsc_readl(port); if (temp == ~(u32)0) { xhci_hc_died(xhci); retval = -ENODEV; @@ -1562,7 +1566,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = xhci_port_state_to_neutral(temp); switch (wValue) { case USB_PORT_FEAT_SUSPEND: - temp = readl(port->addr); + temp = xhci_portsc_readl(port); xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n"); xhci_dbg(xhci, "PORTSC %04x\n", temp); if (temp & PORT_RESET) @@ -1583,13 +1587,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } bus_state->port_c_suspend |= 1 << wIndex; - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - portnum1); - if (!slot_id) { + if (!port->slot_id) { xhci_dbg(xhci, "slot_id is zero\n"); goto error; } - xhci_ring_device(xhci, slot_id); + xhci_ring_device(xhci, port->slot_id); break; case USB_PORT_FEAT_C_SUSPEND: bus_state->port_c_suspend &= ~(1 << wIndex); @@ -1601,8 +1603,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_PORT_LINK_STATE: case USB_PORT_FEAT_C_PORT_CONFIG_ERROR: - xhci_clear_port_change_bit(xhci, wValue, wIndex, - port->addr, temp); + xhci_clear_port_change_bit(xhci, wValue, wIndex, port, temp); break; case USB_PORT_FEAT_ENABLE: xhci_disable_port(xhci, port); @@ -1669,7 +1670,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) * SS devices are only visible to roothub after link training completes. * Keep polling roothubs for a grace period after xHC start */ - if (xhci->run_graceperiod) { + if (hcd->speed >= HCD_USB3 && xhci->run_graceperiod) { if (time_before(jiffies, xhci->run_graceperiod)) status = 1; else @@ -1680,13 +1681,13 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) /* For each port, did anything change? If so, set that bit in buf. */ for (i = 0; i < max_ports; i++) { - temp = readl(ports[i]->addr); + temp = xhci_portsc_readl(ports[i]); if (temp == ~(u32)0) { xhci_hc_died(xhci); retval = -ENODEV; break; } - trace_xhci_hub_status_data(i, temp); + trace_xhci_hub_status_data(ports[i], temp); if ((temp & mask) != 0 || (bus_state->port_c_suspend & 1 << i) || @@ -1749,7 +1750,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) u32 t1, t2; int retries = 10; retry: - t1 = readl(ports[port_index]->addr); + t1 = xhci_portsc_readl(ports[port_index]); t2 = xhci_port_state_to_neutral(t1); portsc_buf[port_index] = 0; @@ -1820,17 +1821,14 @@ retry: if (!portsc_buf[port_index]) continue; if (test_bit(port_index, &bus_state->bus_suspended)) { - int slot_id; - - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - port_index + 1); + int slot_id = ports[port_index]->slot_id; if (slot_id) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_stop_device(xhci, slot_id, 1); spin_lock_irqsave(&xhci->lock, flags); } } - writel(portsc_buf[port_index], ports[port_index]->addr); + xhci_portsc_writel(ports[port_index], portsc_buf[port_index]); } hcd->state = HC_STATE_SUSPENDED; bus_state->next_statechange = jiffies + msecs_to_jiffies(10); @@ -1851,7 +1849,7 @@ static bool xhci_port_missing_cas_quirk(struct xhci_port *port) { u32 portsc; - portsc = readl(port->addr); + portsc = xhci_portsc_readl(port); /* if any of these are set we are not stuck */ if (portsc & (PORT_CONNECT | PORT_CAS)) @@ -1864,9 +1862,9 @@ static bool xhci_port_missing_cas_quirk(struct xhci_port *port) /* clear wakeup/change bits, and do a warm port reset */ portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); portsc |= PORT_WR; - writel(portsc, port->addr); + xhci_portsc_writel(port, portsc); /* flush write */ - readl(port->addr); + xhci_portsc_readl(port); return true; } @@ -1876,12 +1874,12 @@ int xhci_bus_resume(struct usb_hcd *hcd) struct xhci_bus_state *bus_state; unsigned long flags; int max_ports, port_index; - int slot_id; int sret; u32 next_state; - u32 temp, portsc; + u32 portsc; struct xhci_hub *rhub; struct xhci_port **ports; + bool disabled_irq = false; rhub = xhci_get_rhub(hcd); ports = rhub->ports; @@ -1897,20 +1895,23 @@ int xhci_bus_resume(struct usb_hcd *hcd) return -ESHUTDOWN; } - /* delay the irqs */ - temp = readl(&xhci->op_regs->command); - temp &= ~CMD_EIE; - writel(temp, &xhci->op_regs->command); - /* bus specific resume for ports we suspended at bus_suspend */ - if (hcd->speed >= HCD_USB3) + if (hcd->speed >= HCD_USB3) { next_state = XDEV_U0; - else + } else { next_state = XDEV_RESUME; - + if (bus_state->bus_suspended) { + /* + * prevent port event interrupts from interfering + * with usb2 port resume process + */ + xhci_disable_interrupter(xhci, xhci->interrupters[0]); + disabled_irq = true; + } + } port_index = max_ports; while (port_index--) { - portsc = readl(ports[port_index]->addr); + portsc = xhci_portsc_readl(ports[port_index]); /* warm reset CAS limited ports stuck in polling/compliance */ if ((xhci->quirks & XHCI_MISSING_CAS) && @@ -1933,14 +1934,14 @@ int xhci_bus_resume(struct usb_hcd *hcd) /* resume already initiated */ break; default: - /* not in a resumeable state, ignore it */ + /* not in a resumable state, ignore it */ clear_bit(port_index, &bus_state->bus_suspended); break; } /* disable wake for all ports, write new link state if needed */ portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); - writel(portsc, ports[port_index]->addr); + xhci_portsc_writel(ports[port_index], portsc); } /* USB2 specific resume signaling delay and U0 link state transition */ @@ -1961,7 +1962,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) /* poll for U0 link state complete, both USB2 and USB3 */ for_each_set_bit(port_index, &bus_state->bus_suspended, BITS_PER_LONG) { - sret = xhci_handshake(ports[port_index]->addr, PORT_PLC, + sret = xhci_handshake(&ports[port_index]->port_reg->portsc, PORT_PLC, PORT_PLC, 10 * 1000); if (sret) { xhci_warn(xhci, "port %d-%d resume PLC timeout\n", @@ -1969,18 +1970,15 @@ int xhci_bus_resume(struct usb_hcd *hcd) continue; } xhci_test_and_clear_bit(xhci, ports[port_index], PORT_PLC); - slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); - if (slot_id) - xhci_ring_device(xhci, slot_id); + if (ports[port_index]->slot_id) + xhci_ring_device(xhci, ports[port_index]->slot_id); } (void) readl(&xhci->op_regs->command); bus_state->next_statechange = jiffies + msecs_to_jiffies(5); - /* re-enable irqs */ - temp = readl(&xhci->op_regs->command); - temp |= CMD_EIE; - writel(temp, &xhci->op_regs->command); - temp = readl(&xhci->op_regs->command); + /* re-enable interrupter */ + if (disabled_irq) + xhci_enable_interrupter(xhci->interrupters[0]); spin_unlock_irqrestore(&xhci->lock, flags); return 0; |
