162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2011 Red Hat, Inc. 362306a36Sopenharmony_ci * Copyright © 2014 The Chromium OS Authors 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 662306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software") 762306a36Sopenharmony_ci * to deal in the software without restriction, including without limitation 862306a36Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 962306a36Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 1062306a36Sopenharmony_ci * them Software is furnished to do so, subject to the following conditions: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next 1362306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 1462306a36Sopenharmony_ci * Software. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY, 1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1962306a36Sopenharmony_ci * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER 2062306a36Sopenharmony_ci * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN 2162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Authors: 2462306a36Sopenharmony_ci * Adam Jackson <ajax@redhat.com> 2562306a36Sopenharmony_ci * Ben Widawsky <ben@bwidawsk.net> 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * This is vgem, a (non-hardware-backed) GEM service. This is used by Mesa's 3062306a36Sopenharmony_ci * software renderer and the X server for efficient buffer sharing. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/dma-buf.h> 3462306a36Sopenharmony_ci#include <linux/module.h> 3562306a36Sopenharmony_ci#include <linux/platform_device.h> 3662306a36Sopenharmony_ci#include <linux/shmem_fs.h> 3762306a36Sopenharmony_ci#include <linux/vmalloc.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <drm/drm_drv.h> 4062306a36Sopenharmony_ci#include <drm/drm_file.h> 4162306a36Sopenharmony_ci#include <drm/drm_gem_shmem_helper.h> 4262306a36Sopenharmony_ci#include <drm/drm_ioctl.h> 4362306a36Sopenharmony_ci#include <drm/drm_managed.h> 4462306a36Sopenharmony_ci#include <drm/drm_prime.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include "vgem_drv.h" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define DRIVER_NAME "vgem" 4962306a36Sopenharmony_ci#define DRIVER_DESC "Virtual GEM provider" 5062306a36Sopenharmony_ci#define DRIVER_DATE "20120112" 5162306a36Sopenharmony_ci#define DRIVER_MAJOR 1 5262306a36Sopenharmony_ci#define DRIVER_MINOR 0 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic struct vgem_device { 5562306a36Sopenharmony_ci struct drm_device drm; 5662306a36Sopenharmony_ci struct platform_device *platform; 5762306a36Sopenharmony_ci} *vgem_device; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int vgem_open(struct drm_device *dev, struct drm_file *file) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct vgem_file *vfile; 6262306a36Sopenharmony_ci int ret; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci vfile = kzalloc(sizeof(*vfile), GFP_KERNEL); 6562306a36Sopenharmony_ci if (!vfile) 6662306a36Sopenharmony_ci return -ENOMEM; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci file->driver_priv = vfile; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci ret = vgem_fence_open(vfile); 7162306a36Sopenharmony_ci if (ret) { 7262306a36Sopenharmony_ci kfree(vfile); 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void vgem_postclose(struct drm_device *dev, struct drm_file *file) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct vgem_file *vfile = file->driver_priv; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci vgem_fence_close(vfile); 8462306a36Sopenharmony_ci kfree(vfile); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic struct drm_ioctl_desc vgem_ioctls[] = { 8862306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VGEM_FENCE_ATTACH, vgem_fence_attach_ioctl, DRM_RENDER_ALLOW), 8962306a36Sopenharmony_ci DRM_IOCTL_DEF_DRV(VGEM_FENCE_SIGNAL, vgem_fence_signal_ioctl, DRM_RENDER_ALLOW), 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciDEFINE_DRM_GEM_FOPS(vgem_driver_fops); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic struct drm_gem_object *vgem_gem_create_object(struct drm_device *dev, size_t size) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct drm_gem_shmem_object *obj; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci obj = kzalloc(sizeof(*obj), GFP_KERNEL); 9962306a36Sopenharmony_ci if (!obj) 10062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* 10362306a36Sopenharmony_ci * vgem doesn't have any begin/end cpu access ioctls, therefore must use 10462306a36Sopenharmony_ci * coherent memory or dma-buf sharing just wont work. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci obj->map_wc = true; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return &obj->base; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic const struct drm_driver vgem_driver = { 11262306a36Sopenharmony_ci .driver_features = DRIVER_GEM | DRIVER_RENDER, 11362306a36Sopenharmony_ci .open = vgem_open, 11462306a36Sopenharmony_ci .postclose = vgem_postclose, 11562306a36Sopenharmony_ci .ioctls = vgem_ioctls, 11662306a36Sopenharmony_ci .num_ioctls = ARRAY_SIZE(vgem_ioctls), 11762306a36Sopenharmony_ci .fops = &vgem_driver_fops, 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci DRM_GEM_SHMEM_DRIVER_OPS, 12062306a36Sopenharmony_ci .gem_create_object = vgem_gem_create_object, 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci .name = DRIVER_NAME, 12362306a36Sopenharmony_ci .desc = DRIVER_DESC, 12462306a36Sopenharmony_ci .date = DRIVER_DATE, 12562306a36Sopenharmony_ci .major = DRIVER_MAJOR, 12662306a36Sopenharmony_ci .minor = DRIVER_MINOR, 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int __init vgem_init(void) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci int ret; 13262306a36Sopenharmony_ci struct platform_device *pdev; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci pdev = platform_device_register_simple("vgem", -1, NULL, 0); 13562306a36Sopenharmony_ci if (IS_ERR(pdev)) 13662306a36Sopenharmony_ci return PTR_ERR(pdev); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { 13962306a36Sopenharmony_ci ret = -ENOMEM; 14062306a36Sopenharmony_ci goto out_unregister; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci dma_coerce_mask_and_coherent(&pdev->dev, 14462306a36Sopenharmony_ci DMA_BIT_MASK(64)); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci vgem_device = devm_drm_dev_alloc(&pdev->dev, &vgem_driver, 14762306a36Sopenharmony_ci struct vgem_device, drm); 14862306a36Sopenharmony_ci if (IS_ERR(vgem_device)) { 14962306a36Sopenharmony_ci ret = PTR_ERR(vgem_device); 15062306a36Sopenharmony_ci goto out_devres; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci vgem_device->platform = pdev; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Final step: expose the device/driver to userspace */ 15562306a36Sopenharmony_ci ret = drm_dev_register(&vgem_device->drm, 0); 15662306a36Sopenharmony_ci if (ret) 15762306a36Sopenharmony_ci goto out_devres; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciout_devres: 16262306a36Sopenharmony_ci devres_release_group(&pdev->dev, NULL); 16362306a36Sopenharmony_ciout_unregister: 16462306a36Sopenharmony_ci platform_device_unregister(pdev); 16562306a36Sopenharmony_ci return ret; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void __exit vgem_exit(void) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct platform_device *pdev = vgem_device->platform; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci drm_dev_unregister(&vgem_device->drm); 17362306a36Sopenharmony_ci devres_release_group(&pdev->dev, NULL); 17462306a36Sopenharmony_ci platform_device_unregister(pdev); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cimodule_init(vgem_init); 17862306a36Sopenharmony_cimodule_exit(vgem_exit); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc."); 18162306a36Sopenharmony_ciMODULE_AUTHOR("Intel Corporation"); 18262306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 18362306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 184