@@ -11,10 +11,14 @@
#include <array>
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <linux/dma-buf.h>
#include <linux/dma-heap.h>
+#include <linux/udmabuf.h>
#include <libcamera/base/log.h>
@@ -84,6 +88,18 @@ public:
UniqueFD alloc(const char *name, std::size_t size) override;
};
+/**
+ * \class UdmaHeap
+ * \brief The derived class of Heap with Udmabuf implementation
+ */
+class UdmaHeap : public Heap
+{
+public:
+ UdmaHeap();
+ ~UdmaHeap();
+ UniqueFD alloc(const char *name, std::size_t size) override;
+};
+
/**
* \brief Construct a DmaHeap with a list of |dmaHeapNames|
*/
@@ -98,6 +114,7 @@ DmaHeap::DmaHeap()
continue;
}
+ LOG(HeapAllocator, Info) << "Using DmaHeap allocator";
handle_ = UniqueFD(ret);
break;
}
@@ -138,6 +155,92 @@ UniqueFD DmaHeap::alloc(const char *name, std::size_t size)
return allocFd;
}
+/**
+ * \brief Construct a UdmaHeap with `/udev/udmabuf`.
+ */
+UdmaHeap::UdmaHeap()
+{
+ int ret = ::open("/dev/udmabuf", O_RDWR);
+ if (ret < 0) {
+ ret = errno;
+ LOG(HeapAllocator, Error)
+ << "UdmaHeap failed to open allocator: " << strerror(ret);
+ return;
+ }
+
+ LOG(HeapAllocator, Info) << "Using UdmaHeap allocator";
+ handle_ = UniqueFD(ret);
+}
+
+UdmaHeap::~UdmaHeap() = default;
+
+UniqueFD UdmaHeap::alloc(const char *name, std::size_t size)
+{
+ int ret = memfd_create(name, MFD_ALLOW_SEALING);
+ if (ret < 0) {
+ ret = errno;
+ LOG(HeapAllocator, Error)
+ << "UdmaHeap failed to allocate memfd storage: "
+ << strerror(ret);
+ return {};
+ }
+
+ UniqueFD memfd(ret);
+
+ ret = ftruncate(memfd.get(), size);
+ if (ret < 0) {
+ ret = errno;
+ LOG(HeapAllocator, 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(HeapAllocator, 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(handle_.get(), UDMABUF_CREATE, &create);
+ if (ret < 0) {
+ ret = errno;
+ LOG(HeapAllocator, Error)
+ << "UdmaHeap failed to allocate " << size << " bytes: "
+ << strerror(ret);
+ return {};
+ }
+
+ if (create.size < size) {
+ LOG(HeapAllocator, Error)
+ << "UdmaHeap allocated " << create.size << " bytes instead of "
+ << size << " bytes";
+ return {};
+ }
+
+ if (create.size != size)
+ LOG(HeapAllocator, 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(HeapAllocator, Debug) << "UdmaHeap allocated " << create.size << " bytes";
+
+ /* The underlying memfd is kept as as a reference in the kernel */
+ UniqueFD uDma(ret);
+
+ return uDma;
+}
+
/**
* \class HeapAllocator
* \brief The allocator that allocates heap buffers
@@ -160,6 +263,8 @@ UniqueFD DmaHeap::alloc(const char *name, std::size_t size)
HeapAllocator::HeapAllocator()
{
heap_ = std::make_unique<DmaHeap>();
+ if (!isValid())
+ heap_ = std::make_unique<UdmaHeap>();
}
HeapAllocator::~HeapAllocator() = default;
If DmaHeap is not valid, fall back to UdmaHeap to allocate buffers. Signed-off-by: Harvey Yang <chenghaoyang@chromium.org> --- src/libcamera/heap_allocator.cpp | 105 +++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+)