From patchwork Tue Nov 6 16:18:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrzej Pietrasiewicz X-Patchwork-Id: 10670777 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 419DA1709 for ; Tue, 6 Nov 2018 16:19:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 363C12A739 for ; Tue, 6 Nov 2018 16:19:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2A90C2A746; Tue, 6 Nov 2018 16:19:22 +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 070012A865 for ; Tue, 6 Nov 2018 16:19:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389169AbeKGBpO (ORCPT ); Tue, 6 Nov 2018 20:45:14 -0500 Received: from mailout1.w1.samsung.com ([210.118.77.11]:56474 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387685AbeKGBpO (ORCPT ); Tue, 6 Nov 2018 20:45:14 -0500 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20181106161915euoutp019d3d8b3a61c5859fdc41dab805663e04~klVL0oA0M0418004180euoutp01W; Tue, 6 Nov 2018 16:19:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20181106161915euoutp019d3d8b3a61c5859fdc41dab805663e04~klVL0oA0M0418004180euoutp01W DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1541521156; bh=PAyIO0J5pczWNPU1fV8NXqnkAn8e3xrYYeWtuuRNeII=; h=From:To:Cc:Subject:Date:References:From; b=N/wwA+Tk3O8W+ud97pt29y5lg7MW2CzorxitiN10L1Da+5QZSkDJNAwLmehDxrW3Y w8Dt/VTKeqtlAhAGnMtG5PWNdaaXNDqXKCsC1GbIrgjQwc8SQZpZ5Of3bpzGGTuWxn kTH/2n8gj7h9tZeN6Eeu7Wyxgasnbtequkfy5Z6o= Received: from eusmges1new.samsung.com (unknown [203.254.199.242]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20181106161915eucas1p1cbd5e5aa72a35f63bdc2acc7592db0a5~klVLCBFIV1540815408eucas1p18; Tue, 6 Nov 2018 16:19:15 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges1new.samsung.com (EUCPMTA) with SMTP id 11.39.04441.20FB1EB5; Tue, 6 Nov 2018 16:19:14 +0000 (GMT) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20181106161914eucas1p25517eb3e8815ac7aae03c5b054e16992~klVKTaf5h0235102351eucas1p2H; Tue, 6 Nov 2018 16:19:14 +0000 (GMT) X-AuditID: cbfec7f2-5e3ff70000001159-0d-5be1bf020105 Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id 64.AF.04284.20FB1EB5; Tue, 6 Nov 2018 16:19:14 +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 <0PHS00KDE5BUCP30@eusync1.samsung.com>; Tue, 06 Nov 2018 16:19:14 +0000 (GMT) From: Andrzej Pietrasiewicz To: linux-usb@vger.kernel.org Cc: Andrzej Pietrasiewicz , Greg Kroah-Hartman , Felipe Balbi , Marek Szyprowski , Bartlomiej Zolnierkiewicz , Michal Nazarewicz Subject: [PATCH] usb: gadget: f_fs: Allow scatter-gather buffers Date: Tue, 06 Nov 2018 17:18:58 +0100 Message-id: <20181106161858.1471-1-andrzej.p@samsung.com> X-Mailer: git-send-email 2.11.0 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprFIsWRmVeSWpSXmKPExsWy7djPc7pM+x9GGyzbZmAx62U7i8XGGetZ LQ7er7doXryezWLRslZmi7VH7rJbLDjewurA7rF/7hp2j3V/XjF59G1Zxehx/MZ2Jo/Pm+QC WKO4bFJSczLLUov07RK4Mq6tTy54olGx/9wh5gbGuwpdjJwcEgImEg0L1rB0MXJxCAmsYJR4 OmcalPOZUeLWtdvsMFVvHl+HSixjlOg5fw7KaWKSuPb7CxtIFZuAscTegx2MILaIgKzE4Su/ mUGKmAX6mSSmvd0HlhAWcJDY+24TM4jNIqAqMfXmQdYuRg4OXgFLiR8ToiG2yUvsarvICtIr IfCWVWLryUksEAkXiel7TkHZwhKvjm+BOk9GorPjIBOEXS+x6cseNgh7CqPEvbneELa1xOHj IEM5gQ7ik5i0bTozyF4JAV6JjjYhiBIPiTf3WsFOExKIlfhz4zPbBEaJBYwMqxjFU0uLc9NT iw3zUsv1ihNzi0vz0vWS83M3MQJj7PS/4592MH69lHSIUYCDUYmH98LWh9FCrIllxZW5hxgl OJiVRHhPrwYK8aYkVlalFuXHF5XmpBYfYpTmYFES561meBAtJJCeWJKanZpakFoEk2Xi4JRq YPS3frc/pYq5/sfywMvmLxQPsHIePN/AOn0dc4jcp/3Fz6fvMMmsOBrb56agFVmiuMBK50TX vzg5le8bvxR2OnVeE99Xz+T+KM3vf0aGx8WXLpuWr+5d+z90sa1gZJ9Gs5itvVZZpyBPxuou r22a/Nffimy6qXvF4NWaDZyz/lhGP6oX+HtyphJLcUaioRZzUXEiAL1SPC6tAgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrDJMWRmVeSWpSXmKPExsVy+t/xy7pM+x9GG2x6yW8x62U7i8XGGetZ LQ7er7doXryezWLRslZmi7VH7rJbLDjewurA7rF/7hp2j3V/XjF59G1Zxehx/MZ2Jo/Pm+QC WKO4bFJSczLLUov07RK4Mq6tTy54olGx/9wh5gbGuwpdjJwcEgImEm8eX2cBsYUEljBKLDol 2MXIBWS3MEmsOnqMHSTBJmAssfdgByOILSIgK3H4ym9mkCJmgYlMEqebX7CCJIQFHCT2vtvE DGKzCKhKTL15ECjOwcErYCnxY0I0xDJ5iV1tF1knMHItYGRYxSiSWlqcm55bbKhXnJhbXJqX rpecn7uJERgG24793LyD8dLG4EOMAhyMSjy8GjseRguxJpYVV+YeYpTgYFYS4T29GijEm5JY WZValB9fVJqTWnyIUZqDRUmc97xBZZSQQHpiSWp2ampBahFMlomDU6qBMeyiaaX+n4uv7n64 d9vaVSvmqvxj37s7p0Z1+krP2J185eDqWYd5lV7/VO8+Y/Li5pR2tScv/z58yfzdmtHi/Oq4 OXl+2k6Zn2f8zV535eWiz1yZ3J/XcdjMP5M6i/ub//V1badN76Q4mLU9XK6Zeq5HXvruH6GV ST+seFqXlq9d3p/YVCp3Y6YSS3FGoqEWc1FxIgD8V1T7/wEAAA== X-CMS-MailID: 20181106161914eucas1p25517eb3e8815ac7aae03c5b054e16992 X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20181106161914eucas1p25517eb3e8815ac7aae03c5b054e16992 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 Some protocols implemented in userspace with FunctionFS might require large buffers, e.g. 64kB or more. Currently the said memory is allocated with kmalloc, which might fail should system memory be highly fragmented. On the other hand, some UDC hardware allows scatter-gather operation and this patch takes advantage of this capability: if the requested buffer is larger than PAGE_SIZE and the UDC allows scatter-gather operation, then the buffer is allocated with vmalloc and a scatterlist describing it is created and passed to usb request. Signed-off-by: Andrzej Pietrasiewicz --- drivers/usb/gadget/function/f_fs.c | 92 +++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 3ada83d..e83fa63 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -219,6 +220,8 @@ struct ffs_io_data { struct usb_ep *ep; struct usb_request *req; + struct sg_table sgt; + bool use_sg; struct ffs_data *ffs; }; @@ -750,6 +753,70 @@ static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) return ret; } +/* + * allocate a virtually contiguous buffer and create a scatterlist describing it + * @sg_table - pointer to a place to be filled with sg_table contents + * @size - required buffer size + */ +static void *ffs_build_sg_list(struct sg_table *sg_table, size_t size) +{ + struct page **pages; + void *vaddr; + unsigned long ptr; + unsigned int n_pages; + int i; + + vaddr = vmalloc(size); + if (!vaddr) + return NULL; + + n_pages = (PAGE_ALIGN((unsigned long)vaddr + size) - + ((unsigned long)vaddr & PAGE_MASK)) + >> PAGE_SHIFT; + pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL); + if (!pages) { + vfree(vaddr); + + return NULL; + } + for (i = 0, ptr = (unsigned long)vaddr & PAGE_MASK; i < n_pages; + ++i, ptr += PAGE_SIZE) + pages[i] = vmalloc_to_page((void *)ptr); + + if (sg_alloc_table_from_pages(sg_table, pages, n_pages, + ((unsigned long)vaddr) & ~PAGE_MASK, size, GFP_KERNEL)) { + kvfree(pages); + vfree(vaddr); + + return NULL; + } + kvfree(pages); + + return vaddr; +} + +static inline void *ffs_alloc_buffer(struct ffs_io_data *io_data, + size_t data_len) +{ + if (io_data->use_sg) + return ffs_build_sg_list(&io_data->sgt, data_len); + + return kmalloc(data_len, GFP_KERNEL); +} + +static inline void ffs_free_buffer(struct ffs_io_data *io_data) +{ + if (!io_data->buf) + return; + + if (io_data->use_sg) { + sg_free_table(&io_data->sgt); + vfree(io_data->buf); + } else { + kfree(io_data->buf); + } +} + static void ffs_user_copy_worker(struct work_struct *work) { struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, @@ -777,7 +844,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read) kfree(io_data->to_free); - kfree(io_data->buf); + ffs_free_buffer(io_data); kfree(io_data); } @@ -933,6 +1000,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * earlier */ gadget = epfile->ffs->gadget; + io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE; spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ @@ -949,7 +1017,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); spin_unlock_irq(&epfile->ffs->eps_lock); - data = kmalloc(data_len, GFP_KERNEL); + data = ffs_alloc_buffer(io_data, data_len); if (unlikely(!data)) { ret = -ENOMEM; goto error_mutex; @@ -989,9 +1057,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) bool interrupted = false; req = ep->req; - req->buf = data; + if (io_data->use_sg) { + req->buf = NULL; + req->sg = io_data->sgt.sgl; + req->num_sgs = io_data->sgt.nents; + } else { + req->buf = data; + } req->length = data_len; + io_data->buf = data; + req->context = &done; req->complete = ffs_epfile_io_complete; @@ -1023,7 +1099,13 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) { ret = -ENOMEM; } else { - req->buf = data; + if (io_data->use_sg) { + req->buf = NULL; + req->sg = io_data->sgt.sgl; + req->num_sgs = io_data->sgt.nents; + } else { + req->buf = data; + } req->length = data_len; io_data->buf = data; @@ -1053,7 +1135,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) error_mutex: mutex_unlock(&epfile->mutex); error: - kfree(data); + ffs_free_buffer(io_data); return ret; }