1 /* 2 * Copyright 2011 Red Hat, Inc. 3 * Copyright © 2014 The Chromium OS Authors 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software") 7 * to deal in the software without restriction, including without limitation 8 * on the rights to use, copy, modify, merge, publish, distribute, sub 9 * license, and/or sell copies of the Software, and to permit persons to whom 10 * them Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER 20 * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Adam Jackson <ajax@redhat.com> 25 * Ben Widawsky <ben@bwidawsk.net> 26 */ 27 28 /** 29 * This is vgem, a (non-hardware-backed) GEM service. This is used by Mesa's 30 * software renderer and the X server for efficient buffer sharing. 31 */ 32 33 #include <linux/module.h> 34 #include <linux/ramfs.h> 35 #include <linux/shmem_fs.h> 36 #include <linux/dma-buf.h> 37 #include "vgem_drv.h" 38 39 #define DRIVER_NAME "vgem" 40 #define DRIVER_DESC "Virtual GEM provider" 41 #define DRIVER_DATE "20120112" 42 #define DRIVER_MAJOR 1 43 #define DRIVER_MINOR 0 44 45 static void vgem_gem_free_object(struct drm_gem_object *obj) 46 { 47 struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj); 48 49 drm_gem_object_release(obj); 50 kfree(vgem_obj); 51 } 52 53 static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 54 { 55 struct drm_vgem_gem_object *obj = vma->vm_private_data; 56 /* We don't use vmf->pgoff since that has the fake offset */ 57 unsigned long vaddr = (unsigned long)vmf->virtual_address; 58 struct page *page; 59 60 page = shmem_read_mapping_page(file_inode(obj->base.filp)->i_mapping, 61 (vaddr - vma->vm_start) >> PAGE_SHIFT); 62 if (!IS_ERR(page)) { 63 vmf->page = page; 64 return 0; 65 } else switch (PTR_ERR(page)) { 66 case -ENOSPC: 67 case -ENOMEM: 68 return VM_FAULT_OOM; 69 case -EBUSY: 70 return VM_FAULT_RETRY; 71 case -EFAULT: 72 case -EINVAL: 73 return VM_FAULT_SIGBUS; 74 default: 75 WARN_ON_ONCE(PTR_ERR(page)); 76 return VM_FAULT_SIGBUS; 77 } 78 } 79 80 static const struct vm_operations_struct vgem_gem_vm_ops = { 81 .fault = vgem_gem_fault, 82 .open = drm_gem_vm_open, 83 .close = drm_gem_vm_close, 84 }; 85 86 static int vgem_open(struct drm_device *dev, struct drm_file *file) 87 { 88 struct vgem_file *vfile; 89 int ret; 90 91 vfile = kzalloc(sizeof(*vfile), GFP_KERNEL); 92 if (!vfile) 93 return -ENOMEM; 94 95 file->driver_priv = vfile; 96 97 ret = vgem_fence_open(vfile); 98 if (ret) { 99 kfree(vfile); 100 return ret; 101 } 102 103 return 0; 104 } 105 106 static void vgem_preclose(struct drm_device *dev, struct drm_file *file) 107 { 108 struct vgem_file *vfile = file->driver_priv; 109 110 vgem_fence_close(vfile); 111 kfree(vfile); 112 } 113 114 /* ioctls */ 115 116 static struct drm_gem_object *vgem_gem_create(struct drm_device *dev, 117 struct drm_file *file, 118 unsigned int *handle, 119 unsigned long size) 120 { 121 struct drm_vgem_gem_object *obj; 122 int ret; 123 124 obj = kzalloc(sizeof(*obj), GFP_KERNEL); 125 if (!obj) 126 return ERR_PTR(-ENOMEM); 127 128 ret = drm_gem_object_init(dev, &obj->base, roundup(size, PAGE_SIZE)); 129 if (ret) 130 goto err_free; 131 132 ret = drm_gem_handle_create(file, &obj->base, handle); 133 drm_gem_object_unreference_unlocked(&obj->base); 134 if (ret) 135 goto err; 136 137 return &obj->base; 138 139 err_free: 140 kfree(obj); 141 err: 142 return ERR_PTR(ret); 143 } 144 145 static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev, 146 struct drm_mode_create_dumb *args) 147 { 148 struct drm_gem_object *gem_object; 149 u64 pitch, size; 150 151 pitch = args->width * DIV_ROUND_UP(args->bpp, 8); 152 size = args->height * pitch; 153 if (size == 0) 154 return -EINVAL; 155 156 gem_object = vgem_gem_create(dev, file, &args->handle, size); 157 if (IS_ERR(gem_object)) 158 return PTR_ERR(gem_object); 159 160 args->size = gem_object->size; 161 args->pitch = pitch; 162 163 DRM_DEBUG_DRIVER("Created object of size %lld\n", size); 164 165 return 0; 166 } 167 168 static int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev, 169 uint32_t handle, uint64_t *offset) 170 { 171 struct drm_gem_object *obj; 172 int ret; 173 174 obj = drm_gem_object_lookup(file, handle); 175 if (!obj) 176 return -ENOENT; 177 178 if (!obj->filp) { 179 ret = -EINVAL; 180 goto unref; 181 } 182 183 ret = drm_gem_create_mmap_offset(obj); 184 if (ret) 185 goto unref; 186 187 *offset = drm_vma_node_offset_addr(&obj->vma_node); 188 unref: 189 drm_gem_object_unreference_unlocked(obj); 190 191 return ret; 192 } 193 194 static struct drm_ioctl_desc vgem_ioctls[] = { 195 DRM_IOCTL_DEF_DRV(VGEM_FENCE_ATTACH, vgem_fence_attach_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), 196 DRM_IOCTL_DEF_DRV(VGEM_FENCE_SIGNAL, vgem_fence_signal_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), 197 }; 198 199 static int vgem_mmap(struct file *filp, struct vm_area_struct *vma) 200 { 201 unsigned long flags = vma->vm_flags; 202 int ret; 203 204 ret = drm_gem_mmap(filp, vma); 205 if (ret) 206 return ret; 207 208 /* Keep the WC mmaping set by drm_gem_mmap() but our pages 209 * are ordinary and not special. 210 */ 211 vma->vm_flags = flags | VM_DONTEXPAND | VM_DONTDUMP; 212 return 0; 213 } 214 215 static const struct file_operations vgem_driver_fops = { 216 .owner = THIS_MODULE, 217 .open = drm_open, 218 .mmap = vgem_mmap, 219 .poll = drm_poll, 220 .read = drm_read, 221 .unlocked_ioctl = drm_ioctl, 222 .release = drm_release, 223 }; 224 225 static int vgem_prime_pin(struct drm_gem_object *obj) 226 { 227 long n_pages = obj->size >> PAGE_SHIFT; 228 struct page **pages; 229 230 /* Flush the object from the CPU cache so that importers can rely 231 * on coherent indirect access via the exported dma-address. 232 */ 233 pages = drm_gem_get_pages(obj); 234 if (IS_ERR(pages)) 235 return PTR_ERR(pages); 236 237 drm_clflush_pages(pages, n_pages); 238 drm_gem_put_pages(obj, pages, true, false); 239 240 return 0; 241 } 242 243 static struct sg_table *vgem_prime_get_sg_table(struct drm_gem_object *obj) 244 { 245 struct sg_table *st; 246 struct page **pages; 247 248 pages = drm_gem_get_pages(obj); 249 if (IS_ERR(pages)) 250 return ERR_CAST(pages); 251 252 st = drm_prime_pages_to_sg(pages, obj->size >> PAGE_SHIFT); 253 drm_gem_put_pages(obj, pages, false, false); 254 255 return st; 256 } 257 258 static void *vgem_prime_vmap(struct drm_gem_object *obj) 259 { 260 long n_pages = obj->size >> PAGE_SHIFT; 261 struct page **pages; 262 void *addr; 263 264 pages = drm_gem_get_pages(obj); 265 if (IS_ERR(pages)) 266 return NULL; 267 268 addr = vmap(pages, n_pages, 0, pgprot_writecombine(PAGE_KERNEL)); 269 drm_gem_put_pages(obj, pages, false, false); 270 271 return addr; 272 } 273 274 static void vgem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) 275 { 276 vunmap(vaddr); 277 } 278 279 static int vgem_prime_mmap(struct drm_gem_object *obj, 280 struct vm_area_struct *vma) 281 { 282 int ret; 283 284 if (obj->size < vma->vm_end - vma->vm_start) 285 return -EINVAL; 286 287 if (!obj->filp) 288 return -ENODEV; 289 290 ret = obj->filp->f_op->mmap(obj->filp, vma); 291 if (ret) 292 return ret; 293 294 fput(vma->vm_file); 295 vma->vm_file = get_file(obj->filp); 296 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; 297 vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 298 299 return 0; 300 } 301 302 static struct drm_driver vgem_driver = { 303 .driver_features = DRIVER_GEM | DRIVER_PRIME, 304 .open = vgem_open, 305 .preclose = vgem_preclose, 306 .gem_free_object_unlocked = vgem_gem_free_object, 307 .gem_vm_ops = &vgem_gem_vm_ops, 308 .ioctls = vgem_ioctls, 309 .num_ioctls = ARRAY_SIZE(vgem_ioctls), 310 .fops = &vgem_driver_fops, 311 312 .dumb_create = vgem_gem_dumb_create, 313 .dumb_map_offset = vgem_gem_dumb_map, 314 315 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 316 .gem_prime_pin = vgem_prime_pin, 317 .gem_prime_export = drm_gem_prime_export, 318 .gem_prime_get_sg_table = vgem_prime_get_sg_table, 319 .gem_prime_vmap = vgem_prime_vmap, 320 .gem_prime_vunmap = vgem_prime_vunmap, 321 .gem_prime_mmap = vgem_prime_mmap, 322 323 .name = DRIVER_NAME, 324 .desc = DRIVER_DESC, 325 .date = DRIVER_DATE, 326 .major = DRIVER_MAJOR, 327 .minor = DRIVER_MINOR, 328 }; 329 330 static struct drm_device *vgem_device; 331 332 static int __init vgem_init(void) 333 { 334 int ret; 335 336 vgem_device = drm_dev_alloc(&vgem_driver, NULL); 337 if (!vgem_device) { 338 ret = -ENOMEM; 339 goto out; 340 } 341 342 ret = drm_dev_register(vgem_device, 0); 343 if (ret) 344 goto out_unref; 345 346 return 0; 347 348 out_unref: 349 drm_dev_unref(vgem_device); 350 out: 351 return ret; 352 } 353 354 static void __exit vgem_exit(void) 355 { 356 drm_dev_unregister(vgem_device); 357 drm_dev_unref(vgem_device); 358 } 359 360 module_init(vgem_init); 361 module_exit(vgem_exit); 362 363 MODULE_AUTHOR("Red Hat, Inc."); 364 MODULE_AUTHOR("Intel Corporation"); 365 MODULE_DESCRIPTION(DRIVER_DESC); 366 MODULE_LICENSE("GPL and additional rights"); 367