summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/vgem/vgem_drv.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-05-18 12:57:06 +1000
committerDave Airlie <airlied@redhat.com>2017-05-18 12:57:06 +1000
commite98c58e55f68f8785aebfab1f8c9a03d8de0afe1 (patch)
tree8357e8fda6efb0867ac39fc6b9211a579721d00a /drivers/gpu/drm/vgem/vgem_drv.c
parent2ea659a9ef488125eb46da6eb571de5eae5c43f6 (diff)
parent9cf8f5802f39d9991158b29033c852bccfc3a4d4 (diff)
Merge tag 'drm-misc-next-2017-05-16' of git://anongit.freedesktop.org/git/drm-misc into drm-next
UAPI Changes: - Return -ENODEV instead of -ENXIO when creating cma fb w/o valid gem (Daniel) - Add aspect ratio and custom scaling propertis to connector state (Maarten) Cross-subsystem Changes: - None Core Changes: - Add Laurent as bridge reviewer and Andrzej as bridge maintainer (Archit) - Maintain new STM driver through -misc (Yannick) - Misc doc improvements (as is tradition) (Daniel) - Add driver-private objects to atomic state (Dhinakaran) - Deprecate preclose hook in modern drivers (use postclose) (Daniel) - Add hwmode to vblank struct. This fixes mode access in irq context and reduced a bunch of boilerplate (Daniel) Driver Changes: - vc4: Add out-fence support to vc4 V3D rendering (Eric) - stm: Add stm32f429 display hw and am-480272h3tmqw-t01h panel support (Yannick) - vc4: Remove 256MB cma limit from vc4 (Eric) - dw-hdmi: Disable audio when inactive, instead of always enabled (Romain) - zte: Add support for VGA to the ZTE driver (Shawn) - i915: Track DP MST bandwidth and check it in atomic_check (Dhinakaran) - vgem: Enable gem dmabuf import iface to facilitate ion testing (Laura) - vc4: Add support for Cygnus (new dt compat string + couple bug fixes) (Eric) - pl111: Add driver for pl111 CLCD display controller (Eric/Tom) - vgem: Subclass drm_device instead of standalone platform device (Chris) Cc: Archit Taneja <architt@codeaurora.org> Cc: Eric Anholt <eric@anholt.net> Cc: Yannick Fertre <yannick.fertre@st.com> Cc: Romain Perier <romain.perier@collabora.com> Cc: Navare, Manasi D <manasi.d.navare@intel.com> Cc: Shawn Guo <shawn.guo@linaro.org> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Laura Abbott <labbott@redhat.com> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Tom Cooksey <tom.cooksey@arm.com> Cc: Daniel Vetter <daniel.vetter@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> * tag 'drm-misc-next-2017-05-16' of git://anongit.freedesktop.org/git/drm-misc: (72 commits) drm: add missing declaration to drm_blend.h drm/dp: Wait up all outstanding tx waiters drm/dp: Read the tx msg state once after checking for an event drm/prime: Forward declare struct device drm/vblank: Lock down vblank->hwmode more drm/vblank: drop the mode argument from drm_calc_vbltimestamp_from_scanoutpos drm/vblank: Add FIXME comments about moving the vblank ts hooks drm/vblank: Switch to bool in_vblank_irq in get_vblank_timestamp drm/vblank: Switch drm_driver->get_vblank_timestamp to return a bool drm/vgem: Convert to a struct drm_device subclass gpu: drm: gma500: remove dead code drm/sti: Adjust two checks for null pointers in sti_hqvdp_probe() drm/sti: Fix typos in a comment line drm/sti: Fix a typo in a comment line drm/sti: Replace 17 seq_puts() calls by seq_putc() drm/sti: Reduce function calls for sequence output at five places drm/sti: use seq_puts to display a string drm: Nerf the preclose callback for modern drivers drm/exynos: Merge pre/postclose hooks drm/tegra: switch to postclose ...
Diffstat (limited to 'drivers/gpu/drm/vgem/vgem_drv.c')
-rw-r--r--drivers/gpu/drm/vgem/vgem_drv.c194
1 files changed, 152 insertions, 42 deletions
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
index 9fee38a942c4..4b23ba049632 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.c
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
@@ -42,10 +42,20 @@
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
+static struct vgem_device {
+ struct drm_device drm;
+ struct platform_device *platform;
+} *vgem_device;
+
static void vgem_gem_free_object(struct drm_gem_object *obj)
{
struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj);
+ drm_free_large(vgem_obj->pages);
+
+ if (obj->import_attach)
+ drm_prime_gem_destroy(obj, vgem_obj->table);
+
drm_gem_object_release(obj);
kfree(vgem_obj);
}
@@ -56,26 +66,49 @@ static int vgem_gem_fault(struct vm_fault *vmf)
struct drm_vgem_gem_object *obj = vma->vm_private_data;
/* We don't use vmf->pgoff since that has the fake offset */
unsigned long vaddr = vmf->address;
- struct page *page;
-
- page = shmem_read_mapping_page(file_inode(obj->base.filp)->i_mapping,
- (vaddr - vma->vm_start) >> PAGE_SHIFT);
- if (!IS_ERR(page)) {
- vmf->page = page;
- return 0;
- } else switch (PTR_ERR(page)) {
- case -ENOSPC:
- case -ENOMEM:
- return VM_FAULT_OOM;
- case -EBUSY:
- return VM_FAULT_RETRY;
- case -EFAULT:
- case -EINVAL:
- return VM_FAULT_SIGBUS;
- default:
- WARN_ON_ONCE(PTR_ERR(page));
- return VM_FAULT_SIGBUS;
+ int ret;
+ loff_t num_pages;
+ pgoff_t page_offset;
+ page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT;
+
+ num_pages = DIV_ROUND_UP(obj->base.size, PAGE_SIZE);
+
+ if (page_offset > num_pages)
+ return VM_FAULT_SIGBUS;
+
+ if (obj->pages) {
+ get_page(obj->pages[page_offset]);
+ vmf->page = obj->pages[page_offset];
+ ret = 0;
+ } else {
+ struct page *page;
+
+ page = shmem_read_mapping_page(
+ file_inode(obj->base.filp)->i_mapping,
+ page_offset);
+ if (!IS_ERR(page)) {
+ vmf->page = page;
+ ret = 0;
+ } else switch (PTR_ERR(page)) {
+ case -ENOSPC:
+ case -ENOMEM:
+ ret = VM_FAULT_OOM;
+ break;
+ case -EBUSY:
+ ret = VM_FAULT_RETRY;
+ break;
+ case -EFAULT:
+ case -EINVAL:
+ ret = VM_FAULT_SIGBUS;
+ break;
+ default:
+ WARN_ON(PTR_ERR(page));
+ ret = VM_FAULT_SIGBUS;
+ break;
+ }
+
}
+ return ret;
}
static const struct vm_operations_struct vgem_gem_vm_ops = {
@@ -112,12 +145,8 @@ static void vgem_postclose(struct drm_device *dev, struct drm_file *file)
kfree(vfile);
}
-/* ioctls */
-
-static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
- struct drm_file *file,
- unsigned int *handle,
- unsigned long size)
+static struct drm_vgem_gem_object *__vgem_gem_create(struct drm_device *dev,
+ unsigned long size)
{
struct drm_vgem_gem_object *obj;
int ret;
@@ -127,8 +156,31 @@ static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
return ERR_PTR(-ENOMEM);
ret = drm_gem_object_init(dev, &obj->base, roundup(size, PAGE_SIZE));
- if (ret)
- goto err_free;
+ if (ret) {
+ kfree(obj);
+ return ERR_PTR(ret);
+ }
+
+ return obj;
+}
+
+static void __vgem_gem_destroy(struct drm_vgem_gem_object *obj)
+{
+ drm_gem_object_release(&obj->base);
+ kfree(obj);
+}
+
+static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
+ struct drm_file *file,
+ unsigned int *handle,
+ unsigned long size)
+{
+ struct drm_vgem_gem_object *obj;
+ int ret;
+
+ obj = __vgem_gem_create(dev, size);
+ if (IS_ERR(obj))
+ return ERR_CAST(obj);
ret = drm_gem_handle_create(file, &obj->base, handle);
drm_gem_object_unreference_unlocked(&obj->base);
@@ -137,9 +189,8 @@ static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
return &obj->base;
-err_free:
- kfree(obj);
err:
+ __vgem_gem_destroy(obj);
return ERR_PTR(ret);
}
@@ -256,6 +307,37 @@ static struct sg_table *vgem_prime_get_sg_table(struct drm_gem_object *obj)
return st;
}
+static struct drm_gem_object* vgem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct vgem_device *vgem = container_of(dev, typeof(*vgem), drm);
+
+ return drm_gem_prime_import_dev(dev, dma_buf, &vgem->platform->dev);
+}
+
+static struct drm_gem_object *vgem_prime_import_sg_table(struct drm_device *dev,
+ struct dma_buf_attachment *attach, struct sg_table *sg)
+{
+ struct drm_vgem_gem_object *obj;
+ int npages;
+
+ obj = __vgem_gem_create(dev, attach->dmabuf->size);
+ if (IS_ERR(obj))
+ return ERR_CAST(obj);
+
+ npages = PAGE_ALIGN(attach->dmabuf->size) / PAGE_SIZE;
+
+ obj->table = sg;
+ obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+ if (!obj->pages) {
+ __vgem_gem_destroy(obj);
+ return ERR_PTR(-ENOMEM);
+ }
+ drm_prime_sg_to_page_addr_arrays(obj->table, obj->pages, NULL,
+ npages);
+ return &obj->base;
+}
+
static void *vgem_prime_vmap(struct drm_gem_object *obj)
{
long n_pages = obj->size >> PAGE_SHIFT;
@@ -300,8 +382,19 @@ static int vgem_prime_mmap(struct drm_gem_object *obj,
return 0;
}
+static void vgem_release(struct drm_device *dev)
+{
+ struct vgem_device *vgem = container_of(dev, typeof(*vgem), drm);
+
+ platform_device_unregister(vgem->platform);
+ drm_dev_fini(&vgem->drm);
+
+ kfree(vgem);
+}
+
static struct drm_driver vgem_driver = {
.driver_features = DRIVER_GEM | DRIVER_PRIME,
+ .release = vgem_release,
.open = vgem_open,
.postclose = vgem_postclose,
.gem_free_object_unlocked = vgem_gem_free_object,
@@ -314,8 +407,11 @@ static struct drm_driver vgem_driver = {
.dumb_map_offset = vgem_gem_dumb_map,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_pin = vgem_prime_pin,
+ .gem_prime_import = vgem_prime_import,
.gem_prime_export = drm_gem_prime_export,
+ .gem_prime_import_sg_table = vgem_prime_import_sg_table,
.gem_prime_get_sg_table = vgem_prime_get_sg_table,
.gem_prime_vmap = vgem_prime_vmap,
.gem_prime_vunmap = vgem_prime_vunmap,
@@ -328,34 +424,48 @@ static struct drm_driver vgem_driver = {
.minor = DRIVER_MINOR,
};
-static struct drm_device *vgem_device;
-
static int __init vgem_init(void)
{
int ret;
- vgem_device = drm_dev_alloc(&vgem_driver, NULL);
- if (IS_ERR(vgem_device)) {
- ret = PTR_ERR(vgem_device);
- goto out;
+ vgem_device = kzalloc(sizeof(*vgem_device), GFP_KERNEL);
+ if (!vgem_device)
+ return -ENOMEM;
+
+ ret = drm_dev_init(&vgem_device->drm, &vgem_driver, NULL);
+ if (ret)
+ goto out_free;
+
+ vgem_device->platform =
+ platform_device_register_simple("vgem", -1, NULL, 0);
+ if (!vgem_device->platform) {
+ ret = -ENODEV;
+ goto out_fini;
}
- ret = drm_dev_register(vgem_device, 0);
+ dma_coerce_mask_and_coherent(&vgem_device->platform->dev,
+ DMA_BIT_MASK(64));
+
+ /* Final step: expose the device/driver to userspace */
+ ret = drm_dev_register(&vgem_device->drm, 0);
if (ret)
- goto out_unref;
+ goto out_unregister;
return 0;
-out_unref:
- drm_dev_unref(vgem_device);
-out:
+out_unregister:
+ platform_device_unregister(vgem_device->platform);
+out_fini:
+ drm_dev_fini(&vgem_device->drm);
+out_free:
+ kfree(vgem_device);
return ret;
}
static void __exit vgem_exit(void)
{
- drm_dev_unregister(vgem_device);
- drm_dev_unref(vgem_device);
+ drm_dev_unregister(&vgem_device->drm);
+ drm_dev_unref(&vgem_device->drm);
}
module_init(vgem_init);