Commit | Line | Data |
---|---|---|
85438a8d TZ |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | ||
3 | #include <drm/drm_gem_vram_helper.h> | |
59f5989a | 4 | #include <drm/drm_device.h> |
fed1eec0 | 5 | #include <drm/drm_mode.h> |
1f460b49 | 6 | #include <drm/drm_prime.h> |
5c9dcacf | 7 | #include <drm/drm_vram_mm_helper.h> |
85438a8d TZ |
8 | #include <drm/ttm/ttm_page_alloc.h> |
9 | ||
31070a87 TZ |
10 | static const struct drm_gem_object_funcs drm_gem_vram_object_funcs; |
11 | ||
85438a8d TZ |
12 | /** |
13 | * DOC: overview | |
14 | * | |
15 | * This library provides a GEM buffer object that is backed by video RAM | |
16 | * (VRAM). It can be used for framebuffer devices with dedicated memory. | |
17 | */ | |
18 | ||
19 | /* | |
20 | * Buffer-objects helpers | |
21 | */ | |
22 | ||
23 | static void drm_gem_vram_cleanup(struct drm_gem_vram_object *gbo) | |
24 | { | |
25 | /* We got here via ttm_bo_put(), which means that the | |
26 | * TTM buffer object in 'bo' has already been cleaned | |
27 | * up; only release the GEM object. | |
28 | */ | |
37a48adf TZ |
29 | |
30 | WARN_ON(gbo->kmap_use_count); | |
31 | ||
0e580c6d | 32 | drm_gem_object_release(&gbo->bo.base); |
85438a8d TZ |
33 | } |
34 | ||
35 | static void drm_gem_vram_destroy(struct drm_gem_vram_object *gbo) | |
36 | { | |
37 | drm_gem_vram_cleanup(gbo); | |
38 | kfree(gbo); | |
39 | } | |
40 | ||
41 | static void ttm_buffer_object_destroy(struct ttm_buffer_object *bo) | |
42 | { | |
43 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_bo(bo); | |
44 | ||
45 | drm_gem_vram_destroy(gbo); | |
46 | } | |
47 | ||
48 | static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo, | |
49 | unsigned long pl_flag) | |
50 | { | |
51 | unsigned int i; | |
52 | unsigned int c = 0; | |
53 | ||
54 | gbo->placement.placement = gbo->placements; | |
55 | gbo->placement.busy_placement = gbo->placements; | |
56 | ||
57 | if (pl_flag & TTM_PL_FLAG_VRAM) | |
58 | gbo->placements[c++].flags = TTM_PL_FLAG_WC | | |
59 | TTM_PL_FLAG_UNCACHED | | |
60 | TTM_PL_FLAG_VRAM; | |
61 | ||
62 | if (pl_flag & TTM_PL_FLAG_SYSTEM) | |
63 | gbo->placements[c++].flags = TTM_PL_MASK_CACHING | | |
64 | TTM_PL_FLAG_SYSTEM; | |
65 | ||
66 | if (!c) | |
67 | gbo->placements[c++].flags = TTM_PL_MASK_CACHING | | |
68 | TTM_PL_FLAG_SYSTEM; | |
69 | ||
70 | gbo->placement.num_placement = c; | |
71 | gbo->placement.num_busy_placement = c; | |
72 | ||
73 | for (i = 0; i < c; ++i) { | |
74 | gbo->placements[i].fpfn = 0; | |
75 | gbo->placements[i].lpfn = 0; | |
76 | } | |
77 | } | |
78 | ||
79 | static int drm_gem_vram_init(struct drm_device *dev, | |
80 | struct ttm_bo_device *bdev, | |
81 | struct drm_gem_vram_object *gbo, | |
82 | size_t size, unsigned long pg_align, | |
83 | bool interruptible) | |
84 | { | |
85 | int ret; | |
86 | size_t acc_size; | |
87 | ||
0e580c6d GH |
88 | if (!gbo->bo.base.funcs) |
89 | gbo->bo.base.funcs = &drm_gem_vram_object_funcs; | |
31070a87 | 90 | |
0e580c6d | 91 | ret = drm_gem_object_init(dev, &gbo->bo.base, size); |
85438a8d TZ |
92 | if (ret) |
93 | return ret; | |
94 | ||
95 | acc_size = ttm_bo_dma_acc_size(bdev, size, sizeof(*gbo)); | |
96 | ||
97 | gbo->bo.bdev = bdev; | |
98 | drm_gem_vram_placement(gbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); | |
99 | ||
100 | ret = ttm_bo_init(bdev, &gbo->bo, size, ttm_bo_type_device, | |
101 | &gbo->placement, pg_align, interruptible, acc_size, | |
102 | NULL, NULL, ttm_buffer_object_destroy); | |
103 | if (ret) | |
104 | goto err_drm_gem_object_release; | |
105 | ||
106 | return 0; | |
107 | ||
108 | err_drm_gem_object_release: | |
0e580c6d | 109 | drm_gem_object_release(&gbo->bo.base); |
85438a8d TZ |
110 | return ret; |
111 | } | |
112 | ||
113 | /** | |
114 | * drm_gem_vram_create() - Creates a VRAM-backed GEM object | |
115 | * @dev: the DRM device | |
116 | * @bdev: the TTM BO device backing the object | |
117 | * @size: the buffer size in bytes | |
118 | * @pg_align: the buffer's alignment in multiples of the page size | |
119 | * @interruptible: sleep interruptible if waiting for memory | |
120 | * | |
121 | * Returns: | |
122 | * A new instance of &struct drm_gem_vram_object on success, or | |
123 | * an ERR_PTR()-encoded error code otherwise. | |
124 | */ | |
125 | struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, | |
126 | struct ttm_bo_device *bdev, | |
127 | size_t size, | |
128 | unsigned long pg_align, | |
129 | bool interruptible) | |
130 | { | |
131 | struct drm_gem_vram_object *gbo; | |
132 | int ret; | |
133 | ||
134 | gbo = kzalloc(sizeof(*gbo), GFP_KERNEL); | |
135 | if (!gbo) | |
136 | return ERR_PTR(-ENOMEM); | |
137 | ||
138 | ret = drm_gem_vram_init(dev, bdev, gbo, size, pg_align, interruptible); | |
139 | if (ret < 0) | |
140 | goto err_kfree; | |
141 | ||
142 | return gbo; | |
143 | ||
144 | err_kfree: | |
145 | kfree(gbo); | |
146 | return ERR_PTR(ret); | |
147 | } | |
148 | EXPORT_SYMBOL(drm_gem_vram_create); | |
149 | ||
150 | /** | |
151 | * drm_gem_vram_put() - Releases a reference to a VRAM-backed GEM object | |
152 | * @gbo: the GEM VRAM object | |
153 | * | |
154 | * See ttm_bo_put() for more information. | |
155 | */ | |
156 | void drm_gem_vram_put(struct drm_gem_vram_object *gbo) | |
157 | { | |
158 | ttm_bo_put(&gbo->bo); | |
159 | } | |
160 | EXPORT_SYMBOL(drm_gem_vram_put); | |
161 | ||
85438a8d TZ |
162 | /** |
163 | * drm_gem_vram_mmap_offset() - Returns a GEM VRAM object's mmap offset | |
164 | * @gbo: the GEM VRAM object | |
165 | * | |
166 | * See drm_vma_node_offset_addr() for more information. | |
167 | * | |
168 | * Returns: | |
169 | * The buffer object's offset for userspace mappings on success, or | |
170 | * 0 if no offset is allocated. | |
171 | */ | |
172 | u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo) | |
173 | { | |
b96f3e7c | 174 | return drm_vma_node_offset_addr(&gbo->bo.base.vma_node); |
85438a8d TZ |
175 | } |
176 | EXPORT_SYMBOL(drm_gem_vram_mmap_offset); | |
177 | ||
178 | /** | |
179 | * drm_gem_vram_offset() - \ | |
180 | Returns a GEM VRAM object's offset in video memory | |
181 | * @gbo: the GEM VRAM object | |
182 | * | |
183 | * This function returns the buffer object's offset in the device's video | |
184 | * memory. The buffer object has to be pinned to %TTM_PL_VRAM. | |
185 | * | |
186 | * Returns: | |
187 | * The buffer object's offset in video memory on success, or | |
188 | * a negative errno code otherwise. | |
189 | */ | |
190 | s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo) | |
191 | { | |
192 | if (WARN_ON_ONCE(!gbo->pin_count)) | |
193 | return (s64)-ENODEV; | |
194 | return gbo->bo.offset; | |
195 | } | |
196 | EXPORT_SYMBOL(drm_gem_vram_offset); | |
197 | ||
198 | /** | |
199 | * drm_gem_vram_pin() - Pins a GEM VRAM object in a region. | |
200 | * @gbo: the GEM VRAM object | |
201 | * @pl_flag: a bitmask of possible memory regions | |
202 | * | |
203 | * Pinning a buffer object ensures that it is not evicted from | |
204 | * a memory region. A pinned buffer object has to be unpinned before | |
a6c3464f TZ |
205 | * it can be pinned to another region. If the pl_flag argument is 0, |
206 | * the buffer is pinned at its current location (video RAM or system | |
207 | * memory). | |
85438a8d TZ |
208 | * |
209 | * Returns: | |
210 | * 0 on success, or | |
211 | * a negative error code otherwise. | |
212 | */ | |
213 | int drm_gem_vram_pin(struct drm_gem_vram_object *gbo, unsigned long pl_flag) | |
214 | { | |
215 | int i, ret; | |
216 | struct ttm_operation_ctx ctx = { false, false }; | |
217 | ||
5b24f715 TZ |
218 | ret = ttm_bo_reserve(&gbo->bo, true, false, NULL); |
219 | if (ret < 0) | |
220 | return ret; | |
221 | ||
222 | if (gbo->pin_count) | |
223 | goto out; | |
85438a8d | 224 | |
a6c3464f TZ |
225 | if (pl_flag) |
226 | drm_gem_vram_placement(gbo, pl_flag); | |
227 | ||
85438a8d TZ |
228 | for (i = 0; i < gbo->placement.num_placement; ++i) |
229 | gbo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; | |
230 | ||
231 | ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx); | |
232 | if (ret < 0) | |
5b24f715 | 233 | goto err_ttm_bo_unreserve; |
85438a8d | 234 | |
5b24f715 TZ |
235 | out: |
236 | ++gbo->pin_count; | |
237 | ttm_bo_unreserve(&gbo->bo); | |
85438a8d TZ |
238 | |
239 | return 0; | |
5b24f715 TZ |
240 | |
241 | err_ttm_bo_unreserve: | |
242 | ttm_bo_unreserve(&gbo->bo); | |
243 | return ret; | |
85438a8d TZ |
244 | } |
245 | EXPORT_SYMBOL(drm_gem_vram_pin); | |
246 | ||
247 | /** | |
248 | * drm_gem_vram_unpin() - Unpins a GEM VRAM object | |
249 | * @gbo: the GEM VRAM object | |
250 | * | |
251 | * Returns: | |
252 | * 0 on success, or | |
253 | * a negative error code otherwise. | |
254 | */ | |
255 | int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo) | |
256 | { | |
257 | int i, ret; | |
258 | struct ttm_operation_ctx ctx = { false, false }; | |
259 | ||
5b24f715 TZ |
260 | ret = ttm_bo_reserve(&gbo->bo, true, false, NULL); |
261 | if (ret < 0) | |
262 | return ret; | |
263 | ||
85438a8d | 264 | if (WARN_ON_ONCE(!gbo->pin_count)) |
5b24f715 | 265 | goto out; |
85438a8d TZ |
266 | |
267 | --gbo->pin_count; | |
268 | if (gbo->pin_count) | |
5b24f715 | 269 | goto out; |
85438a8d TZ |
270 | |
271 | for (i = 0; i < gbo->placement.num_placement ; ++i) | |
272 | gbo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; | |
273 | ||
274 | ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx); | |
275 | if (ret < 0) | |
5b24f715 TZ |
276 | goto err_ttm_bo_unreserve; |
277 | ||
278 | out: | |
279 | ttm_bo_unreserve(&gbo->bo); | |
85438a8d TZ |
280 | |
281 | return 0; | |
5b24f715 TZ |
282 | |
283 | err_ttm_bo_unreserve: | |
284 | ttm_bo_unreserve(&gbo->bo); | |
285 | return ret; | |
85438a8d TZ |
286 | } |
287 | EXPORT_SYMBOL(drm_gem_vram_unpin); | |
288 | ||
37a48adf TZ |
289 | static void *drm_gem_vram_kmap_locked(struct drm_gem_vram_object *gbo, |
290 | bool map, bool *is_iomem) | |
291 | { | |
292 | int ret; | |
293 | struct ttm_bo_kmap_obj *kmap = &gbo->kmap; | |
294 | ||
295 | if (gbo->kmap_use_count > 0) | |
296 | goto out; | |
297 | ||
298 | if (kmap->virtual || !map) | |
299 | goto out; | |
300 | ||
301 | ret = ttm_bo_kmap(&gbo->bo, 0, gbo->bo.num_pages, kmap); | |
302 | if (ret) | |
303 | return ERR_PTR(ret); | |
304 | ||
305 | out: | |
306 | if (!kmap->virtual) { | |
307 | if (is_iomem) | |
308 | *is_iomem = false; | |
309 | return NULL; /* not mapped; don't increment ref */ | |
310 | } | |
311 | ++gbo->kmap_use_count; | |
312 | if (is_iomem) | |
313 | return ttm_kmap_obj_virtual(kmap, is_iomem); | |
314 | return kmap->virtual; | |
315 | } | |
316 | ||
85438a8d | 317 | /** |
92172173 | 318 | * drm_gem_vram_kmap() - Maps a GEM VRAM object into kernel address space |
85438a8d TZ |
319 | * @gbo: the GEM VRAM object |
320 | * @map: establish a mapping if necessary | |
321 | * @is_iomem: returns true if the mapped memory is I/O memory, or false \ | |
322 | otherwise; can be NULL | |
85438a8d TZ |
323 | * |
324 | * This function maps the buffer object into the kernel's address space | |
325 | * or returns the current mapping. If the parameter map is false, the | |
326 | * function only queries the current mapping, but does not establish a | |
327 | * new one. | |
328 | * | |
329 | * Returns: | |
330 | * The buffers virtual address if mapped, or | |
331 | * NULL if not mapped, or | |
332 | * an ERR_PTR()-encoded error code otherwise. | |
333 | */ | |
92172173 TZ |
334 | void *drm_gem_vram_kmap(struct drm_gem_vram_object *gbo, bool map, |
335 | bool *is_iomem) | |
85438a8d TZ |
336 | { |
337 | int ret; | |
37a48adf | 338 | void *virtual; |
85438a8d | 339 | |
37a48adf | 340 | ret = ttm_bo_reserve(&gbo->bo, true, false, NULL); |
85438a8d TZ |
341 | if (ret) |
342 | return ERR_PTR(ret); | |
37a48adf TZ |
343 | virtual = drm_gem_vram_kmap_locked(gbo, map, is_iomem); |
344 | ttm_bo_unreserve(&gbo->bo); | |
85438a8d | 345 | |
37a48adf | 346 | return virtual; |
85438a8d | 347 | } |
85438a8d TZ |
348 | EXPORT_SYMBOL(drm_gem_vram_kmap); |
349 | ||
37a48adf | 350 | static void drm_gem_vram_kunmap_locked(struct drm_gem_vram_object *gbo) |
85438a8d | 351 | { |
92172173 TZ |
352 | struct ttm_bo_kmap_obj *kmap = &gbo->kmap; |
353 | ||
37a48adf TZ |
354 | if (WARN_ON_ONCE(!gbo->kmap_use_count)) |
355 | return; | |
356 | if (--gbo->kmap_use_count > 0) | |
357 | return; | |
358 | ||
85438a8d TZ |
359 | if (!kmap->virtual) |
360 | return; | |
361 | ||
362 | ttm_bo_kunmap(kmap); | |
363 | kmap->virtual = NULL; | |
364 | } | |
37a48adf TZ |
365 | |
366 | /** | |
367 | * drm_gem_vram_kunmap() - Unmaps a GEM VRAM object | |
368 | * @gbo: the GEM VRAM object | |
369 | */ | |
370 | void drm_gem_vram_kunmap(struct drm_gem_vram_object *gbo) | |
371 | { | |
372 | int ret; | |
373 | ||
374 | ret = ttm_bo_reserve(&gbo->bo, false, false, NULL); | |
375 | if (WARN_ONCE(ret, "ttm_bo_reserve_failed(): ret=%d\n", ret)) | |
376 | return; | |
377 | drm_gem_vram_kunmap_locked(gbo); | |
378 | ttm_bo_unreserve(&gbo->bo); | |
379 | } | |
85438a8d | 380 | EXPORT_SYMBOL(drm_gem_vram_kunmap); |
6c812bc5 | 381 | |
fed1eec0 TZ |
382 | /** |
383 | * drm_gem_vram_fill_create_dumb() - \ | |
384 | Helper for implementing &struct drm_driver.dumb_create | |
385 | * @file: the DRM file | |
386 | * @dev: the DRM device | |
387 | * @bdev: the TTM BO device managing the buffer object | |
388 | * @pg_align: the buffer's alignment in multiples of the page size | |
389 | * @interruptible: sleep interruptible if waiting for memory | |
390 | * @args: the arguments as provided to \ | |
391 | &struct drm_driver.dumb_create | |
392 | * | |
393 | * This helper function fills &struct drm_mode_create_dumb, which is used | |
394 | * by &struct drm_driver.dumb_create. Implementations of this interface | |
395 | * should forwards their arguments to this helper, plus the driver-specific | |
396 | * parameters. | |
397 | * | |
398 | * Returns: | |
399 | * 0 on success, or | |
400 | * a negative error code otherwise. | |
401 | */ | |
402 | int drm_gem_vram_fill_create_dumb(struct drm_file *file, | |
403 | struct drm_device *dev, | |
404 | struct ttm_bo_device *bdev, | |
405 | unsigned long pg_align, | |
406 | bool interruptible, | |
407 | struct drm_mode_create_dumb *args) | |
408 | { | |
409 | size_t pitch, size; | |
410 | struct drm_gem_vram_object *gbo; | |
411 | int ret; | |
412 | u32 handle; | |
413 | ||
414 | pitch = args->width * ((args->bpp + 7) / 8); | |
415 | size = pitch * args->height; | |
416 | ||
417 | size = roundup(size, PAGE_SIZE); | |
418 | if (!size) | |
419 | return -EINVAL; | |
420 | ||
421 | gbo = drm_gem_vram_create(dev, bdev, size, pg_align, interruptible); | |
422 | if (IS_ERR(gbo)) | |
423 | return PTR_ERR(gbo); | |
424 | ||
0e580c6d | 425 | ret = drm_gem_handle_create(file, &gbo->bo.base, &handle); |
fed1eec0 TZ |
426 | if (ret) |
427 | goto err_drm_gem_object_put_unlocked; | |
428 | ||
0e580c6d | 429 | drm_gem_object_put_unlocked(&gbo->bo.base); |
fed1eec0 TZ |
430 | |
431 | args->pitch = pitch; | |
432 | args->size = size; | |
433 | args->handle = handle; | |
434 | ||
435 | return 0; | |
436 | ||
437 | err_drm_gem_object_put_unlocked: | |
0e580c6d | 438 | drm_gem_object_put_unlocked(&gbo->bo.base); |
fed1eec0 TZ |
439 | return ret; |
440 | } | |
441 | EXPORT_SYMBOL(drm_gem_vram_fill_create_dumb); | |
442 | ||
6c812bc5 TZ |
443 | /* |
444 | * Helpers for struct ttm_bo_driver | |
445 | */ | |
446 | ||
447 | static bool drm_is_gem_vram(struct ttm_buffer_object *bo) | |
448 | { | |
449 | return (bo->destroy == ttm_buffer_object_destroy); | |
450 | } | |
451 | ||
452 | /** | |
453 | * drm_gem_vram_bo_driver_evict_flags() - \ | |
454 | Implements &struct ttm_bo_driver.evict_flags | |
455 | * @bo: TTM buffer object. Refers to &struct drm_gem_vram_object.bo | |
456 | * @pl: TTM placement information. | |
457 | */ | |
458 | void drm_gem_vram_bo_driver_evict_flags(struct ttm_buffer_object *bo, | |
459 | struct ttm_placement *pl) | |
460 | { | |
461 | struct drm_gem_vram_object *gbo; | |
462 | ||
463 | /* TTM may pass BOs that are not GEM VRAM BOs. */ | |
464 | if (!drm_is_gem_vram(bo)) | |
465 | return; | |
466 | ||
467 | gbo = drm_gem_vram_of_bo(bo); | |
468 | drm_gem_vram_placement(gbo, TTM_PL_FLAG_SYSTEM); | |
469 | *pl = gbo->placement; | |
470 | } | |
471 | EXPORT_SYMBOL(drm_gem_vram_bo_driver_evict_flags); | |
472 | ||
473 | /** | |
474 | * drm_gem_vram_bo_driver_verify_access() - \ | |
475 | Implements &struct ttm_bo_driver.verify_access | |
476 | * @bo: TTM buffer object. Refers to &struct drm_gem_vram_object.bo | |
477 | * @filp: File pointer. | |
478 | * | |
479 | * Returns: | |
480 | * 0 on success, or | |
481 | * a negative errno code otherwise. | |
482 | */ | |
483 | int drm_gem_vram_bo_driver_verify_access(struct ttm_buffer_object *bo, | |
484 | struct file *filp) | |
485 | { | |
486 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_bo(bo); | |
487 | ||
0e580c6d | 488 | return drm_vma_node_verify_access(&gbo->bo.base.vma_node, |
6c812bc5 TZ |
489 | filp->private_data); |
490 | } | |
491 | EXPORT_SYMBOL(drm_gem_vram_bo_driver_verify_access); | |
737000fd | 492 | |
1a1e5c0f | 493 | /* |
5c9dcacf TZ |
494 | * drm_gem_vram_mm_funcs - Functions for &struct drm_vram_mm |
495 | * | |
496 | * Most users of @struct drm_gem_vram_object will also use | |
497 | * @struct drm_vram_mm. This instance of &struct drm_vram_mm_funcs | |
498 | * can be used to connect both. | |
499 | */ | |
500 | const struct drm_vram_mm_funcs drm_gem_vram_mm_funcs = { | |
501 | .evict_flags = drm_gem_vram_bo_driver_evict_flags, | |
502 | .verify_access = drm_gem_vram_bo_driver_verify_access | |
503 | }; | |
504 | EXPORT_SYMBOL(drm_gem_vram_mm_funcs); | |
505 | ||
737000fd | 506 | /* |
0ccf52ba | 507 | * Helpers for struct drm_gem_object_funcs |
737000fd TZ |
508 | */ |
509 | ||
510 | /** | |
0ccf52ba TZ |
511 | * drm_gem_vram_object_free() - \ |
512 | Implements &struct drm_gem_object_funcs.free | |
513 | * @gem: GEM object. Refers to &struct drm_gem_vram_object.gem | |
737000fd | 514 | */ |
0ccf52ba | 515 | static void drm_gem_vram_object_free(struct drm_gem_object *gem) |
737000fd TZ |
516 | { |
517 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | |
518 | ||
519 | drm_gem_vram_put(gbo); | |
520 | } | |
0ccf52ba TZ |
521 | |
522 | /* | |
523 | * Helpers for dump buffers | |
524 | */ | |
737000fd | 525 | |
59f5989a TZ |
526 | /** |
527 | * drm_gem_vram_driver_create_dumb() - \ | |
528 | Implements &struct drm_driver.dumb_create | |
529 | * @file: the DRM file | |
530 | * @dev: the DRM device | |
531 | * @args: the arguments as provided to \ | |
532 | &struct drm_driver.dumb_create | |
533 | * | |
534 | * This function requires the driver to use @drm_device.vram_mm for its | |
535 | * instance of VRAM MM. | |
536 | * | |
537 | * Returns: | |
538 | * 0 on success, or | |
539 | * a negative error code otherwise. | |
540 | */ | |
541 | int drm_gem_vram_driver_dumb_create(struct drm_file *file, | |
542 | struct drm_device *dev, | |
543 | struct drm_mode_create_dumb *args) | |
544 | { | |
545 | if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized")) | |
546 | return -EINVAL; | |
547 | ||
548 | return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev, 0, | |
549 | false, args); | |
550 | } | |
551 | EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create); | |
552 | ||
737000fd TZ |
553 | /** |
554 | * drm_gem_vram_driver_dumb_mmap_offset() - \ | |
555 | Implements &struct drm_driver.dumb_mmap_offset | |
556 | * @file: DRM file pointer. | |
557 | * @dev: DRM device. | |
558 | * @handle: GEM handle | |
559 | * @offset: Returns the mapping's memory offset on success | |
560 | * | |
561 | * Returns: | |
562 | * 0 on success, or | |
563 | * a negative errno code otherwise. | |
564 | */ | |
565 | int drm_gem_vram_driver_dumb_mmap_offset(struct drm_file *file, | |
566 | struct drm_device *dev, | |
567 | uint32_t handle, uint64_t *offset) | |
568 | { | |
569 | struct drm_gem_object *gem; | |
570 | struct drm_gem_vram_object *gbo; | |
571 | ||
572 | gem = drm_gem_object_lookup(file, handle); | |
573 | if (!gem) | |
574 | return -ENOENT; | |
575 | ||
576 | gbo = drm_gem_vram_of_gem(gem); | |
577 | *offset = drm_gem_vram_mmap_offset(gbo); | |
578 | ||
579 | drm_gem_object_put_unlocked(gem); | |
580 | ||
581 | return 0; | |
582 | } | |
583 | EXPORT_SYMBOL(drm_gem_vram_driver_dumb_mmap_offset); | |
1f460b49 TZ |
584 | |
585 | /* | |
0ccf52ba | 586 | * PRIME helpers |
1f460b49 TZ |
587 | */ |
588 | ||
589 | /** | |
0ccf52ba TZ |
590 | * drm_gem_vram_object_pin() - \ |
591 | Implements &struct drm_gem_object_funcs.pin | |
1f460b49 TZ |
592 | * @gem: The GEM object to pin |
593 | * | |
594 | * Returns: | |
595 | * 0 on success, or | |
596 | * a negative errno code otherwise. | |
597 | */ | |
0ccf52ba | 598 | static int drm_gem_vram_object_pin(struct drm_gem_object *gem) |
1f460b49 TZ |
599 | { |
600 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | |
601 | ||
a6c3464f TZ |
602 | /* Fbdev console emulation is the use case of these PRIME |
603 | * helpers. This may involve updating a hardware buffer from | |
604 | * a shadow FB. We pin the buffer to it's current location | |
605 | * (either video RAM or system memory) to prevent it from | |
606 | * being relocated during the update operation. If you require | |
607 | * the buffer to be pinned to VRAM, implement a callback that | |
608 | * sets the flags accordingly. | |
609 | */ | |
610 | return drm_gem_vram_pin(gbo, 0); | |
1f460b49 | 611 | } |
1f460b49 TZ |
612 | |
613 | /** | |
0ccf52ba TZ |
614 | * drm_gem_vram_object_unpin() - \ |
615 | Implements &struct drm_gem_object_funcs.unpin | |
1f460b49 TZ |
616 | * @gem: The GEM object to unpin |
617 | */ | |
0ccf52ba | 618 | static void drm_gem_vram_object_unpin(struct drm_gem_object *gem) |
1f460b49 TZ |
619 | { |
620 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | |
621 | ||
622 | drm_gem_vram_unpin(gbo); | |
623 | } | |
1f460b49 TZ |
624 | |
625 | /** | |
0ccf52ba TZ |
626 | * drm_gem_vram_object_vmap() - \ |
627 | Implements &struct drm_gem_object_funcs.vmap | |
1f460b49 TZ |
628 | * @gem: The GEM object to map |
629 | * | |
630 | * Returns: | |
631 | * The buffers virtual address on success, or | |
632 | * NULL otherwise. | |
633 | */ | |
0ccf52ba | 634 | static void *drm_gem_vram_object_vmap(struct drm_gem_object *gem) |
1f460b49 TZ |
635 | { |
636 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | |
637 | int ret; | |
638 | void *base; | |
639 | ||
a6c3464f | 640 | ret = drm_gem_vram_pin(gbo, 0); |
1f460b49 TZ |
641 | if (ret) |
642 | return NULL; | |
643 | base = drm_gem_vram_kmap(gbo, true, NULL); | |
644 | if (IS_ERR(base)) { | |
645 | drm_gem_vram_unpin(gbo); | |
646 | return NULL; | |
647 | } | |
648 | return base; | |
649 | } | |
1f460b49 TZ |
650 | |
651 | /** | |
0ccf52ba TZ |
652 | * drm_gem_vram_object_vunmap() - \ |
653 | Implements &struct drm_gem_object_funcs.vunmap | |
1f460b49 TZ |
654 | * @gem: The GEM object to unmap |
655 | * @vaddr: The mapping's base address | |
656 | */ | |
0ccf52ba TZ |
657 | static void drm_gem_vram_object_vunmap(struct drm_gem_object *gem, |
658 | void *vaddr) | |
1f460b49 TZ |
659 | { |
660 | struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); | |
661 | ||
662 | drm_gem_vram_kunmap(gbo); | |
663 | drm_gem_vram_unpin(gbo); | |
664 | } | |
31070a87 TZ |
665 | |
666 | /* | |
667 | * GEM object funcs | |
668 | */ | |
669 | ||
670 | static const struct drm_gem_object_funcs drm_gem_vram_object_funcs = { | |
0ccf52ba TZ |
671 | .free = drm_gem_vram_object_free, |
672 | .pin = drm_gem_vram_object_pin, | |
673 | .unpin = drm_gem_vram_object_unpin, | |
674 | .vmap = drm_gem_vram_object_vmap, | |
675 | .vunmap = drm_gem_vram_object_vunmap | |
31070a87 | 676 | }; |