From patchwork Fri Dec 14 10:33:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrzej Pietrasiewicz X-Patchwork-Id: 10730837 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E13CF14BD for ; Fri, 14 Dec 2018 10:33:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C0DBC2962A for ; Fri, 14 Dec 2018 10:33:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A293129666; Fri, 14 Dec 2018 10:33:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CF8F92962A for ; Fri, 14 Dec 2018 10:33:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727403AbeLNKdt (ORCPT ); Fri, 14 Dec 2018 05:33:49 -0500 Received: from mailout1.w1.samsung.com ([210.118.77.11]:47213 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726683AbeLNKdt (ORCPT ); Fri, 14 Dec 2018 05:33:49 -0500 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20181214103346euoutp0197e86130371dcff7b79f82044ec52076~wLIYFX2Ma0592805928euoutp01I; Fri, 14 Dec 2018 10:33:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20181214103346euoutp0197e86130371dcff7b79f82044ec52076~wLIYFX2Ma0592805928euoutp01I DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1544783626; bh=wPNTs9vJapgVwpgwZCbZLm/pLitrhLzSG5kVPWOUL4I=; h=From:To:Cc:Subject:Date:References:From; b=Mt+PuHzChLXrbQ+Imkh3ArfqZ4tPhqLWOmYbgTPyYURaxJgtsuI5QnmqUe1PrRuQB trCuuhmZfTbkjJiyxEuvX8xDLL0dVnn4iX0VicdpgF8nKGmX+CBXwEDB+2Ub+LixgK oRnB/7BPGvJnoz5c2WnwYZCcIZhGt7chMDhoFOTc= Received: from eusmges2new.samsung.com (unknown [203.254.199.244]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20181214103345eucas1p1dd03418967c543f4cc79acc00058dd47~wLIXpdPZM1216112161eucas1p18; Fri, 14 Dec 2018 10:33:45 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges2new.samsung.com (EUCPMTA) with SMTP id 0F.B1.04294.907831C5; Fri, 14 Dec 2018 10:33:45 +0000 (GMT) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20181214103344eucas1p1f185709890577dc9767ea0b6286792b0~wLIWups3L0563905639eucas1p1m; Fri, 14 Dec 2018 10:33:44 +0000 (GMT) X-AuditID: cbfec7f4-c77a99c0000010c6-61-5c138709a45f Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id 0C.51.04284.807831C5; Fri, 14 Dec 2018 10:33:44 +0000 (GMT) Received: from mcdsrvbld02.digital.local ([106.116.37.23]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0PJQ000GJ2O3R300@eusync1.samsung.com>; Fri, 14 Dec 2018 10:33:44 +0000 (GMT) From: Andrzej Pietrasiewicz To: linux-usb@vger.kernel.org Cc: Minas Harutyunyan , Andrzej Pietrasiewicz , Greg Kroah-Hartman , Marek Szyprowski , Bartlomiej Zolnierkiewicz Subject: [PATCH] usb: dwc2: gadget: Add scatter-gather mode Date: Fri, 14 Dec 2018 11:33:36 +0100 Message-id: <20181214103336.23240-1-andrzej.p@samsung.com> X-Mailer: git-send-email 2.11.0 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprAIsWRmVeSWpSXmKPExsWy7djPc7qc7cIxBosOiVvMetnOYrFxxnpW i+bF69ksGn/tZbdYtKyV2WLtkbvsDmwe++euYffo27KK0WPL/s+MHp83yQWwRHHZpKTmZJal FunbJXBlzOxqYCroNak4skmkgfG8ZhcjJ4eEgInExUk/WEBsIYEVjBJ/Z8Z2MXIB2Z8ZJQ4/ eM8OUzRx7T42iMQyRonef2uhnCYmiZOT37CCVLEJGEvsPdjBCGKLCMhKHL7ymxmkiFngC6PE l6ONYDuEBawlDn0+zgZiswioSkzsvwlm8wpYSfyffZ4RYp28xK62i6wgzRICd1klzsybygqR cJHYfGktG4QtLPHq+Bao+2QkOjsOMkHY9RKbvuyBqpnCKHFvrjeEbS1x+PhFsDnMAnwSk7ZN B7qOAyjOK9HRJgRR4iGxasJeVpCwkECsxP05mhMYJRYwMqxiFE8tLc5NTy02ykst1ytOzC0u zUvXS87P3cQIjKfT/45/2cG460/SIUYBDkYlHt6MSUIxQqyJZcWVuYcYJTiYlUR4w1qFY4R4 UxIrq1KL8uOLSnNSiw8xSnOwKInzVjM8iBYSSE8sSc1OTS1ILYLJMnFwSjUwbiguEjbu/W+a oFC39uj74D2mLw5P+8nYWX6RjTndSH2fb9Lv7M3GPNN+WyQnbP6r/FbHyits+4dZdUdPHPA/ uXsSY+279iCvDT8PLxLO/KxySyegJ129d+W66GsaN7usn0kdki/ZM+/ohLely6TsNQ6IqvWw awS+UU10NZuzNLjAZYH2Wz4xJZbijERDLeai4kQAzFReE6MCAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrCJMWRmVeSWpSXmKPExsVy+t/xy7oc7cIxBiufy1rMetnOYrFxxnpW i+bF69ksGn/tZbdYtKyV2WLtkbvsDmwe++euYffo27KK0WPL/s+MHp83yQWwRHHZpKTmZJal FunbJXBlzOxqYCroNak4skmkgfG8ZhcjJ4eEgInExLX72LoYuTiEBJYwSuw5dJkFwmlhklj5 5gALSBWbgLHE3oMdjCC2iICsxOErv5lBbGaBb4wS8x4FgdjCAtYShz4fZwOxWQRUJSb23wSz eQWsJP7PPs8IsU1eYlfbRdYJjFwLGBlWMYqklhbnpucWG+oVJ+YWl+al6yXn525iBPp927Gf m3cwXtoYfIhRgINRiYf3wBShGCHWxLLiytxDjBIczEoivGGtwjFCvCmJlVWpRfnxRaU5qcWH GKU5WJTEec8bVEYJCaQnlqRmp6YWpBbBZJk4OKUaGAsn3jv36szlDjneWU9mzs/fkOAddUH/ 9bttRutK/LffSwiaJ1Z2aY38WiaFo9flpnts2LR4d7xS74ENmmuceh4v3vimuKyCz1nr/RyH X+zz733s+dyx5IhXn+3uWbxWOw11Xf88uPRy7dPQN+l+e17vWHImiFdhm++q0qzF7fLTT6xo mHj0Tu1NJZbijERDLeai4kQArHvZvfcBAAA= X-CMS-MailID: 20181214103344eucas1p1f185709890577dc9767ea0b6286792b0 X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20181214103344eucas1p1f185709890577dc9767ea0b6286792b0 References: Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Non-isochronous transfers: dwc2_gadget_config_nonisoc_xfer_ddma() name is prepended with underscore and the function is adapted to process descriptors passed from outside and to handle end of current sg list element differently from handling the end of the entire buffer. A wrapper for the said function is added which, for sg mode, iterates over scatterlist elements and for each of them calls the function mentioned above. Isochronous transfers: If the usb request contains a scatterlist, the address from the first element is used as dma address at dwc2_gadget_fill_isoc_desc() invocations. Current code for isoc transfers does not allow more than 4096 bytes per transfer, so it is assumed there is only one element in the scatterlist. If there are more, a warning is issued. Please see the fragment under the comment: /* In DDMA mode for ISOC's don't queue request if length greater * than descriptor limits. */ in dwc2_hsotg_ep_queue() to see the limits for isoc transfers. Signed-off-by: Andrzej Pietrasiewicz --- @Minas: I was actually unable to test the isochronous transfers. drivers/usb/dwc2/gadget.c | 104 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 31 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index d9bb6cb..90df8f4 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -768,22 +768,13 @@ static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) return desc_size; } -/* - * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. - * @hs_ep: The endpoint - * @dma_buff: DMA address to use - * @len: Length of the transfer - * - * This function will iterate over descriptor chain and fill its entries - * with corresponding information based on transfer data. - */ -static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, +static void _dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, + struct dwc2_dma_desc **desc, dma_addr_t dma_buff, - unsigned int len) + unsigned int len, + bool true_last) { - struct dwc2_hsotg *hsotg = hs_ep->parent; int dir_in = hs_ep->dir_in; - struct dwc2_dma_desc *desc = hs_ep->desc_list; u32 mps = hs_ep->ep.maxpacket; u32 maxsize = 0; u32 offset = 0; @@ -798,42 +789,80 @@ static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, hs_ep->desc_count = 1; for (i = 0; i < hs_ep->desc_count; ++i) { - desc->status = 0; - desc->status |= (DEV_DMA_BUFF_STS_HBUSY + (*desc)->status = 0; + (*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); if (len > maxsize) { if (!hs_ep->index && !dir_in) - desc->status |= (DEV_DMA_L | DEV_DMA_IOC); + (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); - desc->status |= (maxsize << - DEV_DMA_NBYTES_SHIFT & mask); - desc->buf = dma_buff + offset; + (*desc)->status |= + maxsize << DEV_DMA_NBYTES_SHIFT & mask; + (*desc)->buf = dma_buff + offset; len -= maxsize; offset += maxsize; } else { - desc->status |= (DEV_DMA_L | DEV_DMA_IOC); + if (true_last) + (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); if (dir_in) - desc->status |= (len % mps) ? DEV_DMA_SHORT : - ((hs_ep->send_zlp) ? DEV_DMA_SHORT : 0); - if (len > maxsize) - dev_err(hsotg->dev, "wrong len %d\n", len); + (*desc)->status |= (len % mps) ? DEV_DMA_SHORT : + ((hs_ep->send_zlp && true_last) ? + DEV_DMA_SHORT : 0); - desc->status |= + (*desc)->status |= len << DEV_DMA_NBYTES_SHIFT & mask; - desc->buf = dma_buff + offset; + (*desc)->buf = dma_buff + offset; } - desc->status &= ~DEV_DMA_BUFF_STS_MASK; - desc->status |= (DEV_DMA_BUFF_STS_HREADY + (*desc)->status &= ~DEV_DMA_BUFF_STS_MASK; + (*desc)->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); - desc++; + (*desc)++; } } /* + * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. + * @hs_ep: The endpoint + * @dma_buff: DMA address to use + * @len: Length of the transfer + * + * This function will iterate over descriptor chain and fill its entries + * with corresponding information based on transfer data. + */ +static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, + dma_addr_t dma_buff, + unsigned int len) +{ + struct usb_request *ureq = &hs_ep->req->req; + struct dwc2_dma_desc *desc = hs_ep->desc_list; + struct scatterlist *sg; + int i; + u8 desc_count = 0; + + /* non-DMA sg buffer */ + if (!ureq->num_sgs) { + _dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, &desc, + dma_buff, len, true); + + return; + } + + /* DMA sg buffer */ + for_each_sg(ureq->sg, sg, ureq->num_sgs, i) { + _dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, &desc, + sg_dma_address(sg) + sg->offset, sg_dma_len(sg), + sg_is_last(sg)); + desc_count += hs_ep->desc_count; + } + + hs_ep->desc_count = desc_count; +} + +/* * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain. * @hs_ep: The isochronous endpoint. * @dma_buff: usb requests dma buffer. @@ -944,7 +973,13 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) hs_ep->next_desc = 0; list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { - ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + dma_addr_t dma_addr = hs_req->req.dma; + + if (hs_req->req.num_sgs) { + WARN_ON(hs_req->req.num_sgs > 1); + dma_addr = sg_dma_address(hs_req->req.sg); + } + ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, hs_req->req.length); if (ret) break; @@ -1399,7 +1434,13 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, */ if (using_desc_dma(hs) && hs_ep->isochronous) { if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { - dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + dma_addr_t dma_addr = hs_req->req.dma; + + if (hs_req->req.num_sgs) { + WARN_ON(hs_req->req.num_sgs > 1); + dma_addr = sg_dma_address(hs_req->req.sg); + } + dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, hs_req->req.length); } return 0; @@ -4364,6 +4405,7 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); + gadget->sg_supported = true; dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); return 0;