Message ID | 20200717001518.20285-3-laurent.pinchart@ideasonboard.com |
---|---|
State | Accepted |
Commit | 3e7aa49344ad5233f644703559898572b57f9613 |
Headers | show |
Series |
|
Related | show |
Hi Laurent, Thank you for the changes. On Fri, 17 Jul 2020 at 01:15, Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote: > > From: Naushir Patuck <naush@raspberrypi.com> > > Remove use of vcsm allocations and replace with dma heap allocations. > The pipeline handler now passes the fd of the allocation over to the IPA > instead of the raw pointer. > > Also use libcamera::FileDescriptor for fd lifetime management. > > This commit must be built alongside the accompanying BCM2835 ISP kernel > driver changes at https://github.com/raspberrypi/linux/pull/3715. > Otherwise a mismatch will cause undefined behavior. > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Naushir Patuck <naush@raspberrypi.com> > --- > include/linux/bcm2835-isp.h | 4 +- > include/linux/vc_sm_cma_ioctl.h | 135 ---------------- > src/ipa/raspberrypi/raspberrypi.cpp | 28 +++- > .../pipeline/raspberrypi/dma_heaps.cpp | 84 ++++++++++ > .../pipeline/raspberrypi/dma_heaps.h | 31 ++++ > .../pipeline/raspberrypi/meson.build | 1 + > .../pipeline/raspberrypi/raspberrypi.cpp | 49 ++---- > src/libcamera/pipeline/raspberrypi/vcsm.h | 149 ------------------ > 8 files changed, 154 insertions(+), 327 deletions(-) > delete mode 100644 include/linux/vc_sm_cma_ioctl.h > create mode 100644 src/libcamera/pipeline/raspberrypi/dma_heaps.cpp > create mode 100644 src/libcamera/pipeline/raspberrypi/dma_heaps.h > delete mode 100644 src/libcamera/pipeline/raspberrypi/vcsm.h > > diff --git a/include/linux/bcm2835-isp.h b/include/linux/bcm2835-isp.h > index e7afc367fd76..45abb681517e 100644 > --- a/include/linux/bcm2835-isp.h > +++ b/include/linux/bcm2835-isp.h > @@ -108,7 +108,7 @@ enum bcm2835_isp_gain_format { > * @grid_stride: Row to row distance (in grid cells) between grid cells > * in the same horizontal location. > * @grid_height: Height of lens shading tables in grid cells. > - * @mem_handle_table: Memory handle to the tables. > + * @dmabuf: dmabuf file handle containing the table. > * @ref_transform: Reference transform - unsupported, please pass zero. > * @corner_sampled: Whether the gains are sampled at the corner points > * of the grid cells or in the cell centres. > @@ -120,7 +120,7 @@ struct bcm2835_isp_lens_shading { > __u32 grid_width; > __u32 grid_stride; > __u32 grid_height; > - __u32 mem_handle_table; > + __s32 dmabuf; > __u32 ref_transform; > __u32 corner_sampled; > __u32 gain_format; > diff --git a/include/linux/vc_sm_cma_ioctl.h b/include/linux/vc_sm_cma_ioctl.h > deleted file mode 100644 > index 21b8758ea03f..000000000000 > --- a/include/linux/vc_sm_cma_ioctl.h > +++ /dev/null > @@ -1,135 +0,0 @@ > -/* > -Copyright (c) 2012, Broadcom Europe Ltd > -All rights reserved. > - > -Redistribution and use in source and binary forms, with or without > -modification, are permitted provided that the following conditions are met: > - * Redistributions of source code must retain the above copyright > - notice, this list of conditions and the following disclaimer. > - * Redistributions in binary form must reproduce the above copyright > - notice, this list of conditions and the following disclaimer in the > - documentation and/or other materials provided with the distribution. > - * Neither the name of the copyright holder nor the > - names of its contributors may be used to endorse or promote products > - derived from this software without specific prior written permission. > - > -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND > -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED > -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY > -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES > -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; > -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS > -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > -*/ > - > -/* > - * Copyright 2019 Raspberry Pi (Trading) Ltd. All rights reserved. > - * > - * Based on vmcs_sm_ioctl.h Copyright Broadcom Corporation. > - */ > - > -#ifndef __VC_SM_CMA_IOCTL_H > -#define __VC_SM_CMA_IOCTL_H > - > -/* ---- Include Files ---------------------------------------------------- */ > - > -#include <linux/types.h> /* Needed for standard types */ > - > -#include <linux/ioctl.h> > - > -/* ---- Constants and Types ---------------------------------------------- */ > - > -#define VC_SM_CMA_RESOURCE_NAME 32 > -#define VC_SM_CMA_RESOURCE_NAME_DEFAULT "sm-host-resource" > - > -/* Type define used to create unique IOCTL number */ > -#define VC_SM_CMA_MAGIC_TYPE 'J' > - > -/* IOCTL commands on /dev/vc-sm-cma */ > -enum vc_sm_cma_cmd_e { > - VC_SM_CMA_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */ > - > - VC_SM_CMA_CMD_IMPORT_DMABUF, > - > - VC_SM_CMA_CMD_CLEAN_INVALID2, > - > - VC_SM_CMA_CMD_LAST /* Do not delete */ > -}; > - > -/* Cache type supported, conveniently matches the user space definition in > - * user-vcsm.h. > - */ > -enum vc_sm_cma_cache_e { > - VC_SM_CMA_CACHE_NONE, > - VC_SM_CMA_CACHE_HOST, > - VC_SM_CMA_CACHE_VC, > - VC_SM_CMA_CACHE_BOTH, > -}; > - > -/* IOCTL Data structures */ > -struct vc_sm_cma_ioctl_alloc { > - /* user -> kernel */ > - __u32 size; > - __u32 num; > - __u32 cached; /* enum vc_sm_cma_cache_e */ > - __u32 pad; > - __u8 name[VC_SM_CMA_RESOURCE_NAME]; > - > - /* kernel -> user */ > - __s32 handle; > - __u32 vc_handle; > - __u64 dma_addr; > -}; > - > -struct vc_sm_cma_ioctl_import_dmabuf { > - /* user -> kernel */ > - __s32 dmabuf_fd; > - __u32 cached; /* enum vc_sm_cma_cache_e */ > - __u8 name[VC_SM_CMA_RESOURCE_NAME]; > - > - /* kernel -> user */ > - __s32 handle; > - __u32 vc_handle; > - __u32 size; > - __u32 pad; > - __u64 dma_addr; > -}; > - > -/* > - * Cache functions to be set to struct vc_sm_cma_ioctl_clean_invalid2 > - * invalidate_mode. > - */ > -#define VC_SM_CACHE_OP_NOP 0x00 > -#define VC_SM_CACHE_OP_INV 0x01 > -#define VC_SM_CACHE_OP_CLEAN 0x02 > -#define VC_SM_CACHE_OP_FLUSH 0x03 > - > -struct vc_sm_cma_ioctl_clean_invalid2 { > - __u32 op_count; > - __u32 pad; > - struct vc_sm_cma_ioctl_clean_invalid_block { > - __u32 invalidate_mode; > - __u32 block_count; > - void * /*__user */start_address; > - __u32 block_size; > - __u32 inter_block_stride; > - } s[0]; > -}; > - > -/* IOCTL numbers */ > -#define VC_SM_CMA_IOCTL_MEM_ALLOC\ > - _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\ > - struct vc_sm_cma_ioctl_alloc) > - > -#define VC_SM_CMA_IOCTL_MEM_IMPORT_DMABUF\ > - _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\ > - struct vc_sm_cma_ioctl_import_dmabuf) > - > -#define VC_SM_CMA_IOCTL_MEM_CLEAN_INVALID2\ > - _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\ > - struct vc_sm_cma_ioctl_clean_invalid2) > - > -#endif /* __VC_SM_CMA_IOCTL_H */ > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp > index 2fcbc782f8b8..7bd0488089e8 100644 > --- a/src/ipa/raspberrypi/raspberrypi.cpp > +++ b/src/ipa/raspberrypi/raspberrypi.cpp > @@ -15,6 +15,7 @@ > #include <libcamera/buffer.h> > #include <libcamera/control_ids.h> > #include <libcamera/controls.h> > +#include <libcamera/file_descriptor.h> > #include <libcamera/ipa/ipa_interface.h> > #include <libcamera/ipa/ipa_module_info.h> > #include <libcamera/ipa/raspberrypi.h> > @@ -65,12 +66,14 @@ public: > IPARPi() > : lastMode_({}), controller_(), controllerInit_(false), > frame_count_(0), check_count_(0), hide_count_(0), > - mistrust_count_(0), lsTableHandle_(0), lsTable_(nullptr) > + mistrust_count_(0), lsTable_(nullptr) > { > } > > ~IPARPi() > { > + if (lsTable_) > + munmap(lsTable_, MAX_LS_GRID_SIZE); > } > > int init(const IPASettings &settings) override; > @@ -139,7 +142,7 @@ private: > /* How many frames we should avoid running control algos on. */ > unsigned int mistrust_count_; > /* LS table allocation passed in from the pipeline handler. */ > - uint32_t lsTableHandle_; > + FileDescriptor lsTableHandle_; > void *lsTable_; > }; > > @@ -280,8 +283,23 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo, > > /* Store the lens shading table pointer and handle if available. */ > if (ipaConfig.operation & RPI_IPA_CONFIG_LS_TABLE) { > - lsTable_ = reinterpret_cast<void *>(ipaConfig.data[0]); > - lsTableHandle_ = ipaConfig.data[1]; > + /* Remove any previous table, if there was one. */ > + if (lsTable_) { > + munmap(lsTable_, MAX_LS_GRID_SIZE); > + lsTable_ = nullptr; > + } > + > + /* Map the LS table buffer into user space. */ > + lsTableHandle_ = FileDescriptor(ipaConfig.data[0]); > + if (lsTableHandle_.isValid()) { > + lsTable_ = mmap(nullptr, MAX_LS_GRID_SIZE, PROT_READ | PROT_WRITE, > + MAP_SHARED, lsTableHandle_.fd(), 0); > + > + if (lsTable_ == MAP_FAILED) { > + LOG(IPARPI, Error) << "dmaHeap mmap failure for LS table."; > + lsTable_ = nullptr; > + } > + } > } > } > > @@ -1030,7 +1048,7 @@ void IPARPi::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls) > .grid_width = w, > .grid_stride = w, > .grid_height = h, > - .mem_handle_table = lsTableHandle_, > + .dmabuf = lsTableHandle_.fd(), > .ref_transform = 0, > .corner_sampled = 1, > .gain_format = GAIN_FORMAT_U4P10 > diff --git a/src/libcamera/pipeline/raspberrypi/dma_heaps.cpp b/src/libcamera/pipeline/raspberrypi/dma_heaps.cpp > new file mode 100644 > index 000000000000..6769c04640f1 > --- /dev/null > +++ b/src/libcamera/pipeline/raspberrypi/dma_heaps.cpp > @@ -0,0 +1,84 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2020, Raspberry Pi (Trading) Limited > + * > + * dma_heaps.h - Helper class for dma-heap allocations. > + */ > + > +#include "dma_heaps.h" > + > +#include <fcntl.h> > +#include <linux/dma-buf.h> > +#include <linux/dma-heap.h> > +#include <sys/ioctl.h> > +#include <unistd.h> > + > +#include "libcamera/internal/log.h" > + > +/* > + * /dev/dma-heap/linux,cma is the dma-heap allocator, which allows dmaheap-cma > + * to only have to worry about importing. > + * > + * Annoyingly, should the cma heap size be specified on the kernel command line > + * instead of DT, the heap gets named "reserved" instead. > + */ > +#define DMA_HEAP_CMA_NAME "/dev/dma_heap/linux,cma" > +#define DMA_HEAP_CMA_ALT_NAME "/dev/dma_heap/reserved" > + > +namespace libcamera { > + > +LOG_DECLARE_CATEGORY(RPI) > + > +namespace RPi { > + > +DmaHeap::DmaHeap() > +{ > + dmaHeapHandle_ = ::open(DMA_HEAP_CMA_NAME, O_RDWR, 0); > + if (dmaHeapHandle_ == -1) { > + dmaHeapHandle_ = ::open(DMA_HEAP_CMA_ALT_NAME, O_RDWR, 0); > + if (dmaHeapHandle_ == -1) { > + LOG(RPI, Error) << "Could not open dmaHeap device"; > + } > + } > +} > + > +DmaHeap::~DmaHeap() > +{ > + if (dmaHeapHandle_) > + ::close(dmaHeapHandle_); > +} > + > +FileDescriptor DmaHeap::alloc(const char *name, std::size_t size) > +{ > + int ret; > + > + if (!name) > + return FileDescriptor(); > + > + struct dma_heap_allocation_data alloc = {}; > + > + alloc.len = size; > + alloc.fd_flags = O_CLOEXEC | O_RDWR; > + > + ret = ::ioctl(dmaHeapHandle_, DMA_HEAP_IOCTL_ALLOC, &alloc); > + > + if (ret < 0) { > + LOG(RPI, Error) << "dmaHeap allocation failure for " > + << name; > + return FileDescriptor(); > + } > + > + ret = ::ioctl(alloc.fd, DMA_BUF_SET_NAME, name); > + if (ret < 0) { > + LOG(RPI, Error) << "dmaHeap naming failure for " > + << name; > + ::close(alloc.fd); > + return FileDescriptor(); > + } > + > + return FileDescriptor(std::move(alloc.fd)); > +} > + > +} /* namespace RPi */ > + > +} /* namespace libcamera */ > diff --git a/src/libcamera/pipeline/raspberrypi/dma_heaps.h b/src/libcamera/pipeline/raspberrypi/dma_heaps.h > new file mode 100644 > index 000000000000..ae6be1135f17 > --- /dev/null > +++ b/src/libcamera/pipeline/raspberrypi/dma_heaps.h > @@ -0,0 +1,31 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2020, Raspberry Pi (Trading) Limited > + * > + * dma_heaps.h - Helper class for dma-heap allocations. > + */ > +#ifndef __LIBCAMERA_PIPELINE_RASPBERRYPI_DMA_HEAPS_H__ > +#define __LIBCAMERA_PIPELINE_RASPBERRYPI_DMA_HEAPS_H__ > + > +#include <libcamera/file_descriptor.h> > + > +namespace libcamera { > + > +namespace RPi { > + > +class DmaHeap > +{ > +public: > + DmaHeap(); > + ~DmaHeap(); > + FileDescriptor alloc(const char *name, std::size_t size); > + > +private: > + int dmaHeapHandle_; > +}; > + > +} /* namespace RPi */ > + > +} /* namespace libcamera */ > + > +#endif /* __LIBCAMERA_PIPELINE_RASPBERRYPI_DMA_HEAPS_H__ */ > diff --git a/src/libcamera/pipeline/raspberrypi/meson.build b/src/libcamera/pipeline/raspberrypi/meson.build > index dcfe07c5b720..ae0aed3b5234 100644 > --- a/src/libcamera/pipeline/raspberrypi/meson.build > +++ b/src/libcamera/pipeline/raspberrypi/meson.build > @@ -1,6 +1,7 @@ > # SPDX-License-Identifier: CC0-1.0 > > libcamera_sources += files([ > + 'dma_heaps.cpp', > 'raspberrypi.cpp', > 'staggered_ctrl.cpp', > ]) > diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp > index 718749af5a6e..bf1c77144f85 100644 > --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp > +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp > @@ -13,6 +13,7 @@ > > #include <libcamera/camera.h> > #include <libcamera/control_ids.h> > +#include <libcamera/file_descriptor.h> > #include <libcamera/formats.h> > #include <libcamera/ipa/raspberrypi.h> > #include <libcamera/logging.h> > @@ -31,8 +32,8 @@ > #include "libcamera/internal/v4l2_controls.h" > #include "libcamera/internal/v4l2_videodevice.h" > > +#include "dma_heaps.h" > #include "staggered_ctrl.h" > -#include "vcsm.h" > > namespace libcamera { > > @@ -286,24 +287,11 @@ class RPiCameraData : public CameraData > { > public: > RPiCameraData(PipelineHandler *pipe) > - : CameraData(pipe), sensor_(nullptr), lsTable_(nullptr), > - state_(State::Stopped), dropFrame_(false), ispOutputCount_(0) > + : CameraData(pipe), sensor_(nullptr), state_(State::Stopped), > + dropFrame_(false), ispOutputCount_(0) > { > } > > - ~RPiCameraData() > - { > - /* > - * Free the LS table if we have allocated one. Another > - * allocation will occur in applyLS() with the appropriate > - * size. > - */ > - if (lsTable_) { > - vcsm_.free(lsTable_); > - lsTable_ = nullptr; > - } > - } > - > void frameStarted(uint32_t sequence); > > int loadIPA(); > @@ -329,9 +317,9 @@ public: > /* Buffers passed to the IPA. */ > std::vector<IPABuffer> ipaBuffers_; > > - /* VCSM allocation helper. */ > - ::RPi::Vcsm vcsm_; > - void *lsTable_; > + /* DMAHEAP allocation helper. */ > + RPi::DmaHeap dmaHeap_; > + FileDescriptor lsTable_; > > RPi::StaggeredCtrl staggeredCtrl_; > uint32_t expectedSequence_; > @@ -1142,26 +1130,15 @@ int RPiCameraData::configureIPA() > entityControls.emplace(0, unicam_[Unicam::Image].dev()->controls()); > entityControls.emplace(1, isp_[Isp::Input].dev()->controls()); > > - /* Allocate the lens shading table via vcsm and pass to the IPA. */ > - if (!lsTable_) { > - lsTable_ = vcsm_.alloc("ls_grid", MAX_LS_GRID_SIZE); > - uintptr_t ptr = reinterpret_cast<uintptr_t>(lsTable_); > - > - if (!lsTable_) > + /* Allocate the lens shading table via dmaHeap and pass to the IPA. */ > + if (!lsTable_.isValid()) { > + lsTable_ = dmaHeap_.alloc("ls_grid", MAX_LS_GRID_SIZE); > + if (!lsTable_.isValid()) > return -ENOMEM; > > - /* > - * The vcsm allocation will always be in the memory region > - * < 32-bits to allow Videocore to access the memory. > - * > - * \todo Sending a pointer to the IPA is a workaround for > - * vc_sm_cma not yet supporting dmabuf. This will not work with > - * IPA module isolation and should be reworked when vc_sma_cma > - * will permit. > - */ > + /* Allow the IPA to mmap the LS table via the file descriptor. */ > ipaConfig.operation = RPI_IPA_CONFIG_LS_TABLE; > - ipaConfig.data = { static_cast<uint32_t>(ptr & 0xffffffff), > - vcsm_.getVCHandle(lsTable_) }; > + ipaConfig.data = { static_cast<unsigned int>(lsTable_.fd()) }; > } > > CameraSensorInfo sensorInfo = {}; > diff --git a/src/libcamera/pipeline/raspberrypi/vcsm.h b/src/libcamera/pipeline/raspberrypi/vcsm.h > deleted file mode 100644 > index bebe86a76450..000000000000 > --- a/src/libcamera/pipeline/raspberrypi/vcsm.h > +++ /dev/null > @@ -1,149 +0,0 @@ > -/* SPDX-License-Identifier: LGPL-2.1-or-later */ > -/* > - * Copyright (C) 2019, Raspberry Pi (Trading) Limited > - * > - * vcsm.h - Helper class for vcsm allocations. > - */ > -#ifndef __LIBCAMERA_PIPELINE_RASPBERRYPI_VCSM_H__ > -#define __LIBCAMERA_PIPELINE_RASPBERRYPI_VCSM_H__ > - > -#include <iostream> > -#include <mutex> > - > -#include <fcntl.h> > -#include <linux/vc_sm_cma_ioctl.h> > -#include <sys/ioctl.h> > -#include <sys/mman.h> > -#include <unistd.h> > - > -namespace RPi { > - > -#define VCSM_CMA_DEVICE_NAME "/dev/vcsm-cma" > - > -class Vcsm > -{ > -public: > - Vcsm() > - { > - vcsmHandle_ = ::open(VCSM_CMA_DEVICE_NAME, O_RDWR, 0); > - if (vcsmHandle_ == -1) { > - std::cerr << "Could not open vcsm device: " > - << VCSM_CMA_DEVICE_NAME; > - } > - } > - > - ~Vcsm() > - { > - /* Free all existing allocations. */ > - auto it = allocMap_.begin(); > - while (it != allocMap_.end()) > - it = remove(it->first); > - > - if (vcsmHandle_) > - ::close(vcsmHandle_); > - } > - > - void *alloc(const char *name, unsigned int size, > - vc_sm_cma_cache_e cache = VC_SM_CMA_CACHE_NONE) > - { > - unsigned int pageSize = getpagesize(); > - void *user_ptr; > - int ret; > - > - if (!name) > - return nullptr; > - > - /* Ask for page aligned allocation. */ > - size = (size + pageSize - 1) & ~(pageSize - 1); > - > - struct vc_sm_cma_ioctl_alloc alloc; > - memset(&alloc, 0, sizeof(alloc)); > - alloc.size = size; > - alloc.num = 1; > - alloc.cached = cache; > - alloc.handle = 0; > - memcpy(alloc.name, name, 32); > - > - ret = ::ioctl(vcsmHandle_, VC_SM_CMA_IOCTL_MEM_ALLOC, &alloc); > - > - if (ret < 0 || alloc.handle < 0) { > - std::cerr << "vcsm allocation failure for " > - << name << std::endl; > - return nullptr; > - } > - > - /* Map the buffer into user space. */ > - user_ptr = ::mmap(0, alloc.size, PROT_READ | PROT_WRITE, > - MAP_SHARED, alloc.handle, 0); > - > - if (user_ptr == MAP_FAILED) { > - std::cerr << "vcsm mmap failure for " << name << std::endl; > - ::close(alloc.handle); > - return nullptr; > - } > - > - std::lock_guard<std::mutex> lock(lock_); > - allocMap_.emplace(user_ptr, AllocInfo(alloc.handle, > - alloc.size, alloc.vc_handle)); > - > - return user_ptr; > - } > - > - void free(void *user_ptr) > - { > - std::lock_guard<std::mutex> lock(lock_); > - remove(user_ptr); > - } > - > - unsigned int getVCHandle(void *user_ptr) > - { > - std::lock_guard<std::mutex> lock(lock_); > - auto it = allocMap_.find(user_ptr); > - if (it != allocMap_.end()) > - return it->second.vcHandle; > - > - return 0; > - } > - > -private: > - struct AllocInfo { > - AllocInfo(int handle_, int size_, int vcHandle_) > - : handle(handle_), size(size_), vcHandle(vcHandle_) > - { > - } > - > - int handle; > - int size; > - uint32_t vcHandle; > - }; > - > - /* Map of all allocations that have been requested. */ > - using AllocMap = std::map<void *, AllocInfo>; > - > - AllocMap::iterator remove(void *user_ptr) > - { > - auto it = allocMap_.find(user_ptr); > - if (it != allocMap_.end()) { > - int handle = it->second.handle; > - int size = it->second.size; > - ::munmap(user_ptr, size); > - ::close(handle); > - /* > - * Remove the allocation from the map. This returns > - * an iterator to the next element. > - */ > - it = allocMap_.erase(it); > - } > - > - /* Returns an iterator to the next element. */ > - return it; > - } > - > - AllocMap allocMap_; > - int vcsmHandle_; > - std::mutex lock_; > -}; > - > -} /* namespace RPi */ > - > -#endif /* __LIBCAMERA_PIPELINE_RASPBERRYPI_VCSM_H__ */ > -- > Regards, > > Laurent Pinchart >
diff --git a/include/linux/bcm2835-isp.h b/include/linux/bcm2835-isp.h index e7afc367fd76..45abb681517e 100644 --- a/include/linux/bcm2835-isp.h +++ b/include/linux/bcm2835-isp.h @@ -108,7 +108,7 @@ enum bcm2835_isp_gain_format { * @grid_stride: Row to row distance (in grid cells) between grid cells * in the same horizontal location. * @grid_height: Height of lens shading tables in grid cells. - * @mem_handle_table: Memory handle to the tables. + * @dmabuf: dmabuf file handle containing the table. * @ref_transform: Reference transform - unsupported, please pass zero. * @corner_sampled: Whether the gains are sampled at the corner points * of the grid cells or in the cell centres. @@ -120,7 +120,7 @@ struct bcm2835_isp_lens_shading { __u32 grid_width; __u32 grid_stride; __u32 grid_height; - __u32 mem_handle_table; + __s32 dmabuf; __u32 ref_transform; __u32 corner_sampled; __u32 gain_format; diff --git a/include/linux/vc_sm_cma_ioctl.h b/include/linux/vc_sm_cma_ioctl.h deleted file mode 100644 index 21b8758ea03f..000000000000 --- a/include/linux/vc_sm_cma_ioctl.h +++ /dev/null @@ -1,135 +0,0 @@ -/* -Copyright (c) 2012, Broadcom Europe Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* - * Copyright 2019 Raspberry Pi (Trading) Ltd. All rights reserved. - * - * Based on vmcs_sm_ioctl.h Copyright Broadcom Corporation. - */ - -#ifndef __VC_SM_CMA_IOCTL_H -#define __VC_SM_CMA_IOCTL_H - -/* ---- Include Files ---------------------------------------------------- */ - -#include <linux/types.h> /* Needed for standard types */ - -#include <linux/ioctl.h> - -/* ---- Constants and Types ---------------------------------------------- */ - -#define VC_SM_CMA_RESOURCE_NAME 32 -#define VC_SM_CMA_RESOURCE_NAME_DEFAULT "sm-host-resource" - -/* Type define used to create unique IOCTL number */ -#define VC_SM_CMA_MAGIC_TYPE 'J' - -/* IOCTL commands on /dev/vc-sm-cma */ -enum vc_sm_cma_cmd_e { - VC_SM_CMA_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */ - - VC_SM_CMA_CMD_IMPORT_DMABUF, - - VC_SM_CMA_CMD_CLEAN_INVALID2, - - VC_SM_CMA_CMD_LAST /* Do not delete */ -}; - -/* Cache type supported, conveniently matches the user space definition in - * user-vcsm.h. - */ -enum vc_sm_cma_cache_e { - VC_SM_CMA_CACHE_NONE, - VC_SM_CMA_CACHE_HOST, - VC_SM_CMA_CACHE_VC, - VC_SM_CMA_CACHE_BOTH, -}; - -/* IOCTL Data structures */ -struct vc_sm_cma_ioctl_alloc { - /* user -> kernel */ - __u32 size; - __u32 num; - __u32 cached; /* enum vc_sm_cma_cache_e */ - __u32 pad; - __u8 name[VC_SM_CMA_RESOURCE_NAME]; - - /* kernel -> user */ - __s32 handle; - __u32 vc_handle; - __u64 dma_addr; -}; - -struct vc_sm_cma_ioctl_import_dmabuf { - /* user -> kernel */ - __s32 dmabuf_fd; - __u32 cached; /* enum vc_sm_cma_cache_e */ - __u8 name[VC_SM_CMA_RESOURCE_NAME]; - - /* kernel -> user */ - __s32 handle; - __u32 vc_handle; - __u32 size; - __u32 pad; - __u64 dma_addr; -}; - -/* - * Cache functions to be set to struct vc_sm_cma_ioctl_clean_invalid2 - * invalidate_mode. - */ -#define VC_SM_CACHE_OP_NOP 0x00 -#define VC_SM_CACHE_OP_INV 0x01 -#define VC_SM_CACHE_OP_CLEAN 0x02 -#define VC_SM_CACHE_OP_FLUSH 0x03 - -struct vc_sm_cma_ioctl_clean_invalid2 { - __u32 op_count; - __u32 pad; - struct vc_sm_cma_ioctl_clean_invalid_block { - __u32 invalidate_mode; - __u32 block_count; - void * /*__user */start_address; - __u32 block_size; - __u32 inter_block_stride; - } s[0]; -}; - -/* IOCTL numbers */ -#define VC_SM_CMA_IOCTL_MEM_ALLOC\ - _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\ - struct vc_sm_cma_ioctl_alloc) - -#define VC_SM_CMA_IOCTL_MEM_IMPORT_DMABUF\ - _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\ - struct vc_sm_cma_ioctl_import_dmabuf) - -#define VC_SM_CMA_IOCTL_MEM_CLEAN_INVALID2\ - _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\ - struct vc_sm_cma_ioctl_clean_invalid2) - -#endif /* __VC_SM_CMA_IOCTL_H */ diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 2fcbc782f8b8..7bd0488089e8 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -15,6 +15,7 @@ #include <libcamera/buffer.h> #include <libcamera/control_ids.h> #include <libcamera/controls.h> +#include <libcamera/file_descriptor.h> #include <libcamera/ipa/ipa_interface.h> #include <libcamera/ipa/ipa_module_info.h> #include <libcamera/ipa/raspberrypi.h> @@ -65,12 +66,14 @@ public: IPARPi() : lastMode_({}), controller_(), controllerInit_(false), frame_count_(0), check_count_(0), hide_count_(0), - mistrust_count_(0), lsTableHandle_(0), lsTable_(nullptr) + mistrust_count_(0), lsTable_(nullptr) { } ~IPARPi() { + if (lsTable_) + munmap(lsTable_, MAX_LS_GRID_SIZE); } int init(const IPASettings &settings) override; @@ -139,7 +142,7 @@ private: /* How many frames we should avoid running control algos on. */ unsigned int mistrust_count_; /* LS table allocation passed in from the pipeline handler. */ - uint32_t lsTableHandle_; + FileDescriptor lsTableHandle_; void *lsTable_; }; @@ -280,8 +283,23 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo, /* Store the lens shading table pointer and handle if available. */ if (ipaConfig.operation & RPI_IPA_CONFIG_LS_TABLE) { - lsTable_ = reinterpret_cast<void *>(ipaConfig.data[0]); - lsTableHandle_ = ipaConfig.data[1]; + /* Remove any previous table, if there was one. */ + if (lsTable_) { + munmap(lsTable_, MAX_LS_GRID_SIZE); + lsTable_ = nullptr; + } + + /* Map the LS table buffer into user space. */ + lsTableHandle_ = FileDescriptor(ipaConfig.data[0]); + if (lsTableHandle_.isValid()) { + lsTable_ = mmap(nullptr, MAX_LS_GRID_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED, lsTableHandle_.fd(), 0); + + if (lsTable_ == MAP_FAILED) { + LOG(IPARPI, Error) << "dmaHeap mmap failure for LS table."; + lsTable_ = nullptr; + } + } } } @@ -1030,7 +1048,7 @@ void IPARPi::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls) .grid_width = w, .grid_stride = w, .grid_height = h, - .mem_handle_table = lsTableHandle_, + .dmabuf = lsTableHandle_.fd(), .ref_transform = 0, .corner_sampled = 1, .gain_format = GAIN_FORMAT_U4P10 diff --git a/src/libcamera/pipeline/raspberrypi/dma_heaps.cpp b/src/libcamera/pipeline/raspberrypi/dma_heaps.cpp new file mode 100644 index 000000000000..6769c04640f1 --- /dev/null +++ b/src/libcamera/pipeline/raspberrypi/dma_heaps.cpp @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Raspberry Pi (Trading) Limited + * + * dma_heaps.h - Helper class for dma-heap allocations. + */ + +#include "dma_heaps.h" + +#include <fcntl.h> +#include <linux/dma-buf.h> +#include <linux/dma-heap.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include "libcamera/internal/log.h" + +/* + * /dev/dma-heap/linux,cma is the dma-heap allocator, which allows dmaheap-cma + * to only have to worry about importing. + * + * Annoyingly, should the cma heap size be specified on the kernel command line + * instead of DT, the heap gets named "reserved" instead. + */ +#define DMA_HEAP_CMA_NAME "/dev/dma_heap/linux,cma" +#define DMA_HEAP_CMA_ALT_NAME "/dev/dma_heap/reserved" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(RPI) + +namespace RPi { + +DmaHeap::DmaHeap() +{ + dmaHeapHandle_ = ::open(DMA_HEAP_CMA_NAME, O_RDWR, 0); + if (dmaHeapHandle_ == -1) { + dmaHeapHandle_ = ::open(DMA_HEAP_CMA_ALT_NAME, O_RDWR, 0); + if (dmaHeapHandle_ == -1) { + LOG(RPI, Error) << "Could not open dmaHeap device"; + } + } +} + +DmaHeap::~DmaHeap() +{ + if (dmaHeapHandle_) + ::close(dmaHeapHandle_); +} + +FileDescriptor DmaHeap::alloc(const char *name, std::size_t size) +{ + int ret; + + if (!name) + return FileDescriptor(); + + struct dma_heap_allocation_data alloc = {}; + + alloc.len = size; + alloc.fd_flags = O_CLOEXEC | O_RDWR; + + ret = ::ioctl(dmaHeapHandle_, DMA_HEAP_IOCTL_ALLOC, &alloc); + + if (ret < 0) { + LOG(RPI, Error) << "dmaHeap allocation failure for " + << name; + return FileDescriptor(); + } + + ret = ::ioctl(alloc.fd, DMA_BUF_SET_NAME, name); + if (ret < 0) { + LOG(RPI, Error) << "dmaHeap naming failure for " + << name; + ::close(alloc.fd); + return FileDescriptor(); + } + + return FileDescriptor(std::move(alloc.fd)); +} + +} /* namespace RPi */ + +} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/raspberrypi/dma_heaps.h b/src/libcamera/pipeline/raspberrypi/dma_heaps.h new file mode 100644 index 000000000000..ae6be1135f17 --- /dev/null +++ b/src/libcamera/pipeline/raspberrypi/dma_heaps.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Raspberry Pi (Trading) Limited + * + * dma_heaps.h - Helper class for dma-heap allocations. + */ +#ifndef __LIBCAMERA_PIPELINE_RASPBERRYPI_DMA_HEAPS_H__ +#define __LIBCAMERA_PIPELINE_RASPBERRYPI_DMA_HEAPS_H__ + +#include <libcamera/file_descriptor.h> + +namespace libcamera { + +namespace RPi { + +class DmaHeap +{ +public: + DmaHeap(); + ~DmaHeap(); + FileDescriptor alloc(const char *name, std::size_t size); + +private: + int dmaHeapHandle_; +}; + +} /* namespace RPi */ + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PIPELINE_RASPBERRYPI_DMA_HEAPS_H__ */ diff --git a/src/libcamera/pipeline/raspberrypi/meson.build b/src/libcamera/pipeline/raspberrypi/meson.build index dcfe07c5b720..ae0aed3b5234 100644 --- a/src/libcamera/pipeline/raspberrypi/meson.build +++ b/src/libcamera/pipeline/raspberrypi/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: CC0-1.0 libcamera_sources += files([ + 'dma_heaps.cpp', 'raspberrypi.cpp', 'staggered_ctrl.cpp', ]) diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 718749af5a6e..bf1c77144f85 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -13,6 +13,7 @@ #include <libcamera/camera.h> #include <libcamera/control_ids.h> +#include <libcamera/file_descriptor.h> #include <libcamera/formats.h> #include <libcamera/ipa/raspberrypi.h> #include <libcamera/logging.h> @@ -31,8 +32,8 @@ #include "libcamera/internal/v4l2_controls.h" #include "libcamera/internal/v4l2_videodevice.h" +#include "dma_heaps.h" #include "staggered_ctrl.h" -#include "vcsm.h" namespace libcamera { @@ -286,24 +287,11 @@ class RPiCameraData : public CameraData { public: RPiCameraData(PipelineHandler *pipe) - : CameraData(pipe), sensor_(nullptr), lsTable_(nullptr), - state_(State::Stopped), dropFrame_(false), ispOutputCount_(0) + : CameraData(pipe), sensor_(nullptr), state_(State::Stopped), + dropFrame_(false), ispOutputCount_(0) { } - ~RPiCameraData() - { - /* - * Free the LS table if we have allocated one. Another - * allocation will occur in applyLS() with the appropriate - * size. - */ - if (lsTable_) { - vcsm_.free(lsTable_); - lsTable_ = nullptr; - } - } - void frameStarted(uint32_t sequence); int loadIPA(); @@ -329,9 +317,9 @@ public: /* Buffers passed to the IPA. */ std::vector<IPABuffer> ipaBuffers_; - /* VCSM allocation helper. */ - ::RPi::Vcsm vcsm_; - void *lsTable_; + /* DMAHEAP allocation helper. */ + RPi::DmaHeap dmaHeap_; + FileDescriptor lsTable_; RPi::StaggeredCtrl staggeredCtrl_; uint32_t expectedSequence_; @@ -1142,26 +1130,15 @@ int RPiCameraData::configureIPA() entityControls.emplace(0, unicam_[Unicam::Image].dev()->controls()); entityControls.emplace(1, isp_[Isp::Input].dev()->controls()); - /* Allocate the lens shading table via vcsm and pass to the IPA. */ - if (!lsTable_) { - lsTable_ = vcsm_.alloc("ls_grid", MAX_LS_GRID_SIZE); - uintptr_t ptr = reinterpret_cast<uintptr_t>(lsTable_); - - if (!lsTable_) + /* Allocate the lens shading table via dmaHeap and pass to the IPA. */ + if (!lsTable_.isValid()) { + lsTable_ = dmaHeap_.alloc("ls_grid", MAX_LS_GRID_SIZE); + if (!lsTable_.isValid()) return -ENOMEM; - /* - * The vcsm allocation will always be in the memory region - * < 32-bits to allow Videocore to access the memory. - * - * \todo Sending a pointer to the IPA is a workaround for - * vc_sm_cma not yet supporting dmabuf. This will not work with - * IPA module isolation and should be reworked when vc_sma_cma - * will permit. - */ + /* Allow the IPA to mmap the LS table via the file descriptor. */ ipaConfig.operation = RPI_IPA_CONFIG_LS_TABLE; - ipaConfig.data = { static_cast<uint32_t>(ptr & 0xffffffff), - vcsm_.getVCHandle(lsTable_) }; + ipaConfig.data = { static_cast<unsigned int>(lsTable_.fd()) }; } CameraSensorInfo sensorInfo = {}; diff --git a/src/libcamera/pipeline/raspberrypi/vcsm.h b/src/libcamera/pipeline/raspberrypi/vcsm.h deleted file mode 100644 index bebe86a76450..000000000000 --- a/src/libcamera/pipeline/raspberrypi/vcsm.h +++ /dev/null @@ -1,149 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2019, Raspberry Pi (Trading) Limited - * - * vcsm.h - Helper class for vcsm allocations. - */ -#ifndef __LIBCAMERA_PIPELINE_RASPBERRYPI_VCSM_H__ -#define __LIBCAMERA_PIPELINE_RASPBERRYPI_VCSM_H__ - -#include <iostream> -#include <mutex> - -#include <fcntl.h> -#include <linux/vc_sm_cma_ioctl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <unistd.h> - -namespace RPi { - -#define VCSM_CMA_DEVICE_NAME "/dev/vcsm-cma" - -class Vcsm -{ -public: - Vcsm() - { - vcsmHandle_ = ::open(VCSM_CMA_DEVICE_NAME, O_RDWR, 0); - if (vcsmHandle_ == -1) { - std::cerr << "Could not open vcsm device: " - << VCSM_CMA_DEVICE_NAME; - } - } - - ~Vcsm() - { - /* Free all existing allocations. */ - auto it = allocMap_.begin(); - while (it != allocMap_.end()) - it = remove(it->first); - - if (vcsmHandle_) - ::close(vcsmHandle_); - } - - void *alloc(const char *name, unsigned int size, - vc_sm_cma_cache_e cache = VC_SM_CMA_CACHE_NONE) - { - unsigned int pageSize = getpagesize(); - void *user_ptr; - int ret; - - if (!name) - return nullptr; - - /* Ask for page aligned allocation. */ - size = (size + pageSize - 1) & ~(pageSize - 1); - - struct vc_sm_cma_ioctl_alloc alloc; - memset(&alloc, 0, sizeof(alloc)); - alloc.size = size; - alloc.num = 1; - alloc.cached = cache; - alloc.handle = 0; - memcpy(alloc.name, name, 32); - - ret = ::ioctl(vcsmHandle_, VC_SM_CMA_IOCTL_MEM_ALLOC, &alloc); - - if (ret < 0 || alloc.handle < 0) { - std::cerr << "vcsm allocation failure for " - << name << std::endl; - return nullptr; - } - - /* Map the buffer into user space. */ - user_ptr = ::mmap(0, alloc.size, PROT_READ | PROT_WRITE, - MAP_SHARED, alloc.handle, 0); - - if (user_ptr == MAP_FAILED) { - std::cerr << "vcsm mmap failure for " << name << std::endl; - ::close(alloc.handle); - return nullptr; - } - - std::lock_guard<std::mutex> lock(lock_); - allocMap_.emplace(user_ptr, AllocInfo(alloc.handle, - alloc.size, alloc.vc_handle)); - - return user_ptr; - } - - void free(void *user_ptr) - { - std::lock_guard<std::mutex> lock(lock_); - remove(user_ptr); - } - - unsigned int getVCHandle(void *user_ptr) - { - std::lock_guard<std::mutex> lock(lock_); - auto it = allocMap_.find(user_ptr); - if (it != allocMap_.end()) - return it->second.vcHandle; - - return 0; - } - -private: - struct AllocInfo { - AllocInfo(int handle_, int size_, int vcHandle_) - : handle(handle_), size(size_), vcHandle(vcHandle_) - { - } - - int handle; - int size; - uint32_t vcHandle; - }; - - /* Map of all allocations that have been requested. */ - using AllocMap = std::map<void *, AllocInfo>; - - AllocMap::iterator remove(void *user_ptr) - { - auto it = allocMap_.find(user_ptr); - if (it != allocMap_.end()) { - int handle = it->second.handle; - int size = it->second.size; - ::munmap(user_ptr, size); - ::close(handle); - /* - * Remove the allocation from the map. This returns - * an iterator to the next element. - */ - it = allocMap_.erase(it); - } - - /* Returns an iterator to the next element. */ - return it; - } - - AllocMap allocMap_; - int vcsmHandle_; - std::mutex lock_; -}; - -} /* namespace RPi */ - -#endif /* __LIBCAMERA_PIPELINE_RASPBERRYPI_VCSM_H__ */