{"id":20150,"url":"https://patchwork.libcamera.org/api/patches/20150/?format=json","web_url":"https://patchwork.libcamera.org/patch/20150/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20240530171600.259495-5-hdegoede@redhat.com>","date":"2024-05-30T17:15:59","name":"[v2,4/5] libcamera: DmaBufAllocator: Support allocating from /dev/udmabuf","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"96bf8e14633247420bbfa7d78562e1d291501cac","submitter":{"id":102,"url":"https://patchwork.libcamera.org/api/people/102/?format=json","name":"Hans de Goede","email":"hdegoede@redhat.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/20150/mbox/","series":[{"id":4341,"url":"https://patchwork.libcamera.org/api/series/4341/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4341","date":"2024-05-30T17:15:55","name":"libcamera: dma_buffer_allocator: Add support for using udmabuf to alloc dma-buffers","version":2,"mbox":"https://patchwork.libcamera.org/series/4341/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/20150/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/20150/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id A1D4EC32C8\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 30 May 2024 17:16:16 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 373FA634BC;\n\tThu, 30 May 2024 19:16:16 +0200 (CEST)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8CB20634BF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 30 May 2024 19:16:12 +0200 (CEST)","from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73])\n\tby relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n\tcipher=TLS_AES_256_GCM_SHA384) id us-mta-376-CiTVMzbcOPCFWU_uFjCSOw-1;\n\tThu, 30 May 2024 13:16:07 -0400","from smtp.corp.redhat.com\n\t(int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\tkey-exchange X25519 server-signature RSA-PSS (2048 bits)\n\tserver-digest SHA256) (No client certificate requested)\n\tby mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3365529AA384;\n\tThu, 30 May 2024 17:16:07 +0000 (UTC)","from shalem.redhat.com (unknown [10.39.192.43])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id 2CEFE2870;\n\tThu, 30 May 2024 17:16:06 +0000 (UTC)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"QYNpnnE4\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1717089371;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=GJGT5SGX+45TyeAMVbELgwP/fWygeI2hHcPQENMgcbc=;\n\tb=QYNpnnE43KxS7KU6aB4OvXnZoXpVYzBCzYEmcpi7T8PmWXdqzY5GooLKrZWSZhmhAj1TUl\n\tQb9kwKjD/lW1HbUi25YqGPGjNwq2GzOQPRwXGPb58PTVTBYTo74RpZCDndHPgyQ3CbzOMf\n\tCBAWoeJvk+JcgyTAatel43ut6PDMV8E=","X-MC-Unique":"CiTVMzbcOPCFWU_uFjCSOw-1","From":"Hans de Goede <hdegoede@redhat.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Andrey Konovalov <andrey.konovalov.ynk@gmail.com>,\n\tPavel Machek <pavel@ucw.cz>,\n\tBryan O'Donoghue <bryan.odonoghue@linaro.org>, \n\tMilan Zamazal <mzamazal@redhat.com>, Maxime Ripard <mripard@redhat.com>, \n\tHans de Goede <hdegoede@redhat.com>,\n\tHarvey Yang <chenghaoyang@chromium.org>","Subject":"[PATCH v2 4/5] libcamera: DmaBufAllocator: Support allocating from\n\t/dev/udmabuf","Date":"Thu, 30 May 2024 19:15:59 +0200","Message-ID":"<20240530171600.259495-5-hdegoede@redhat.com>","In-Reply-To":"<20240530171600.259495-1-hdegoede@redhat.com>","References":"<20240530171600.259495-1-hdegoede@redhat.com>","MIME-Version":"1.0","X-Scanned-By":"MIMEDefang 3.4.1 on 10.11.54.5","X-Mimecast-Spam-Score":"0","X-Mimecast-Originator":"redhat.com","Content-Transfer-Encoding":"8bit","Content-Type":"text/plain; charset=\"US-ASCII\"; x-default=true","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"The dma-buf allocator currently allocates from CMA and system heaps.\n\nExtend the dma-buf allocator to support allocating dma-buffers by creating\nmemfd-s and turning those into dma-buffers using /dev/udmabuf.\n\nThe buffers allocated through memfd/udmabuf are not suitable for zero-copy\nbuffer sharing with other devices.\n\nCo-developed-by: Harvey Yang <chenghaoyang@chromium.org>\nSigned-off-by: Harvey Yang <chenghaoyang@chromium.org>\nSigned-off-by: Hans de Goede <hdegoede@redhat.com>\n---\nChanges in v2:\n- Reword the commit message\n- Add a new DmaBufAllocator::DmaBufAllocatorFlag::UDmaBuf type for udmabuf\n- Drop unnecessary size != size check\n- Reword log messages to be more like the DMA heap alloc path\n- Move UniqueFD(ret) up so as to not leak the fd on errors\n---\n .../libcamera/internal/dma_buf_allocator.h    |   4 +\n src/libcamera/dma_buf_allocator.cpp           | 111 +++++++++++++++---\n 2 files changed, 100 insertions(+), 15 deletions(-)","diff":"diff --git a/include/libcamera/internal/dma_buf_allocator.h b/include/libcamera/internal/dma_buf_allocator.h\nindex a881042e..36ec1696 100644\n--- a/include/libcamera/internal/dma_buf_allocator.h\n+++ b/include/libcamera/internal/dma_buf_allocator.h\n@@ -20,6 +20,7 @@ public:\n \tenum class DmaBufAllocatorFlag {\n \t\tCmaHeap = 1 << 0,\n \t\tSystemHeap = 1 << 1,\n+\t\tUDmaBuf = 1 << 2,\n \t};\n \n \tusing DmaBufAllocatorFlags = Flags<DmaBufAllocatorFlag>;\n@@ -30,7 +31,10 @@ public:\n \tUniqueFD alloc(const char *name, std::size_t size);\n \n private:\n+\tUniqueFD allocFromHeap(const char *name, std::size_t size);\n+\tUniqueFD allocFromUDmaBuf(const char *name, std::size_t size);\n \tUniqueFD providerHandle_;\n+\tDmaBufAllocatorFlag type_;\n };\n \n LIBCAMERA_FLAGS_ENABLE_OPERATORS(DmaBufAllocator::DmaBufAllocatorFlag)\ndiff --git a/src/libcamera/dma_buf_allocator.cpp b/src/libcamera/dma_buf_allocator.cpp\nindex bc0d78ef..369a419a 100644\n--- a/src/libcamera/dma_buf_allocator.cpp\n+++ b/src/libcamera/dma_buf_allocator.cpp\n@@ -11,10 +11,14 @@\n #include <array>\n #include <fcntl.h>\n #include <sys/ioctl.h>\n+#include <sys/mman.h>\n+#include <sys/stat.h>\n+#include <sys/types.h>\n #include <unistd.h>\n \n #include <linux/dma-buf.h>\n #include <linux/dma-heap.h>\n+#include <linux/udmabuf.h>\n \n #include <libcamera/base/log.h>\n \n@@ -32,7 +36,7 @@ struct DmaBufAllocatorInfo {\n };\n #endif\n \n-static constexpr std::array<DmaBufAllocatorInfo, 3> providerInfos = { {\n+static constexpr std::array<DmaBufAllocatorInfo, 4> providerInfos = { {\n \t/*\n \t * /dev/dma_heap/linux,cma is the CMA dma-heap. When the cma heap size is\n \t * specified on the kernel command line, this gets renamed to \"reserved\".\n@@ -40,6 +44,7 @@ static constexpr std::array<DmaBufAllocatorInfo, 3> providerInfos = { {\n \t{ DmaBufAllocator::DmaBufAllocatorFlag::CmaHeap, \"/dev/dma_heap/linux,cma\" },\n \t{ DmaBufAllocator::DmaBufAllocatorFlag::CmaHeap, \"/dev/dma_heap/reserved\" },\n \t{ DmaBufAllocator::DmaBufAllocatorFlag::SystemHeap, \"/dev/dma_heap/system\" },\n+\t{ DmaBufAllocator::DmaBufAllocatorFlag::UDmaBuf, \"/dev/udmabuf\" },\n } };\n \n LOG_DEFINE_CATEGORY(DmaBufAllocator)\n@@ -63,6 +68,8 @@ LOG_DEFINE_CATEGORY(DmaBufAllocator)\n  * \\brief Allocate from a CMA dma-heap, providing physically-contiguous memory\n  * \\var DmaBufAllocator::SystemHeap\n  * \\brief Allocate from the system dma-heap, using the page allocator\n+ * \\var DmaBufAllocator::UDmaBuf\n+ * \\brief Allocate using a memfd + /dev/udmabuf\n  */\n \n /**\n@@ -99,6 +106,7 @@ DmaBufAllocator::DmaBufAllocator(DmaBufAllocatorFlags type)\n \n \t\tLOG(DmaBufAllocator, Debug) << \"Using \" << info.deviceNodeName;\n \t\tproviderHandle_ = UniqueFD(ret);\n+\t\ttype_ = info.type;\n \t\tbreak;\n \t}\n \n@@ -117,25 +125,76 @@ DmaBufAllocator::~DmaBufAllocator() = default;\n  * \\return True if the DmaBufAllocator is valid, false otherwise\n  */\n \n-/**\n- * \\brief Allocate a dma-buf from the DmaBufAllocator\n- * \\param [in] name The name to set for the allocated buffer\n- * \\param [in] size The size of the buffer to allocate\n- *\n- * Allocates a dma-buf with read/write access.\n- *\n- * If the allocation fails, return an invalid UniqueFD.\n- *\n- * \\return The UniqueFD of the allocated buffer\n- */\n-UniqueFD DmaBufAllocator::alloc(const char *name, std::size_t size)\n+UniqueFD DmaBufAllocator::allocFromUDmaBuf(const char *name, std::size_t size)\n {\n-\tint ret;\n+\t/* Size must be a multiple of the page-size round it up. */\n+\tstd::size_t pageMask = sysconf(_SC_PAGESIZE) - 1;\n+\tsize = (size + pageMask) & ~pageMask;\n \n-\tif (!name)\n+\tint ret = memfd_create(name, MFD_ALLOW_SEALING);\n+\tif (ret < 0) {\n+\t\tret = errno;\n+\t\tLOG(DmaBufAllocator, Error)\n+\t\t\t<< \"Failed to allocate memfd storage for \" << name\n+\t\t\t<< \": \" << strerror(ret);\n \t\treturn {};\n+\t}\n \n+\tUniqueFD memfd(ret);\n+\n+\tret = ftruncate(memfd.get(), size);\n+\tif (ret < 0) {\n+\t\tret = errno;\n+\t\tLOG(DmaBufAllocator, Error)\n+\t\t\t<< \"Failed to set memfd size for \" << name\n+\t\t\t<< \": \" << strerror(ret);\n+\t\treturn {};\n+\t}\n+\n+\t/* udmabuf dma-buffers *must* have the F_SEAL_SHRINK seal. */\n+\tret = fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_SHRINK);\n+\tif (ret < 0) {\n+\t\tret = errno;\n+\t\tLOG(DmaBufAllocator, Error)\n+\t\t\t<< \"Failed to seal the memfd for \" << name\n+\t\t\t<< \": \" << strerror(ret);\n+\t\treturn {};\n+\t}\n+\n+\tstruct udmabuf_create create;\n+\n+\tcreate.memfd = memfd.get();\n+\tcreate.flags = UDMABUF_FLAGS_CLOEXEC;\n+\tcreate.offset = 0;\n+\tcreate.size = size;\n+\n+\tret = ::ioctl(providerHandle_.get(), UDMABUF_CREATE, &create);\n+\tif (ret < 0) {\n+\t\tret = errno;\n+\t\tLOG(DmaBufAllocator, Error)\n+\t\t\t<< \"Failed to allocate \" << size << \" bytes for \"\n+\t\t\t<< name << \": \" << strerror(ret);\n+\t\treturn {};\n+\t}\n+\n+\t/* The underlying memfd is kept as as a reference in the kernel */\n+\tUniqueFD uDma(ret);\n+\n+\t/* Fail if not suitable, the allocation will be free'd by UniqueFD */\n+\tif (create.size < size) {\n+\t\tLOG(DmaBufAllocator, Error)\n+\t\t\t<< \"UDMABUF_CREATE for \" << name << \" allocated \"\n+\t\t\t<< create.size << \" bytes instead of \" << size << \" bytes\";\n+\t\treturn {};\n+\t}\n+\n+\treturn uDma;\n+}\n+\n+UniqueFD DmaBufAllocator::allocFromHeap(const char *name, std::size_t size)\n+{\n \tstruct dma_heap_allocation_data alloc = {};\n+\tint ret;\n \n \talloc.len = size;\n \talloc.fd_flags = O_CLOEXEC | O_RDWR;\n@@ -156,4 +215,26 @@ UniqueFD DmaBufAllocator::alloc(const char *name, std::size_t size)\n \treturn allocFd;\n }\n \n+/**\n+ * \\brief Allocate a dma-buf from the DmaBufAllocator\n+ * \\param [in] name The name to set for the allocated buffer\n+ * \\param [in] size The size of the buffer to allocate\n+ *\n+ * Allocates a dma-buf with read/write access.\n+ *\n+ * If the allocation fails, return an invalid UniqueFD.\n+ *\n+ * \\return The UniqueFD of the allocated buffer\n+ */\n+UniqueFD DmaBufAllocator::alloc(const char *name, std::size_t size)\n+{\n+\tif (!name)\n+\t\treturn {};\n+\n+\tif (type_ == DmaBufAllocator::DmaBufAllocatorFlag::UDmaBuf)\n+\t\treturn allocFromUDmaBuf(name, size);\n+\telse\n+\t\treturn allocFromHeap(name, size);\n+}\n+\n } /* namespace libcamera */\n","prefixes":["v2","4/5"]}