Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/gem: Add drm_gem_object_funcs

This adds an optional function table on GEM objects.
The main benefit is for drivers that support more than one type of
memory (shmem,vram,cma) for their buffers depending on the hardware it
runs on. With the callbacks attached to the GEM object itself, it is
easier to have core helpers for the the various buffer types. The driver
only has to make the decision about buffer type on GEM object creation
and all other callbacks can be handled by the chosen helper.

drm_driver->gem_prime_res_obj has not been added since there's a todo to
put a reservation_object into drm_gem_object.

v3: Add todo entry

v2: Drop drm_gem_object_funcs->prime_mmap in favour of
drm_gem_prime_mmap() (Daniel Vetter)

v1:
- drm_gem_object_funcs.map -> .prime_map let it only do PRIME mmap like
the function it superseeds (Daniel Vetter)
- Flip around the if ladders and make obj->funcs the first choice
highlighting the fact that this the new default way of doing it
(Daniel Vetter)

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Acked-by: Christian König <christian.koenig@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181110145647.17580-4-noralf@tronnes.org

+258 -34
+6
Documentation/gpu/todo.rst
··· 241 241 ->gem_prime_export now that drm_gem_prime_import() and drm_gem_prime_export() 242 242 are the default. 243 243 244 + struct drm_gem_object_funcs 245 + --------------------------- 246 + 247 + GEM objects can now have a function table instead of having the callbacks on the 248 + DRM driver struct. This is now the preferred way and drivers can be moved over. 249 + 244 250 Core refactorings 245 251 ================= 246 252
+5 -7
drivers/gpu/drm/drm_client.c
··· 81 81 { 82 82 int ret; 83 83 84 - if (!drm_core_check_feature(dev, DRIVER_MODESET) || 85 - !dev->driver->dumb_create || !dev->driver->gem_prime_vmap) 84 + if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create) 86 85 return -EOPNOTSUPP; 87 86 88 87 if (funcs && !try_module_get(funcs->owner)) ··· 228 229 { 229 230 struct drm_device *dev = buffer->client->dev; 230 231 231 - if (buffer->vaddr && dev->driver->gem_prime_vunmap) 232 - dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr); 232 + drm_gem_vunmap(buffer->gem, buffer->vaddr); 233 233 234 234 if (buffer->gem) 235 235 drm_gem_object_put_unlocked(buffer->gem); ··· 281 283 * fd_install step out of the driver backend hooks, to make that 282 284 * final step optional for internal users. 283 285 */ 284 - vaddr = dev->driver->gem_prime_vmap(obj); 285 - if (!vaddr) { 286 - ret = -ENOMEM; 286 + vaddr = drm_gem_vmap(obj); 287 + if (IS_ERR(vaddr)) { 288 + ret = PTR_ERR(vaddr); 287 289 goto err_delete; 288 290 } 289 291
+100 -9
drivers/gpu/drm/drm_gem.c
··· 257 257 struct drm_gem_object *obj = ptr; 258 258 struct drm_device *dev = obj->dev; 259 259 260 - if (dev->driver->gem_close_object) 260 + if (obj->funcs && obj->funcs->close) 261 + obj->funcs->close(obj, file_priv); 262 + else if (dev->driver->gem_close_object) 261 263 dev->driver->gem_close_object(obj, file_priv); 262 264 263 265 if (drm_core_check_feature(dev, DRIVER_PRIME)) ··· 412 410 if (ret) 413 411 goto err_remove; 414 412 415 - if (dev->driver->gem_open_object) { 413 + if (obj->funcs && obj->funcs->open) { 414 + ret = obj->funcs->open(obj, file_priv); 415 + if (ret) 416 + goto err_revoke; 417 + } else if (dev->driver->gem_open_object) { 416 418 ret = dev->driver->gem_open_object(obj, file_priv); 417 419 if (ret) 418 420 goto err_revoke; ··· 841 835 container_of(kref, struct drm_gem_object, refcount); 842 836 struct drm_device *dev = obj->dev; 843 837 844 - if (dev->driver->gem_free_object_unlocked) { 838 + if (obj->funcs) { 839 + obj->funcs->free(obj); 840 + } else if (dev->driver->gem_free_object_unlocked) { 845 841 dev->driver->gem_free_object_unlocked(obj); 846 842 } else if (dev->driver->gem_free_object) { 847 843 WARN_ON(!mutex_is_locked(&dev->struct_mutex)); ··· 872 864 873 865 dev = obj->dev; 874 866 875 - if (dev->driver->gem_free_object_unlocked) { 876 - kref_put(&obj->refcount, drm_gem_object_free); 877 - } else { 867 + if (dev->driver->gem_free_object) { 878 868 might_lock(&dev->struct_mutex); 879 869 if (kref_put_mutex(&obj->refcount, drm_gem_object_free, 880 870 &dev->struct_mutex)) 881 871 mutex_unlock(&dev->struct_mutex); 872 + } else { 873 + kref_put(&obj->refcount, drm_gem_object_free); 882 874 } 883 875 } 884 876 EXPORT_SYMBOL(drm_gem_object_put_unlocked); ··· 968 960 if (obj_size < vma->vm_end - vma->vm_start) 969 961 return -EINVAL; 970 962 971 - if (!dev->driver->gem_vm_ops) 963 + if (obj->funcs && obj->funcs->vm_ops) 964 + vma->vm_ops = obj->funcs->vm_ops; 965 + else if (dev->driver->gem_vm_ops) 966 + vma->vm_ops = dev->driver->gem_vm_ops; 967 + else 972 968 return -EINVAL; 973 969 974 970 vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; 975 - vma->vm_ops = dev->driver->gem_vm_ops; 976 971 vma->vm_private_data = obj; 977 972 vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 978 973 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); ··· 1077 1066 drm_printf_indent(p, indent, "imported=%s\n", 1078 1067 obj->import_attach ? "yes" : "no"); 1079 1068 1080 - if (obj->dev->driver->gem_print_info) 1069 + if (obj->funcs && obj->funcs->print_info) 1070 + obj->funcs->print_info(p, indent, obj); 1071 + else if (obj->dev->driver->gem_print_info) 1081 1072 obj->dev->driver->gem_print_info(p, indent, obj); 1082 1073 } 1074 + 1075 + /** 1076 + * drm_gem_pin - Pin backing buffer in memory 1077 + * @obj: GEM object 1078 + * 1079 + * Make sure the backing buffer is pinned in memory. 1080 + * 1081 + * Returns: 1082 + * 0 on success or a negative error code on failure. 1083 + */ 1084 + int drm_gem_pin(struct drm_gem_object *obj) 1085 + { 1086 + if (obj->funcs && obj->funcs->pin) 1087 + return obj->funcs->pin(obj); 1088 + else if (obj->dev->driver->gem_prime_pin) 1089 + return obj->dev->driver->gem_prime_pin(obj); 1090 + else 1091 + return 0; 1092 + } 1093 + EXPORT_SYMBOL(drm_gem_pin); 1094 + 1095 + /** 1096 + * drm_gem_unpin - Unpin backing buffer from memory 1097 + * @obj: GEM object 1098 + * 1099 + * Relax the requirement that the backing buffer is pinned in memory. 1100 + */ 1101 + void drm_gem_unpin(struct drm_gem_object *obj) 1102 + { 1103 + if (obj->funcs && obj->funcs->unpin) 1104 + obj->funcs->unpin(obj); 1105 + else if (obj->dev->driver->gem_prime_unpin) 1106 + obj->dev->driver->gem_prime_unpin(obj); 1107 + } 1108 + EXPORT_SYMBOL(drm_gem_unpin); 1109 + 1110 + /** 1111 + * drm_gem_vmap - Map buffer into kernel virtual address space 1112 + * @obj: GEM object 1113 + * 1114 + * Returns: 1115 + * A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative 1116 + * error code on failure. 1117 + */ 1118 + void *drm_gem_vmap(struct drm_gem_object *obj) 1119 + { 1120 + void *vaddr; 1121 + 1122 + if (obj->funcs && obj->funcs->vmap) 1123 + vaddr = obj->funcs->vmap(obj); 1124 + else if (obj->dev->driver->gem_prime_vmap) 1125 + vaddr = obj->dev->driver->gem_prime_vmap(obj); 1126 + else 1127 + vaddr = ERR_PTR(-EOPNOTSUPP); 1128 + 1129 + if (!vaddr) 1130 + vaddr = ERR_PTR(-ENOMEM); 1131 + 1132 + return vaddr; 1133 + } 1134 + EXPORT_SYMBOL(drm_gem_vmap); 1135 + 1136 + /** 1137 + * drm_gem_vunmap - Remove buffer mapping from kernel virtual address space 1138 + * @obj: GEM object 1139 + * @vaddr: Virtual address (can be NULL) 1140 + */ 1141 + void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr) 1142 + { 1143 + if (!vaddr) 1144 + return; 1145 + 1146 + if (obj->funcs && obj->funcs->vunmap) 1147 + obj->funcs->vunmap(obj, vaddr); 1148 + else if (obj->dev->driver->gem_prime_vunmap) 1149 + obj->dev->driver->gem_prime_vunmap(obj, vaddr); 1150 + } 1151 + EXPORT_SYMBOL(drm_gem_vunmap);
+16 -18
drivers/gpu/drm/drm_prime.c
··· 199 199 { 200 200 struct drm_prime_attachment *prime_attach; 201 201 struct drm_gem_object *obj = dma_buf->priv; 202 - struct drm_device *dev = obj->dev; 203 202 204 203 prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL); 205 204 if (!prime_attach) ··· 207 208 prime_attach->dir = DMA_NONE; 208 209 attach->priv = prime_attach; 209 210 210 - if (!dev->driver->gem_prime_pin) 211 - return 0; 212 - 213 - return dev->driver->gem_prime_pin(obj); 211 + return drm_gem_pin(obj); 214 212 } 215 213 EXPORT_SYMBOL(drm_gem_map_attach); 216 214 ··· 224 228 { 225 229 struct drm_prime_attachment *prime_attach = attach->priv; 226 230 struct drm_gem_object *obj = dma_buf->priv; 227 - struct drm_device *dev = obj->dev; 228 231 229 232 if (prime_attach) { 230 233 struct sg_table *sgt = prime_attach->sgt; ··· 242 247 attach->priv = NULL; 243 248 } 244 249 245 - if (dev->driver->gem_prime_unpin) 246 - dev->driver->gem_prime_unpin(obj); 250 + drm_gem_unpin(obj); 247 251 } 248 252 EXPORT_SYMBOL(drm_gem_map_detach); 249 253 ··· 304 310 if (WARN_ON(prime_attach->dir != DMA_NONE)) 305 311 return ERR_PTR(-EBUSY); 306 312 307 - sgt = obj->dev->driver->gem_prime_get_sg_table(obj); 313 + if (obj->funcs) 314 + sgt = obj->funcs->get_sg_table(obj); 315 + else 316 + sgt = obj->dev->driver->gem_prime_get_sg_table(obj); 308 317 309 318 if (!IS_ERR(sgt)) { 310 319 if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir, ··· 403 406 void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf) 404 407 { 405 408 struct drm_gem_object *obj = dma_buf->priv; 406 - struct drm_device *dev = obj->dev; 409 + void *vaddr; 407 410 408 - if (dev->driver->gem_prime_vmap) 409 - return dev->driver->gem_prime_vmap(obj); 410 - else 411 - return NULL; 411 + vaddr = drm_gem_vmap(obj); 412 + if (IS_ERR(vaddr)) 413 + vaddr = NULL; 414 + 415 + return vaddr; 412 416 } 413 417 EXPORT_SYMBOL(drm_gem_dmabuf_vmap); 414 418 ··· 424 426 void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) 425 427 { 426 428 struct drm_gem_object *obj = dma_buf->priv; 427 - struct drm_device *dev = obj->dev; 428 429 429 - if (dev->driver->gem_prime_vunmap) 430 - dev->driver->gem_prime_vunmap(obj, vaddr); 430 + drm_gem_vunmap(obj, vaddr); 431 431 } 432 432 EXPORT_SYMBOL(drm_gem_dmabuf_vunmap); 433 433 ··· 525 529 return dmabuf; 526 530 } 527 531 528 - if (dev->driver->gem_prime_export) 532 + if (obj->funcs && obj->funcs->export) 533 + dmabuf = obj->funcs->export(obj, flags); 534 + else if (dev->driver->gem_prime_export) 529 535 dmabuf = dev->driver->gem_prime_export(dev, obj, flags); 530 536 else 531 537 dmabuf = drm_gem_prime_export(dev, obj, flags);
+131
include/drm/drm_gem.h
··· 38 38 39 39 #include <drm/drm_vma_manager.h> 40 40 41 + struct drm_gem_object; 42 + 43 + /** 44 + * struct drm_gem_object_funcs - GEM object functions 45 + */ 46 + struct drm_gem_object_funcs { 47 + /** 48 + * @free: 49 + * 50 + * Deconstructor for drm_gem_objects. 51 + * 52 + * This callback is mandatory. 53 + */ 54 + void (*free)(struct drm_gem_object *obj); 55 + 56 + /** 57 + * @open: 58 + * 59 + * Called upon GEM handle creation. 60 + * 61 + * This callback is optional. 62 + */ 63 + int (*open)(struct drm_gem_object *obj, struct drm_file *file); 64 + 65 + /** 66 + * @close: 67 + * 68 + * Called upon GEM handle release. 69 + * 70 + * This callback is optional. 71 + */ 72 + void (*close)(struct drm_gem_object *obj, struct drm_file *file); 73 + 74 + /** 75 + * @print_info: 76 + * 77 + * If driver subclasses struct &drm_gem_object, it can implement this 78 + * optional hook for printing additional driver specific info. 79 + * 80 + * drm_printf_indent() should be used in the callback passing it the 81 + * indent argument. 82 + * 83 + * This callback is called from drm_gem_print_info(). 84 + * 85 + * This callback is optional. 86 + */ 87 + void (*print_info)(struct drm_printer *p, unsigned int indent, 88 + const struct drm_gem_object *obj); 89 + 90 + /** 91 + * @export: 92 + * 93 + * Export backing buffer as a &dma_buf. 94 + * If this is not set drm_gem_prime_export() is used. 95 + * 96 + * This callback is optional. 97 + */ 98 + struct dma_buf *(*export)(struct drm_gem_object *obj, int flags); 99 + 100 + /** 101 + * @pin: 102 + * 103 + * Pin backing buffer in memory. 104 + * 105 + * This callback is optional. 106 + */ 107 + int (*pin)(struct drm_gem_object *obj); 108 + 109 + /** 110 + * @unpin: 111 + * 112 + * Unpin backing buffer. 113 + * 114 + * This callback is optional. 115 + */ 116 + void (*unpin)(struct drm_gem_object *obj); 117 + 118 + /** 119 + * @get_sg_table: 120 + * 121 + * Returns a Scatter-Gather table representation of the buffer. 122 + * Used when exporting a buffer. 123 + * 124 + * This callback is mandatory if buffer export is supported. 125 + */ 126 + struct sg_table *(*get_sg_table)(struct drm_gem_object *obj); 127 + 128 + /** 129 + * @vmap: 130 + * 131 + * Returns a virtual address for the buffer. 132 + * 133 + * This callback is optional. 134 + */ 135 + void *(*vmap)(struct drm_gem_object *obj); 136 + 137 + /** 138 + * @vunmap: 139 + * 140 + * Releases the the address previously returned by @vmap. 141 + * 142 + * This callback is optional. 143 + */ 144 + void (*vunmap)(struct drm_gem_object *obj, void *vaddr); 145 + 146 + /** 147 + * @vm_ops: 148 + * 149 + * Virtual memory operations used with mmap. 150 + * 151 + * This is optional but necessary for mmap support. 152 + */ 153 + const struct vm_operations_struct *vm_ops; 154 + }; 155 + 41 156 /** 42 157 * struct drm_gem_object - GEM buffer object 43 158 * ··· 261 146 * simply leave it as NULL. 262 147 */ 263 148 struct dma_buf_attachment *import_attach; 149 + 150 + /** 151 + * @funcs: 152 + * 153 + * Optional GEM object functions. If this is set, it will be used instead of the 154 + * corresponding &drm_driver GEM callbacks. 155 + * 156 + * New drivers should use this. 157 + * 158 + */ 159 + const struct drm_gem_object_funcs *funcs; 264 160 }; 265 161 266 162 /** ··· 418 292 int drm_gem_dumb_destroy(struct drm_file *file, 419 293 struct drm_device *dev, 420 294 uint32_t handle); 295 + 296 + int drm_gem_pin(struct drm_gem_object *obj); 297 + void drm_gem_unpin(struct drm_gem_object *obj); 298 + void *drm_gem_vmap(struct drm_gem_object *obj); 299 + void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr); 421 300 422 301 #endif /* __DRM_GEM_H__ */