| From dad2aff3e827b112f27fa5e6f2bf87a110067c3f Mon Sep 17 00:00:00 2001 |
| From: Pratham Pratap <prathampratap@codeaurora.org> |
| Date: Mon, 2 Mar 2020 21:44:43 +0000 |
| Subject: usb: dwc3: gadget: Update chain bit correctly when using sg list |
| |
| From: Pratham Pratap <prathampratap@codeaurora.org> |
| |
| commit dad2aff3e827b112f27fa5e6f2bf87a110067c3f upstream. |
| |
| If scatter-gather operation is allowed, a large USB request is split |
| into multiple TRBs. For preparing TRBs for sg list, driver iterates |
| over the list and creates TRB for each sg and mark the chain bit to |
| false for the last sg. The current IOMMU driver is clubbing the list |
| of sgs which shares a page boundary into one and giving it to USB driver. |
| With this the number of sgs mapped it not equal to the the number of sgs |
| passed. Because of this USB driver is not marking the chain bit to false |
| since it couldn't iterate to the last sg. This patch addresses this issue |
| by marking the chain bit to false if it is the last mapped sg. |
| |
| At a practical level, this patch resolves USB transfer stalls |
| seen with adb on dwc3 based db845c, pixel3 and other qcom |
| hardware after functionfs gadget added scatter-gather support |
| around v4.20. |
| |
| Credit also to Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com> |
| who implemented a very similar fix to this issue. |
| |
| Cc: Felipe Balbi <balbi@kernel.org> |
| Cc: Yang Fei <fei.yang@intel.com> |
| Cc: Thinh Nguyen <thinhn@synopsys.com> |
| Cc: Tejas Joglekar <tejas.joglekar@synopsys.com> |
| Cc: Andrzej Pietrasiewicz <andrzej.p@collabora.com> |
| Cc: Jack Pham <jackp@codeaurora.org> |
| Cc: Todd Kjos <tkjos@google.com> |
| Cc: Greg KH <gregkh@linuxfoundation.org> |
| Cc: Linux USB List <linux-usb@vger.kernel.org> |
| Cc: stable <stable@vger.kernel.org> #4.20+ |
| Signed-off-by: Pratham Pratap <prathampratap@codeaurora.org> |
| [jstultz: Slight tweak to remove sg_is_last() usage, reworked |
| commit message, minor comment tweak] |
| Signed-off-by: John Stultz <john.stultz@linaro.org> |
| Link: https://lore.kernel.org/r/20200302214443.55783-1-john.stultz@linaro.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/dwc3/gadget.c | 9 ++++++++- |
| 1 file changed, 8 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/usb/dwc3/gadget.c |
| +++ b/drivers/usb/dwc3/gadget.c |
| @@ -1068,7 +1068,14 @@ static void dwc3_prepare_one_trb_sg(stru |
| unsigned int rem = length % maxp; |
| unsigned chain = true; |
| |
| - if (sg_is_last(s)) |
| + /* |
| + * IOMMU driver is coalescing the list of sgs which shares a |
| + * page boundary into one and giving it to USB driver. With |
| + * this the number of sgs mapped is not equal to the number of |
| + * sgs passed. So mark the chain bit to false if it isthe last |
| + * mapped sg. |
| + */ |
| + if (i == remaining - 1) |
| chain = false; |
| |
| if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) { |