]>
Commit | Line | Data |
---|---|---|
b0c1a8bd GKH |
1 | From 69307ccb9ad7ccb653e332de68effdeaaab6907d Mon Sep 17 00:00:00 2001 |
2 | From: Roger Quadros <rogerq@ti.com> | |
3 | Date: Fri, 7 Apr 2017 17:57:12 +0300 | |
4 | Subject: usb: xhci: bInterval quirk for TI TUSB73x0 | |
5 | ||
6 | From: Roger Quadros <rogerq@ti.com> | |
7 | ||
8 | commit 69307ccb9ad7ccb653e332de68effdeaaab6907d upstream. | |
9 | ||
10 | As per [1] issue #4, | |
11 | "The periodic EP scheduler always tries to schedule the EPs | |
12 | that have large intervals (interval equal to or greater than | |
13 | 128 microframes) into different microframes. So it maintains | |
14 | an internal counter and increments for each large interval | |
15 | EP added. When the counter is greater than 128, the scheduler | |
16 | rejects the new EP. So when the hub re-enumerated 128 times, | |
17 | it triggers this condition." | |
18 | ||
19 | This results in Bandwidth error when devices with periodic | |
20 | endpoints (ISO/INT) having bInterval > 7 are plugged and | |
21 | unplugged several times on a TUSB73x0 XHCI host. | |
22 | ||
23 | Workaround this issue by limiting the bInterval to 7 | |
24 | (i.e. interval to 6) for High-speed or faster periodic endpoints. | |
25 | ||
26 | [1] - http://www.ti.com/lit/er/sllz076/sllz076.pdf | |
27 | ||
28 | Signed-off-by: Roger Quadros <rogerq@ti.com> | |
29 | Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> | |
30 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
31 | ||
32 | --- | |
33 | drivers/usb/host/xhci-mem.c | 11 +++++++++++ | |
34 | drivers/usb/host/xhci-pci.c | 3 +++ | |
35 | drivers/usb/host/xhci.h | 1 + | |
36 | 3 files changed, 15 insertions(+) | |
37 | ||
38 | --- a/drivers/usb/host/xhci-mem.c | |
39 | +++ b/drivers/usb/host/xhci-mem.c | |
40 | @@ -1502,6 +1502,17 @@ int xhci_endpoint_init(struct xhci_hcd * | |
41 | */ | |
42 | max_esit_payload = xhci_get_max_esit_payload(udev, ep); | |
43 | interval = xhci_get_endpoint_interval(udev, ep); | |
44 | + | |
45 | + /* Periodic endpoint bInterval limit quirk */ | |
46 | + if (usb_endpoint_xfer_int(&ep->desc) || | |
47 | + usb_endpoint_xfer_isoc(&ep->desc)) { | |
48 | + if ((xhci->quirks & XHCI_LIMIT_ENDPOINT_INTERVAL_7) && | |
49 | + udev->speed >= USB_SPEED_HIGH && | |
50 | + interval >= 7) { | |
51 | + interval = 6; | |
52 | + } | |
53 | + } | |
54 | + | |
55 | mult = xhci_get_endpoint_mult(udev, ep); | |
56 | max_packet = usb_endpoint_maxp(&ep->desc); | |
57 | max_burst = xhci_get_endpoint_max_burst(udev, ep); | |
58 | --- a/drivers/usb/host/xhci-pci.c | |
59 | +++ b/drivers/usb/host/xhci-pci.c | |
60 | @@ -199,6 +199,9 @@ static void xhci_pci_quirks(struct devic | |
61 | pdev->device == 0x1042) | |
62 | xhci->quirks |= XHCI_BROKEN_STREAMS; | |
63 | ||
64 | + if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241) | |
65 | + xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7; | |
66 | + | |
67 | if (xhci->quirks & XHCI_RESET_ON_RESUME) | |
68 | xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, | |
69 | "QUIRK: Resetting on resume"); | |
70 | --- a/drivers/usb/host/xhci.h | |
71 | +++ b/drivers/usb/host/xhci.h | |
72 | @@ -1818,6 +1818,7 @@ struct xhci_hcd { | |
73 | #define XHCI_MISSING_CAS (1 << 24) | |
74 | /* For controller with a broken Port Disable implementation */ | |
75 | #define XHCI_BROKEN_PORT_PED (1 << 25) | |
76 | +#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26) | |
77 | ||
78 | unsigned int num_active_eps; | |
79 | unsigned int limit_active_eps; |