From patchwork Wed Mar 22 09:21:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 73320 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:604a:0:0:0:0:0 with SMTP id j10csp2248521wrt; Wed, 22 Mar 2023 02:47:53 -0700 (PDT) X-Google-Smtp-Source: AK7set/Fxph+OP/PXXofAjTWOVtiGintO0bp3ILnnfxV4aQWjpgSYptywHa/KPzQKIf9aoS0DWT4 X-Received: by 2002:a17:907:2da0:b0:939:ad91:adf5 with SMTP id gt32-20020a1709072da000b00939ad91adf5mr8629663ejc.25.1679478473420; Wed, 22 Mar 2023 02:47:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1679478473; cv=none; d=google.com; s=arc-20160816; b=TGl/WK20lXlxOlMOoJ0PHkiqmr/JxOEcu7qhRMW0XDxcD56sxw8VLHHqIodjdrxXls 6orfccIpr8N5JX9/nMyNbDCXsW6OBOlw/p1iZAAMhzB5rhI1lXtfNPmmlHPwJuIkmopd pH4Eu4vyGHBMhEEzQCjZUO6br2WprlKjV1CdgvvmUFhg/M+Vd5S6gQdaSrLoAeYlGkhd m+SnAR8dNEUT8qvFXr33tA9uBpr/7o5B16u4OAKZtYPlUcOLGYrobr4JvHQ/k/79UME5 znLLIBuBLZD15RsxrzedystRJx3bB8BotN8WP+C0yapnsakktdZl0MO+lJWeRHdBa9Tv LNZg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=jxfNorIALSXTIcdSKIDH829B6vo4dZmRww3AUKQcurM=; b=zph9YwofJnKLmSjhRqOIblpOaBSW6lFIxmvApS5WCpcqtNoa6VVHLOMWzKBG0eWQX/ hAaRBERnA1HmBrp8xM221aVdClUK63HNdNZOl0FxBuMxd30BYpkuejUp/rnEv9xLg0og YH6nQPmUPMFOC6rKJXeEXiE8Ecm1QNGLsUyxgGOBDG/5bWj8ooRahiaNn1nAacv8kck8 yRjN21XV53XLxkOZ7hTOv2KEMO51DxbDX3Y6TjABZCZg8ejo9iustUvDRoa8kLfHfa7R lsWrB0xQ547RXQ1tvUQxSWHr2conUtELJCMOUZO3Dc3EkrSVwE9OTXxp4+h9Oc10kbqr so0Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=nY11iy8f; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c24-20020a170906341800b0092ce46fd9b3si16080904ejb.998.2023.03.22.02.47.30; Wed, 22 Mar 2023 02:47:53 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=nY11iy8f; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231168AbjCVJhQ (ORCPT + 99 others); Wed, 22 Mar 2023 05:37:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39300 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231137AbjCVJhM (ORCPT ); Wed, 22 Mar 2023 05:37:12 -0400 Received: from aposti.net (aposti.net [89.234.176.197]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E65625F202; Wed, 22 Mar 2023 02:37:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1679476887; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jxfNorIALSXTIcdSKIDH829B6vo4dZmRww3AUKQcurM=; b=nY11iy8fR6a2aO+VbjSDeYST0gxDZ1H3hICGOlxr1xoSatxZjWgjvB/vOm6EOOTffEXXW6 1HJCf1NwDmxoUNOG207QaX8dJ1ezKV+dUj+GpVSIt6RdmulX3Xauvj2ny0Bs4YqNt5iGil Jx0mM2Oaw+GfvIAXkLkO0opvKA+tTiY= From: Paul Cercueil To: Greg Kroah-Hartman , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: michael.hennerich@analog.com, nuno.sa@analog.com, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, Paul Cercueil Subject: [PATCH v2 1/3] usb: gadget: Support already-mapped DMA SGs Date: Wed, 22 Mar 2023 10:21:16 +0100 Message-Id: <20230322092118.9213-2-paul@crapouillou.net> In-Reply-To: <20230322092118.9213-1-paul@crapouillou.net> References: <20230322092118.9213-1-paul@crapouillou.net> MIME-Version: 1.0 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1761060819863497760?= X-GMAIL-MSGID: =?utf-8?q?1761060819863497760?= Add a new 'sg_was_mapped' field to the struct usb_request. This field can be used to indicate that the scatterlist associated to the USB transfer has already been mapped into the DMA space, and it does not have to be done internally. Signed-off-by: Paul Cercueil --- drivers/usb/gadget/udc/core.c | 7 ++++++- include/linux/usb/gadget.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 23b0629a8774..5f2c4933769d 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -829,6 +829,11 @@ int usb_gadget_map_request_by_dev(struct device *dev, if (req->length == 0) return 0; + if (req->sg_was_mapped) { + req->num_mapped_sgs = req->num_sgs; + return 0; + } + if (req->num_sgs) { int mapped; @@ -874,7 +879,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_map_request); void usb_gadget_unmap_request_by_dev(struct device *dev, struct usb_request *req, int is_in) { - if (req->length == 0) + if (req->length == 0 || req->sg_was_mapped) return; if (req->num_mapped_sgs) { diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 00750f7020f3..9dd829b8974a 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -52,6 +52,7 @@ struct usb_ep; * @short_not_ok: When reading data, makes short packets be * treated as errors (queue stops advancing till cleanup). * @dma_mapped: Indicates if request has been mapped to DMA (internal) + * @sg_was_mapped: Set if the scatterlist has been mapped before the request * @complete: Function called when request completes, so this request and * its buffer may be re-used. The function will always be called with * interrupts disabled, and it must not sleep. @@ -111,6 +112,7 @@ struct usb_request { unsigned zero:1; unsigned short_not_ok:1; unsigned dma_mapped:1; + unsigned sg_was_mapped:1; void (*complete)(struct usb_ep *ep, struct usb_request *req); From patchwork Wed Mar 22 09:21:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 73312 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:604a:0:0:0:0:0 with SMTP id j10csp2248297wrt; Wed, 22 Mar 2023 02:46:59 -0700 (PDT) X-Google-Smtp-Source: AK7set9VKX/wZhtS262hQqedyRu6pzXqs37MrEnZjL5NdKVYt+eqXEX7RMhn0WtHPUIRZED5j9q+ X-Received: by 2002:a17:907:1def:b0:8b2:d30:e722 with SMTP id og47-20020a1709071def00b008b20d30e722mr5858896ejc.3.1679478419173; Wed, 22 Mar 2023 02:46:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1679478419; cv=none; d=google.com; s=arc-20160816; b=h1xM7VDQo89UzVFa0h9EsnpJXYotECVQ9iZp4VTdzq1nHJ30ckJOVJFlGfH+sRV0QJ JWxOE9xyfN2OrDjvnR2Z2mfLmBDyQDVzS9xr7Twl/MA2Uv5LvaRdE4cq3KSw86v5aW/N y6PrYg6Ff0Nr9hxfnwS20ve25bOKmsUxTypj/ykHz6dOOfEFousQFrDkKHMNG61lZe5b 6OkrBlTqkzggJGGdHyM/PnVXuvINa3gJOu3B6gKZx8GQM2ffnUCodU0+lEdlBpwbIRRF YdstN8qZLd+qV6c2DSXA1D5CI93hHUxOnNR1a2iPUJtUcxCBSUsV1BAQXT3BmEw2crGK qcXA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=CN+sVrd+5zFw4phF+tfY1VTRoiHERXU6QZdwnYlGtLk=; b=sRPAtlDfdhSrNRRqnT6RWOFCS8LzmuKh1wbegwwKbZpxKMp//gMW6jZfUDOB+LQiVI tBJPbTGfNZN2ocJtZgv4CIzkOAALTfXRCzKJtMY06FO6Qp9zTNu1m7+0Xp8HgVENLKyh YJjVeRY+Jh/q6GNhp8HxK/q6BAIWVyCa+8ght+dc6OipRbp30kfqYmjI9ghctc7tzQHe +f/0KmyBDC35hBzlpp1z/3bcfUI0QAC2hcza84X6MYJwE0+3h+cf4QGzTtX6YX1uDsuy cBQBVDHJvmLj64QD6rCFxJQ0CKaAPaTMUi9hMTshdq5dGOwOriF5PS9UdzR0FWCTDnz9 DEJA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b="290ybhb/"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e21-20020a170906845500b0092679d231easi14649506ejy.332.2023.03.22.02.46.35; Wed, 22 Mar 2023 02:46:59 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b="290ybhb/"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230502AbjCVJg7 (ORCPT + 99 others); Wed, 22 Mar 2023 05:36:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38648 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230491AbjCVJg5 (ORCPT ); Wed, 22 Mar 2023 05:36:57 -0400 Received: from aposti.net (aposti.net [89.234.176.197]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 80F7F5FA69; Wed, 22 Mar 2023 02:36:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1679476888; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CN+sVrd+5zFw4phF+tfY1VTRoiHERXU6QZdwnYlGtLk=; b=290ybhb/nQSzlWwiqepHlmfRl6bBQAeQpsu2kCX6juwdFufQnTL2q9cWMSt3BFfqDHY8C/ YBuHTnA/oFffaBiMc0xDnycFtNmmDF5gB1zoXuIyV3EXGi4mHcg5sJ335CVRlVNFYq5f7t ko18FMhNgLfOeOQTzPqtKDHEyqvOl1o= From: Paul Cercueil To: Greg Kroah-Hartman , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: michael.hennerich@analog.com, nuno.sa@analog.com, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, Paul Cercueil Subject: [PATCH v2 2/3] usb: gadget: functionfs: Factorize wait-for-endpoint code Date: Wed, 22 Mar 2023 10:21:17 +0100 Message-Id: <20230322092118.9213-3-paul@crapouillou.net> In-Reply-To: <20230322092118.9213-1-paul@crapouillou.net> References: <20230322092118.9213-1-paul@crapouillou.net> MIME-Version: 1.0 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1761060763025157812?= X-GMAIL-MSGID: =?utf-8?q?1761060763025157812?= This exact same code was duplicated in two different places. Signed-off-by: Paul Cercueil --- drivers/usb/gadget/function/f_fs.c | 48 +++++++++++++++++------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index ddfc537c7526..8da64f0fdef0 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -947,31 +947,44 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, return ret; } -static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) +static struct ffs_ep *ffs_epfile_wait_ep(struct file *file) { struct ffs_epfile *epfile = file->private_data; - struct usb_request *req; struct ffs_ep *ep; - char *data = NULL; - ssize_t ret, data_len = -EINVAL; - int halt; - - /* Are we still active? */ - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) - return -ENODEV; + int ret; /* Wait for endpoint to be enabled */ ep = epfile->ep; if (!ep) { if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + return ERR_PTR(-EAGAIN); ret = wait_event_interruptible( epfile->ffs->wait, (ep = epfile->ep)); if (ret) - return -EINTR; + return ERR_PTR(-EINTR); } + return ep; +} + +static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) +{ + struct ffs_epfile *epfile = file->private_data; + struct usb_request *req; + struct ffs_ep *ep; + char *data = NULL; + ssize_t ret, data_len = -EINVAL; + int halt; + + /* Are we still active? */ + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) + return -ENODEV; + + ep = ffs_epfile_wait_ep(file); + if (IS_ERR(ep)) + return PTR_ERR(ep); + /* Do we halt? */ halt = (!io_data->read == !epfile->in); if (halt && epfile->isoc) @@ -1305,16 +1318,9 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, return -ENODEV; /* Wait for endpoint to be enabled */ - ep = epfile->ep; - if (!ep) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - ret = wait_event_interruptible( - epfile->ffs->wait, (ep = epfile->ep)); - if (ret) - return -EINTR; - } + ep = ffs_epfile_wait_ep(file); + if (IS_ERR(ep)) + return PTR_ERR(ep); spin_lock_irq(&epfile->ffs->eps_lock); From patchwork Wed Mar 22 09:21:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 73322 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:604a:0:0:0:0:0 with SMTP id j10csp2249009wrt; Wed, 22 Mar 2023 02:49:38 -0700 (PDT) X-Google-Smtp-Source: AK7set+1ULCAVBkCLBK9I9qWrH41W6hEefjHyA8mFgOMiY/lP2Rp5wkjBwCF+q/0pr3oO2GMZeYi X-Received: by 2002:a17:90b:3a89:b0:23d:e0e8:f453 with SMTP id om9-20020a17090b3a8900b0023de0e8f453mr2715936pjb.38.1679478578521; Wed, 22 Mar 2023 02:49:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1679478578; cv=none; d=google.com; s=arc-20160816; b=bH8K6Y8XJ2Og6Y5DCeXWZfGggZSlzL6d8uOK5U6KFkorw0nwuAh0GS7IntRdKOtUQc HGb51q2GpGnot5m8zqVHX2M1lIrd51FdW79LEWMQTD1Y32mHdSPIvtCSv5bL6dbPNIEV 07yGCuHVxn2uWRzgVSx1nmLEJpVS7yQStnQ3djtjwGwEs9yP0Jsht+sdMv7YGYbecqvr 2rDOMHE5PzaGrLe2iilV4lXaSSQguOFSuaEW2UtU4STPKf90jcg8aHn5Hrh7ptdtFj0L YrxOozEToXH9fBwZFXh5e2CdDz+BfzxmuUs01F3B69CU6zsRnSjMe1k/jtwnqopaF8ZC 6Ajw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=n9BZxja6OPxkoW/Pr/5zyuJjOVcEhn2qcfBGacm4biQ=; b=Sy2ch+BEoFJA/mixqzkfvR4J9dUtTrD46gHqmKjWYuaPg8RjYo5mwkMu1qdtvgVvd6 lSM8WgXESpBvFKMJbb97wv78D+w+4p+vsnN+3Yw4SGNGsOZEw47mIn8ZwW8FkyvEC6kO T+bkYIymFZod3ZjmL6opvzBHJ07zmEqeCV8leUH9OCCA8G/hwL/KXke2Hng0Vx9Ce9BZ S/O2pODTjwY0DZnyo5sEwroKfoDHJvY8/7nXh58Z6j2cR+h1fiYGqxLgU+1s7vJAD/ND emyNXcgU4xJY5WdS63GYfLiNMWjh+YbIn8kKMqBmj3MTXUamMwNt26pK9/XFg6mcaYzy RxUA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=wthtQQZt; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ot2-20020a17090b3b4200b0023495f71234si23419100pjb.67.2023.03.22.02.49.26; Wed, 22 Mar 2023 02:49:38 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=wthtQQZt; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230445AbjCVJgR (ORCPT + 99 others); Wed, 22 Mar 2023 05:36:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36880 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229764AbjCVJgQ (ORCPT ); Wed, 22 Mar 2023 05:36:16 -0400 Received: from aposti.net (aposti.net [89.234.176.197]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 309155B5EB; Wed, 22 Mar 2023 02:36:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1679476889; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n9BZxja6OPxkoW/Pr/5zyuJjOVcEhn2qcfBGacm4biQ=; b=wthtQQZtyOnhrcXoagzWxiGeNSkDkiK92F55Rvw8/gnwMW7uRURTfIP5aGPWyvLYOWKlKT dZYDw5Plukkkb4jsnERKRMidJMCuT2Ntc2ub5gkjyLhdOFvbPh+Vd7MjOhcdMZM0N0ATi5 0YlnjWFPNv7irFugz8kjYJaIhIKGuFI= From: Paul Cercueil To: Greg Kroah-Hartman , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: michael.hennerich@analog.com, nuno.sa@analog.com, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, Paul Cercueil Subject: [PATCH v2 3/3] usb: gadget: functionfs: Add DMABUF import interface Date: Wed, 22 Mar 2023 10:21:18 +0100 Message-Id: <20230322092118.9213-4-paul@crapouillou.net> In-Reply-To: <20230322092118.9213-1-paul@crapouillou.net> References: <20230322092118.9213-1-paul@crapouillou.net> MIME-Version: 1.0 X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1761060929975947399?= X-GMAIL-MSGID: =?utf-8?q?1761060929975947399?= This patch introduces three new ioctls. They all should be called on a data endpoint (ie. not ep0). They are: - FUNCTIONFS_DMABUF_ATTACH, which takes the file descriptor of a DMABUF object to attach to the endpoint. - FUNCTIONFS_DMABUF_DETACH, which takes the file descriptor of the DMABUF to detach from the endpoint. Note that closing the endpoint's file descriptor will automatically detach all attached DMABUFs. - FUNCTIONFS_DMABUF_TRANSFER, which requests a data transfer from / to the given DMABUF. Its argument is a structure that packs the DMABUF's file descriptor, the size in bytes to transfer (which should generally be set to the size of the DMABUF), and a 'flags' field which is unused for now. Before this ioctl can be used, the related DMABUF must be attached with FUNCTIONFS_DMABUF_ATTACH. These three ioctls enable the FunctionFS code to transfer data between the USB stack and a DMABUF object, which can be provided by a driver from a completely different subsystem, in a zero-copy fashion. Signed-off-by: Paul Cercueil --- v2: - Make ffs_dma_resv_lock() static - Add MODULE_IMPORT_NS(DMA_BUF); - The attach/detach functions are now performed without locking the eps_lock spinlock. The transfer function starts with the spinlock unlocked, then locks it before allocating and queueing the USB transfer. --- drivers/usb/gadget/function/f_fs.c | 421 ++++++++++++++++++++++++++++ include/uapi/linux/usb/functionfs.h | 14 +- 2 files changed, 434 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 8da64f0fdef0..f5c609c83b36 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -15,6 +15,9 @@ /* #define VERBOSE_DEBUG */ #include +#include +#include +#include #include #include #include @@ -43,6 +46,8 @@ #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ +MODULE_IMPORT_NS(DMA_BUF); + /* Reference counter handling */ static void ffs_data_get(struct ffs_data *ffs); static void ffs_data_put(struct ffs_data *ffs); @@ -124,6 +129,26 @@ struct ffs_ep { u8 num; }; +struct ffs_dmabuf_priv { + struct list_head entry; + struct kref ref; + struct dma_buf_attachment *attach; + spinlock_t lock; + u64 context; +}; + +struct ffs_dma_fence { + struct dma_fence base; + struct ffs_dmabuf_priv *priv; + struct sg_table *sgt; + enum dma_data_direction dir; +}; + +static inline struct ffs_dma_fence *to_ffs_dma_fence(struct dma_fence *fence) +{ + return container_of(fence, struct ffs_dma_fence, base); +} + struct ffs_epfile { /* Protects ep->ep and ep->req. */ struct mutex mutex; @@ -197,6 +222,8 @@ struct ffs_epfile { unsigned char isoc; /* P: ffs->eps_lock */ unsigned char _pad; + + struct list_head dmabufs; }; struct ffs_buffer { @@ -1292,19 +1319,374 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) return res; } +static void ffs_dmabuf_release(struct kref *ref) +{ + struct ffs_dmabuf_priv *priv = container_of(ref, struct ffs_dmabuf_priv, ref); + struct dma_buf_attachment *attach = priv->attach; + struct dma_buf *dmabuf = attach->dmabuf; + + pr_debug("FFS DMABUF release\n"); + dma_buf_detach(attach->dmabuf, attach); + dma_buf_put(dmabuf); + + list_del(&priv->entry); + kfree(priv); +} + +static void ffs_dmabuf_get(struct dma_buf_attachment *attach) +{ + struct ffs_dmabuf_priv *priv = attach->importer_priv; + + kref_get(&priv->ref); +} + +static void ffs_dmabuf_put(struct dma_buf_attachment *attach) +{ + struct ffs_dmabuf_priv *priv = attach->importer_priv; + + kref_put(&priv->ref, ffs_dmabuf_release); +} + static int ffs_epfile_release(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; + struct ffs_dmabuf_priv *priv, *tmp; ENTER(); + /* Close all attached DMABUFs */ + list_for_each_entry_safe(priv, tmp, &epfile->dmabufs, entry) { + ffs_dmabuf_put(priv->attach); + } + __ffs_epfile_read_buffer_free(epfile); ffs_data_closed(epfile->ffs); return 0; } +static void ffs_dmabuf_signal_done(struct ffs_dma_fence *dma_fence, int ret) +{ + struct ffs_dmabuf_priv *priv = dma_fence->priv; + struct dma_fence *fence = &dma_fence->base; + + dma_fence_get(fence); + fence->error = ret; + dma_fence_signal(fence); + + dma_buf_unmap_attachment(priv->attach, dma_fence->sgt, dma_fence->dir); + dma_fence_put(fence); + ffs_dmabuf_put(priv->attach); +} + +static void ffs_epfile_dmabuf_io_complete(struct usb_ep *ep, + struct usb_request *req) +{ + ENTER(); + + pr_debug("FFS: DMABUF transfer complete, status=%d\n", req->status); + ffs_dmabuf_signal_done(req->context, req->status); + usb_ep_free_request(ep, req); +} + +static const char *ffs_dmabuf_get_driver_name(struct dma_fence *fence) +{ + return "functionfs"; +} + +static const char *ffs_dmabuf_get_timeline_name(struct dma_fence *fence) +{ + return ""; +} + +static void ffs_dmabuf_fence_release(struct dma_fence *fence) +{ + struct ffs_dma_fence *dma_fence = to_ffs_dma_fence(fence); + + kfree(dma_fence); +} + +static const struct dma_fence_ops ffs_dmabuf_fence_ops = { + .get_driver_name = ffs_dmabuf_get_driver_name, + .get_timeline_name = ffs_dmabuf_get_timeline_name, + .release = ffs_dmabuf_fence_release, +}; + +static int ffs_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock) +{ + int ret; + + ret = dma_resv_lock_interruptible(dmabuf->resv, NULL); + if (ret) { + if (ret != -EDEADLK) + goto out; + if (nonblock) { + ret = -EBUSY; + goto out; + } + + ret = dma_resv_lock_slow_interruptible(dmabuf->resv, NULL); + } + +out: + return ret; +} + +static struct dma_buf_attachment * +ffs_dmabuf_find_attachment(struct device *dev, struct dma_buf *dmabuf, + bool nonblock) +{ + struct dma_buf_attachment *elm, *attach = NULL; + int ret; + + ret = ffs_dma_resv_lock(dmabuf, nonblock); + if (ret) + return ERR_PTR(ret); + + list_for_each_entry(elm, &dmabuf->attachments, node) { + if (elm->dev == dev) { + attach = elm; + break; + } + } + + if (attach) + ffs_dmabuf_get(elm); + + dma_resv_unlock(dmabuf->resv); + + return attach ?: ERR_PTR(-EPERM); +} + +static int ffs_dmabuf_attach(struct file *file, int fd) +{ + struct ffs_epfile *epfile = file->private_data; + struct usb_gadget *gadget = epfile->ffs->gadget; + struct dma_buf_attachment *attach; + struct ffs_dmabuf_priv *priv; + struct dma_buf *dmabuf; + int err; + + if (!gadget || !gadget->sg_supported) + return -EPERM; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + attach = dma_buf_attach(dmabuf, gadget->dev.parent); + if (IS_ERR(attach)) { + err = PTR_ERR(attach); + goto err_dmabuf_put; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + err = -ENOMEM; + goto err_dmabuf_detach; + } + + attach->importer_priv = priv; + + priv->attach = attach; + spin_lock_init(&priv->lock); + kref_init(&priv->ref); + priv->context = dma_fence_context_alloc(1); + + list_add(&priv->entry, &epfile->dmabufs); + + return 0; + +err_dmabuf_detach: + dma_buf_detach(dmabuf, attach); +err_dmabuf_put: + dma_buf_put(dmabuf); + + return err; +} + +static int ffs_dmabuf_detach(struct file *file, int fd) +{ + struct ffs_epfile *epfile = file->private_data; + struct usb_gadget *gadget = epfile->ffs->gadget; + bool nonblock = file->f_flags & O_NONBLOCK; + struct dma_buf_attachment *attach; + struct dma_buf *dmabuf; + int ret = 0; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + attach = ffs_dmabuf_find_attachment(gadget->dev.parent, + dmabuf, nonblock); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + goto out_dmabuf_put; + } + + ffs_dmabuf_put(attach); + ffs_dmabuf_put(attach); + +out_dmabuf_put: + dma_buf_put(dmabuf); + return ret; +} + +static int ffs_dmabuf_transfer(struct file *file, + const struct usb_ffs_dmabuf_transfer_req *req) +{ + bool dma_to_ram, nonblock = file->f_flags & O_NONBLOCK; + struct ffs_epfile *epfile = file->private_data; + struct usb_gadget *gadget = epfile->ffs->gadget; + struct dma_buf_attachment *attach; + struct ffs_dmabuf_priv *priv; + enum dma_data_direction dir; + struct ffs_dma_fence *fence; + struct usb_request *usb_req; + struct sg_table *sg_table; + struct dma_buf *dmabuf; + struct ffs_ep *ep; + int ret; + + if (req->flags & ~USB_FFS_DMABUF_TRANSFER_MASK) + return -EINVAL; + + dmabuf = dma_buf_get(req->fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + if (req->length > dmabuf->size || req->length == 0) { + ret = -EINVAL; + goto err_dmabuf_put; + } + + attach = ffs_dmabuf_find_attachment(gadget->dev.parent, + dmabuf, nonblock); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + goto err_dmabuf_put; + } + + priv = attach->importer_priv; + + if (epfile->in) + dir = DMA_FROM_DEVICE; + else + dir = DMA_TO_DEVICE; + + sg_table = dma_buf_map_attachment(attach, dir); + if (IS_ERR(sg_table)) { + ret = PTR_ERR(sg_table); + goto err_attachment_put; + } + + ep = ffs_epfile_wait_ep(file); + if (IS_ERR(ep)) { + ret = PTR_ERR(ep); + goto err_unmap_attachment; + } + + ret = ffs_dma_resv_lock(dmabuf, nonblock); + if (ret) + goto err_unmap_attachment; + + /* Make sure we don't have writers */ + if (!dma_resv_test_signaled(dmabuf->resv, DMA_RESV_USAGE_WRITE)) { + pr_debug("FFS WRITE fence is not signaled\n"); + ret = -EBUSY; + goto err_resv_unlock; + } + + dma_to_ram = dir == DMA_FROM_DEVICE; + + /* If we're writing to the DMABUF, make sure we don't have readers */ + if (dma_to_ram && + !dma_resv_test_signaled(dmabuf->resv, DMA_RESV_USAGE_READ)) { + pr_debug("FFS READ fence is not signaled\n"); + ret = -EBUSY; + goto err_resv_unlock; + } + + ret = dma_resv_reserve_fences(dmabuf->resv, 1); + if (ret) + goto err_resv_unlock; + + fence = kmalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) { + ret = -ENOMEM; + goto err_resv_unlock; + } + + fence->sgt = sg_table; + fence->dir = dir; + fence->priv = priv; + + dma_fence_init(&fence->base, &ffs_dmabuf_fence_ops, + &priv->lock, priv->context, 0); + + spin_lock_irq(&epfile->ffs->eps_lock); + + /* In the meantime, endpoint got disabled or changed. */ + if (epfile->ep != ep) { + ret = -ESHUTDOWN; + goto err_spin_unlock; + } + + usb_req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC); + if (!usb_req) { + ret = -ENOMEM; + goto err_spin_unlock; + } + + dma_resv_add_fence(dmabuf->resv, &fence->base, + dma_resv_usage_rw(dma_to_ram)); + dma_resv_unlock(dmabuf->resv); + + /* Now that the dma_fence is in place, queue the transfer. */ + + usb_req->length = req->length; + usb_req->buf = NULL; + usb_req->sg = sg_table->sgl; + usb_req->num_sgs = sg_nents_for_len(sg_table->sgl, req->length); + usb_req->sg_was_mapped = true; + usb_req->context = fence; + usb_req->complete = ffs_epfile_dmabuf_io_complete; + + ret = usb_ep_queue(ep->ep, usb_req, GFP_ATOMIC); + if (ret) { + usb_ep_free_request(ep->ep, usb_req); + + spin_unlock_irq(&epfile->ffs->eps_lock); + + pr_warn("FFS: Failed to queue DMABUF: %d\n", ret); + ffs_dmabuf_signal_done(fence, ret); + goto out_dma_buf_put; + } + + spin_unlock_irq(&epfile->ffs->eps_lock); + +out_dma_buf_put: + dma_buf_put(dmabuf); + + return ret; + +err_spin_unlock: + spin_unlock_irq(&epfile->ffs->eps_lock); + dma_fence_put(&fence->base); +err_resv_unlock: + dma_resv_unlock(dmabuf->resv); +err_unmap_attachment: + dma_buf_unmap_attachment(attach, sg_table, dir); +err_attachment_put: + ffs_dmabuf_put(attach); +err_dmabuf_put: + dma_buf_put(dmabuf); + + return ret; +} + static long ffs_epfile_ioctl(struct file *file, unsigned code, unsigned long value) { @@ -1317,6 +1699,44 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; + switch (code) { + case FUNCTIONFS_DMABUF_ATTACH: + { + int fd; + + if (copy_from_user(&fd, (void __user *)value, sizeof(fd))) { + ret = -EFAULT; + break; + } + + return ffs_dmabuf_attach(file, fd); + } + case FUNCTIONFS_DMABUF_DETACH: + { + int fd; + + if (copy_from_user(&fd, (void __user *)value, sizeof(fd))) { + ret = -EFAULT; + break; + } + + return ffs_dmabuf_detach(file, fd); + } + case FUNCTIONFS_DMABUF_TRANSFER: + { + struct usb_ffs_dmabuf_transfer_req req; + + if (copy_from_user(&req, (void __user *)value, sizeof(req))) { + ret = -EFAULT; + break; + } + + return ffs_dmabuf_transfer(file, &req); + } + default: + break; + } + /* Wait for endpoint to be enabled */ ep = ffs_epfile_wait_ep(file); if (IS_ERR(ep)) @@ -1931,6 +2351,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs) for (i = 1; i <= count; ++i, ++epfile) { epfile->ffs = ffs; mutex_init(&epfile->mutex); + INIT_LIST_HEAD(&epfile->dmabufs); if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]); else diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h index d77ee6b65328..1412ab9f8ccc 100644 --- a/include/uapi/linux/usb/functionfs.h +++ b/include/uapi/linux/usb/functionfs.h @@ -84,6 +84,15 @@ struct usb_ext_prop_desc { __le16 wPropertyNameLength; } __attribute__((packed)); +/* Flags for usb_ffs_dmabuf_transfer_req->flags (none for now) */ +#define USB_FFS_DMABUF_TRANSFER_MASK 0x0 + +struct usb_ffs_dmabuf_transfer_req { + int fd; + __u32 flags; + __u64 length; +} __attribute__((packed)); + #ifndef __KERNEL__ /* @@ -288,6 +297,9 @@ struct usb_functionfs_event { #define FUNCTIONFS_ENDPOINT_DESC _IOR('g', 130, \ struct usb_endpoint_descriptor) - +#define FUNCTIONFS_DMABUF_ATTACH _IOW('g', 131, int) +#define FUNCTIONFS_DMABUF_DETACH _IOW('g', 132, int) +#define FUNCTIONFS_DMABUF_TRANSFER _IOW('g', 133, \ + struct usb_ffs_dmabuf_transfer_req) #endif /* _UAPI__LINUX_FUNCTIONFS_H__ */