Initial accel subsystem support. There are no drivers yet, just the framework. New driver: - ofdrm - replacement for offb fbdev: - add support for nomodeset fourcc: - add Vivante tiled modifier core: - atomic-helpers: CRTC primary plane test fixes, fb access hooks - connector: TV API consistency, cmdline parser improvements - send connector hotplug on cleanup - sort makefile objects tests: - sort kunit tests - improve DP-MST tests - add kunit helpers to create a device sched: - module param for scheduling policy - refcounting fix buddy: - add back random seed log ttm: - convert ttm_resource to size_t - optimize pool allocations edid: - HFVSDB parsing support fixes - logging/debug improvements - DSC quirks dma-buf: - Add unlocked vmap and attachment mapping - move drivers to common locking convention - locking improvements firmware: - new API for rPI firmware and vc4 xilinx: - zynqmp: displayport bridge support - dpsub fix bridge: - adv7533: Remove dynamic lane switching - it6505: Runtime PM support, sync improvements - ps8640: Handle AUX defer messages - tc358775: Drop soft-reset over I2C panel: - panel-edp: Add INX N116BGE-EA2 C2 and C4 support. - Jadard JD9365DA-H3 - NewVision NV3051D amdgpu: - DCN support on ARM - DCN 2.1 secure display - Sienna Cichlid mode2 reset fixes - new GC 11.x firmware versions - drop AMD specific DSC workarounds in favour of drm code - clang warning fixes - scheduler rework - SR-IOV fixes - GPUVM locking fixes - fix memory leak in CS IOCTL error path - flexible array updates - enable new GC/PSP/SMU/NBIO IP - GFX preemption support for gfx9 amdkfd: - cache size fixes - userptr fixes - enable cooperative launch on gfx 10.3 - enable GC 11.0.4 KFD support radeon: - replace kmap with kmap_local_page - ACPI ref count fix - HDA audio notifier support i915: - DG2 enabled by default - MTL enablement work - hotplug refactoring - VBT improvements - Display and watermark refactoring - ADL-P workaround - temp disable runtime_pm for discrete- - fix for A380 as a secondary GPU - Wa_18017747507 for DG2 - CS timestamp support fixes for gen5 and earlier - never purge busy TTM objects - use i915_sg_dma_sizes for all backends - demote GuC kernel contexts to normal priority - gvt: refactor for new MDEV interface - enable DC power states on eDP ports - fix gen 2/3 workarounds nouveau: - fix page fault handling - Ampere acceleration support - driver stability improvements - nva3 backlight support msm: - MSM_INFO_GET_FLAGS support - DPU: XR30 and P010 image formats - Qualcomm SM6115 support - DSI PHY support for QCM2290 - HDMI: refactored dev init path - remove exclusive-fence hack - fix speed-bin detection - enable clamp to idle on 7c3 - improved hangcheck detection vmwgfx: - fb and cursor refactoring - convert to generic hashtable - cursor improvements etnaviv: - hw workarounds - softpin MMU fixes ast: - atomic gamma LUT support - convert to SHMEM lcdif: - support YUV planes - Increase DMA burst size - FIFO threshold tuning meson: - fix return type of cvbs mode_valid mgag200: - fix PLL setup on some revisions sun4i: - A100 and D1 support udl: - modesetting improvements - hot unplug support vc4: - support PAL-M - fix regression preventing 4K @ 60Hz - fix NULL ptr deref v3d: - switch to drm managed resources renesas: - RZ/G2L DSI support - DU Kconfig cleanup mediatek: - fixup dpi and hdmi - MT8188 dpi support - MT8195 AFBC support tegra: - NVDEC hardware on Tegra234 SoC hdlcd: - switch to drm managed resources ingenic: - fix registration error path hisilicon: - convert to drm_mode_init maildp: - use managed resources mtk: - use drm_mode_init rockchip: - use drm_mode_copy -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmOXxI0ACgkQDHTzWXnE hr4NyBAAojK3N+XJf2b8LWuRKsShCr5FXlteEDxiYGLeB8/g4x3LztSfHgUg0iuS nP1m7Cx4snXcVNS6iyOsoZVq1EGUAWvv+mPWJe1UywjpyqtciTVQ11GEHRvI/w+V GRvkhmt/TsoZA0QIlS2MaOmhn9j17QOcuYTUjYdyRL4tsrHWrTASH5W1Jt2xmDyw 5FUJvfukPWm100DVWbh6hWbCKL22bDDF/nj1H+G6hYSyTjVbk7wZ0vy2m6TnIHNF iyBHBIzFPg3BveiSlKe6aVX7Gq2d8bfqjHsgN5f1qcS4ejWEkHLVxJtBdOB+fOSC 7o8Ms7WHi1AmnkOVCGRIjJ0cJrLZu2HDlyhViguAO1XQ3Jvuo/4WW3mplv+YPOMc c+P/zuPG42d4lrISuB8wspTdOgxmqpZDkg3HE6n1+jiVR0u4hTTYktoPnLsHX6KG l/l2B6aVAxE4b6P0q3ofYoAnk5rNsb1YUS+a8kC6f97TQ3gmOsN75iZXD/ASHg2r ozhh2wcFxIPkJhE7vqLWPIBCWQs93sGyQXoI7Q0TJaIAZTXV0VmO1BIofetpVImE 7FhDC4wvBedXywN8NYUEFbCTOnIcDMteM/i6S1ns78s5UjDa5osPuS5I02VT1lbN tvnJoHNkhCt13lJz63b0HNFm3cPKoRosCQhJeshyUYaFKs+evL0= =pABG -----END PGP SIGNATURE----- Merge tag 'drm-next-2022-12-13' of git://anongit.freedesktop.org/drm/drm Pull drm updates from Dave Airlie: "The biggest highlight is that the accel subsystem framework is merged. Hopefully for 6.3 we will be able to line up a driver to use it. In drivers land, i915 enables DG2 support by default now, and nouveau has a big stability refactoring and initial ampere support, AMD includes new hw IP support and should build on ARM again. There is also an ofdrm driver to take over offb on platforms it's used. Stuff outside my tree, the dma-buf patches hit a few places, the vc4 firmware changes also do, and i915 has some interactions with MEI for discrete GPUs. I think all of those should have been acked/reviewed by relevant parties. New driver: - ofdrm - replacement for offb fbdev: - add support for nomodeset fourcc: - add Vivante tiled modifier core: - atomic-helpers: CRTC primary plane test fixes, fb access hooks - connector: TV API consistency, cmdline parser improvements - send connector hotplug on cleanup - sort makefile objects tests: - sort kunit tests - improve DP-MST tests - add kunit helpers to create a device sched: - module param for scheduling policy - refcounting fix buddy: - add back random seed log ttm: - convert ttm_resource to size_t - optimize pool allocations edid: - HFVSDB parsing support fixes - logging/debug improvements - DSC quirks dma-buf: - Add unlocked vmap and attachment mapping - move drivers to common locking convention - locking improvements firmware: - new API for rPI firmware and vc4 xilinx: - zynqmp: displayport bridge support - dpsub fix bridge: - adv7533: Remove dynamic lane switching - it6505: Runtime PM support, sync improvements - ps8640: Handle AUX defer messages - tc358775: Drop soft-reset over I2C panel: - panel-edp: Add INX N116BGE-EA2 C2 and C4 support. - Jadard JD9365DA-H3 - NewVision NV3051D amdgpu: - DCN support on ARM - DCN 2.1 secure display - Sienna Cichlid mode2 reset fixes - new GC 11.x firmware versions - drop AMD specific DSC workarounds in favour of drm code - clang warning fixes - scheduler rework - SR-IOV fixes - GPUVM locking fixes - fix memory leak in CS IOCTL error path - flexible array updates - enable new GC/PSP/SMU/NBIO IP - GFX preemption support for gfx9 amdkfd: - cache size fixes - userptr fixes - enable cooperative launch on gfx 10.3 - enable GC 11.0.4 KFD support radeon: - replace kmap with kmap_local_page - ACPI ref count fix - HDA audio notifier support i915: - DG2 enabled by default - MTL enablement work - hotplug refactoring - VBT improvements - Display and watermark refactoring - ADL-P workaround - temp disable runtime_pm for discrete- - fix for A380 as a secondary GPU - Wa_18017747507 for DG2 - CS timestamp support fixes for gen5 and earlier - never purge busy TTM objects - use i915_sg_dma_sizes for all backends - demote GuC kernel contexts to normal priority - gvt: refactor for new MDEV interface - enable DC power states on eDP ports - fix gen 2/3 workarounds nouveau: - fix page fault handling - Ampere acceleration support - driver stability improvements - nva3 backlight support msm: - MSM_INFO_GET_FLAGS support - DPU: XR30 and P010 image formats - Qualcomm SM6115 support - DSI PHY support for QCM2290 - HDMI: refactored dev init path - remove exclusive-fence hack - fix speed-bin detection - enable clamp to idle on 7c3 - improved hangcheck detection vmwgfx: - fb and cursor refactoring - convert to generic hashtable - cursor improvements etnaviv: - hw workarounds - softpin MMU fixes ast: - atomic gamma LUT support - convert to SHMEM lcdif: - support YUV planes - Increase DMA burst size - FIFO threshold tuning meson: - fix return type of cvbs mode_valid mgag200: - fix PLL setup on some revisions sun4i: - A100 and D1 support udl: - modesetting improvements - hot unplug support vc4: - support PAL-M - fix regression preventing 4K @ 60Hz - fix NULL ptr deref v3d: - switch to drm managed resources renesas: - RZ/G2L DSI support - DU Kconfig cleanup mediatek: - fixup dpi and hdmi - MT8188 dpi support - MT8195 AFBC support tegra: - NVDEC hardware on Tegra234 SoC hdlcd: - switch to drm managed resources ingenic: - fix registration error path hisilicon: - convert to drm_mode_init maildp: - use managed resources mtk: - use drm_mode_init rockchip: - use drm_mode_copy" * tag 'drm-next-2022-12-13' of git://anongit.freedesktop.org/drm/drm: (1397 commits) drm/amdgpu: fix mmhub register base coding error drm/amdgpu: add tmz support for GC IP v11.0.4 drm/amdgpu: enable GFX Clock Gating control for GC IP v11.0.4 drm/amdgpu: enable GFX Power Gating for GC IP v11.0.4 drm/amdgpu: enable GFX IP v11.0.4 CG support drm/amdgpu: Make amdgpu_ring_mux functions as static drm/amdgpu: generally allow over-commit during BO allocation drm/amd/display: fix array index out of bound error in DCN32 DML drm/amd/display: 3.2.215 drm/amd/display: set optimized required for comp buf changes drm/amd/display: Add debug option to skip PSR CRTC disable drm/amd/display: correct DML calc error of UrgentLatency drm/amd/display: correct static_screen_event_mask drm/amd/display: Ensure commit_streams returns the DC return code drm/amd/display: read invalid ddc pin status cause engine busy drm/amd/display: Bypass DET swath fill check for max clocks drm/amd/display: Disable uclk pstate for subvp pipes drm/amd/display: Fix DCN2.1 default DSC clocks drm/amd/display: Enable dp_hdmi21_pcon support drm/amd/display: prevent seamless boot on displays that don't have the preferred dig ...
446 lines
10 KiB
C
446 lines
10 KiB
C
/*
|
|
* videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
|
|
*
|
|
* Copyright (C) 2010 Samsung Electronics
|
|
*
|
|
* Author: Pawel Osciak <pawel@osciak.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/dma-resv.h>
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/refcount.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include <media/videobuf2-v4l2.h>
|
|
#include <media/videobuf2-vmalloc.h>
|
|
#include <media/videobuf2-memops.h>
|
|
|
|
struct vb2_vmalloc_buf {
|
|
void *vaddr;
|
|
struct frame_vector *vec;
|
|
enum dma_data_direction dma_dir;
|
|
unsigned long size;
|
|
refcount_t refcount;
|
|
struct vb2_vmarea_handler handler;
|
|
struct dma_buf *dbuf;
|
|
};
|
|
|
|
static void vb2_vmalloc_put(void *buf_priv);
|
|
|
|
static void *vb2_vmalloc_alloc(struct vb2_buffer *vb, struct device *dev,
|
|
unsigned long size)
|
|
{
|
|
struct vb2_vmalloc_buf *buf;
|
|
|
|
buf = kzalloc(sizeof(*buf), GFP_KERNEL | vb->vb2_queue->gfp_flags);
|
|
if (!buf)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
buf->size = size;
|
|
buf->vaddr = vmalloc_user(buf->size);
|
|
if (!buf->vaddr) {
|
|
pr_debug("vmalloc of size %ld failed\n", buf->size);
|
|
kfree(buf);
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
|
|
buf->dma_dir = vb->vb2_queue->dma_dir;
|
|
buf->handler.refcount = &buf->refcount;
|
|
buf->handler.put = vb2_vmalloc_put;
|
|
buf->handler.arg = buf;
|
|
|
|
refcount_set(&buf->refcount, 1);
|
|
return buf;
|
|
}
|
|
|
|
static void vb2_vmalloc_put(void *buf_priv)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = buf_priv;
|
|
|
|
if (refcount_dec_and_test(&buf->refcount)) {
|
|
vfree(buf->vaddr);
|
|
kfree(buf);
|
|
}
|
|
}
|
|
|
|
static void *vb2_vmalloc_get_userptr(struct vb2_buffer *vb, struct device *dev,
|
|
unsigned long vaddr, unsigned long size)
|
|
{
|
|
struct vb2_vmalloc_buf *buf;
|
|
struct frame_vector *vec;
|
|
int n_pages, offset, i;
|
|
int ret = -ENOMEM;
|
|
|
|
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
|
|
if (!buf)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
buf->dma_dir = vb->vb2_queue->dma_dir;
|
|
offset = vaddr & ~PAGE_MASK;
|
|
buf->size = size;
|
|
vec = vb2_create_framevec(vaddr, size,
|
|
buf->dma_dir == DMA_FROM_DEVICE ||
|
|
buf->dma_dir == DMA_BIDIRECTIONAL);
|
|
if (IS_ERR(vec)) {
|
|
ret = PTR_ERR(vec);
|
|
goto fail_pfnvec_create;
|
|
}
|
|
buf->vec = vec;
|
|
n_pages = frame_vector_count(vec);
|
|
if (frame_vector_to_pages(vec) < 0) {
|
|
unsigned long *nums = frame_vector_pfns(vec);
|
|
|
|
/*
|
|
* We cannot get page pointers for these pfns. Check memory is
|
|
* physically contiguous and use direct mapping.
|
|
*/
|
|
for (i = 1; i < n_pages; i++)
|
|
if (nums[i-1] + 1 != nums[i])
|
|
goto fail_map;
|
|
buf->vaddr = (__force void *)
|
|
ioremap(__pfn_to_phys(nums[0]), size + offset);
|
|
} else {
|
|
buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1);
|
|
}
|
|
|
|
if (!buf->vaddr)
|
|
goto fail_map;
|
|
buf->vaddr += offset;
|
|
return buf;
|
|
|
|
fail_map:
|
|
vb2_destroy_framevec(vec);
|
|
fail_pfnvec_create:
|
|
kfree(buf);
|
|
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
static void vb2_vmalloc_put_userptr(void *buf_priv)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = buf_priv;
|
|
unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
|
|
unsigned int i;
|
|
struct page **pages;
|
|
unsigned int n_pages;
|
|
|
|
if (!buf->vec->is_pfns) {
|
|
n_pages = frame_vector_count(buf->vec);
|
|
pages = frame_vector_pages(buf->vec);
|
|
if (vaddr)
|
|
vm_unmap_ram((void *)vaddr, n_pages);
|
|
if (buf->dma_dir == DMA_FROM_DEVICE ||
|
|
buf->dma_dir == DMA_BIDIRECTIONAL)
|
|
for (i = 0; i < n_pages; i++)
|
|
set_page_dirty_lock(pages[i]);
|
|
} else {
|
|
iounmap((__force void __iomem *)buf->vaddr);
|
|
}
|
|
vb2_destroy_framevec(buf->vec);
|
|
kfree(buf);
|
|
}
|
|
|
|
static void *vb2_vmalloc_vaddr(struct vb2_buffer *vb, void *buf_priv)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = buf_priv;
|
|
|
|
if (!buf->vaddr) {
|
|
pr_err("Address of an unallocated plane requested or cannot map user pointer\n");
|
|
return NULL;
|
|
}
|
|
|
|
return buf->vaddr;
|
|
}
|
|
|
|
static unsigned int vb2_vmalloc_num_users(void *buf_priv)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = buf_priv;
|
|
return refcount_read(&buf->refcount);
|
|
}
|
|
|
|
static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = buf_priv;
|
|
int ret;
|
|
|
|
if (!buf) {
|
|
pr_err("No memory to map\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = remap_vmalloc_range(vma, buf->vaddr, 0);
|
|
if (ret) {
|
|
pr_err("Remapping vmalloc memory, error: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Make sure that vm_areas for 2 buffers won't be merged together
|
|
*/
|
|
vma->vm_flags |= VM_DONTEXPAND;
|
|
|
|
/*
|
|
* Use common vm_area operations to track buffer refcount.
|
|
*/
|
|
vma->vm_private_data = &buf->handler;
|
|
vma->vm_ops = &vb2_common_vm_ops;
|
|
|
|
vma->vm_ops->open(vma);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_HAS_DMA
|
|
/*********************************************/
|
|
/* DMABUF ops for exporters */
|
|
/*********************************************/
|
|
|
|
struct vb2_vmalloc_attachment {
|
|
struct sg_table sgt;
|
|
enum dma_data_direction dma_dir;
|
|
};
|
|
|
|
static int vb2_vmalloc_dmabuf_ops_attach(struct dma_buf *dbuf,
|
|
struct dma_buf_attachment *dbuf_attach)
|
|
{
|
|
struct vb2_vmalloc_attachment *attach;
|
|
struct vb2_vmalloc_buf *buf = dbuf->priv;
|
|
int num_pages = PAGE_ALIGN(buf->size) / PAGE_SIZE;
|
|
struct sg_table *sgt;
|
|
struct scatterlist *sg;
|
|
void *vaddr = buf->vaddr;
|
|
int ret;
|
|
int i;
|
|
|
|
attach = kzalloc(sizeof(*attach), GFP_KERNEL);
|
|
if (!attach)
|
|
return -ENOMEM;
|
|
|
|
sgt = &attach->sgt;
|
|
ret = sg_alloc_table(sgt, num_pages, GFP_KERNEL);
|
|
if (ret) {
|
|
kfree(attach);
|
|
return ret;
|
|
}
|
|
for_each_sgtable_sg(sgt, sg, i) {
|
|
struct page *page = vmalloc_to_page(vaddr);
|
|
|
|
if (!page) {
|
|
sg_free_table(sgt);
|
|
kfree(attach);
|
|
return -ENOMEM;
|
|
}
|
|
sg_set_page(sg, page, PAGE_SIZE, 0);
|
|
vaddr += PAGE_SIZE;
|
|
}
|
|
|
|
attach->dma_dir = DMA_NONE;
|
|
dbuf_attach->priv = attach;
|
|
return 0;
|
|
}
|
|
|
|
static void vb2_vmalloc_dmabuf_ops_detach(struct dma_buf *dbuf,
|
|
struct dma_buf_attachment *db_attach)
|
|
{
|
|
struct vb2_vmalloc_attachment *attach = db_attach->priv;
|
|
struct sg_table *sgt;
|
|
|
|
if (!attach)
|
|
return;
|
|
|
|
sgt = &attach->sgt;
|
|
|
|
/* release the scatterlist cache */
|
|
if (attach->dma_dir != DMA_NONE)
|
|
dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0);
|
|
sg_free_table(sgt);
|
|
kfree(attach);
|
|
db_attach->priv = NULL;
|
|
}
|
|
|
|
static struct sg_table *vb2_vmalloc_dmabuf_ops_map(
|
|
struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
|
|
{
|
|
struct vb2_vmalloc_attachment *attach = db_attach->priv;
|
|
struct sg_table *sgt;
|
|
|
|
sgt = &attach->sgt;
|
|
/* return previously mapped sg table */
|
|
if (attach->dma_dir == dma_dir)
|
|
return sgt;
|
|
|
|
/* release any previous cache */
|
|
if (attach->dma_dir != DMA_NONE) {
|
|
dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0);
|
|
attach->dma_dir = DMA_NONE;
|
|
}
|
|
|
|
/* mapping to the client with new direction */
|
|
if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) {
|
|
pr_err("failed to map scatterlist\n");
|
|
return ERR_PTR(-EIO);
|
|
}
|
|
|
|
attach->dma_dir = dma_dir;
|
|
|
|
return sgt;
|
|
}
|
|
|
|
static void vb2_vmalloc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach,
|
|
struct sg_table *sgt, enum dma_data_direction dma_dir)
|
|
{
|
|
/* nothing to be done here */
|
|
}
|
|
|
|
static void vb2_vmalloc_dmabuf_ops_release(struct dma_buf *dbuf)
|
|
{
|
|
/* drop reference obtained in vb2_vmalloc_get_dmabuf */
|
|
vb2_vmalloc_put(dbuf->priv);
|
|
}
|
|
|
|
static int vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf,
|
|
struct iosys_map *map)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = dbuf->priv;
|
|
|
|
iosys_map_set_vaddr(map, buf->vaddr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf,
|
|
struct vm_area_struct *vma)
|
|
{
|
|
dma_resv_assert_held(dbuf->resv);
|
|
|
|
return vb2_vmalloc_mmap(dbuf->priv, vma);
|
|
}
|
|
|
|
static const struct dma_buf_ops vb2_vmalloc_dmabuf_ops = {
|
|
.attach = vb2_vmalloc_dmabuf_ops_attach,
|
|
.detach = vb2_vmalloc_dmabuf_ops_detach,
|
|
.map_dma_buf = vb2_vmalloc_dmabuf_ops_map,
|
|
.unmap_dma_buf = vb2_vmalloc_dmabuf_ops_unmap,
|
|
.vmap = vb2_vmalloc_dmabuf_ops_vmap,
|
|
.mmap = vb2_vmalloc_dmabuf_ops_mmap,
|
|
.release = vb2_vmalloc_dmabuf_ops_release,
|
|
};
|
|
|
|
static struct dma_buf *vb2_vmalloc_get_dmabuf(struct vb2_buffer *vb,
|
|
void *buf_priv,
|
|
unsigned long flags)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = buf_priv;
|
|
struct dma_buf *dbuf;
|
|
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
|
|
|
exp_info.ops = &vb2_vmalloc_dmabuf_ops;
|
|
exp_info.size = buf->size;
|
|
exp_info.flags = flags;
|
|
exp_info.priv = buf;
|
|
|
|
if (WARN_ON(!buf->vaddr))
|
|
return NULL;
|
|
|
|
dbuf = dma_buf_export(&exp_info);
|
|
if (IS_ERR(dbuf))
|
|
return NULL;
|
|
|
|
/* dmabuf keeps reference to vb2 buffer */
|
|
refcount_inc(&buf->refcount);
|
|
|
|
return dbuf;
|
|
}
|
|
#endif /* CONFIG_HAS_DMA */
|
|
|
|
|
|
/*********************************************/
|
|
/* callbacks for DMABUF buffers */
|
|
/*********************************************/
|
|
|
|
static int vb2_vmalloc_map_dmabuf(void *mem_priv)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = mem_priv;
|
|
struct iosys_map map;
|
|
int ret;
|
|
|
|
ret = dma_buf_vmap_unlocked(buf->dbuf, &map);
|
|
if (ret)
|
|
return -EFAULT;
|
|
buf->vaddr = map.vaddr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void vb2_vmalloc_unmap_dmabuf(void *mem_priv)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = mem_priv;
|
|
struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
|
|
|
|
dma_buf_vunmap_unlocked(buf->dbuf, &map);
|
|
buf->vaddr = NULL;
|
|
}
|
|
|
|
static void vb2_vmalloc_detach_dmabuf(void *mem_priv)
|
|
{
|
|
struct vb2_vmalloc_buf *buf = mem_priv;
|
|
struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr);
|
|
|
|
if (buf->vaddr)
|
|
dma_buf_vunmap_unlocked(buf->dbuf, &map);
|
|
|
|
kfree(buf);
|
|
}
|
|
|
|
static void *vb2_vmalloc_attach_dmabuf(struct vb2_buffer *vb,
|
|
struct device *dev,
|
|
struct dma_buf *dbuf,
|
|
unsigned long size)
|
|
{
|
|
struct vb2_vmalloc_buf *buf;
|
|
|
|
if (dbuf->size < size)
|
|
return ERR_PTR(-EFAULT);
|
|
|
|
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
|
|
if (!buf)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
buf->dbuf = dbuf;
|
|
buf->dma_dir = vb->vb2_queue->dma_dir;
|
|
buf->size = size;
|
|
|
|
return buf;
|
|
}
|
|
|
|
|
|
const struct vb2_mem_ops vb2_vmalloc_memops = {
|
|
.alloc = vb2_vmalloc_alloc,
|
|
.put = vb2_vmalloc_put,
|
|
.get_userptr = vb2_vmalloc_get_userptr,
|
|
.put_userptr = vb2_vmalloc_put_userptr,
|
|
#ifdef CONFIG_HAS_DMA
|
|
.get_dmabuf = vb2_vmalloc_get_dmabuf,
|
|
#endif
|
|
.map_dmabuf = vb2_vmalloc_map_dmabuf,
|
|
.unmap_dmabuf = vb2_vmalloc_unmap_dmabuf,
|
|
.attach_dmabuf = vb2_vmalloc_attach_dmabuf,
|
|
.detach_dmabuf = vb2_vmalloc_detach_dmabuf,
|
|
.vaddr = vb2_vmalloc_vaddr,
|
|
.mmap = vb2_vmalloc_mmap,
|
|
.num_users = vb2_vmalloc_num_users,
|
|
};
|
|
EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
|
|
|
|
MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
|
|
MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_IMPORT_NS(DMA_BUF);
|