1135 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3#include <linux/iosys-map.h>4#include <linux/module.h>5 6#include <drm/drm_debugfs.h>7#include <drm/drm_device.h>8#include <drm/drm_drv.h>9#include <drm/drm_file.h>10#include <drm/drm_framebuffer.h>11#include <drm/drm_gem_atomic_helper.h>12#include <drm/drm_gem_framebuffer_helper.h>13#include <drm/drm_gem_ttm_helper.h>14#include <drm/drm_gem_vram_helper.h>15#include <drm/drm_managed.h>16#include <drm/drm_mode.h>17#include <drm/drm_plane.h>18#include <drm/drm_prime.h>19#include <drm/drm_simple_kms_helper.h>20 21#include <drm/ttm/ttm_range_manager.h>22#include <drm/ttm/ttm_tt.h>23 24static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;25 26/**27 * DOC: overview28 *29 * This library provides &struct drm_gem_vram_object (GEM VRAM), a GEM30 * buffer object that is backed by video RAM (VRAM). It can be used for31 * framebuffer devices with dedicated memory.32 *33 * The data structure &struct drm_vram_mm and its helpers implement a memory34 * manager for simple framebuffer devices with dedicated video memory. GEM35 * VRAM buffer objects are either placed in the video memory or remain evicted36 * to system memory.37 *38 * With the GEM interface userspace applications create, manage and destroy39 * graphics buffers, such as an on-screen framebuffer. GEM does not provide40 * an implementation of these interfaces. It's up to the DRM driver to41 * provide an implementation that suits the hardware. If the hardware device42 * contains dedicated video memory, the DRM driver can use the VRAM helper43 * library. Each active buffer object is stored in video RAM. Active44 * buffer are used for drawing the current frame, typically something like45 * the frame's scanout buffer or the cursor image. If there's no more space46 * left in VRAM, inactive GEM objects can be moved to system memory.47 *48 * To initialize the VRAM helper library call drmm_vram_helper_init().49 * The function allocates and initializes an instance of &struct drm_vram_mm50 * in &struct drm_device.vram_mm . Use &DRM_GEM_VRAM_DRIVER to initialize51 * &struct drm_driver and &DRM_VRAM_MM_FILE_OPERATIONS to initialize52 * &struct file_operations; as illustrated below.53 *54 * .. code-block:: c55 *56 * struct file_operations fops ={57 * .owner = THIS_MODULE,58 * DRM_VRAM_MM_FILE_OPERATION59 * };60 * struct drm_driver drv = {61 * .driver_feature = DRM_ ... ,62 * .fops = &fops,63 * DRM_GEM_VRAM_DRIVER64 * };65 *66 * int init_drm_driver()67 * {68 * struct drm_device *dev;69 * uint64_t vram_base;70 * unsigned long vram_size;71 * int ret;72 *73 * // setup device, vram base and size74 * // ...75 *76 * ret = drmm_vram_helper_init(dev, vram_base, vram_size);77 * if (ret)78 * return ret;79 * return 0;80 * }81 *82 * This creates an instance of &struct drm_vram_mm, exports DRM userspace83 * interfaces for GEM buffer management and initializes file operations to84 * allow for accessing created GEM buffers. With this setup, the DRM driver85 * manages an area of video RAM with VRAM MM and provides GEM VRAM objects86 * to userspace.87 *88 * You don't have to clean up the instance of VRAM MM.89 * drmm_vram_helper_init() is a managed interface that installs a90 * clean-up handler to run during the DRM device's release.91 *92 * For drawing or scanout operations, rsp. buffer objects have to be pinned93 * in video RAM. Call drm_gem_vram_pin() with &DRM_GEM_VRAM_PL_FLAG_VRAM or94 * &DRM_GEM_VRAM_PL_FLAG_SYSTEM to pin a buffer object in video RAM or system95 * memory. Call drm_gem_vram_unpin() to release the pinned object afterwards.96 *97 * A buffer object that is pinned in video RAM has a fixed address within that98 * memory region. Call drm_gem_vram_offset() to retrieve this value. Typically99 * it's used to program the hardware's scanout engine for framebuffers, set100 * the cursor overlay's image for a mouse cursor, or use it as input to the101 * hardware's drawing engine.102 *103 * To access a buffer object's memory from the DRM driver, call104 * drm_gem_vram_vmap(). It maps the buffer into kernel address105 * space and returns the memory address. Use drm_gem_vram_vunmap() to106 * release the mapping.107 */108 109/*110 * Buffer-objects helpers111 */112 113static void drm_gem_vram_cleanup(struct drm_gem_vram_object *gbo)114{115 /* We got here via ttm_bo_put(), which means that the116 * TTM buffer object in 'bo' has already been cleaned117 * up; only release the GEM object.118 */119 120 WARN_ON(gbo->vmap_use_count);121 WARN_ON(iosys_map_is_set(&gbo->map));122 123 drm_gem_object_release(&gbo->bo.base);124}125 126static void drm_gem_vram_destroy(struct drm_gem_vram_object *gbo)127{128 drm_gem_vram_cleanup(gbo);129 kfree(gbo);130}131 132static void ttm_buffer_object_destroy(struct ttm_buffer_object *bo)133{134 struct drm_gem_vram_object *gbo = drm_gem_vram_of_bo(bo);135 136 drm_gem_vram_destroy(gbo);137}138 139static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo,140 unsigned long pl_flag)141{142 u32 invariant_flags = 0;143 unsigned int i;144 unsigned int c = 0;145 146 if (pl_flag & DRM_GEM_VRAM_PL_FLAG_TOPDOWN)147 invariant_flags = TTM_PL_FLAG_TOPDOWN;148 149 gbo->placement.placement = gbo->placements;150 151 if (pl_flag & DRM_GEM_VRAM_PL_FLAG_VRAM) {152 gbo->placements[c].mem_type = TTM_PL_VRAM;153 gbo->placements[c++].flags = invariant_flags;154 }155 156 if (pl_flag & DRM_GEM_VRAM_PL_FLAG_SYSTEM || !c) {157 gbo->placements[c].mem_type = TTM_PL_SYSTEM;158 gbo->placements[c++].flags = invariant_flags;159 }160 161 gbo->placement.num_placement = c;162 163 for (i = 0; i < c; ++i) {164 gbo->placements[i].fpfn = 0;165 gbo->placements[i].lpfn = 0;166 }167}168 169/**170 * drm_gem_vram_create() - Creates a VRAM-backed GEM object171 * @dev: the DRM device172 * @size: the buffer size in bytes173 * @pg_align: the buffer's alignment in multiples of the page size174 *175 * GEM objects are allocated by calling struct drm_driver.gem_create_object,176 * if set. Otherwise kzalloc() will be used. Drivers can set their own GEM177 * object functions in struct drm_driver.gem_create_object. If no functions178 * are set, the new GEM object will use the default functions from GEM VRAM179 * helpers.180 *181 * Returns:182 * A new instance of &struct drm_gem_vram_object on success, or183 * an ERR_PTR()-encoded error code otherwise.184 */185struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev,186 size_t size,187 unsigned long pg_align)188{189 struct drm_gem_vram_object *gbo;190 struct drm_gem_object *gem;191 struct drm_vram_mm *vmm = dev->vram_mm;192 struct ttm_device *bdev;193 int ret;194 195 if (WARN_ONCE(!vmm, "VRAM MM not initialized"))196 return ERR_PTR(-EINVAL);197 198 if (dev->driver->gem_create_object) {199 gem = dev->driver->gem_create_object(dev, size);200 if (IS_ERR(gem))201 return ERR_CAST(gem);202 gbo = drm_gem_vram_of_gem(gem);203 } else {204 gbo = kzalloc(sizeof(*gbo), GFP_KERNEL);205 if (!gbo)206 return ERR_PTR(-ENOMEM);207 gem = &gbo->bo.base;208 }209 210 if (!gem->funcs)211 gem->funcs = &drm_gem_vram_object_funcs;212 213 ret = drm_gem_object_init(dev, gem, size);214 if (ret) {215 kfree(gbo);216 return ERR_PTR(ret);217 }218 219 bdev = &vmm->bdev;220 221 gbo->bo.bdev = bdev;222 drm_gem_vram_placement(gbo, DRM_GEM_VRAM_PL_FLAG_SYSTEM);223 224 /*225 * A failing ttm_bo_init will call ttm_buffer_object_destroy226 * to release gbo->bo.base and kfree gbo.227 */228 ret = ttm_bo_init_validate(bdev, &gbo->bo, ttm_bo_type_device,229 &gbo->placement, pg_align, false, NULL, NULL,230 ttm_buffer_object_destroy);231 if (ret)232 return ERR_PTR(ret);233 234 return gbo;235}236EXPORT_SYMBOL(drm_gem_vram_create);237 238/**239 * drm_gem_vram_put() - Releases a reference to a VRAM-backed GEM object240 * @gbo: the GEM VRAM object241 *242 * See ttm_bo_put() for more information.243 */244void drm_gem_vram_put(struct drm_gem_vram_object *gbo)245{246 ttm_bo_put(&gbo->bo);247}248EXPORT_SYMBOL(drm_gem_vram_put);249 250static u64 drm_gem_vram_pg_offset(struct drm_gem_vram_object *gbo)251{252 /* Keep TTM behavior for now, remove when drivers are audited */253 if (WARN_ON_ONCE(!gbo->bo.resource ||254 gbo->bo.resource->mem_type == TTM_PL_SYSTEM))255 return 0;256 257 return gbo->bo.resource->start;258}259 260/**261 * drm_gem_vram_offset() - Returns a GEM VRAM object's offset in video memory262 * @gbo: the GEM VRAM object263 *264 * This function returns the buffer object's offset in the device's video265 * memory. The buffer object has to be pinned to %TTM_PL_VRAM.266 *267 * Returns:268 * The buffer object's offset in video memory on success, or269 * a negative errno code otherwise.270 */271s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo)272{273 if (WARN_ON_ONCE(!gbo->bo.pin_count))274 return (s64)-ENODEV;275 return drm_gem_vram_pg_offset(gbo) << PAGE_SHIFT;276}277EXPORT_SYMBOL(drm_gem_vram_offset);278 279static int drm_gem_vram_pin_locked(struct drm_gem_vram_object *gbo,280 unsigned long pl_flag)281{282 struct ttm_operation_ctx ctx = { false, false };283 int ret;284 285 dma_resv_assert_held(gbo->bo.base.resv);286 287 if (gbo->bo.pin_count)288 goto out;289 290 if (pl_flag)291 drm_gem_vram_placement(gbo, pl_flag);292 293 ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx);294 if (ret < 0)295 return ret;296 297out:298 ttm_bo_pin(&gbo->bo);299 300 return 0;301}302 303/**304 * drm_gem_vram_pin() - Pins a GEM VRAM object in a region.305 * @gbo: the GEM VRAM object306 * @pl_flag: a bitmask of possible memory regions307 *308 * Pinning a buffer object ensures that it is not evicted from309 * a memory region. A pinned buffer object has to be unpinned before310 * it can be pinned to another region. If the pl_flag argument is 0,311 * the buffer is pinned at its current location (video RAM or system312 * memory).313 *314 * Small buffer objects, such as cursor images, can lead to memory315 * fragmentation if they are pinned in the middle of video RAM. This316 * is especially a problem on devices with only a small amount of317 * video RAM. Fragmentation can prevent the primary framebuffer from318 * fitting in, even though there's enough memory overall. The modifier319 * DRM_GEM_VRAM_PL_FLAG_TOPDOWN marks the buffer object to be pinned320 * at the high end of the memory region to avoid fragmentation.321 *322 * Returns:323 * 0 on success, or324 * a negative error code otherwise.325 */326int drm_gem_vram_pin(struct drm_gem_vram_object *gbo, unsigned long pl_flag)327{328 int ret;329 330 ret = ttm_bo_reserve(&gbo->bo, true, false, NULL);331 if (ret)332 return ret;333 ret = drm_gem_vram_pin_locked(gbo, pl_flag);334 ttm_bo_unreserve(&gbo->bo);335 336 return ret;337}338EXPORT_SYMBOL(drm_gem_vram_pin);339 340static void drm_gem_vram_unpin_locked(struct drm_gem_vram_object *gbo)341{342 dma_resv_assert_held(gbo->bo.base.resv);343 344 ttm_bo_unpin(&gbo->bo);345}346 347/**348 * drm_gem_vram_unpin() - Unpins a GEM VRAM object349 * @gbo: the GEM VRAM object350 *351 * Returns:352 * 0 on success, or353 * a negative error code otherwise.354 */355int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo)356{357 int ret;358 359 ret = ttm_bo_reserve(&gbo->bo, true, false, NULL);360 if (ret)361 return ret;362 363 drm_gem_vram_unpin_locked(gbo);364 ttm_bo_unreserve(&gbo->bo);365 366 return 0;367}368EXPORT_SYMBOL(drm_gem_vram_unpin);369 370/**371 * drm_gem_vram_vmap() - Pins and maps a GEM VRAM object into kernel address372 * space373 * @gbo: The GEM VRAM object to map374 * @map: Returns the kernel virtual address of the VRAM GEM object's backing375 * store.376 *377 * The vmap function pins a GEM VRAM object to its current location, either378 * system or video memory, and maps its buffer into kernel address space.379 * As pinned object cannot be relocated, you should avoid pinning objects380 * permanently. Call drm_gem_vram_vunmap() with the returned address to381 * unmap and unpin the GEM VRAM object.382 *383 * Returns:384 * 0 on success, or a negative error code otherwise.385 */386int drm_gem_vram_vmap(struct drm_gem_vram_object *gbo, struct iosys_map *map)387{388 int ret;389 390 dma_resv_assert_held(gbo->bo.base.resv);391 392 if (gbo->vmap_use_count > 0)393 goto out;394 395 /*396 * VRAM helpers unmap the BO only on demand. So the previous397 * page mapping might still be around. Only vmap if the there's398 * no mapping present.399 */400 if (iosys_map_is_null(&gbo->map)) {401 ret = ttm_bo_vmap(&gbo->bo, &gbo->map);402 if (ret)403 return ret;404 }405 406out:407 ++gbo->vmap_use_count;408 *map = gbo->map;409 410 return 0;411}412EXPORT_SYMBOL(drm_gem_vram_vmap);413 414/**415 * drm_gem_vram_vunmap() - Unmaps and unpins a GEM VRAM object416 * @gbo: The GEM VRAM object to unmap417 * @map: Kernel virtual address where the VRAM GEM object was mapped418 *419 * A call to drm_gem_vram_vunmap() unmaps and unpins a GEM VRAM buffer. See420 * the documentation for drm_gem_vram_vmap() for more information.421 */422void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo,423 struct iosys_map *map)424{425 struct drm_device *dev = gbo->bo.base.dev;426 427 dma_resv_assert_held(gbo->bo.base.resv);428 429 if (drm_WARN_ON_ONCE(dev, !gbo->vmap_use_count))430 return;431 432 if (drm_WARN_ON_ONCE(dev, !iosys_map_is_equal(&gbo->map, map)))433 return; /* BUG: map not mapped from this BO */434 435 if (--gbo->vmap_use_count > 0)436 return;437 438 /*439 * Permanently mapping and unmapping buffers adds overhead from440 * updating the page tables and creates debugging output. Therefore,441 * we delay the actual unmap operation until the BO gets evicted442 * from memory. See drm_gem_vram_bo_driver_move_notify().443 */444}445EXPORT_SYMBOL(drm_gem_vram_vunmap);446 447/**448 * drm_gem_vram_fill_create_dumb() - Helper for implementing449 * &struct drm_driver.dumb_create450 *451 * @file: the DRM file452 * @dev: the DRM device453 * @pg_align: the buffer's alignment in multiples of the page size454 * @pitch_align: the scanline's alignment in powers of 2455 * @args: the arguments as provided to456 * &struct drm_driver.dumb_create457 *458 * This helper function fills &struct drm_mode_create_dumb, which is used459 * by &struct drm_driver.dumb_create. Implementations of this interface460 * should forwards their arguments to this helper, plus the driver-specific461 * parameters.462 *463 * Returns:464 * 0 on success, or465 * a negative error code otherwise.466 */467int drm_gem_vram_fill_create_dumb(struct drm_file *file,468 struct drm_device *dev,469 unsigned long pg_align,470 unsigned long pitch_align,471 struct drm_mode_create_dumb *args)472{473 size_t pitch, size;474 struct drm_gem_vram_object *gbo;475 int ret;476 u32 handle;477 478 pitch = args->width * DIV_ROUND_UP(args->bpp, 8);479 if (pitch_align) {480 if (WARN_ON_ONCE(!is_power_of_2(pitch_align)))481 return -EINVAL;482 pitch = ALIGN(pitch, pitch_align);483 }484 size = pitch * args->height;485 486 size = roundup(size, PAGE_SIZE);487 if (!size)488 return -EINVAL;489 490 gbo = drm_gem_vram_create(dev, size, pg_align);491 if (IS_ERR(gbo))492 return PTR_ERR(gbo);493 494 ret = drm_gem_handle_create(file, &gbo->bo.base, &handle);495 if (ret)496 goto err_drm_gem_object_put;497 498 drm_gem_object_put(&gbo->bo.base);499 500 args->pitch = pitch;501 args->size = size;502 args->handle = handle;503 504 return 0;505 506err_drm_gem_object_put:507 drm_gem_object_put(&gbo->bo.base);508 return ret;509}510EXPORT_SYMBOL(drm_gem_vram_fill_create_dumb);511 512/*513 * Helpers for struct ttm_device_funcs514 */515 516static bool drm_is_gem_vram(struct ttm_buffer_object *bo)517{518 return (bo->destroy == ttm_buffer_object_destroy);519}520 521static void drm_gem_vram_bo_driver_evict_flags(struct drm_gem_vram_object *gbo,522 struct ttm_placement *pl)523{524 drm_gem_vram_placement(gbo, DRM_GEM_VRAM_PL_FLAG_SYSTEM);525 *pl = gbo->placement;526}527 528static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo)529{530 struct ttm_buffer_object *bo = &gbo->bo;531 struct drm_device *dev = bo->base.dev;532 533 if (drm_WARN_ON_ONCE(dev, gbo->vmap_use_count))534 return;535 536 ttm_bo_vunmap(bo, &gbo->map);537 iosys_map_clear(&gbo->map); /* explicitly clear mapping for next vmap call */538}539 540static int drm_gem_vram_bo_driver_move(struct drm_gem_vram_object *gbo,541 bool evict,542 struct ttm_operation_ctx *ctx,543 struct ttm_resource *new_mem)544{545 drm_gem_vram_bo_driver_move_notify(gbo);546 return ttm_bo_move_memcpy(&gbo->bo, ctx, new_mem);547}548 549/*550 * Helpers for struct drm_gem_object_funcs551 */552 553/**554 * drm_gem_vram_object_free() - Implements &struct drm_gem_object_funcs.free555 * @gem: GEM object. Refers to &struct drm_gem_vram_object.gem556 */557static void drm_gem_vram_object_free(struct drm_gem_object *gem)558{559 struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem);560 561 drm_gem_vram_put(gbo);562}563 564/*565 * Helpers for dump buffers566 */567 568/**569 * drm_gem_vram_driver_dumb_create() - Implements &struct drm_driver.dumb_create570 * @file: the DRM file571 * @dev: the DRM device572 * @args: the arguments as provided to573 * &struct drm_driver.dumb_create574 *575 * This function requires the driver to use @drm_device.vram_mm for its576 * instance of VRAM MM.577 *578 * Returns:579 * 0 on success, or580 * a negative error code otherwise.581 */582int drm_gem_vram_driver_dumb_create(struct drm_file *file,583 struct drm_device *dev,584 struct drm_mode_create_dumb *args)585{586 if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized"))587 return -EINVAL;588 589 return drm_gem_vram_fill_create_dumb(file, dev, 0, 0, args);590}591EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create);592 593/*594 * Helpers for struct drm_plane_helper_funcs595 */596 597static void __drm_gem_vram_plane_helper_cleanup_fb(struct drm_plane *plane,598 struct drm_plane_state *state,599 unsigned int num_planes)600{601 struct drm_gem_object *obj;602 struct drm_gem_vram_object *gbo;603 struct drm_framebuffer *fb = state->fb;604 605 while (num_planes) {606 --num_planes;607 obj = drm_gem_fb_get_obj(fb, num_planes);608 if (!obj)609 continue;610 gbo = drm_gem_vram_of_gem(obj);611 drm_gem_vram_unpin(gbo);612 }613}614 615/**616 * drm_gem_vram_plane_helper_prepare_fb() - Implements &struct617 * drm_plane_helper_funcs.prepare_fb618 * @plane: a DRM plane619 * @new_state: the plane's new state620 *621 * During plane updates, this function sets the plane's fence and622 * pins the GEM VRAM objects of the plane's new framebuffer to VRAM.623 * Call drm_gem_vram_plane_helper_cleanup_fb() to unpin them.624 *625 * Returns:626 * 0 on success, or627 * a negative errno code otherwise.628 */629int630drm_gem_vram_plane_helper_prepare_fb(struct drm_plane *plane,631 struct drm_plane_state *new_state)632{633 struct drm_framebuffer *fb = new_state->fb;634 struct drm_gem_vram_object *gbo;635 struct drm_gem_object *obj;636 unsigned int i;637 int ret;638 639 if (!fb)640 return 0;641 642 for (i = 0; i < fb->format->num_planes; ++i) {643 obj = drm_gem_fb_get_obj(fb, i);644 if (!obj) {645 ret = -EINVAL;646 goto err_drm_gem_vram_unpin;647 }648 gbo = drm_gem_vram_of_gem(obj);649 ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM);650 if (ret)651 goto err_drm_gem_vram_unpin;652 }653 654 ret = drm_gem_plane_helper_prepare_fb(plane, new_state);655 if (ret)656 goto err_drm_gem_vram_unpin;657 658 return 0;659 660err_drm_gem_vram_unpin:661 __drm_gem_vram_plane_helper_cleanup_fb(plane, new_state, i);662 return ret;663}664EXPORT_SYMBOL(drm_gem_vram_plane_helper_prepare_fb);665 666/**667 * drm_gem_vram_plane_helper_cleanup_fb() - Implements &struct668 * drm_plane_helper_funcs.cleanup_fb669 * @plane: a DRM plane670 * @old_state: the plane's old state671 *672 * During plane updates, this function unpins the GEM VRAM673 * objects of the plane's old framebuffer from VRAM. Complements674 * drm_gem_vram_plane_helper_prepare_fb().675 */676void677drm_gem_vram_plane_helper_cleanup_fb(struct drm_plane *plane,678 struct drm_plane_state *old_state)679{680 struct drm_framebuffer *fb = old_state->fb;681 682 if (!fb)683 return;684 685 __drm_gem_vram_plane_helper_cleanup_fb(plane, old_state, fb->format->num_planes);686}687EXPORT_SYMBOL(drm_gem_vram_plane_helper_cleanup_fb);688 689/*690 * Helpers for struct drm_simple_display_pipe_funcs691 */692 693/**694 * drm_gem_vram_simple_display_pipe_prepare_fb() - Implements &struct695 * drm_simple_display_pipe_funcs.prepare_fb696 * @pipe: a simple display pipe697 * @new_state: the plane's new state698 *699 * During plane updates, this function pins the GEM VRAM700 * objects of the plane's new framebuffer to VRAM. Call701 * drm_gem_vram_simple_display_pipe_cleanup_fb() to unpin them.702 *703 * Returns:704 * 0 on success, or705 * a negative errno code otherwise.706 */707int drm_gem_vram_simple_display_pipe_prepare_fb(708 struct drm_simple_display_pipe *pipe,709 struct drm_plane_state *new_state)710{711 return drm_gem_vram_plane_helper_prepare_fb(&pipe->plane, new_state);712}713EXPORT_SYMBOL(drm_gem_vram_simple_display_pipe_prepare_fb);714 715/**716 * drm_gem_vram_simple_display_pipe_cleanup_fb() - Implements &struct717 * drm_simple_display_pipe_funcs.cleanup_fb718 * @pipe: a simple display pipe719 * @old_state: the plane's old state720 *721 * During plane updates, this function unpins the GEM VRAM722 * objects of the plane's old framebuffer from VRAM. Complements723 * drm_gem_vram_simple_display_pipe_prepare_fb().724 */725void drm_gem_vram_simple_display_pipe_cleanup_fb(726 struct drm_simple_display_pipe *pipe,727 struct drm_plane_state *old_state)728{729 drm_gem_vram_plane_helper_cleanup_fb(&pipe->plane, old_state);730}731EXPORT_SYMBOL(drm_gem_vram_simple_display_pipe_cleanup_fb);732 733/*734 * PRIME helpers735 */736 737/**738 * drm_gem_vram_object_pin() - Implements &struct drm_gem_object_funcs.pin739 * @gem: The GEM object to pin740 *741 * Returns:742 * 0 on success, or743 * a negative errno code otherwise.744 */745static int drm_gem_vram_object_pin(struct drm_gem_object *gem)746{747 struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem);748 749 /*750 * Fbdev console emulation is the use case of these PRIME751 * helpers. This may involve updating a hardware buffer from752 * a shadow FB. We pin the buffer to it's current location753 * (either video RAM or system memory) to prevent it from754 * being relocated during the update operation. If you require755 * the buffer to be pinned to VRAM, implement a callback that756 * sets the flags accordingly.757 */758 return drm_gem_vram_pin_locked(gbo, 0);759}760 761/**762 * drm_gem_vram_object_unpin() - Implements &struct drm_gem_object_funcs.unpin763 * @gem: The GEM object to unpin764 */765static void drm_gem_vram_object_unpin(struct drm_gem_object *gem)766{767 struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem);768 769 drm_gem_vram_unpin_locked(gbo);770}771 772/**773 * drm_gem_vram_object_vmap() -774 * Implements &struct drm_gem_object_funcs.vmap775 * @gem: The GEM object to map776 * @map: Returns the kernel virtual address of the VRAM GEM object's backing777 * store.778 *779 * Returns:780 * 0 on success, or a negative error code otherwise.781 */782static int drm_gem_vram_object_vmap(struct drm_gem_object *gem,783 struct iosys_map *map)784{785 struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem);786 787 return drm_gem_vram_vmap(gbo, map);788}789 790/**791 * drm_gem_vram_object_vunmap() -792 * Implements &struct drm_gem_object_funcs.vunmap793 * @gem: The GEM object to unmap794 * @map: Kernel virtual address where the VRAM GEM object was mapped795 */796static void drm_gem_vram_object_vunmap(struct drm_gem_object *gem,797 struct iosys_map *map)798{799 struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem);800 801 drm_gem_vram_vunmap(gbo, map);802}803 804/*805 * GEM object funcs806 */807 808static const struct drm_gem_object_funcs drm_gem_vram_object_funcs = {809 .free = drm_gem_vram_object_free,810 .pin = drm_gem_vram_object_pin,811 .unpin = drm_gem_vram_object_unpin,812 .vmap = drm_gem_vram_object_vmap,813 .vunmap = drm_gem_vram_object_vunmap,814 .mmap = drm_gem_ttm_mmap,815 .print_info = drm_gem_ttm_print_info,816};817 818/*819 * VRAM memory manager820 */821 822/*823 * TTM TT824 */825 826static void bo_driver_ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *tt)827{828 ttm_tt_fini(tt);829 kfree(tt);830}831 832/*833 * TTM BO device834 */835 836static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo,837 uint32_t page_flags)838{839 struct ttm_tt *tt;840 int ret;841 842 tt = kzalloc(sizeof(*tt), GFP_KERNEL);843 if (!tt)844 return NULL;845 846 ret = ttm_tt_init(tt, bo, page_flags, ttm_cached, 0);847 if (ret < 0)848 goto err_ttm_tt_init;849 850 return tt;851 852err_ttm_tt_init:853 kfree(tt);854 return NULL;855}856 857static void bo_driver_evict_flags(struct ttm_buffer_object *bo,858 struct ttm_placement *placement)859{860 struct drm_gem_vram_object *gbo;861 862 /* TTM may pass BOs that are not GEM VRAM BOs. */863 if (!drm_is_gem_vram(bo))864 return;865 866 gbo = drm_gem_vram_of_bo(bo);867 868 drm_gem_vram_bo_driver_evict_flags(gbo, placement);869}870 871static void bo_driver_delete_mem_notify(struct ttm_buffer_object *bo)872{873 struct drm_gem_vram_object *gbo;874 875 /* TTM may pass BOs that are not GEM VRAM BOs. */876 if (!drm_is_gem_vram(bo))877 return;878 879 gbo = drm_gem_vram_of_bo(bo);880 881 drm_gem_vram_bo_driver_move_notify(gbo);882}883 884static int bo_driver_move(struct ttm_buffer_object *bo,885 bool evict,886 struct ttm_operation_ctx *ctx,887 struct ttm_resource *new_mem,888 struct ttm_place *hop)889{890 struct drm_gem_vram_object *gbo;891 892 if (!bo->resource) {893 if (new_mem->mem_type != TTM_PL_SYSTEM) {894 hop->mem_type = TTM_PL_SYSTEM;895 hop->flags = TTM_PL_FLAG_TEMPORARY;896 return -EMULTIHOP;897 }898 899 ttm_bo_move_null(bo, new_mem);900 return 0;901 }902 903 gbo = drm_gem_vram_of_bo(bo);904 905 return drm_gem_vram_bo_driver_move(gbo, evict, ctx, new_mem);906}907 908static int bo_driver_io_mem_reserve(struct ttm_device *bdev,909 struct ttm_resource *mem)910{911 struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bdev);912 913 switch (mem->mem_type) {914 case TTM_PL_SYSTEM: /* nothing to do */915 break;916 case TTM_PL_VRAM:917 mem->bus.offset = (mem->start << PAGE_SHIFT) + vmm->vram_base;918 mem->bus.is_iomem = true;919 mem->bus.caching = ttm_write_combined;920 break;921 default:922 return -EINVAL;923 }924 925 return 0;926}927 928static struct ttm_device_funcs bo_driver = {929 .ttm_tt_create = bo_driver_ttm_tt_create,930 .ttm_tt_destroy = bo_driver_ttm_tt_destroy,931 .eviction_valuable = ttm_bo_eviction_valuable,932 .evict_flags = bo_driver_evict_flags,933 .move = bo_driver_move,934 .delete_mem_notify = bo_driver_delete_mem_notify,935 .io_mem_reserve = bo_driver_io_mem_reserve,936};937 938/*939 * struct drm_vram_mm940 */941 942static int drm_vram_mm_debugfs(struct seq_file *m, void *data)943{944 struct drm_debugfs_entry *entry = m->private;945 struct drm_vram_mm *vmm = entry->dev->vram_mm;946 struct ttm_resource_manager *man = ttm_manager_type(&vmm->bdev, TTM_PL_VRAM);947 struct drm_printer p = drm_seq_file_printer(m);948 949 ttm_resource_manager_debug(man, &p);950 return 0;951}952 953static const struct drm_debugfs_info drm_vram_mm_debugfs_list[] = {954 { "vram-mm", drm_vram_mm_debugfs, 0, NULL },955};956 957/**958 * drm_vram_mm_debugfs_init() - Register VRAM MM debugfs file.959 *960 * @minor: drm minor device.961 *962 */963void drm_vram_mm_debugfs_init(struct drm_minor *minor)964{965 drm_debugfs_add_files(minor->dev, drm_vram_mm_debugfs_list,966 ARRAY_SIZE(drm_vram_mm_debugfs_list));967}968EXPORT_SYMBOL(drm_vram_mm_debugfs_init);969 970static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev,971 uint64_t vram_base, size_t vram_size)972{973 int ret;974 975 vmm->vram_base = vram_base;976 vmm->vram_size = vram_size;977 978 ret = ttm_device_init(&vmm->bdev, &bo_driver, dev->dev,979 dev->anon_inode->i_mapping,980 dev->vma_offset_manager,981 false, true);982 if (ret)983 return ret;984 985 ret = ttm_range_man_init(&vmm->bdev, TTM_PL_VRAM,986 false, vram_size >> PAGE_SHIFT);987 if (ret)988 return ret;989 990 return 0;991}992 993static void drm_vram_mm_cleanup(struct drm_vram_mm *vmm)994{995 ttm_range_man_fini(&vmm->bdev, TTM_PL_VRAM);996 ttm_device_fini(&vmm->bdev);997}998 999/*1000 * Helpers for integration with struct drm_device1001 */1002 1003static struct drm_vram_mm *drm_vram_helper_alloc_mm(struct drm_device *dev, uint64_t vram_base,1004 size_t vram_size)1005{1006 int ret;1007 1008 if (WARN_ON(dev->vram_mm))1009 return dev->vram_mm;1010 1011 dev->vram_mm = kzalloc(sizeof(*dev->vram_mm), GFP_KERNEL);1012 if (!dev->vram_mm)1013 return ERR_PTR(-ENOMEM);1014 1015 ret = drm_vram_mm_init(dev->vram_mm, dev, vram_base, vram_size);1016 if (ret)1017 goto err_kfree;1018 1019 return dev->vram_mm;1020 1021err_kfree:1022 kfree(dev->vram_mm);1023 dev->vram_mm = NULL;1024 return ERR_PTR(ret);1025}1026 1027static void drm_vram_helper_release_mm(struct drm_device *dev)1028{1029 if (!dev->vram_mm)1030 return;1031 1032 drm_vram_mm_cleanup(dev->vram_mm);1033 kfree(dev->vram_mm);1034 dev->vram_mm = NULL;1035}1036 1037static void drm_vram_mm_release(struct drm_device *dev, void *ptr)1038{1039 drm_vram_helper_release_mm(dev);1040}1041 1042/**1043 * drmm_vram_helper_init - Initializes a device's instance of1044 * &struct drm_vram_mm1045 * @dev: the DRM device1046 * @vram_base: the base address of the video memory1047 * @vram_size: the size of the video memory in bytes1048 *1049 * Creates a new instance of &struct drm_vram_mm and stores it in1050 * struct &drm_device.vram_mm. The instance is auto-managed and cleaned1051 * up as part of device cleanup. Calling this function multiple times1052 * will generate an error message.1053 *1054 * Returns:1055 * 0 on success, or a negative errno code otherwise.1056 */1057int drmm_vram_helper_init(struct drm_device *dev, uint64_t vram_base,1058 size_t vram_size)1059{1060 struct drm_vram_mm *vram_mm;1061 1062 if (drm_WARN_ON_ONCE(dev, dev->vram_mm))1063 return 0;1064 1065 vram_mm = drm_vram_helper_alloc_mm(dev, vram_base, vram_size);1066 if (IS_ERR(vram_mm))1067 return PTR_ERR(vram_mm);1068 return drmm_add_action_or_reset(dev, drm_vram_mm_release, NULL);1069}1070EXPORT_SYMBOL(drmm_vram_helper_init);1071 1072/*1073 * Mode-config helpers1074 */1075 1076static enum drm_mode_status1077drm_vram_helper_mode_valid_internal(struct drm_device *dev,1078 const struct drm_display_mode *mode,1079 unsigned long max_bpp)1080{1081 struct drm_vram_mm *vmm = dev->vram_mm;1082 unsigned long fbsize, fbpages, max_fbpages;1083 1084 if (WARN_ON(!dev->vram_mm))1085 return MODE_BAD;1086 1087 max_fbpages = (vmm->vram_size / 2) >> PAGE_SHIFT;1088 1089 fbsize = mode->hdisplay * mode->vdisplay * max_bpp;1090 fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE);1091 1092 if (fbpages > max_fbpages)1093 return MODE_MEM;1094 1095 return MODE_OK;1096}1097 1098/**1099 * drm_vram_helper_mode_valid - Tests if a display mode's1100 * framebuffer fits into the available video memory.1101 * @dev: the DRM device1102 * @mode: the mode to test1103 *1104 * This function tests if enough video memory is available for using the1105 * specified display mode. Atomic modesetting requires importing the1106 * designated framebuffer into video memory before evicting the active1107 * one. Hence, any framebuffer may consume at most half of the available1108 * VRAM. Display modes that require a larger framebuffer can not be used,1109 * even if the CRTC does support them. Each framebuffer is assumed to1110 * have 32-bit color depth.1111 *1112 * Note:1113 * The function can only test if the display mode is supported in1114 * general. If there are too many framebuffers pinned to video memory,1115 * a display mode may still not be usable in practice. The color depth of1116 * 32-bit fits all current use case. A more flexible test can be added1117 * when necessary.1118 *1119 * Returns:1120 * MODE_OK if the display mode is supported, or an error code of type1121 * enum drm_mode_status otherwise.1122 */1123enum drm_mode_status1124drm_vram_helper_mode_valid(struct drm_device *dev,1125 const struct drm_display_mode *mode)1126{1127 static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGB8888 */1128 1129 return drm_vram_helper_mode_valid_internal(dev, mode, max_bpp);1130}1131EXPORT_SYMBOL(drm_vram_helper_mode_valid);1132 1133MODULE_DESCRIPTION("DRM VRAM memory-management helpers");1134MODULE_LICENSE("GPL");1135