summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@nxp.com>2019-06-16 21:49:07 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-06-17 09:08:33 -0400
commitc19dffc0a9511a7d7493ec21019aefd97e9a111b (patch)
treeb43ab256803ad9bef0ec9c3a83f754834628e66a /drivers/usb
parent9e0babf2c06c73cda2c0cd37a1653d823adb40ec (diff)
usb: chipidea: udc: workaround for endpoint conflict issue
An endpoint conflict occurs when the USB is working in device mode during an isochronous communication. When the endpointA IN direction is an isochronous IN endpoint, and the host sends an IN token to endpointA on another device, then the OUT transaction may be missed regardless the OUT endpoint number. Generally, this occurs when the device is connected to the host through a hub and other devices are connected to the same hub. The affected OUT endpoint can be either control, bulk, isochronous, or an interrupt endpoint. After the OUT endpoint is primed, if an IN token to the same endpoint number on another device is received, then the OUT endpoint may be unprimed (cannot be detected by software), which causes this endpoint to no longer respond to the host OUT token, and thus, no corresponding interrupt occurs. There is no good workaround for this issue, the only thing the software could do is numbering isochronous IN from the highest endpoint since we have observed most of device number endpoint from the lowest. Cc: <stable@vger.kernel.org> #v3.14+ Cc: Fabio Estevam <festevam@gmail.com> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> Cc: Jun Li <jun.li@nxp.com> Signed-off-by: Peter Chen <peter.chen@nxp.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/chipidea/udc.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 829e947cabf5..6a5ee8e6da10 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1622,6 +1622,25 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
1622static int ci_udc_start(struct usb_gadget *gadget, 1622static int ci_udc_start(struct usb_gadget *gadget,
1623 struct usb_gadget_driver *driver); 1623 struct usb_gadget_driver *driver);
1624static int ci_udc_stop(struct usb_gadget *gadget); 1624static int ci_udc_stop(struct usb_gadget *gadget);
1625
1626/* Match ISOC IN from the highest endpoint */
1627static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget,
1628 struct usb_endpoint_descriptor *desc,
1629 struct usb_ss_ep_comp_descriptor *comp_desc)
1630{
1631 struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
1632 struct usb_ep *ep;
1633
1634 if (usb_endpoint_xfer_isoc(desc) && usb_endpoint_dir_in(desc)) {
1635 list_for_each_entry_reverse(ep, &ci->gadget.ep_list, ep_list) {
1636 if (ep->caps.dir_in && !ep->claimed)
1637 return ep;
1638 }
1639 }
1640
1641 return NULL;
1642}
1643
1625/** 1644/**
1626 * Device operations part of the API to the USB controller hardware, 1645 * Device operations part of the API to the USB controller hardware,
1627 * which don't involve endpoints (or i/o) 1646 * which don't involve endpoints (or i/o)
@@ -1635,6 +1654,7 @@ static const struct usb_gadget_ops usb_gadget_ops = {
1635 .vbus_draw = ci_udc_vbus_draw, 1654 .vbus_draw = ci_udc_vbus_draw,
1636 .udc_start = ci_udc_start, 1655 .udc_start = ci_udc_start,
1637 .udc_stop = ci_udc_stop, 1656 .udc_stop = ci_udc_stop,
1657 .match_ep = ci_udc_match_ep,
1638}; 1658};
1639 1659
1640static int init_eps(struct ci_hdrc *ci) 1660static int init_eps(struct ci_hdrc *ci)