This patch adds support for USB2 test mode (Test_J, Test_K, Test_SE0_NAK and Test_Packet) per XHCI spec 4.19.6.
USB2 test mode is a required hardware feature for system integrators validating their hardware according to USB spec, regarding signal strength and stuff. It is purely a hardware test feature. Usually you need an oscilloscope and have to enable those test modes on the hardware. This will send some specific test patterns on D+/D-. There is no report available (in Linux itself) as it is purely externally visible. Regular USB usage is not possible at that time. Anyone (well access to e.g. /dev/bus/usb/001/001 provided) can use it by sending appropriate USB_PORT_FEAT_TEST requests to the hub. The same feature for ehci based hosts is already available at https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/host/ehci-hub.c#n1267 Signed-off-by: "Wang, Yu" <yu.y.w...@intel.com> Signed-off-by: "Li, Guanglei" <guangleix...@intel.com> Signed-off-by: "Wu, Hao" <hao...@intel.com> Signed-off-by: Alexander Stein <alexander.st...@systec-electronic.com> --- Changes in v2: * Added additional info about USB2 test modes itself into commit message * Add URL for same test mode feature on ehci hosts. drivers/usb/host/xhci-hub.c | 63 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 0ef1690..cd561f1 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -879,13 +879,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, int max_ports; unsigned long flags; u32 temp, status; - int retval = 0; + int i, retval = 0; __le32 __iomem **port_array; int slot_id; struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; u16 timeout = 0; + u16 selector = 0; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; @@ -959,6 +960,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, link_state = (wIndex & 0xff00) >> 3; if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) wake_mask = wIndex & 0xff00; + if (wValue == USB_PORT_FEAT_TEST) + selector = (wIndex & 0xff00) >> 8; /* The MSB of wIndex is the U1/U2 timeout */ timeout = (wIndex & 0xff00) >> 8; wIndex &= 0xff; @@ -1134,6 +1137,64 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp |= PORT_U2_TIMEOUT(timeout); writel(temp, port_array[wIndex] + PORTPMSC); break; + case USB_PORT_FEAT_TEST: + /* 4.19.6 Port Test Modes (USB2 Test Mode) */ + if (hcd->speed != HCD_USB2) + goto error; + + /* FIXME: Test_Force_Enable case to be implemented */ + if (selector < TEST_J || selector > TEST_PACKET) + goto error; + + /* Disable all Device Slots */ + for (i = 0; i < MAX_HC_SLOTS; i++) { + struct xhci_command *command; + + if (!xhci->dcbaa->dev_context_ptrs[i]) + continue; + command = xhci_alloc_command(xhci, false, + false, GFP_ATOMIC); + if (!command) + return -ENOMEM; + if (xhci_queue_slot_control(xhci, command, + TRB_DISABLE_SLOT, i)) { + xhci_err(xhci, + "Disable slot[%d] fail!\n", i); + goto error; + } + xhci_dbg(xhci, "Disable Slot[%d].\n", i); + } + + /* Put all ports to the Disable state by clear PP */ + xhci_dbg(xhci, "Disable all port (PP = 0)\n"); + for (i = 0; i < max_ports; i++) { + temp = readl(port_array[i]); + temp &= ~PORT_POWER; + writel(temp, port_array[i]); + } + + /* Stop the controller */ + xhci_dbg(xhci, "Stop controller\n"); + temp = readl(&xhci->op_regs->command); + temp &= ~CMD_RUN; + writel(temp, &xhci->op_regs->command); + + if (xhci_handshake(&xhci->op_regs->status, + STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) { + xhci_warn(xhci, "Stop controller timeout\n"); + return -ETIMEDOUT; + } + + /* Disable runtime PM for test mode */ + pm_runtime_forbid(hcd->self.controller); + + /* Set PORTPMSC.PTC field for selected test mode */ + xhci_dbg(xhci, "Enter Test Mode: %d\n", selector); + temp = readl(port_array[wIndex] + PORTPMSC); + temp |= selector << 28; + writel(temp, port_array[wIndex] + PORTPMSC); + + break; default: goto error; } -- 2.10.2 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html