diff options
Diffstat (limited to 'drivers/media/v4l2-core/videobuf2-dma-contig.c')
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-dma-contig.c | 88 |
1 files changed, 55 insertions, 33 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 5361197f3e57..863f658a3fa1 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -21,11 +21,6 @@ #include <media/videobuf2-dma-contig.h> #include <media/videobuf2-memops.h> -struct vb2_dc_conf { - struct device *dev; - struct dma_attrs attrs; -}; - struct vb2_dc_buf { struct device *dev; void *vaddr; @@ -140,18 +135,18 @@ static void vb2_dc_put(void *buf_priv) kfree(buf); } -static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, - enum dma_data_direction dma_dir, gfp_t gfp_flags) +static void *vb2_dc_alloc(struct device *dev, const struct dma_attrs *attrs, + unsigned long size, enum dma_data_direction dma_dir, + gfp_t gfp_flags) { - struct vb2_dc_conf *conf = alloc_ctx; - struct device *dev = conf->dev; struct vb2_dc_buf *buf; buf = kzalloc(sizeof *buf, GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); - buf->attrs = conf->attrs; + if (attrs) + buf->attrs = *attrs; buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr, GFP_KERNEL | gfp_flags, &buf->attrs); if (!buf->cookie) { @@ -478,10 +473,9 @@ static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn } #endif -static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, +static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, unsigned long size, enum dma_data_direction dma_dir) { - struct vb2_dc_conf *conf = alloc_ctx; struct vb2_dc_buf *buf; struct frame_vector *vec; unsigned long offset; @@ -509,7 +503,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, if (!buf) return ERR_PTR(-ENOMEM); - buf->dev = conf->dev; + buf->dev = dev; buf->dma_dir = dma_dir; offset = vaddr & ~PAGE_MASK; @@ -676,10 +670,9 @@ static void vb2_dc_detach_dmabuf(void *mem_priv) kfree(buf); } -static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, +static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, unsigned long size, enum dma_data_direction dma_dir) { - struct vb2_dc_conf *conf = alloc_ctx; struct vb2_dc_buf *buf; struct dma_buf_attachment *dba; @@ -690,7 +683,7 @@ static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, if (!buf) return ERR_PTR(-ENOMEM); - buf->dev = conf->dev; + buf->dev = dev; /* create attachment for the dmabuf with the user device */ dba = dma_buf_attach(dbuf, buf->dev); if (IS_ERR(dba)) { @@ -729,29 +722,58 @@ const struct vb2_mem_ops vb2_dma_contig_memops = { }; EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); -void *vb2_dma_contig_init_ctx_attrs(struct device *dev, - struct dma_attrs *attrs) +/** + * vb2_dma_contig_set_max_seg_size() - configure DMA max segment size + * @dev: device for configuring DMA parameters + * @size: size of DMA max segment size to set + * + * To allow mapping the scatter-list into a single chunk in the DMA + * address space, the device is required to have the DMA max segment + * size parameter set to a value larger than the buffer size. Otherwise, + * the DMA-mapping subsystem will split the mapping into max segment + * size chunks. This function sets the DMA max segment size + * parameter to let DMA-mapping map a buffer as a single chunk in DMA + * address space. + * This code assumes that the DMA-mapping subsystem will merge all + * scatterlist segments if this is really possible (for example when + * an IOMMU is available and enabled). + * Ideally, this parameter should be set by the generic bus code, but it + * is left with the default 64KiB value due to historical litmiations in + * other subsystems (like limited USB host drivers) and there no good + * place to set it to the proper value. + * This function should be called from the drivers, which are known to + * operate on platforms with IOMMU and provide access to shared buffers + * (either USERPTR or DMABUF). This should be done before initializing + * videobuf2 queue. + */ +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size) { - struct vb2_dc_conf *conf; - - conf = kzalloc(sizeof *conf, GFP_KERNEL); - if (!conf) - return ERR_PTR(-ENOMEM); - - conf->dev = dev; - if (attrs) - conf->attrs = *attrs; + if (!dev->dma_parms) { + dev->dma_parms = kzalloc(sizeof(dev->dma_parms), GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + if (dma_get_max_seg_size(dev) < size) + return dma_set_max_seg_size(dev, size); - return conf; + return 0; } -EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx_attrs); +EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size); -void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) +/* + * vb2_dma_contig_clear_max_seg_size() - release resources for DMA parameters + * @dev: device for configuring DMA parameters + * + * This function releases resources allocated to configure DMA parameters + * (see vb2_dma_contig_set_max_seg_size() function). It should be called from + * device drivers on driver remove. + */ +void vb2_dma_contig_clear_max_seg_size(struct device *dev) { - if (!IS_ERR_OR_NULL(alloc_ctx)) - kfree(alloc_ctx); + kfree(dev->dma_parms); + dev->dma_parms = NULL; } -EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); +EXPORT_SYMBOL_GPL(vb2_dma_contig_clear_max_seg_size); MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>"); |