diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-05 10:26:01 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-05 10:26:01 -0700 |
commit | 1a3b85ea36d38d5732fdd86b321b10bcaeb53512 (patch) | |
tree | f3a7abeb6acaa47019e3d53b7ae75f7ae4361803 /drivers/usb/host/xhci-hub.c | |
parent | 04759194dc447ff0b9ef35bc641ce3bb076c2930 (diff) | |
parent | 46f5489f781ae3e4d23a4e8e29e0ea3626739d2d (diff) | |
download | linux-1a3b85ea36d38d5732fdd86b321b10bcaeb53512.tar.gz linux-1a3b85ea36d38d5732fdd86b321b10bcaeb53512.tar.xz |
Merge tag 'usb-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY driver updates from Greg KH:
"Here is the large USB and PHY driver update for 4.14-rc1.
Not all that exciting, a few new PHY drivers, the usual mess of gadget
driver updates and fixes, and of course, xhci updates to try to tame
that beast.
A number of usb-serial updates and other small fixes all over the USB
driver tree are in here as well. Full details are in the shortlog.
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (171 commits)
usbip: vhci-hcd: make vhci_hc_driver const
usb: phy: Avoid unchecked dereference warning
usb: imx21-hcd: make imx21_hc_driver const
usb: host: make ehci_fsl_overrides const and __initconst
dt-bindings: mt8173-mtu3: add generic compatible and rename file
dt-bindings: mt8173-xhci: add generic compatible and rename file
usb: xhci-mtk: add generic compatible string
usbip: auto retry for concurrent attach
USB: serial: option: simplify 3 D-Link device entries
USB: serial: option: add support for D-Link DWM-157 C1
usb: core: usbport: fix "BUG: key not in .data" when lockdep is enabled
usb: chipidea: usb2: check memory allocation failure
usb: Add device quirk for Logitech HD Pro Webcam C920-C
usb: misc: lvstest: add entry to place port in compliance mode
usb: xhci: Support enabling of compliance mode for xhci 1.1
usb:xhci:Fix regression when ATI chipsets detected
usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard
usb: gadget: make snd_pcm_hardware const
usb: common: use of_property_read_bool()
USB: core: constify vm_operations_struct
...
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 127 |
1 files changed, 84 insertions, 43 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 00721e8807ab..ad89a6d4111b 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1179,6 +1179,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; } + /* + * For xHCI 1.1 according to section 4.19.1.2.4.1 a + * root hub port's transition to compliance mode upon + * detecting LFPS timeout may be controlled by an + * Compliance Transition Enabled (CTE) flag (not + * software visible). This flag is set by writing 0xA + * to PORTSC PLS field which will allow transition to + * compliance mode the next time LFPS timeout is + * encountered. A warm reset will clear it. + * + * The CTE flag is only supported if the HCCPARAMS2 CTC + * flag is set, otherwise, the compliance substate is + * automatically entered as on 1.0 and prior. + */ + if (link_state == USB_SS_PORT_LS_COMP_MOD) { + if (!HCC2_CTC(xhci->hcc_params2)) { + xhci_dbg(xhci, "CTC flag is 0, port already supports entering compliance mode\n"); + break; + } + + if ((temp & PORT_CONNECT)) { + xhci_warn(xhci, "Can't set compliance mode when port is connected\n"); + goto error; + } + + xhci_dbg(xhci, "Enable compliance mode transition for port %d\n", + wIndex); + xhci_set_link_state(xhci, port_array, wIndex, + link_state); + temp = readl(port_array[wIndex]); + break; + } + /* Software should not attempt to set * port link state above '3' (U3) and the port * must be enabled. @@ -1521,15 +1554,14 @@ static bool xhci_port_missing_cas_quirk(int port_index, int xhci_bus_resume(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int max_ports, port_index; - __le32 __iomem **port_array; struct xhci_bus_state *bus_state; - u32 temp; + __le32 __iomem **port_array; unsigned long flags; - unsigned long port_was_suspended = 0; - bool need_usb2_u3_exit = false; + int max_ports, port_index; int slot_id; int sret; + u32 next_state; + u32 temp, portsc; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; @@ -1548,68 +1580,77 @@ int xhci_bus_resume(struct usb_hcd *hcd) temp &= ~CMD_EIE; writel(temp, &xhci->op_regs->command); + /* bus specific resume for ports we suspended at bus_suspend */ + if (hcd->speed >= HCD_USB3) + next_state = XDEV_U0; + else + next_state = XDEV_RESUME; + port_index = max_ports; while (port_index--) { - /* Check whether need resume ports. If needed - resume port and disable remote wakeup */ - u32 temp; - - temp = readl(port_array[port_index]); + portsc = readl(port_array[port_index]); /* warm reset CAS limited ports stuck in polling/compliance */ if ((xhci->quirks & XHCI_MISSING_CAS) && (hcd->speed >= HCD_USB3) && xhci_port_missing_cas_quirk(port_index, port_array)) { xhci_dbg(xhci, "reset stuck port %d\n", port_index); + clear_bit(port_index, &bus_state->bus_suspended); continue; } - if (DEV_SUPERSPEED_ANY(temp)) - temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); - else - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - if (test_bit(port_index, &bus_state->bus_suspended) && - (temp & PORT_PLS_MASK)) { - set_bit(port_index, &port_was_suspended); - if (!DEV_SUPERSPEED_ANY(temp)) { - xhci_set_link_state(xhci, port_array, - port_index, XDEV_RESUME); - need_usb2_u3_exit = true; + /* resume if we suspended the link, and it is still suspended */ + if (test_bit(port_index, &bus_state->bus_suspended)) + switch (portsc & PORT_PLS_MASK) { + case XDEV_U3: + portsc = xhci_port_state_to_neutral(portsc); + portsc &= ~PORT_PLS_MASK; + portsc |= PORT_LINK_STROBE | next_state; + break; + case XDEV_RESUME: + /* resume already initiated */ + break; + default: + /* not in a resumeable state, ignore it */ + clear_bit(port_index, + &bus_state->bus_suspended); + break; } - } else - writel(temp, port_array[port_index]); - } - - if (need_usb2_u3_exit) { - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(USB_RESUME_TIMEOUT); - spin_lock_irqsave(&xhci->lock, flags); + /* disable wake for all ports, write new link state if needed */ + portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); + writel(portsc, port_array[port_index]); } - port_index = max_ports; - while (port_index--) { - if (!(port_was_suspended & BIT(port_index))) - continue; - /* Clear PLC to poll it later after XDEV_U0 */ - xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC); - xhci_set_link_state(xhci, port_array, port_index, XDEV_U0); + /* USB2 specific resume signaling delay and U0 link state transition */ + if (hcd->speed < HCD_USB3) { + if (bus_state->bus_suspended) { + spin_unlock_irqrestore(&xhci->lock, flags); + msleep(USB_RESUME_TIMEOUT); + spin_lock_irqsave(&xhci->lock, flags); + } + for_each_set_bit(port_index, &bus_state->bus_suspended, + BITS_PER_LONG) { + /* Clear PLC to poll it later for U0 transition */ + xhci_test_and_clear_bit(xhci, port_array, port_index, + PORT_PLC); + xhci_set_link_state(xhci, port_array, port_index, + XDEV_U0); + } } - port_index = max_ports; - while (port_index--) { - if (!(port_was_suspended & BIT(port_index))) - continue; - /* Poll and Clear PLC */ + /* 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(port_array[port_index], PORT_PLC, PORT_PLC, 10 * 1000); - if (sret) + if (sret) { xhci_warn(xhci, "port %d resume PLC timeout\n", port_index); + continue; + } xhci_test_and_clear_bit(xhci, port_array, 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); } - (void) readl(&xhci->op_regs->command); bus_state->next_statechange = jiffies + msecs_to_jiffies(5); |