]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - queue-4.9/usb-chipidea-udc-workaround-for-endpoint-conflict-issue.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / queue-4.9 / usb-chipidea-udc-workaround-for-endpoint-conflict-issue.patch
CommitLineData
1db5f20f
GKH
1From c19dffc0a9511a7d7493ec21019aefd97e9a111b Mon Sep 17 00:00:00 2001
2From: Peter Chen <peter.chen@nxp.com>
3Date: Mon, 17 Jun 2019 09:49:07 +0800
4Subject: usb: chipidea: udc: workaround for endpoint conflict issue
5
6From: Peter Chen <peter.chen@nxp.com>
7
8commit c19dffc0a9511a7d7493ec21019aefd97e9a111b upstream.
9
10An endpoint conflict occurs when the USB is working in device mode
11during an isochronous communication. When the endpointA IN direction
12is an isochronous IN endpoint, and the host sends an IN token to
13endpointA on another device, then the OUT transaction may be missed
14regardless the OUT endpoint number. Generally, this occurs when the
15device is connected to the host through a hub and other devices are
16connected to the same hub.
17
18The affected OUT endpoint can be either control, bulk, isochronous, or
19an interrupt endpoint. After the OUT endpoint is primed, if an IN token
20to the same endpoint number on another device is received, then the OUT
21endpoint may be unprimed (cannot be detected by software), which causes
22this endpoint to no longer respond to the host OUT token, and thus, no
23corresponding interrupt occurs.
24
25There is no good workaround for this issue, the only thing the software
26could do is numbering isochronous IN from the highest endpoint since we
27have observed most of device number endpoint from the lowest.
28
29Cc: <stable@vger.kernel.org> #v3.14+
30Cc: Fabio Estevam <festevam@gmail.com>
31Cc: Greg KH <gregkh@linuxfoundation.org>
32Cc: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
33Cc: Jun Li <jun.li@nxp.com>
34Signed-off-by: Peter Chen <peter.chen@nxp.com>
35Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
36
37---
38 drivers/usb/chipidea/udc.c | 20 ++++++++++++++++++++
39 1 file changed, 20 insertions(+)
40
41--- a/drivers/usb/chipidea/udc.c
42+++ b/drivers/usb/chipidea/udc.c
43@@ -1621,6 +1621,25 @@ static int ci_udc_pullup(struct usb_gadg
44 static int ci_udc_start(struct usb_gadget *gadget,
45 struct usb_gadget_driver *driver);
46 static int ci_udc_stop(struct usb_gadget *gadget);
47+
48+/* Match ISOC IN from the highest endpoint */
49+static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget,
50+ struct usb_endpoint_descriptor *desc,
51+ struct usb_ss_ep_comp_descriptor *comp_desc)
52+{
53+ struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
54+ struct usb_ep *ep;
55+
56+ if (usb_endpoint_xfer_isoc(desc) && usb_endpoint_dir_in(desc)) {
57+ list_for_each_entry_reverse(ep, &ci->gadget.ep_list, ep_list) {
58+ if (ep->caps.dir_in && !ep->claimed)
59+ return ep;
60+ }
61+ }
62+
63+ return NULL;
64+}
65+
66 /**
67 * Device operations part of the API to the USB controller hardware,
68 * which don't involve endpoints (or i/o)
69@@ -1634,6 +1653,7 @@ static const struct usb_gadget_ops usb_g
70 .vbus_draw = ci_udc_vbus_draw,
71 .udc_start = ci_udc_start,
72 .udc_stop = ci_udc_stop,
73+ .match_ep = ci_udc_match_ep,
74 };
75
76 static int init_eps(struct ci_hdrc *ci)