DmaBufAllocator: Add Dma Buffer synchronization function & helper class

To synchronize CPU access with mmap and hardware access on DMA buffers,
using `DMA_BUF_IOCTL_SYNC` is required. This patch adds a function and
a helper class to allow users to sync buffers more easily.

Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>
Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>
Signed-off-by: Harvey Yang <chenghaoyang@chromium.org>
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Harvey Yang 2024-11-21 05:51:31 +00:00 committed by Kieran Bingham
parent 562b6335d9
commit 39482d59fe
2 changed files with 95 additions and 0 deletions

View file

@ -12,6 +12,7 @@
#include <vector> #include <vector>
#include <libcamera/base/flags.h> #include <libcamera/base/flags.h>
#include <libcamera/base/shared_fd.h>
#include <libcamera/base/unique_fd.h> #include <libcamera/base/unique_fd.h>
namespace libcamera { namespace libcamera {
@ -48,6 +49,26 @@ private:
DmaBufAllocatorFlag type_; DmaBufAllocatorFlag type_;
}; };
class DmaSyncer final
{
public:
enum class SyncType {
Read = 0,
Write,
ReadWrite,
};
explicit DmaSyncer(SharedFD fd, SyncType type = SyncType::ReadWrite);
~DmaSyncer();
private:
void sync(uint64_t step);
SharedFD fd_;
uint64_t flags_ = 0;
};
LIBCAMERA_FLAGS_ENABLE_OPERATORS(DmaBufAllocator::DmaBufAllocatorFlag) LIBCAMERA_FLAGS_ENABLE_OPERATORS(DmaBufAllocator::DmaBufAllocatorFlag)
} /* namespace libcamera */ } /* namespace libcamera */

View file

@ -262,4 +262,78 @@ DmaBufAllocator::createBuffer(std::string name,
return std::make_unique<FrameBuffer>(planes); return std::make_unique<FrameBuffer>(planes);
} }
/**
* \class DmaSyncer
* \brief Helper class for dma-buf's synchronization
*
* This class wraps a userspace dma-buf's synchronization process with an
* object's lifetime.
*
* It's used when the user needs to access a dma-buf with CPU, mostly mapped
* with MappedFrameBuffer, so that the buffer is synchronized between CPU and
* ISP.
*/
/**
* \enum DmaSyncer::SyncType
* \brief Read and/or write access via the CPU map
* \var DmaSyncer::Read
* \brief Indicates that the mapped dma-buf will be read by the client via the
* CPU map
* \var DmaSyncer::Write
* \brief Indicates that the mapped dm-buf will be written by the client via the
* CPU map
* \var DmaSyncer::ReadWrite
* \brief Indicates that the mapped dma-buf will be read and written by the
* client via the CPU map
*/
/**
* \brief Construct a DmaSyncer with a dma-buf's fd and the access type
* \param[in] fd The dma-buf's file descriptor to synchronize
* \param[in] type Read and/or write access via the CPU map
*/
DmaSyncer::DmaSyncer(SharedFD fd, SyncType type)
: fd_(fd)
{
switch (type) {
case SyncType::Read:
flags_ = DMA_BUF_SYNC_READ;
break;
case SyncType::Write:
flags_ = DMA_BUF_SYNC_WRITE;
break;
case SyncType::ReadWrite:
flags_ = DMA_BUF_SYNC_RW;
break;
}
sync(DMA_BUF_SYNC_START);
}
DmaSyncer::~DmaSyncer()
{
sync(DMA_BUF_SYNC_END);
}
void DmaSyncer::sync(uint64_t step)
{
struct dma_buf_sync sync = {
.flags = flags_ | step
};
int ret;
do {
ret = ioctl(fd_.get(), DMA_BUF_IOCTL_SYNC, &sync);
} while (ret && (errno == EINTR || errno == EAGAIN));
if (ret) {
ret = errno;
LOG(DmaBufAllocator, Error)
<< "Unable to sync dma fd: " << fd_.get()
<< ", err: " << strerror(ret)
<< ", flags: " << sync.flags;
}
}
} /* namespace libcamera */ } /* namespace libcamera */