From patchwork Mon May 27 14:16:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 20102 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 23A4DBDE6B for ; Mon, 27 May 2024 14:16:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B3518634B1; Mon, 27 May 2024 16:16:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="jO9i8IGH"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EA467634AD for ; Mon, 27 May 2024 16:16:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716819413; 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; bh=JNROLB6OZsBKoMRl++54+tyMHVwjrzJ/egqlurgeDbc=; b=jO9i8IGHGMJFI+m88CuenMMVCwDdHSRWaIf2AaesEFtNtJEGHwud97vcnZ0snr/a7Xsd2y RBt84N5aqepWy6BAGAB1h9HlpXkUST4vxFZbj8Y8AFTp3ABpkbNCHM3UbAOXZa4N2WdihS 0utuaC8egwXUBO49p5AzcL+dOuq3OE8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-120-uwLEeCBiNoC0TaDSGKeRFA-1; Mon, 27 May 2024 10:16:50 -0400 X-MC-Unique: uwLEeCBiNoC0TaDSGKeRFA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B53FF800169; Mon, 27 May 2024 14:16:49 +0000 (UTC) Received: from x1.localdomain.com (unknown [10.39.194.78]) by smtp.corp.redhat.com (Postfix) with ESMTP id 540F810004FF; Mon, 27 May 2024 14:16:48 +0000 (UTC) From: Hans de Goede To: libcamera-devel@lists.libcamera.org, Sakari Ailus Cc: Maxime Ripard , Milan Zamazal , Dennis Bonke , Hans de Goede , Harvey Yang Subject: [PATCH] libcamera: dma_heaps: Add support for using udmabuf to alloc DMA heaps Date: Mon, 27 May 2024 16:16:47 +0200 Message-ID: <20240527141647.336633-1-hdegoede@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add support for using udmabuf to alloc DMA heaps, this is basically: https://patchwork.libcamera.org/patch/18922/ ported from the never merged HeapAllocator class to the current DmaHeap class. Co-developed-by: Harvey Yang Signed-off-by: Harvey Yang Signed-off-by: Hans de Goede Reviewed-by: Kieran Bingham --- include/libcamera/internal/dma_heaps.h | 3 + src/libcamera/dma_heaps.cpp | 127 +++++++++++++++++++++---- 2 files changed, 109 insertions(+), 21 deletions(-) diff --git a/include/libcamera/internal/dma_heaps.h b/include/libcamera/internal/dma_heaps.h index f0a8aa5d..7e1271ed 100644 --- a/include/libcamera/internal/dma_heaps.h +++ b/include/libcamera/internal/dma_heaps.h @@ -30,7 +30,10 @@ public: UniqueFD alloc(const char *name, std::size_t size); private: + UniqueFD allocFromHeap(const char *name, std::size_t size); + UniqueFD allocFromUDmaBuf(const char *name, std::size_t size); UniqueFD dmaHeapHandle_; + bool useUDmaBuf_; }; LIBCAMERA_FLAGS_ENABLE_OPERATORS(DmaHeap::DmaHeapFlag) diff --git a/src/libcamera/dma_heaps.cpp b/src/libcamera/dma_heaps.cpp index d4cb880b..bb707786 100644 --- a/src/libcamera/dma_heaps.cpp +++ b/src/libcamera/dma_heaps.cpp @@ -10,10 +10,14 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include @@ -36,13 +40,15 @@ namespace libcamera { struct DmaHeapInfo { DmaHeap::DmaHeapFlag type; const char *deviceNodeName; + bool useUDmaBuf; }; #endif -static constexpr std::array heapInfos = { { - { DmaHeap::DmaHeapFlag::Cma, "/dev/dma_heap/linux,cma" }, - { DmaHeap::DmaHeapFlag::Cma, "/dev/dma_heap/reserved" }, - { DmaHeap::DmaHeapFlag::System, "/dev/dma_heap/system" }, +static constexpr std::array heapInfos = { { + { DmaHeap::DmaHeapFlag::Cma, "/dev/dma_heap/linux,cma", false }, + { DmaHeap::DmaHeapFlag::Cma, "/dev/dma_heap/reserved", false }, + { DmaHeap::DmaHeapFlag::System, "/dev/dma_heap/system", false }, + { DmaHeap::DmaHeapFlag::System, "/dev/udmabuf", true }, } }; LOG_DEFINE_CATEGORY(DmaHeap) @@ -105,6 +111,7 @@ DmaHeap::DmaHeap(DmaHeapFlags type) LOG(DmaHeap, Debug) << "Using " << info.deviceNodeName; dmaHeapHandle_ = UniqueFD(ret); + useUDmaBuf_ = info.useUDmaBuf; break; } @@ -123,25 +130,10 @@ DmaHeap::~DmaHeap() = default; * \return True if the DmaHeap is valid, false otherwise */ -/** - * \brief Allocate a dma-buf from the DmaHeap - * \param [in] name The name to set for the allocated buffer - * \param [in] size The size of the buffer to allocate - * - * Allocates a dma-buf with read/write access. - * - * If the allocation fails, return an invalid UniqueFD. - * - * \return The UniqueFD of the allocated buffer - */ -UniqueFD DmaHeap::alloc(const char *name, std::size_t size) +UniqueFD DmaHeap::allocFromHeap(const char *name, std::size_t size) { - int ret; - - if (!name) - return {}; - struct dma_heap_allocation_data alloc = {}; + int ret; alloc.len = size; alloc.fd_flags = O_CLOEXEC | O_RDWR; @@ -162,4 +154,97 @@ UniqueFD DmaHeap::alloc(const char *name, std::size_t size) return allocFd; } +UniqueFD DmaHeap::allocFromUDmaBuf(const char *name, std::size_t size) +{ + /* size must be a multiple of the page-size round it up */ + std::size_t pageMask = sysconf(_SC_PAGESIZE) - 1; + size = (size + pageMask) & ~pageMask; + + int ret = memfd_create(name, MFD_ALLOW_SEALING); + if (ret < 0) { + ret = errno; + LOG(DmaHeap, Error) + << "UdmaHeap failed to allocate memfd storage: " + << strerror(ret); + return {}; + } + + UniqueFD memfd(ret); + + ret = ftruncate(memfd.get(), size); + if (ret < 0) { + ret = errno; + LOG(DmaHeap, Error) + << "UdmaHeap failed to set memfd size: " << strerror(ret); + return {}; + } + + /* UdmaHeap Buffers *must* have the F_SEAL_SHRINK seal */ + ret = fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_SHRINK); + if (ret < 0) { + ret = errno; + LOG(DmaHeap, Error) + << "UdmaHeap failed to seal the memfd: " << strerror(ret); + return {}; + } + + struct udmabuf_create create; + + create.memfd = memfd.get(); + create.flags = UDMABUF_FLAGS_CLOEXEC; + create.offset = 0; + create.size = size; + + ret = ::ioctl(dmaHeapHandle_.get(), UDMABUF_CREATE, &create); + if (ret < 0) { + ret = errno; + LOG(DmaHeap, Error) + << "UdmaHeap failed to allocate " << size << " bytes: " + << strerror(ret); + return {}; + } + + if (create.size < size) { + LOG(DmaHeap, Error) + << "UdmaHeap allocated " << create.size << " bytes instead of " + << size << " bytes"; + return {}; + } + + if (create.size != size) + LOG(DmaHeap, Warning) + << "UdmaHeap allocated " << create.size << " bytes, " + << "which is greater than requested : " << size << " bytes"; + + /* Fail if not suitable, the allocation will be free'd by UniqueFD */ + LOG(DmaHeap, Debug) << "UdmaHeap allocated " << create.size << " bytes"; + + /* The underlying memfd is kept as as a reference in the kernel */ + UniqueFD uDma(ret); + + return uDma; +} + +/** + * \brief Allocate a dma-buf from the DmaHeap + * \param [in] name The name to set for the allocated buffer + * \param [in] size The size of the buffer to allocate + * + * Allocates a dma-buf with read/write access. + * + * If the allocation fails, return an invalid UniqueFD. + * + * \return The UniqueFD of the allocated buffer + */ +UniqueFD DmaHeap::alloc(const char *name, std::size_t size) +{ + if (!name) + return {}; + + if (useUDmaBuf_) + return allocFromUDmaBuf(name, size); + else + return allocFromHeap(name, size); +} + } /* namespace libcamera */