From patchwork Tue Jan 30 12:23:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 194067 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:2087:b0:106:209c:c626 with SMTP id gs7csp1181186dyb; Tue, 30 Jan 2024 04:24:38 -0800 (PST) X-Google-Smtp-Source: AGHT+IHXkOhjsjpSeb+KSFYSdoUrW2Ln83ODYT5nigm26Wv22GaBk5efDYJ1ykwQleIt6L9MTujW X-Received: by 2002:a05:6402:2cb:b0:55f:2001:bcd2 with SMTP id b11-20020a05640202cb00b0055f2001bcd2mr2468435edx.14.1706617477857; Tue, 30 Jan 2024 04:24:37 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706617477; cv=pass; d=google.com; s=arc-20160816; b=h+WFJBm23uo6K44woc/Wo5B5seeVBhKA9Q2CIugGSncIcmDJSzMEsOmZhKr9L6Nh89 C1HuTX58M5GeohZ1lvTkL15uxGZb6GABnNBMnvhz5SpGH1MQQxG3hnC9abER6H0QAqLy Fy1mvd72F1hPOfhETJIK+dhmZMMF9gEG6vNqw4bZs6Wh3AvCfDl6E0ImU8ZynuX2T+JY nkHVGJrFJ00LiKILihEUkQ51O1SeQeXC7hWyxjkzmoiO7Oyz//kRREMXX+GCCahYR5r9 jKxdxlfgm/fuGMBHfIM6mrg/CuxxsXV07nDLCntSuZx30O0zW1yBCDxgX+kwHYbYNToQ HTTA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=SqXbfp61fzBHWNEqVrElLd46cr7HG/1wYVIvKKSn5jY=; fh=rOwklx3n4HddILOil3p/QTffAKooJ/gOk0lSkLfkcvQ=; b=bUlBgPdU9fJxx6I5pJbMlSRZ5dpC0WVcnCdfOZl46VBaXQ/aaZE1cVoZ0hTeEGsdO7 beKbO0TVGiYkDJEtPIXnGSdyFMyjZSUEUoe5regFBW0Cz9cMhBtJr3pJ4mYJKA28NoDW jLhqtp3hGBMiWsFQZzAPxRFLobwFQ9DG/rgGHwnB/Y6iqpp0IZipKAGgIYw8+gYE5Ge0 5upm7+7OmXd2FnE+veePrdbXxDy/1stV98/Y0VHM1MCPfyIMS0XLYV2uXY2hrDUo6h8U 60QGUfIie2I/b6D761elx6KGZDGo/H5HEUoticr3XvFR4RWtr7FpGXrLWg0cHoBCVYcv 2HYA== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=uStG4m2O; arc=pass (i=1 spf=pass spfdomain=crapouillou.net dkim=pass dkdomain=crapouillou.net dmarc=pass fromdomain=crapouillou.net); spf=pass (google.com: domain of linux-kernel+bounces-44596-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-44596-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id t21-20020a508d55000000b0055f1f8b6f62si1250111edt.252.2024.01.30.04.24.37 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jan 2024 04:24:37 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-44596-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=uStG4m2O; arc=pass (i=1 spf=pass spfdomain=crapouillou.net dkim=pass dkdomain=crapouillou.net dmarc=pass fromdomain=crapouillou.net); spf=pass (google.com: domain of linux-kernel+bounces-44596-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-44596-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 4BED71F25150 for ; Tue, 30 Jan 2024 12:24:37 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id EB6FB6A34F; Tue, 30 Jan 2024 12:24:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b="uStG4m2O" Received: from aposti.net (aposti.net [89.234.176.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B206167E9C; Tue, 30 Jan 2024 12:23:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=89.234.176.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706617440; cv=none; b=NUOu7lHQqmJnEjS3w+D5AajlHIkzFLD1IsrzkVVLdCUe2//MQRZN9aiv6AE0kJHohR5Egx8uhMGWTKXpeKzvZQj3spmE50n8urcDlAUfrHBHg6v3HEumh3vd/u46elOpejjIqqGj3DO8FQllhbQrgWnuUjH37KZsj2b/54SwMzc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706617440; c=relaxed/simple; bh=66FzAt7nJpAY9ka7VMdHoplxE2iQOAZv1WQkaTZVLTI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jNYstDiDeY2lAtcY3BsXlFC2k6xw59IVAIq3RgQ9Bh9kXP2KIyQY7heV35BMYFGZ2ynhKPKI/RsJb0DLN/Vsk2BJkID+yRDYLND1vQeNZbOb6Z0/VUpdbrWfMg1Xl2hBH/1vf0wofzciBj5mTk1S9cbJ7oNADKHBqeU7ilEX7es= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=crapouillou.net; spf=pass smtp.mailfrom=crapouillou.net; dkim=pass (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b=uStG4m2O; arc=none smtp.client-ip=89.234.176.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=crapouillou.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=crapouillou.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1706617428; 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=SqXbfp61fzBHWNEqVrElLd46cr7HG/1wYVIvKKSn5jY=; b=uStG4m2OiYDXjAnbZhvlePwi6RCL5a65XfVMHf3kIDQFND4jkC6cwEBz0jaA9AW1MZbf1/ 2u/o3/68rPjN5owEZJ5rGx2hINs1wO31bHkjYDAEEB8LZF+afk4mDgWOr+EQfngv9sqZL3 QFrIivxNGWeocp6JrbECrSQlqQxE4YQ= From: Paul Cercueil To: Greg Kroah-Hartman , Jonathan Corbet , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Michael Hennerich , linux-usb@vger.kernel.org, linux-doc@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 v6 1/4] usb: gadget: Support already-mapped DMA SGs Date: Tue, 30 Jan 2024 13:23:37 +0100 Message-ID: <20240130122340.54813-2-paul@crapouillou.net> In-Reply-To: <20240130122340.54813-1-paul@crapouillou.net> References: <20240130122340.54813-1-paul@crapouillou.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1789518128387410797 X-GMAIL-MSGID: 1789518128387410797 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 d59f94464b87..9d4150124fdb 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -903,6 +903,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; @@ -948,7 +953,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 a771ccc038ac..c529e4e06997 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 Tue Jan 30 12:23:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 194069 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:2087:b0:106:209c:c626 with SMTP id gs7csp1181378dyb; Tue, 30 Jan 2024 04:24:57 -0800 (PST) X-Google-Smtp-Source: AGHT+IElwekgIAaFBP4OVJr0zwi1XDH5aAj7OX+szwOcxO6QIrBzzr8FIIRauT16HRJt03xxEK6U X-Received: by 2002:a05:620a:14ad:b0:783:b1f6:bcbf with SMTP id x13-20020a05620a14ad00b00783b1f6bcbfmr7531452qkj.5.1706617497016; Tue, 30 Jan 2024 04:24:57 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706617497; cv=pass; d=google.com; s=arc-20160816; b=L2VKI9GEuuvD3Ci3twNzOgFquZEzC+aSTqlhxT/Anm0BfEVWFqVuswQ9wHJ55WoQDo v1jwWc2E9u3VAC5EDjVSM0l7yZD70JLnglphKcXe2RRbA7GP3kipmeknEERA0vhN8AN2 DrAQRIGGG6rM0Mbp8huIzCV77rALtN/HvxxsU+45aK362L7BkzZq1FtVbdb8PA+nx9ye rngtCGRDlCpJ52kRLGXYi+7NJ1KzvJg1vEVD7jDH7dfp2SIjy1USwaMHB/CzSSjWMPmh SBrZqp6De662YUeHQlEdrJ97XuthnsJoo6SCvi4d/WOvV3sGVeA6nyAvFJiUVShzzD/E 6owQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=XWEviP/cSSSXmmQM4aKkBeUs1pfsU9NbxBdr/i8jS+4=; fh=rOwklx3n4HddILOil3p/QTffAKooJ/gOk0lSkLfkcvQ=; b=LvctYTUTDeUnAhmfdMqVHn1cz07JRF3bjGbTc52gSuhIZ96aA+kPtoebjLweHBpEdz mFJA5qOZvnWQBcqklPUG19jTLSDu3JLJZ0bzysUPpBOnHIFZzcN34SxKKM4XgIWKgxml MeHHodTK8D4sr9YXX40XNYPl7WAtzbZSDKFgjIrjt+hAg4kSCBQsZixfkOA9LCHFOjzp s8NNvKvOKao2MZr8Sr4PDh5aRfwpl2DBWXBANT/p245+ygkXdSLk/DQvpjN3+E8H8x1q rQzz3lmppjYLwA0bzAalV0FsLidD0utItVjMQpgKqx8waKvrfrKbD+8LSzrL+E9LDDEn OcTQ== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=jYqDNCvz; arc=pass (i=1 spf=pass spfdomain=crapouillou.net dkim=pass dkdomain=crapouillou.net dmarc=pass fromdomain=crapouillou.net); spf=pass (google.com: domain of linux-kernel+bounces-44597-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-44597-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id f18-20020a05620a409200b00783344715eesi6936581qko.177.2024.01.30.04.24.56 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jan 2024 04:24:57 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-44597-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=jYqDNCvz; arc=pass (i=1 spf=pass spfdomain=crapouillou.net dkim=pass dkdomain=crapouillou.net dmarc=pass fromdomain=crapouillou.net); spf=pass (google.com: domain of linux-kernel+bounces-44597-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-44597-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id CB25F1C24060 for ; Tue, 30 Jan 2024 12:24:56 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 625336BB2D; Tue, 30 Jan 2024 12:24:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b="jYqDNCvz" Received: from aposti.net (aposti.net [89.234.176.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 29E5A67E8D; Tue, 30 Jan 2024 12:24:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=89.234.176.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706617448; cv=none; b=m0WH5dVq402u2AWg4P4EsV+Bg/NF+sPIHeSU7wRuy4h5qbQ/YhL4Jbj4e7n6hYgYHkRHyQKe9KBZo/acsPi8bvr72ywhZ0i+1ulvtptHIKY6RkerBC034erkyqB3++Btf+/99DPL+9IJ3s7XW8YLUE+CqNk4PRStDl+LRAcBiYQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706617448; c=relaxed/simple; bh=BE8sRZ3slJO1R4SWqbcjAAfUIst/OdB5yuqfyw8rI18=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HhUs4zfORPgPDUOMardDNLK0nj9A7jCwSvNUs75sx35GBuzpt5vXWNEeyLjEL7wGLIELz1xmi562McCJXO49f8guPYBxcRcyTKqfb1hbpnNdV/L9gOAdWtCqumBkrn99WK2DX/pU+Yo2+7NTOc8cOYy1XSPYvS6DdlUO0Rf3k4M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=crapouillou.net; spf=pass smtp.mailfrom=crapouillou.net; dkim=pass (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b=jYqDNCvz; arc=none smtp.client-ip=89.234.176.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=crapouillou.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=crapouillou.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1706617429; 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=XWEviP/cSSSXmmQM4aKkBeUs1pfsU9NbxBdr/i8jS+4=; b=jYqDNCvz4OHuusyFV4JsYbmyK6jJ6zUaqU0yJW99Gh2/atzYrLcryXNMQW3pLADkJT1K0B Iq4V3FohKB4OYC1mtJy7RvBYG6+AFRSVH+RXw5ktmum/5Ip2Gnwcgx8khtE/OVPIDGHXAo +niRNnw9UPEzeGuf0yIiByri5iDzOd0= From: Paul Cercueil To: Greg Kroah-Hartman , Jonathan Corbet , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Michael Hennerich , linux-usb@vger.kernel.org, linux-doc@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 v6 2/4] usb: gadget: functionfs: Factorize wait-for-endpoint code Date: Tue, 30 Jan 2024 13:23:38 +0100 Message-ID: <20240130122340.54813-3-paul@crapouillou.net> In-Reply-To: <20240130122340.54813-1-paul@crapouillou.net> References: <20240130122340.54813-1-paul@crapouillou.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1789518148344359287 X-GMAIL-MSGID: 1789518148344359287 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 be3851cffb73..491a1e0f4fa3 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -934,31 +934,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) @@ -1280,16 +1293,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 Tue Jan 30 12:23:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 194070 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:2087:b0:106:209c:c626 with SMTP id gs7csp1181604dyb; Tue, 30 Jan 2024 04:25:20 -0800 (PST) X-Google-Smtp-Source: AGHT+IHKpdNikiVWIW5SrTh3ximIHwZp2ZbEWpFX/+nMngZPFGLpwncLmTT4YjGpWE9y6NsPqL+H X-Received: by 2002:aa7:d60e:0:b0:55e:f8bd:6246 with SMTP id c14-20020aa7d60e000000b0055ef8bd6246mr3453635edr.18.1706617520530; Tue, 30 Jan 2024 04:25:20 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706617520; cv=pass; d=google.com; s=arc-20160816; b=vuutLaeKEm/yj/DW93h83Y+Kmqb9e1mbWrTZr5per1WuX+esjMYNCKDSTQgwpfxCqN yoxkroXWMlhCDhLqdTnix3UbKPXBYR3Cz4Yq46LrWft5qHmKc06QL9DL6cpKK3CDXl2P Qt+wVi60S20a3B+uAvHDzbvTpR1GX5qBB7o2aRtPzGEUnDm/z1qD3Ino6dujiqLhiWzP kVD4qk11mguuU3S+h/aqXKUOJRf92WfTzXuVrNunWGCpqt/973GxlH+ujsAKT7YuZ0rR 33+XFkwffwKV+YDh/OQAE7kRR9YiCL28sOd6HkuqbI5zXG/hVSEnndC9ZU6UkhXfdOek rRSA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=F0IWTO5GhOhb6A40qFrrArST21ZkQRJyFVCmrexpwLA=; fh=fq3Xdj8y7XIuVdymUQQ3AEAyx/7VNFJX500pkAd2mgE=; b=K9bVf2w0NpRawpIIM6t3QkrOMMiYmKAIG+uhYm6Jp/Z+lZFakRwC94NPmuosdekCWF LsQHyX5pw92NvN+fjkBudhpc+xstFuA/3AoMhvN/nDsCB3st9zxCiwuEeSt+5sGUOlvE MFH6OnIkXxwP21919ym1aksTev7pHCQQfl8TkNMRvsJi10EdegCudiAdy+pHVN1ZuPBn eGAFZuvcMTj48UZ/r98ifE8BRLdndGuFsjjO+v2GFgN8Gy8qn4yrswBVnGnBwm62ekSJ EEj0VxY1i4pdIwhtbYtq85RzOfo+WzGJ6mr9JQyN+aP8EMFD9iFrONuXMMPG5IU0yLjo 2VYg== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b="bc/PbOTB"; arc=pass (i=1 spf=pass spfdomain=crapouillou.net dkim=pass dkdomain=crapouillou.net dmarc=pass fromdomain=crapouillou.net); spf=pass (google.com: domain of linux-kernel+bounces-44598-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-44598-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id w14-20020a05640234ce00b00557392e2ed6si4462414edc.429.2024.01.30.04.25.20 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jan 2024 04:25:20 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-44598-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b="bc/PbOTB"; arc=pass (i=1 spf=pass spfdomain=crapouillou.net dkim=pass dkdomain=crapouillou.net dmarc=pass fromdomain=crapouillou.net); spf=pass (google.com: domain of linux-kernel+bounces-44598-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-44598-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id D0EBB1F255FB for ; Tue, 30 Jan 2024 12:25:19 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BA59A6A012; Tue, 30 Jan 2024 12:24:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b="bc/PbOTB" Received: from aposti.net (aposti.net [89.234.176.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 919376BB27; Tue, 30 Jan 2024 12:24:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=89.234.176.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706617456; cv=none; b=CmpQSbUnAsewQCm/Nb5XCMmuHEmHx2LJT7L54lbStOShqujgP7ocRo6q2x45LYhsOOmyLPpsZC0rzkamBBS6ZKedUb3iXOVxWkWDvJ5t5RoD7THng6joA68geEGR6s3Gg2nJJiR+pw8h5fNdBsFwdJsLdsvCadnD5VC2WtKpaeU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706617456; c=relaxed/simple; bh=XnUI63MWP1I2kpdlJ7mvadoWCFKsGi/XeC567t59A08=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Q8QJX7Gacprlwew/T7+fyq0a7ko4mmecpWfWxPiBViQVb5pCR21UG5HaWoXim9Blj9166BqZ1BGWrk9URSg6UNmqPG4luHKTbtH6XrM68CEWjbBFPRtDkGybuim/6TVE9BXD11SEnX8n9WNBY9EuzJGhw5r5hI1YyG0NC7gUriM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=crapouillou.net; spf=pass smtp.mailfrom=crapouillou.net; dkim=pass (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b=bc/PbOTB; arc=none smtp.client-ip=89.234.176.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=crapouillou.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=crapouillou.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1706617429; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=F0IWTO5GhOhb6A40qFrrArST21ZkQRJyFVCmrexpwLA=; b=bc/PbOTBeNd1aAV7/kAEpPInvM5w73re093TBuOfPyZtp63hWr5u0xmRct3IUPj39otuXZ 1cuEw4PUWu6ND4eEO95KxabbE1KPjDp7xlMA6fFGd4qkh1yY/Zo/DQUe4K5iGhHielCmSC 68zPc7BlT6yvkTelG/UfR37DWsgBvUQ= From: Paul Cercueil To: Greg Kroah-Hartman , Jonathan Corbet , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Michael Hennerich , linux-usb@vger.kernel.org, linux-doc@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 , Daniel Vetter Subject: [PATCH v6 3/4] usb: gadget: functionfs: Add DMABUF import interface Date: Tue, 30 Jan 2024 13:23:39 +0100 Message-ID: <20240130122340.54813-4-paul@crapouillou.net> In-Reply-To: <20240130122340.54813-1-paul@crapouillou.net> References: <20240130122340.54813-1-paul@crapouillou.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1789518173280405328 X-GMAIL-MSGID: 1789518173280405328 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 Acked-by: Daniel Vetter Acked-by: Christian König --- 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. v3: - Inline to_ffs_dma_fence() which was called only once. - Simplify ffs_dma_resv_lock() - Add comment explaining why we unref twice in ffs_dmabuf_detach() - Document uapi struct usb_ffs_dmabuf_transfer_req and IOCTLs v4: - Protect the DMABUF list with a mutex - Use incremental sequence number for the dma_fences - Unref attachments and DMABUFs in workers - Remove dead code in ffs_dma_resv_lock() - Fix non-block actually blocking - Use dma_fence_begin/end_signalling() - Add comment about cache-management and dma_buf_unmap_attachment() - Make sure dma_buf_map_attachment() is called with the dma-resv locked v5: - Cache the dma_buf_attachment while the DMABUF is attached. - Use dma_buf_begin/end_access() to ensure that the DMABUF data will be coherent to the hardware. - Remove comment about cache-management and dma_buf_unmap_attachment(), since we now use dma_buf_begin/end_access(). - Added Christian's ACK - Select DMA_SHARED_BUFFER in Kconfig entry v6: - Drop use of dma_buf_begin/end_access(). We now make the assumption that the devices attached to the DMABUFs must be coherent between themselves. The cache coherency issue is a tangential problem, and those functions can be re-introduced in a subsequent patchset. - Unqueue pending requests on detach. Otherwise, when closing the data endpoint the DMABUF will never be signaled. - Use list_for_each_entry_safe() in ffs_dmabuf_detach(), because there is a list_del() in there. - Use pr_vdebug() instead of pr_debug() - Rename ffs_dmabuf_unmap_work() -> ffs_dmabuf_cleanup() --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/function/f_fs.c | 467 ++++++++++++++++++++++++++++ include/uapi/linux/usb/functionfs.h | 41 +++ 3 files changed, 509 insertions(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index b3592bcb0f96..566ff0b1282a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -190,6 +190,7 @@ config USB_F_MASS_STORAGE tristate config USB_F_FS + select DMA_SHARED_BUFFER tristate config USB_F_UAC1 diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 491a1e0f4fa3..bffbc1dc651f 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,25 @@ struct ffs_ep { u8 num; }; +struct ffs_dmabuf_priv { + struct list_head entry; + struct kref ref; + struct ffs_data *ffs; + struct dma_buf_attachment *attach; + struct sg_table *sgt; + enum dma_data_direction dir; + spinlock_t lock; + u64 context; + struct usb_request *req; /* P: ffs->eps_lock */ + struct usb_ep *ep; /* P: ffs->eps_lock */ +}; + +struct ffs_dma_fence { + struct dma_fence base; + struct ffs_dmabuf_priv *priv; + struct work_struct work; +}; + struct ffs_epfile { /* Protects ep->ep and ep->req. */ struct mutex mutex; @@ -197,6 +221,11 @@ struct ffs_epfile { unsigned char isoc; /* P: ffs->eps_lock */ unsigned char _pad; + + /* Protects dmabufs */ + struct mutex dmabufs_mutex; + struct list_head dmabufs; /* P: dmabufs_mutex */ + atomic_t seqno; }; struct ffs_buffer { @@ -1271,10 +1300,58 @@ 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_vdebug("FFS DMABUF release\n"); + dma_resv_lock(dmabuf->resv, NULL); + dma_buf_unmap_attachment(attach, priv->sgt, priv->dir); + dma_resv_unlock(dmabuf->resv); + + dma_buf_detach(attach->dmabuf, attach); + dma_buf_put(dmabuf); + 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; + struct ffs_data *ffs = epfile->ffs; + + mutex_lock(&epfile->dmabufs_mutex); + + /* Close all attached DMABUFs */ + list_for_each_entry_safe(priv, tmp, &epfile->dmabufs, entry) { + /* Cancel any pending transfer */ + spin_lock_irq(&ffs->eps_lock); + if (priv->ep && priv->req) + usb_ep_dequeue(priv->ep, priv->req); + spin_unlock_irq(&ffs->eps_lock); + + list_del(&priv->entry); + ffs_dmabuf_put(priv->attach); + } + + mutex_unlock(&epfile->dmabufs_mutex); __ffs_epfile_read_buffer_free(epfile); ffs_data_closed(epfile->ffs); @@ -1282,6 +1359,356 @@ ffs_epfile_release(struct inode *inode, struct file *file) return 0; } +static void ffs_dmabuf_cleanup(struct work_struct *work) +{ + struct ffs_dma_fence *dma_fence = + container_of(work, struct ffs_dma_fence, work); + struct ffs_dmabuf_priv *priv = dma_fence->priv; + struct dma_buf_attachment *attach = priv->attach; + struct dma_fence *fence = &dma_fence->base; + + ffs_dmabuf_put(attach); + dma_fence_put(fence); +} + +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; + bool cookie = dma_fence_begin_signalling(); + + dma_fence_get(fence); + fence->error = ret; + dma_fence_signal(fence); + dma_fence_end_signalling(cookie); + + /* + * The fence will be unref'd in ffs_dmabuf_cleanup. + * It can't be done here, as the unref functions might try to lock + * the resv object, which would deadlock. + */ + INIT_WORK(&dma_fence->work, ffs_dmabuf_cleanup); + queue_work(priv->ffs->io_completion_wq, &dma_fence->work); +} + +static void ffs_epfile_dmabuf_io_complete(struct usb_ep *ep, + struct usb_request *req) +{ + pr_vdebug("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 = + container_of(fence, struct ffs_dma_fence, base); + + 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) +{ + if (!nonblock) + return dma_resv_lock_interruptible(dmabuf->resv, NULL); + + if (!dma_resv_trylock(dmabuf->resv)) + return -EBUSY; + + return 0; +} + +static struct dma_buf_attachment * +ffs_dmabuf_find_attachment(struct ffs_epfile *epfile, struct dma_buf *dmabuf) +{ + struct device *dev = epfile->ffs->gadget->dev.parent; + struct dma_buf_attachment *attach = NULL; + struct ffs_dmabuf_priv *priv; + + mutex_lock(&epfile->dmabufs_mutex); + + list_for_each_entry(priv, &epfile->dmabufs, entry) { + if (priv->attach->dev == dev + && priv->attach->dmabuf == dmabuf) { + attach = priv->attach; + break; + } + } + + if (attach) + ffs_dmabuf_get(attach); + + mutex_unlock(&epfile->dmabufs_mutex); + + return attach ?: ERR_PTR(-EPERM); +} + +static int ffs_dmabuf_attach(struct file *file, int fd) +{ + bool 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 sg_table *sg_table; + 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; + } + + dir = epfile->in ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + err = ffs_dma_resv_lock(dmabuf, nonblock); + if (err) + goto err_free_priv; + + sg_table = dma_buf_map_attachment(attach, dir); + dma_resv_unlock(dmabuf->resv); + + if (IS_ERR(sg_table)) { + err = PTR_ERR(sg_table); + goto err_free_priv; + } + + attach->importer_priv = priv; + + priv->sgt = sg_table; + priv->dir = dir; + priv->ffs = epfile->ffs; + priv->attach = attach; + spin_lock_init(&priv->lock); + kref_init(&priv->ref); + priv->context = dma_fence_context_alloc(1); + + mutex_lock(&epfile->dmabufs_mutex); + list_add(&priv->entry, &epfile->dmabufs); + mutex_unlock(&epfile->dmabufs_mutex); + + return 0; + +err_free_priv: + kfree(priv); +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 ffs_data *ffs = epfile->ffs; + struct device *dev = ffs->gadget->dev.parent; + struct ffs_dmabuf_priv *priv, *tmp; + struct dma_buf *dmabuf; + int ret = -EPERM; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + mutex_lock(&epfile->dmabufs_mutex); + + list_for_each_entry_safe(priv, tmp, &epfile->dmabufs, entry) { + if (priv->attach->dev == dev + && priv->attach->dmabuf == dmabuf) { + /* Cancel any pending transfer */ + spin_lock_irq(&ffs->eps_lock); + if (priv->ep && priv->req) + usb_ep_dequeue(priv->ep, priv->req); + spin_unlock_irq(&ffs->eps_lock); + + list_del(&priv->entry); + + /* Unref the reference from ffs_dmabuf_attach() */ + ffs_dmabuf_put(priv->attach); + ret = 0; + break; + } + } + + mutex_unlock(&epfile->dmabufs_mutex); + dma_buf_put(dmabuf); + + return ret; +} + +static int ffs_dmabuf_transfer(struct file *file, + const struct usb_ffs_dmabuf_transfer_req *req) +{ + bool nonblock = file->f_flags & O_NONBLOCK; + struct ffs_epfile *epfile = file->private_data; + struct dma_buf_attachment *attach; + struct ffs_dmabuf_priv *priv; + struct ffs_dma_fence *fence; + struct usb_request *usb_req; + struct dma_buf *dmabuf; + struct ffs_ep *ep; + bool cookie; + u32 seqno; + 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(epfile, dmabuf); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + goto err_dmabuf_put; + } + + priv = attach->importer_priv; + + ep = ffs_epfile_wait_ep(file); + if (IS_ERR(ep)) { + ret = PTR_ERR(ep); + goto err_attachment_put; + } + + ret = ffs_dma_resv_lock(dmabuf, nonblock); + if (ret) + goto err_attachment_put; + + /* Make sure we don't have writers */ + if (!dma_resv_test_signaled(dmabuf->resv, DMA_RESV_USAGE_WRITE)) { + pr_vdebug("FFS WRITE fence is not signaled\n"); + ret = -EBUSY; + goto err_resv_unlock; + } + + /* If we're writing to the DMABUF, make sure we don't have readers */ + if (epfile->in && + !dma_resv_test_signaled(dmabuf->resv, DMA_RESV_USAGE_READ)) { + pr_vdebug("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->priv = priv; + + spin_lock_irq(&epfile->ffs->eps_lock); + + /* In the meantime, endpoint got disabled or changed. */ + if (epfile->ep != ep) { + ret = -ESHUTDOWN; + goto err_fence_put; + } + + usb_req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC); + if (!usb_req) { + ret = -ENOMEM; + goto err_fence_put; + } + + /* + * usb_ep_queue() guarantees that all transfers are processed in the + * order they are enqueued, so we can use a simple incrementing + * sequence number for the dma_fence. + */ + seqno = atomic_add_return(1, &epfile->seqno); + + dma_fence_init(&fence->base, &ffs_dmabuf_fence_ops, + &priv->lock, priv->context, seqno); + + dma_resv_add_fence(dmabuf->resv, &fence->base, + dma_resv_usage_rw(epfile->in)); + 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 = priv->sgt->sgl; + usb_req->num_sgs = sg_nents_for_len(priv->sgt->sgl, req->length); + usb_req->sg_was_mapped = true; + usb_req->context = fence; + usb_req->complete = ffs_epfile_dmabuf_io_complete; + + cookie = dma_fence_begin_signalling(); + ret = usb_ep_queue(ep->ep, usb_req, GFP_ATOMIC); + dma_fence_end_signalling(cookie); + if (!ret) { + priv->req = usb_req; + priv->ep = ep->ep; + } else { + pr_warn("FFS: Failed to queue DMABUF: %d\n", ret); + ffs_dmabuf_signal_done(fence, ret); + usb_ep_free_request(ep->ep, usb_req); + } + + spin_unlock_irq(&epfile->ffs->eps_lock); + dma_buf_put(dmabuf); + + return ret; + +err_fence_put: + spin_unlock_irq(&epfile->ffs->eps_lock); + dma_fence_put(&fence->base); +err_resv_unlock: + dma_resv_unlock(dmabuf->resv); +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) { @@ -1292,6 +1719,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)) @@ -1869,6 +2334,8 @@ static int ffs_epfiles_create(struct ffs_data *ffs) for (i = 1; i <= count; ++i, ++epfile) { epfile->ffs = ffs; mutex_init(&epfile->mutex); + mutex_init(&epfile->dmabufs_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 078098e73fd3..9f88de9c3d66 100644 --- a/include/uapi/linux/usb/functionfs.h +++ b/include/uapi/linux/usb/functionfs.h @@ -86,6 +86,22 @@ 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 - Transfer request for a DMABUF object + * @fd: file descriptor of the DMABUF object + * @flags: one or more USB_FFS_DMABUF_TRANSFER_* flags + * @length: number of bytes used in this DMABUF for the data transfer. + * Should generally be set to the DMABUF's size. + */ +struct usb_ffs_dmabuf_transfer_req { + int fd; + __u32 flags; + __u64 length; +} __attribute__((packed)); + #ifndef __KERNEL__ /* @@ -290,6 +306,31 @@ struct usb_functionfs_event { #define FUNCTIONFS_ENDPOINT_DESC _IOR('g', 130, \ struct usb_endpoint_descriptor) +/* + * Attach the DMABUF object, identified by its file descriptor, to the + * data endpoint. Returns zero on success, and a negative errno value + * on error. + */ +#define FUNCTIONFS_DMABUF_ATTACH _IOW('g', 131, int) + +/* + * Detach the given DMABUF object, identified by its file descriptor, + * from the data endpoint. Returns zero on success, and a negative + * errno value on error. Note that closing the endpoint's file + * descriptor will automatically detach all attached DMABUFs. + */ +#define FUNCTIONFS_DMABUF_DETACH _IOW('g', 132, int) + +/* + * Enqueue the previously attached DMABUF to the transfer queue. + * The argument is a structure that packs the DMABUF's file descriptor, + * the size in bytes to transfer (which should generally correspond to + * the size of the DMABUF), and a 'flags' field which is unused + * for now. Returns zero on success, and a negative errno value on + * error. + */ +#define FUNCTIONFS_DMABUF_TRANSFER _IOW('g', 133, \ + struct usb_ffs_dmabuf_transfer_req) #endif /* _UAPI__LINUX_FUNCTIONFS_H__ */ From patchwork Tue Jan 30 12:23:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 194159 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:2087:b0:106:209c:c626 with SMTP id gs7csp1194440dyb; Tue, 30 Jan 2024 04:49:47 -0800 (PST) X-Google-Smtp-Source: AGHT+IGpiZlKqcUJvlLLvifcm4diGQ5jaAD/GpGcF+KdAcI0zEshebzl8835GIV8Yb1NXhGlFiGl X-Received: by 2002:a05:6808:2e94:b0:3be:33a0:739c with SMTP id gt20-20020a0568082e9400b003be33a0739cmr9518914oib.15.1706618987432; Tue, 30 Jan 2024 04:49:47 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706618987; cv=pass; d=google.com; s=arc-20160816; b=z+k0Us305uEjTFWyGkuhmy6BAeU3RtMXKvTrLyjftQ8VLXgcdfPC+WUWnOTD89S/OW MfbP5XTwXA9IMTcfe+JrF2RbyZXg8sILdrNFHVwpyP1JTc67oNjhw34FcAovt0o/3Pf2 2XawOwwmQULDh/HkxU3/KVESH7yxQFLe5MPEjgaElCJtIzi6Rcc9SyMDwNbpPd7im0CU rjgztt//EdcLAVe9mYd/lHmFAFI6AckWssg6F1vi5F8mlr/EULERVvRM+HdWb/CCyOql ak2gIQnaAwrYzYAnPvU3f1kTqa2vCFAE/12QEhuYAstyBaffZ6P1LsdmTIgjONptpkp8 GSfw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=zL3Tp6j0FI2WH0LNy5N+K5/yV+yjLiDhRH8Apc3kyR0=; fh=rOwklx3n4HddILOil3p/QTffAKooJ/gOk0lSkLfkcvQ=; b=A1aVmdcpSpOWYt/uXWRWzBpxIHxjZ1lQjIh3S6vOCGVSNQ//pcWpNbJ+sE+KU/jiLS zxyLt9dDqt7TSM69TnxEn5bpx0v0ThqaTXkj7soQn8grmM+VYdzNuzO7CTq5323/hISP kuNE5//srmkxiZEf6Ntag2Xkzb6vK4rI57PdSaaAWZAbSB0x5D9mJUB7TYc+IZKF+gmR LzEo6s+a6NumCdPAd9x+pjh4YmCP5LV2z1A+XnSS+YwVzgVSZLoufP4NTCvigjfiEPGr suUHXXuDVQBC3dSC2e02mfzb0gkDNzVhHKlBnGEuK9ogFJvgHVcRittu0SZ4SxK60I0s f5OA== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=vWr2oYgi; arc=pass (i=1 spf=pass spfdomain=crapouillou.net dkim=pass dkdomain=crapouillou.net dmarc=pass fromdomain=crapouillou.net); spf=pass (google.com: domain of linux-kernel+bounces-44599-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-44599-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [2604:1380:40f1:3f00::1]) by mx.google.com with ESMTPS id i14-20020a056a00004e00b006d9ac80ad3dsi7404633pfk.146.2024.01.30.04.49.47 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jan 2024 04:49:47 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-44599-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) client-ip=2604:1380:40f1:3f00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@crapouillou.net header.s=mail header.b=vWr2oYgi; arc=pass (i=1 spf=pass spfdomain=crapouillou.net dkim=pass dkdomain=crapouillou.net dmarc=pass fromdomain=crapouillou.net); spf=pass (google.com: domain of linux-kernel+bounces-44599-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-44599-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=crapouillou.net Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id 25114B27451 for ; Tue, 30 Jan 2024 12:25:43 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8B9626D1BC; Tue, 30 Jan 2024 12:24:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b="vWr2oYgi" Received: from aposti.net (aposti.net [89.234.176.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 601296A035; Tue, 30 Jan 2024 12:24:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=89.234.176.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706617465; cv=none; b=INAx3ibGqMWZqZBtfrnl6+EeYgV24rn38JRHKih0lNUc0KLyaxzIaY8fpiLszu0PTki6KV5iVRAb1iwEy/5kCO7y434l3e5qcbH5uPGGrh57huFeCK1YC+Qx9C9DKGFW0fPbec1utTYLWHDXNQvxI0xKyBTMZk6UHK3s94zXuBY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706617465; c=relaxed/simple; bh=cJbgWol1KPqWfYEC1f0fo3P+Gvr3uUpwLWEV8WXaueM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=K+ubo4LuHBmvdqR4Ka/ggToftVThCSvNIX2MzacFwAet80xlu/6Ub37lE5eNKr+8PGTT7rEyftSwB3aDJ5ztHWRx34cs7YK2mraPIT5B3TLjTI32MsWr1ZMgUmvdvLFPrhiaymmLYIgDjRqZomxQG6Q0vQxZC10cqcR1ZVbUYmk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=crapouillou.net; spf=pass smtp.mailfrom=crapouillou.net; dkim=pass (1024-bit key) header.d=crapouillou.net header.i=@crapouillou.net header.b=vWr2oYgi; arc=none smtp.client-ip=89.234.176.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=crapouillou.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=crapouillou.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1706617430; 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=zL3Tp6j0FI2WH0LNy5N+K5/yV+yjLiDhRH8Apc3kyR0=; b=vWr2oYgiEkvETCuZs/8NQXdO8VjlAhSkCj9bk153RIvE9EwoHvlPQ952ZQGv+igCZ1AT0e cXr+/5L1v9tbOkUMhS4DGoIyyRj2/08NDMPa/y85LNGidr13f3FRq3itaNBi7jPJqb8mPJ 74BHeddIzjwI7mxWHT6QLnlZTcLFDy0= From: Paul Cercueil To: Greg Kroah-Hartman , Jonathan Corbet , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: =?utf-8?q?Nuno_S=C3=A1?= , Jonathan Cameron , Michael Hennerich , linux-usb@vger.kernel.org, linux-doc@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 v6 4/4] Documentation: usb: Document FunctionFS DMABUF API Date: Tue, 30 Jan 2024 13:23:40 +0100 Message-ID: <20240130122340.54813-5-paul@crapouillou.net> In-Reply-To: <20240130122340.54813-1-paul@crapouillou.net> References: <20240130122340.54813-1-paul@crapouillou.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1789519711457123494 X-GMAIL-MSGID: 1789519711457123494 Add documentation for the three ioctls used to attach or detach externally-created DMABUFs, and to request transfers from/to previously attached DMABUFs. Signed-off-by: Paul Cercueil --- v3: New patch --- Documentation/usb/functionfs.rst | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Documentation/usb/functionfs.rst b/Documentation/usb/functionfs.rst index a3054bea38f3..d05a775bc45b 100644 --- a/Documentation/usb/functionfs.rst +++ b/Documentation/usb/functionfs.rst @@ -2,6 +2,9 @@ How FunctionFS works ==================== +Overview +======== + From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and @@ -66,3 +69,36 @@ have been written to their ep0's. Conversely, the gadget is unregistered after the first USB function closes its endpoints. + +DMABUF interface +================ + +FunctionFS additionally supports a DMABUF based interface, where the +userspace can attach DMABUF objects (externally created) to an endpoint, +and subsequently use them for data transfers. + +A userspace application can then use this interface to share DMABUF +objects between several interfaces, allowing it to transfer data in a +zero-copy fashion, for instance between IIO and the USB stack. + +As part of this interface, three new IOCTLs have been added. These three +IOCTLs have to be performed on a data endpoint (ie. not ep0). They are: + + ``FUNCTIONFS_DMABUF_ATTACH(int)`` + Attach the DMABUF object, identified by its file descriptor, to the + data endpoint. Returns zero on success, and a negative errno value + on error. + + ``FUNCTIONFS_DMABUF_DETACH(int)`` + Detach the given DMABUF object, identified by its file descriptor, + from the data endpoint. Returns zero on success, and a negative + errno value on error. Note that closing the endpoint's file + descriptor will automatically detach all attached DMABUFs. + + ``FUNCTIONFS_DMABUF_TRANSFER(struct usb_ffs_dmabuf_transfer_req *)`` + Enqueue the previously attached DMABUF to the transfer queue. + The argument is a structure that packs the DMABUF's file descriptor, + the size in bytes to transfer (which should generally correspond to + the size of the DMABUF), and a 'flags' field which is unused + for now. Returns zero on success, and a negative errno value on + error.