From 5a514c08f31ed1a2f6978beb9fc5d2c929a753d2 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 11 Nov 2015 10:33:52 -0800 Subject: [PATCH] UPSTREAM: usb: dwc2: host: Support immediate retries for split transactions In some cases, like when you've got a "Microsoft Wireless Keyboard 2000" connected to dwc2 with a hub, expected that we'll get some transfer errors sometimes. The controller is expected to try at least 3 times before giving up. See figure "Figure A-67. Normal HS CSPLIT 3 Strikes Smash" in the USB spec. The dwc2 controller has a way to support this by using the "EC_MC" field. The Raspberry Pi driver has logic for setting this right. See fiq_fsm_queue_split_transaction() in their "dwc_otg_hcd.c". Let's use the same logic. After making this change, we no longer get dropped characters from the above mentioned keyboard. Other devices on the same bus as the keyboard also behave more properly. Thanks for Julius Werner for the expert analysis and suggestions. Change-Id: I2351f95a0c6db1ca24c54edce574c42e073b7211 Acked-by: John Youn Signed-off-by: Douglas Anderson Signed-off-by: Felipe Balbi Signed-off-by: Huang, Tao (cherry picked from commit 69b76cdff592058ea445cd40e18c75dffaba4cb9) --- drivers/usb/dwc2/core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 40ac99fe6ac9..62505068abf2 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -1721,6 +1721,7 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, u32 hcchar; u32 hctsiz = 0; u16 num_packets; + u32 ec_mc; if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "%s()\n", __func__); @@ -1757,6 +1758,13 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT & TSIZ_XFERSIZE_MASK; + + /* For split set ec_mc for immediate retries */ + if (chan->ep_type == USB_ENDPOINT_XFER_INT || + chan->ep_type == USB_ENDPOINT_XFER_ISOC) + ec_mc = 3; + else + ec_mc = 1; } else { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "no split\n"); @@ -1819,6 +1827,9 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT & TSIZ_XFERSIZE_MASK; + + /* The ec_mc gets the multi_count for non-split */ + ec_mc = chan->multi_count; } chan->start_pkt_count = num_packets; @@ -1869,8 +1880,7 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num)); hcchar &= ~HCCHAR_MULTICNT_MASK; - hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT & - HCCHAR_MULTICNT_MASK; + hcchar |= (ec_mc << HCCHAR_MULTICNT_SHIFT) & HCCHAR_MULTICNT_MASK; dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar); if (hcchar & HCCHAR_CHDIS) -- 2.34.1