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

Configure Feed

Select the types of activity you want to include in your feed.

drm/vmwgfx: Refactor cursor handling

Refactor cursor handling to make the code maintainable again. Over the
last 12 years the svga device improved support for virtualized cursors
and at the same time the drm interfaces evolved quite a bit from
pre-atomic to current atomic ones. vmwgfx only added new code over
the years, instead of adjusting/refactoring the paths.

Export the cursor plane handling to its own file. Remove special
handling of the legacy cursor support to make it fit within the global
cursor plane mechanism.

Finally redo dirty tracking because memcmp never worked correctly
resulting in the cursor not being properly updated in the guest.

Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Reviewed-by: Maaz Mombasawala <maaz.mombasawala@broadcom.com>
Reviewed-by: Martin Krastev <martin.krastev@broadcom.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250307125836.3877138-2-zack.rusin@broadcom.com

+1042 -1064
+1 -1
drivers/gpu/drm/vmwgfx/Makefile
··· 10 10 vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o \ 11 11 vmwgfx_validation.o vmwgfx_page_dirty.o vmwgfx_streamoutput.o \ 12 12 vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \ 13 - vmwgfx_gem.o vmwgfx_vkms.o 13 + vmwgfx_gem.o vmwgfx_vkms.o vmwgfx_cursor_plane.o 14 14 15 15 obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
+6
drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
··· 887 887 surf = vmw_res_to_srf(res); 888 888 return surf; 889 889 } 890 + 891 + s32 vmw_bo_mobid(struct vmw_bo *vbo) 892 + { 893 + WARN_ON(vbo->tbo.resource->mem_type != VMW_PL_MOB); 894 + return (s32)vbo->tbo.resource->start; 895 + }
+2
drivers/gpu/drm/vmwgfx/vmwgfx_bo.h
··· 233 233 return container_of((gobj), struct vmw_bo, tbo.base); 234 234 } 235 235 236 + s32 vmw_bo_mobid(struct vmw_bo *vbo); 237 + 236 238 #endif // VMWGFX_BO_H
+844
drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR MIT 2 + /************************************************************************** 3 + * 4 + * Copyright (c) 2024-2025 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 6 + * 7 + **************************************************************************/ 8 + #include "vmwgfx_cursor_plane.h" 9 + 10 + #include "vmwgfx_bo.h" 11 + #include "vmwgfx_drv.h" 12 + #include "vmwgfx_kms.h" 13 + #include "vmwgfx_resource_priv.h" 14 + #include "vmw_surface_cache.h" 15 + 16 + #include "drm/drm_atomic.h" 17 + #include "drm/drm_atomic_helper.h" 18 + #include "drm/drm_plane.h" 19 + #include <asm/page.h> 20 + 21 + #define VMW_CURSOR_SNOOP_FORMAT SVGA3D_A8R8G8B8 22 + #define VMW_CURSOR_SNOOP_WIDTH 64 23 + #define VMW_CURSOR_SNOOP_HEIGHT 64 24 + 25 + struct vmw_svga_fifo_cmd_define_cursor { 26 + u32 cmd; 27 + SVGAFifoCmdDefineAlphaCursor cursor; 28 + }; 29 + 30 + /** 31 + * vmw_send_define_cursor_cmd - queue a define cursor command 32 + * @dev_priv: the private driver struct 33 + * @image: buffer which holds the cursor image 34 + * @width: width of the mouse cursor image 35 + * @height: height of the mouse cursor image 36 + * @hotspotX: the horizontal position of mouse hotspot 37 + * @hotspotY: the vertical position of mouse hotspot 38 + */ 39 + static void vmw_send_define_cursor_cmd(struct vmw_private *dev_priv, 40 + u32 *image, u32 width, u32 height, 41 + u32 hotspotX, u32 hotspotY) 42 + { 43 + struct vmw_svga_fifo_cmd_define_cursor *cmd; 44 + const u32 image_size = width * height * sizeof(*image); 45 + const u32 cmd_size = sizeof(*cmd) + image_size; 46 + 47 + /* 48 + * Try to reserve fifocmd space and swallow any failures; 49 + * such reservations cannot be left unconsumed for long 50 + * under the risk of clogging other fifocmd users, so 51 + * we treat reservations separtely from the way we treat 52 + * other fallible KMS-atomic resources at prepare_fb 53 + */ 54 + cmd = VMW_CMD_RESERVE(dev_priv, cmd_size); 55 + 56 + if (unlikely(!cmd)) 57 + return; 58 + 59 + memset(cmd, 0, sizeof(*cmd)); 60 + 61 + memcpy(&cmd[1], image, image_size); 62 + 63 + cmd->cmd = SVGA_CMD_DEFINE_ALPHA_CURSOR; 64 + cmd->cursor.id = 0; 65 + cmd->cursor.width = width; 66 + cmd->cursor.height = height; 67 + cmd->cursor.hotspotX = hotspotX; 68 + cmd->cursor.hotspotY = hotspotY; 69 + 70 + vmw_cmd_commit_flush(dev_priv, cmd_size); 71 + } 72 + 73 + static void 74 + vmw_cursor_plane_update_legacy(struct vmw_private *vmw, 75 + struct vmw_plane_state *vps) 76 + { 77 + struct vmw_surface *surface = vmw_user_object_surface(&vps->uo); 78 + s32 hotspot_x = vps->cursor.legacy.hotspot_x + vps->base.hotspot_x; 79 + s32 hotspot_y = vps->cursor.legacy.hotspot_y + vps->base.hotspot_y; 80 + 81 + if (WARN_ON(!surface || !surface->snooper.image)) 82 + return; 83 + 84 + if (vps->cursor.legacy.id != surface->snooper.id) { 85 + vmw_send_define_cursor_cmd(vmw, surface->snooper.image, 86 + vps->base.crtc_w, vps->base.crtc_h, 87 + hotspot_x, hotspot_y); 88 + vps->cursor.legacy.id = surface->snooper.id; 89 + } 90 + } 91 + 92 + static enum vmw_cursor_update_type 93 + vmw_cursor_update_type(struct vmw_private *vmw, struct vmw_plane_state *vps) 94 + { 95 + struct vmw_surface *surface = vmw_user_object_surface(&vps->uo); 96 + 97 + if (surface && surface->snooper.image) 98 + return VMW_CURSOR_UPDATE_LEGACY; 99 + 100 + if (vmw->has_mob) { 101 + if ((vmw->capabilities2 & SVGA_CAP2_CURSOR_MOB) != 0) 102 + return VMW_CURSOR_UPDATE_MOB; 103 + } 104 + 105 + return VMW_CURSOR_UPDATE_NONE; 106 + } 107 + 108 + static void vmw_cursor_update_mob(struct vmw_private *vmw, 109 + struct vmw_plane_state *vps) 110 + { 111 + SVGAGBCursorHeader *header; 112 + SVGAGBAlphaCursorHeader *alpha_header; 113 + struct vmw_bo *bo = vmw_user_object_buffer(&vps->uo); 114 + u32 *image = vmw_bo_map_and_cache(bo); 115 + const u32 image_size = vps->base.crtc_w * vps->base.crtc_h * sizeof(*image); 116 + 117 + header = vmw_bo_map_and_cache(vps->cursor.mob); 118 + alpha_header = &header->header.alphaHeader; 119 + 120 + memset(header, 0, sizeof(*header)); 121 + 122 + header->type = SVGA_ALPHA_CURSOR; 123 + header->sizeInBytes = image_size; 124 + 125 + alpha_header->hotspotX = vps->cursor.legacy.hotspot_x + vps->base.hotspot_x; 126 + alpha_header->hotspotY = vps->cursor.legacy.hotspot_y + vps->base.hotspot_y; 127 + alpha_header->width = vps->base.crtc_w; 128 + alpha_header->height = vps->base.crtc_h; 129 + 130 + memcpy(header + 1, image, image_size); 131 + vmw_write(vmw, SVGA_REG_CURSOR_MOBID, vmw_bo_mobid(vps->cursor.mob)); 132 + 133 + vmw_bo_unmap(bo); 134 + vmw_bo_unmap(vps->cursor.mob); 135 + } 136 + 137 + static u32 vmw_cursor_mob_size(enum vmw_cursor_update_type update_type, 138 + u32 w, u32 h) 139 + { 140 + switch (update_type) { 141 + case VMW_CURSOR_UPDATE_LEGACY: 142 + case VMW_CURSOR_UPDATE_NONE: 143 + return 0; 144 + case VMW_CURSOR_UPDATE_MOB: 145 + return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader); 146 + } 147 + return 0; 148 + } 149 + 150 + static void vmw_cursor_mob_destroy(struct vmw_bo **vbo) 151 + { 152 + if (!(*vbo)) 153 + return; 154 + 155 + ttm_bo_unpin(&(*vbo)->tbo); 156 + vmw_bo_unreference(vbo); 157 + } 158 + 159 + /** 160 + * vmw_cursor_mob_unmap - Unmaps the cursor mobs. 161 + * 162 + * @vps: state of the cursor plane 163 + * 164 + * Returns 0 on success 165 + */ 166 + 167 + static int 168 + vmw_cursor_mob_unmap(struct vmw_plane_state *vps) 169 + { 170 + int ret = 0; 171 + struct vmw_bo *vbo = vps->cursor.mob; 172 + 173 + if (!vbo || !vbo->map.virtual) 174 + return 0; 175 + 176 + ret = ttm_bo_reserve(&vbo->tbo, true, false, NULL); 177 + if (likely(ret == 0)) { 178 + vmw_bo_unmap(vbo); 179 + ttm_bo_unreserve(&vbo->tbo); 180 + } 181 + 182 + return ret; 183 + } 184 + 185 + static void vmw_cursor_mob_put(struct vmw_cursor_plane *vcp, 186 + struct vmw_plane_state *vps) 187 + { 188 + u32 i; 189 + 190 + if (!vps->cursor.mob) 191 + return; 192 + 193 + vmw_cursor_mob_unmap(vps); 194 + 195 + /* Look for a free slot to return this mob to the cache. */ 196 + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 197 + if (!vcp->cursor_mobs[i]) { 198 + vcp->cursor_mobs[i] = vps->cursor.mob; 199 + vps->cursor.mob = NULL; 200 + return; 201 + } 202 + } 203 + 204 + /* Cache is full: See if this mob is bigger than an existing mob. */ 205 + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 206 + if (vcp->cursor_mobs[i]->tbo.base.size < 207 + vps->cursor.mob->tbo.base.size) { 208 + vmw_cursor_mob_destroy(&vcp->cursor_mobs[i]); 209 + vcp->cursor_mobs[i] = vps->cursor.mob; 210 + vps->cursor.mob = NULL; 211 + return; 212 + } 213 + } 214 + 215 + /* Destroy it if it's not worth caching. */ 216 + vmw_cursor_mob_destroy(&vps->cursor.mob); 217 + } 218 + 219 + static int vmw_cursor_mob_get(struct vmw_cursor_plane *vcp, 220 + struct vmw_plane_state *vps) 221 + { 222 + struct vmw_private *dev_priv = vmw_priv(vcp->base.dev); 223 + u32 size = vmw_cursor_mob_size(vps->cursor.update_type, 224 + vps->base.crtc_w, vps->base.crtc_h); 225 + u32 i; 226 + u32 cursor_max_dim, mob_max_size; 227 + struct vmw_fence_obj *fence = NULL; 228 + int ret; 229 + 230 + if (!dev_priv->has_mob || 231 + (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0) 232 + return -EINVAL; 233 + 234 + mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); 235 + cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION); 236 + 237 + if (size > mob_max_size || vps->base.crtc_w > cursor_max_dim || 238 + vps->base.crtc_h > cursor_max_dim) 239 + return -EINVAL; 240 + 241 + if (vps->cursor.mob) { 242 + if (vps->cursor.mob->tbo.base.size >= size) 243 + return 0; 244 + vmw_cursor_mob_put(vcp, vps); 245 + } 246 + 247 + /* Look for an unused mob in the cache. */ 248 + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 249 + if (vcp->cursor_mobs[i] && 250 + vcp->cursor_mobs[i]->tbo.base.size >= size) { 251 + vps->cursor.mob = vcp->cursor_mobs[i]; 252 + vcp->cursor_mobs[i] = NULL; 253 + return 0; 254 + } 255 + } 256 + /* Create a new mob if we can't find an existing one. */ 257 + ret = vmw_bo_create_and_populate(dev_priv, size, VMW_BO_DOMAIN_MOB, 258 + &vps->cursor.mob); 259 + 260 + if (ret != 0) 261 + return ret; 262 + 263 + /* Fence the mob creation so we are guarateed to have the mob */ 264 + ret = ttm_bo_reserve(&vps->cursor.mob->tbo, false, false, NULL); 265 + if (ret != 0) 266 + goto teardown; 267 + 268 + ret = vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 269 + if (ret != 0) { 270 + ttm_bo_unreserve(&vps->cursor.mob->tbo); 271 + goto teardown; 272 + } 273 + 274 + dma_fence_wait(&fence->base, false); 275 + dma_fence_put(&fence->base); 276 + 277 + ttm_bo_unreserve(&vps->cursor.mob->tbo); 278 + 279 + return 0; 280 + 281 + teardown: 282 + vmw_cursor_mob_destroy(&vps->cursor.mob); 283 + return ret; 284 + } 285 + 286 + static void vmw_cursor_update_position(struct vmw_private *dev_priv, 287 + bool show, int x, int y) 288 + { 289 + const u32 svga_cursor_on = show ? SVGA_CURSOR_ON_SHOW 290 + : SVGA_CURSOR_ON_HIDE; 291 + u32 count; 292 + 293 + spin_lock(&dev_priv->cursor_lock); 294 + if (dev_priv->capabilities2 & SVGA_CAP2_EXTRA_REGS) { 295 + vmw_write(dev_priv, SVGA_REG_CURSOR4_X, x); 296 + vmw_write(dev_priv, SVGA_REG_CURSOR4_Y, y); 297 + vmw_write(dev_priv, SVGA_REG_CURSOR4_SCREEN_ID, SVGA3D_INVALID_ID); 298 + vmw_write(dev_priv, SVGA_REG_CURSOR4_ON, svga_cursor_on); 299 + vmw_write(dev_priv, SVGA_REG_CURSOR4_SUBMIT, 1); 300 + } else if (vmw_is_cursor_bypass3_enabled(dev_priv)) { 301 + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, svga_cursor_on); 302 + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_X, x); 303 + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_Y, y); 304 + count = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CURSOR_COUNT); 305 + vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_COUNT, ++count); 306 + } else { 307 + vmw_write(dev_priv, SVGA_REG_CURSOR_X, x); 308 + vmw_write(dev_priv, SVGA_REG_CURSOR_Y, y); 309 + vmw_write(dev_priv, SVGA_REG_CURSOR_ON, svga_cursor_on); 310 + } 311 + spin_unlock(&dev_priv->cursor_lock); 312 + } 313 + 314 + void vmw_kms_cursor_snoop(struct vmw_surface *srf, 315 + struct ttm_object_file *tfile, 316 + struct ttm_buffer_object *bo, 317 + SVGA3dCmdHeader *header) 318 + { 319 + struct ttm_bo_kmap_obj map; 320 + unsigned long kmap_offset; 321 + unsigned long kmap_num; 322 + SVGA3dCopyBox *box; 323 + u32 box_count; 324 + void *virtual; 325 + bool is_iomem; 326 + struct vmw_dma_cmd { 327 + SVGA3dCmdHeader header; 328 + SVGA3dCmdSurfaceDMA dma; 329 + } *cmd; 330 + int i, ret; 331 + const struct SVGA3dSurfaceDesc *desc = 332 + vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 333 + const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock; 334 + 335 + cmd = container_of(header, struct vmw_dma_cmd, header); 336 + 337 + /* No snooper installed, nothing to copy */ 338 + if (!srf->snooper.image) 339 + return; 340 + 341 + if (cmd->dma.host.face != 0 || cmd->dma.host.mipmap != 0) { 342 + DRM_ERROR("face and mipmap for cursors should never != 0\n"); 343 + return; 344 + } 345 + 346 + if (cmd->header.size < 64) { 347 + DRM_ERROR("at least one full copy box must be given\n"); 348 + return; 349 + } 350 + 351 + box = (SVGA3dCopyBox *)&cmd[1]; 352 + box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) / 353 + sizeof(SVGA3dCopyBox); 354 + 355 + if (cmd->dma.guest.ptr.offset % PAGE_SIZE || 356 + box->x != 0 || box->y != 0 || box->z != 0 || 357 + box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || 358 + box->d != 1 || box_count != 1 || 359 + box->w > VMW_CURSOR_SNOOP_WIDTH || box->h > VMW_CURSOR_SNOOP_HEIGHT) { 360 + /* TODO handle none page aligned offsets */ 361 + /* TODO handle more dst & src != 0 */ 362 + /* TODO handle more then one copy */ 363 + DRM_ERROR("Can't snoop dma request for cursor!\n"); 364 + DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n", 365 + box->srcx, box->srcy, box->srcz, 366 + box->x, box->y, box->z, 367 + box->w, box->h, box->d, box_count, 368 + cmd->dma.guest.ptr.offset); 369 + return; 370 + } 371 + 372 + kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT; 373 + kmap_num = (VMW_CURSOR_SNOOP_HEIGHT * image_pitch) >> PAGE_SHIFT; 374 + 375 + ret = ttm_bo_reserve(bo, true, false, NULL); 376 + if (unlikely(ret != 0)) { 377 + DRM_ERROR("reserve failed\n"); 378 + return; 379 + } 380 + 381 + ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map); 382 + if (unlikely(ret != 0)) 383 + goto err_unreserve; 384 + 385 + virtual = ttm_kmap_obj_virtual(&map, &is_iomem); 386 + 387 + if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) { 388 + memcpy(srf->snooper.image, virtual, 389 + VMW_CURSOR_SNOOP_HEIGHT * image_pitch); 390 + } else { 391 + /* Image is unsigned pointer. */ 392 + for (i = 0; i < box->h; i++) 393 + memcpy(srf->snooper.image + i * image_pitch, 394 + virtual + i * cmd->dma.guest.pitch, 395 + box->w * desc->pitchBytesPerBlock); 396 + } 397 + srf->snooper.id++; 398 + 399 + ttm_bo_kunmap(&map); 400 + err_unreserve: 401 + ttm_bo_unreserve(bo); 402 + } 403 + 404 + void vmw_cursor_plane_destroy(struct drm_plane *plane) 405 + { 406 + struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 407 + u32 i; 408 + 409 + vmw_cursor_update_position(vmw_priv(plane->dev), false, 0, 0); 410 + 411 + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) 412 + vmw_cursor_mob_destroy(&vcp->cursor_mobs[i]); 413 + 414 + drm_plane_cleanup(plane); 415 + } 416 + 417 + /** 418 + * vmw_cursor_mob_map - Maps the cursor mobs. 419 + * 420 + * @vps: plane_state 421 + * 422 + * Returns 0 on success 423 + */ 424 + 425 + static int 426 + vmw_cursor_mob_map(struct vmw_plane_state *vps) 427 + { 428 + int ret; 429 + u32 size = vmw_cursor_mob_size(vps->cursor.update_type, 430 + vps->base.crtc_w, vps->base.crtc_h); 431 + struct vmw_bo *vbo = vps->cursor.mob; 432 + 433 + if (!vbo) 434 + return -EINVAL; 435 + 436 + if (vbo->tbo.base.size < size) 437 + return -EINVAL; 438 + 439 + if (vbo->map.virtual) 440 + return 0; 441 + 442 + ret = ttm_bo_reserve(&vbo->tbo, false, false, NULL); 443 + if (unlikely(ret != 0)) 444 + return -ENOMEM; 445 + 446 + vmw_bo_map_and_cache(vbo); 447 + 448 + ttm_bo_unreserve(&vbo->tbo); 449 + 450 + return 0; 451 + } 452 + 453 + /** 454 + * vmw_cursor_plane_cleanup_fb - Unpins the plane surface 455 + * 456 + * @plane: cursor plane 457 + * @old_state: contains the state to clean up 458 + * 459 + * Unmaps all cursor bo mappings and unpins the cursor surface 460 + * 461 + * Returns 0 on success 462 + */ 463 + void 464 + vmw_cursor_plane_cleanup_fb(struct drm_plane *plane, 465 + struct drm_plane_state *old_state) 466 + { 467 + struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 468 + struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 469 + 470 + if (!vmw_user_object_is_null(&vps->uo)) 471 + vmw_user_object_unmap(&vps->uo); 472 + 473 + vmw_cursor_mob_unmap(vps); 474 + vmw_cursor_mob_put(vcp, vps); 475 + 476 + vmw_du_plane_unpin_surf(vps); 477 + vmw_user_object_unref(&vps->uo); 478 + } 479 + 480 + static bool 481 + vmw_cursor_buffer_changed(struct vmw_plane_state *new_vps, 482 + struct vmw_plane_state *old_vps) 483 + { 484 + struct vmw_bo *new_bo = vmw_user_object_buffer(&new_vps->uo); 485 + struct vmw_bo *old_bo = vmw_user_object_buffer(&old_vps->uo); 486 + struct vmw_surface *surf; 487 + bool dirty = false; 488 + int ret; 489 + 490 + if (new_bo != old_bo) 491 + return true; 492 + 493 + if (new_bo) { 494 + if (!old_bo) { 495 + return true; 496 + } else if (new_bo->dirty) { 497 + vmw_bo_dirty_scan(new_bo); 498 + dirty = vmw_bo_is_dirty(new_bo); 499 + if (dirty) { 500 + surf = vmw_user_object_surface(&new_vps->uo); 501 + if (surf) 502 + vmw_bo_dirty_transfer_to_res(&surf->res); 503 + else 504 + vmw_bo_dirty_clear(new_bo); 505 + } 506 + return dirty; 507 + } else if (new_bo != old_bo) { 508 + /* 509 + * Currently unused because the top exits right away. 510 + * In most cases buffer being different will mean 511 + * that the contents is different. For the few percent 512 + * of cases where that's not true the cost of doing 513 + * the memcmp on all other seems to outweight the 514 + * benefits. Leave the conditional to be able to 515 + * trivially validate it by removing the initial 516 + * if (new_bo != old_bo) at the start. 517 + */ 518 + void *old_image; 519 + void *new_image; 520 + bool changed = false; 521 + struct ww_acquire_ctx ctx; 522 + const u32 size = new_vps->base.crtc_w * 523 + new_vps->base.crtc_h * sizeof(u32); 524 + 525 + ww_acquire_init(&ctx, &reservation_ww_class); 526 + 527 + ret = ttm_bo_reserve(&old_bo->tbo, false, false, &ctx); 528 + if (ret != 0) { 529 + ww_acquire_fini(&ctx); 530 + return true; 531 + } 532 + 533 + ret = ttm_bo_reserve(&new_bo->tbo, false, false, &ctx); 534 + if (ret != 0) { 535 + ttm_bo_unreserve(&old_bo->tbo); 536 + ww_acquire_fini(&ctx); 537 + return true; 538 + } 539 + 540 + old_image = vmw_bo_map_and_cache(old_bo); 541 + new_image = vmw_bo_map_and_cache(new_bo); 542 + 543 + if (old_image && new_image && old_image != new_image) 544 + changed = memcmp(old_image, new_image, size) != 545 + 0; 546 + 547 + ttm_bo_unreserve(&new_bo->tbo); 548 + ttm_bo_unreserve(&old_bo->tbo); 549 + 550 + ww_acquire_fini(&ctx); 551 + 552 + return changed; 553 + } 554 + return false; 555 + } 556 + 557 + return false; 558 + } 559 + 560 + static bool 561 + vmw_cursor_plane_changed(struct vmw_plane_state *new_vps, 562 + struct vmw_plane_state *old_vps) 563 + { 564 + if (old_vps->base.crtc_w != new_vps->base.crtc_w || 565 + old_vps->base.crtc_h != new_vps->base.crtc_h) 566 + return true; 567 + 568 + if (old_vps->base.hotspot_x != new_vps->base.hotspot_x || 569 + old_vps->base.hotspot_y != new_vps->base.hotspot_y) 570 + return true; 571 + 572 + if (old_vps->cursor.legacy.hotspot_x != 573 + new_vps->cursor.legacy.hotspot_x || 574 + old_vps->cursor.legacy.hotspot_y != 575 + new_vps->cursor.legacy.hotspot_y) 576 + return true; 577 + 578 + if (old_vps->base.fb != new_vps->base.fb) 579 + return true; 580 + 581 + return false; 582 + } 583 + 584 + /** 585 + * vmw_cursor_plane_prepare_fb - Readies the cursor by referencing it 586 + * 587 + * @plane: display plane 588 + * @new_state: info on the new plane state, including the FB 589 + * 590 + * Returns 0 on success 591 + */ 592 + int vmw_cursor_plane_prepare_fb(struct drm_plane *plane, 593 + struct drm_plane_state *new_state) 594 + { 595 + struct drm_framebuffer *fb = new_state->fb; 596 + struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 597 + struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 598 + struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(plane->state); 599 + struct vmw_private *vmw = vmw_priv(plane->dev); 600 + struct vmw_bo *bo = NULL; 601 + struct vmw_surface *surface; 602 + int ret = 0; 603 + 604 + if (!vmw_user_object_is_null(&vps->uo)) { 605 + vmw_user_object_unmap(&vps->uo); 606 + vmw_user_object_unref(&vps->uo); 607 + } 608 + 609 + if (fb) { 610 + if (vmw_framebuffer_to_vfb(fb)->bo) { 611 + vps->uo.buffer = vmw_framebuffer_to_vfbd(fb)->buffer; 612 + vps->uo.surface = NULL; 613 + } else { 614 + memcpy(&vps->uo, &vmw_framebuffer_to_vfbs(fb)->uo, sizeof(vps->uo)); 615 + } 616 + vmw_user_object_ref(&vps->uo); 617 + } 618 + 619 + vps->cursor.update_type = vmw_cursor_update_type(vmw, vps); 620 + switch (vps->cursor.update_type) { 621 + case VMW_CURSOR_UPDATE_LEGACY: 622 + surface = vmw_user_object_surface(&vps->uo); 623 + if (!surface || vps->cursor.legacy.id == surface->snooper.id) 624 + vps->cursor.update_type = VMW_CURSOR_UPDATE_NONE; 625 + break; 626 + case VMW_CURSOR_UPDATE_MOB: { 627 + bo = vmw_user_object_buffer(&vps->uo); 628 + if (bo) { 629 + struct ttm_operation_ctx ctx = { false, false }; 630 + 631 + ret = ttm_bo_reserve(&bo->tbo, true, false, NULL); 632 + if (ret != 0) 633 + return -ENOMEM; 634 + 635 + ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 636 + if (ret != 0) 637 + return -ENOMEM; 638 + 639 + /* 640 + * vmw_bo_pin_reserved also validates, so to skip 641 + * the extra validation use ttm_bo_pin directly 642 + */ 643 + if (!bo->tbo.pin_count) 644 + ttm_bo_pin(&bo->tbo); 645 + 646 + if (vmw_framebuffer_to_vfb(fb)->bo) { 647 + const u32 size = new_state->crtc_w * 648 + new_state->crtc_h * 649 + sizeof(u32); 650 + 651 + (void)vmw_bo_map_and_cache_size(bo, size); 652 + } else { 653 + vmw_bo_map_and_cache(bo); 654 + } 655 + ttm_bo_unreserve(&bo->tbo); 656 + } 657 + if (!vmw_user_object_is_null(&vps->uo)) { 658 + if (!vmw_cursor_plane_changed(vps, old_vps) && 659 + !vmw_cursor_buffer_changed(vps, old_vps)) { 660 + vps->cursor.update_type = 661 + VMW_CURSOR_UPDATE_NONE; 662 + } else { 663 + vmw_cursor_mob_get(vcp, vps); 664 + vmw_cursor_mob_map(vps); 665 + } 666 + } 667 + } 668 + break; 669 + case VMW_CURSOR_UPDATE_NONE: 670 + /* do nothing */ 671 + break; 672 + } 673 + 674 + return 0; 675 + } 676 + 677 + /** 678 + * vmw_cursor_plane_atomic_check - check if the new state is okay 679 + * 680 + * @plane: cursor plane 681 + * @state: info on the new plane state 682 + * 683 + * This is a chance to fail if the new cursor state does not fit 684 + * our requirements. 685 + * 686 + * Returns 0 on success 687 + */ 688 + int vmw_cursor_plane_atomic_check(struct drm_plane *plane, 689 + struct drm_atomic_state *state) 690 + { 691 + struct drm_plane_state *new_state = 692 + drm_atomic_get_new_plane_state(state, plane); 693 + struct vmw_private *vmw = vmw_priv(plane->dev); 694 + int ret = 0; 695 + struct drm_crtc_state *crtc_state = NULL; 696 + struct vmw_surface *surface = NULL; 697 + struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 698 + enum vmw_cursor_update_type update_type; 699 + struct drm_framebuffer *fb = new_state->fb; 700 + 701 + if (new_state->crtc) 702 + crtc_state = drm_atomic_get_new_crtc_state(new_state->state, 703 + new_state->crtc); 704 + 705 + ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, 706 + DRM_PLANE_NO_SCALING, 707 + DRM_PLANE_NO_SCALING, true, 708 + true); 709 + if (ret) 710 + return ret; 711 + 712 + /* Turning off */ 713 + if (!fb) 714 + return 0; 715 + 716 + update_type = vmw_cursor_update_type(vmw, vps); 717 + if (update_type == VMW_CURSOR_UPDATE_LEGACY) { 718 + if (new_state->crtc_w != VMW_CURSOR_SNOOP_WIDTH || 719 + new_state->crtc_h != VMW_CURSOR_SNOOP_HEIGHT) { 720 + drm_warn(&vmw->drm, 721 + "Invalid cursor dimensions (%d, %d)\n", 722 + new_state->crtc_w, new_state->crtc_h); 723 + return -EINVAL; 724 + } 725 + surface = vmw_user_object_surface(&vps->uo); 726 + if (!surface || !surface->snooper.image) { 727 + drm_warn(&vmw->drm, 728 + "surface not suitable for cursor\n"); 729 + return -EINVAL; 730 + } 731 + } 732 + 733 + return 0; 734 + } 735 + 736 + void 737 + vmw_cursor_plane_atomic_update(struct drm_plane *plane, 738 + struct drm_atomic_state *state) 739 + { 740 + struct drm_plane_state *new_state = 741 + drm_atomic_get_new_plane_state(state, plane); 742 + struct drm_plane_state *old_state = 743 + drm_atomic_get_old_plane_state(state, plane); 744 + struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc; 745 + struct vmw_private *dev_priv = vmw_priv(plane->dev); 746 + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 747 + struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 748 + s32 hotspot_x, hotspot_y, cursor_x, cursor_y; 749 + 750 + /* 751 + * Hide the cursor if the new bo is null 752 + */ 753 + if (vmw_user_object_is_null(&vps->uo)) { 754 + vmw_cursor_update_position(dev_priv, false, 0, 0); 755 + return; 756 + } 757 + 758 + switch (vps->cursor.update_type) { 759 + case VMW_CURSOR_UPDATE_LEGACY: 760 + vmw_cursor_plane_update_legacy(dev_priv, vps); 761 + break; 762 + case VMW_CURSOR_UPDATE_MOB: 763 + vmw_cursor_update_mob(dev_priv, vps); 764 + break; 765 + case VMW_CURSOR_UPDATE_NONE: 766 + /* do nothing */ 767 + break; 768 + } 769 + 770 + /* 771 + * For all update types update the cursor position 772 + */ 773 + cursor_x = new_state->crtc_x + du->set_gui_x; 774 + cursor_y = new_state->crtc_y + du->set_gui_y; 775 + 776 + hotspot_x = vps->cursor.legacy.hotspot_x + new_state->hotspot_x; 777 + hotspot_y = vps->cursor.legacy.hotspot_y + new_state->hotspot_y; 778 + 779 + vmw_cursor_update_position(dev_priv, true, cursor_x + hotspot_x, 780 + cursor_y + hotspot_y); 781 + } 782 + 783 + int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, 784 + struct drm_file *file_priv) 785 + { 786 + struct drm_vmw_cursor_bypass_arg *arg = data; 787 + struct vmw_display_unit *du; 788 + struct vmw_plane_state *vps; 789 + struct drm_crtc *crtc; 790 + int ret = 0; 791 + 792 + mutex_lock(&dev->mode_config.mutex); 793 + if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) { 794 + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 795 + du = vmw_crtc_to_du(crtc); 796 + vps = vmw_plane_state_to_vps(du->cursor.base.state); 797 + vps->cursor.legacy.hotspot_x = arg->xhot; 798 + vps->cursor.legacy.hotspot_y = arg->yhot; 799 + } 800 + 801 + mutex_unlock(&dev->mode_config.mutex); 802 + return 0; 803 + } 804 + 805 + crtc = drm_crtc_find(dev, file_priv, arg->crtc_id); 806 + if (!crtc) { 807 + ret = -ENOENT; 808 + goto out; 809 + } 810 + 811 + du = vmw_crtc_to_du(crtc); 812 + vps = vmw_plane_state_to_vps(du->cursor.base.state); 813 + vps->cursor.legacy.hotspot_x = arg->xhot; 814 + vps->cursor.legacy.hotspot_y = arg->yhot; 815 + 816 + out: 817 + mutex_unlock(&dev->mode_config.mutex); 818 + 819 + return ret; 820 + } 821 + 822 + void *vmw_cursor_snooper_create(struct drm_file *file_priv, 823 + struct vmw_surface_metadata *metadata) 824 + { 825 + if (!file_priv->atomic && metadata->scanout && 826 + metadata->num_sizes == 1 && 827 + metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH && 828 + metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT && 829 + metadata->format == VMW_CURSOR_SNOOP_FORMAT) { 830 + const struct SVGA3dSurfaceDesc *desc = 831 + vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 832 + const u32 cursor_size_bytes = VMW_CURSOR_SNOOP_WIDTH * 833 + VMW_CURSOR_SNOOP_HEIGHT * 834 + desc->pitchBytesPerBlock; 835 + void *image = kzalloc(cursor_size_bytes, GFP_KERNEL); 836 + 837 + if (!image) { 838 + DRM_ERROR("Failed to allocate cursor_image\n"); 839 + return ERR_PTR(-ENOMEM); 840 + } 841 + return image; 842 + } 843 + return NULL; 844 + }
+81
drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 + /************************************************************************** 3 + * 4 + * Copyright (c) 2024-2025 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 6 + * 7 + **************************************************************************/ 8 + 9 + #ifndef VMWGFX_CURSOR_PLANE_H 10 + #define VMWGFX_CURSOR_PLANE_H 11 + 12 + #include "device_include/svga3d_cmd.h" 13 + #include "drm/drm_file.h" 14 + #include "drm/drm_fourcc.h" 15 + #include "drm/drm_plane.h" 16 + 17 + #include <linux/types.h> 18 + 19 + struct SVGA3dCmdHeader; 20 + struct ttm_buffer_object; 21 + struct vmw_bo; 22 + struct vmw_cursor; 23 + struct vmw_private; 24 + struct vmw_surface; 25 + struct vmw_user_object; 26 + 27 + #define vmw_plane_to_vcp(x) container_of(x, struct vmw_cursor_plane, base) 28 + 29 + static const u32 __maybe_unused vmw_cursor_plane_formats[] = { 30 + DRM_FORMAT_ARGB8888, 31 + }; 32 + 33 + enum vmw_cursor_update_type { 34 + VMW_CURSOR_UPDATE_NONE = 0, 35 + VMW_CURSOR_UPDATE_LEGACY, 36 + VMW_CURSOR_UPDATE_MOB, 37 + }; 38 + 39 + struct vmw_cursor_plane_state { 40 + enum vmw_cursor_update_type update_type; 41 + bool changed; 42 + bool surface_changed; 43 + struct vmw_bo *mob; 44 + struct { 45 + s32 hotspot_x; 46 + s32 hotspot_y; 47 + u32 id; 48 + } legacy; 49 + }; 50 + 51 + /** 52 + * Derived class for cursor plane object 53 + * 54 + * @base DRM plane object 55 + * @cursor.cursor_mobs Cursor mobs available for re-use 56 + */ 57 + struct vmw_cursor_plane { 58 + struct drm_plane base; 59 + 60 + struct vmw_bo *cursor_mobs[3]; 61 + }; 62 + 63 + struct vmw_surface_metadata; 64 + void *vmw_cursor_snooper_create(struct drm_file *file_priv, 65 + struct vmw_surface_metadata *metadata); 66 + void vmw_cursor_cmd_dma_snoop(SVGA3dCmdHeader *header, 67 + struct vmw_surface *srf, 68 + struct ttm_buffer_object *bo); 69 + 70 + void vmw_cursor_plane_destroy(struct drm_plane *plane); 71 + 72 + int vmw_cursor_plane_atomic_check(struct drm_plane *plane, 73 + struct drm_atomic_state *state); 74 + void vmw_cursor_plane_atomic_update(struct drm_plane *plane, 75 + struct drm_atomic_state *state); 76 + int vmw_cursor_plane_prepare_fb(struct drm_plane *plane, 77 + struct drm_plane_state *new_state); 78 + void vmw_cursor_plane_cleanup_fb(struct drm_plane *plane, 79 + struct drm_plane_state *old_state); 80 + 81 + #endif /* VMWGFX_CURSOR_H */
+2 -25
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 5 - * 6 - * Permission is hereby granted, free of charge, to any person obtaining a 7 - * copy of this software and associated documentation files (the 8 - * "Software"), to deal in the Software without restriction, including 9 - * without limitation the rights to use, copy, modify, merge, publish, 10 - * distribute, sub license, and/or sell copies of the Software, and to 11 - * permit persons to whom the Software is furnished to do so, subject to 12 - * the following conditions: 13 - * 14 - * The above copyright notice and this permission notice (including the 15 - * next paragraph) shall be included in all copies or substantial portions 16 - * of the Software. 17 - * 18 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 4 + * Copyright (c) 2009-2025 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 25 6 * 26 7 **************************************************************************/ 27 - 28 8 29 9 #include "vmwgfx_drv.h" 30 10 ··· 1304 1324 static void vmw_master_drop(struct drm_device *dev, 1305 1325 struct drm_file *file_priv) 1306 1326 { 1307 - struct vmw_private *dev_priv = vmw_priv(dev); 1308 - 1309 - vmw_kms_legacy_hotspot_clear(dev_priv); 1310 1327 } 1311 1328 1312 1329 bool vmwgfx_supported(struct vmw_private *vmw)
+4 -28
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 2 /************************************************************************** 3 3 * 4 - * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 4 + * Copyright (c) 2009-2025 Broadcom. All Rights Reserved. The term 5 5 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 6 - * 7 - * Permission is hereby granted, free of charge, to any person obtaining a 8 - * copy of this software and associated documentation files (the 9 - * "Software"), to deal in the Software without restriction, including 10 - * without limitation the rights to use, copy, modify, merge, publish, 11 - * distribute, sub license, and/or sell copies of the Software, and to 12 - * permit persons to whom the Software is furnished to do so, subject to 13 - * the following conditions: 14 - * 15 - * The above copyright notice and this permission notice (including the 16 - * next paragraph) shall be included in all copies or substantial portions 17 - * of the Software. 18 - * 19 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 6 * 27 7 **************************************************************************/ 28 8 ··· 79 99 #define VMW_RES_FENCE ttm_driver_type3 80 100 #define VMW_RES_SHADER ttm_driver_type4 81 101 #define VMW_RES_HT_ORDER 12 82 - 83 - #define VMW_CURSOR_SNOOP_FORMAT SVGA3D_A8R8G8B8 84 - #define VMW_CURSOR_SNOOP_WIDTH 64 85 - #define VMW_CURSOR_SNOOP_HEIGHT 64 86 102 87 103 #define MKSSTAT_CAPACITY_LOG2 5U 88 104 #define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2) ··· 177 201 struct vmw_cmdbuf_res_manager; 178 202 179 203 struct vmw_cursor_snooper { 180 - size_t age; 204 + size_t id; 181 205 uint32_t *image; 182 206 }; 183 207 ··· 1026 1050 int vmw_kms_close(struct vmw_private *dev_priv); 1027 1051 int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, 1028 1052 struct drm_file *file_priv); 1029 - void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv); 1030 1053 void vmw_kms_cursor_snoop(struct vmw_surface *srf, 1031 1054 struct ttm_object_file *tfile, 1032 1055 struct ttm_buffer_object *bo, ··· 1042 1067 uint32_t num_clips); 1043 1068 int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, 1044 1069 struct drm_file *file_priv); 1045 - void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv); 1046 1070 int vmw_kms_suspend(struct drm_device *dev); 1047 1071 int vmw_kms_resume(struct drm_device *dev); 1048 1072 void vmw_kms_lost_device(struct drm_device *dev); ··· 1367 1393 DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__) 1368 1394 1369 1395 /* Resource dirtying - vmwgfx_page_dirty.c */ 1396 + bool vmw_bo_is_dirty(struct vmw_bo *vbo); 1370 1397 void vmw_bo_dirty_scan(struct vmw_bo *vbo); 1371 1398 int vmw_bo_dirty_add(struct vmw_bo *vbo); 1399 + void vmw_bo_dirty_clear(struct vmw_bo *vbo); 1372 1400 void vmw_bo_dirty_transfer_to_res(struct vmw_resource *res); 1373 1401 void vmw_bo_dirty_clear_res(struct vmw_resource *res); 1374 1402 void vmw_bo_dirty_release(struct vmw_bo *vbo);
+3 -23
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009 - 2023 VMware, Inc., Palo Alto, CA., USA 5 - * 6 - * Permission is hereby granted, free of charge, to any person obtaining a 7 - * copy of this software and associated documentation files (the 8 - * "Software"), to deal in the Software without restriction, including 9 - * without limitation the rights to use, copy, modify, merge, publish, 10 - * distribute, sub license, and/or sell copies of the Software, and to 11 - * permit persons to whom the Software is furnished to do so, subject to 12 - * the following conditions: 13 - * 14 - * The above copyright notice and this permission notice (including the 15 - * next paragraph) shall be included in all copies or substantial portions 16 - * of the Software. 17 - * 18 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 4 + * Copyright (c) 2009-2025 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 25 6 * 26 7 **************************************************************************/ 8 + 27 9 #include "vmwgfx_binding.h" 28 10 #include "vmwgfx_bo.h" 29 11 #include "vmwgfx_drv.h" ··· 4493 4511 4494 4512 if (unlikely(ret != 0)) 4495 4513 goto out; 4496 - 4497 - vmw_kms_cursor_post_execbuf(dev_priv); 4498 4514 4499 4515 out: 4500 4516 if (in_fence)
+30 -844
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 4 + * Copyright (c) 2009-2025 Broadcom. All Rights Reserved. The term 5 5 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 6 6 * 7 - * Permission is hereby granted, free of charge, to any person obtaining a 8 - * copy of this software and associated documentation files (the 9 - * "Software"), to deal in the Software without restriction, including 10 - * without limitation the rights to use, copy, modify, merge, publish, 11 - * distribute, sub license, and/or sell copies of the Software, and to 12 - * permit persons to whom the Software is furnished to do so, subject to 13 - * the following conditions: 14 - * 15 - * The above copyright notice and this permission notice (including the 16 - * next paragraph) shall be included in all copies or substantial portions 17 - * of the Software. 18 - * 19 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 - * 27 7 **************************************************************************/ 8 + 28 9 #include "vmwgfx_kms.h" 29 10 30 11 #include "vmwgfx_bo.h" 12 + #include "vmwgfx_resource_priv.h" 31 13 #include "vmwgfx_vkms.h" 32 14 #include "vmw_surface_cache.h" 33 15 ··· 39 57 drm_crtc_cleanup(&du->crtc); 40 58 drm_encoder_cleanup(&du->encoder); 41 59 drm_connector_cleanup(&du->connector); 42 - } 43 - 44 - /* 45 - * Display Unit Cursor functions 46 - */ 47 - 48 - static int vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps); 49 - static void vmw_cursor_update_mob(struct vmw_private *dev_priv, 50 - struct vmw_plane_state *vps, 51 - u32 *image, u32 width, u32 height, 52 - u32 hotspotX, u32 hotspotY); 53 - 54 - struct vmw_svga_fifo_cmd_define_cursor { 55 - u32 cmd; 56 - SVGAFifoCmdDefineAlphaCursor cursor; 57 - }; 58 - 59 - /** 60 - * vmw_send_define_cursor_cmd - queue a define cursor command 61 - * @dev_priv: the private driver struct 62 - * @image: buffer which holds the cursor image 63 - * @width: width of the mouse cursor image 64 - * @height: height of the mouse cursor image 65 - * @hotspotX: the horizontal position of mouse hotspot 66 - * @hotspotY: the vertical position of mouse hotspot 67 - */ 68 - static void vmw_send_define_cursor_cmd(struct vmw_private *dev_priv, 69 - u32 *image, u32 width, u32 height, 70 - u32 hotspotX, u32 hotspotY) 71 - { 72 - struct vmw_svga_fifo_cmd_define_cursor *cmd; 73 - const u32 image_size = width * height * sizeof(*image); 74 - const u32 cmd_size = sizeof(*cmd) + image_size; 75 - 76 - /* Try to reserve fifocmd space and swallow any failures; 77 - such reservations cannot be left unconsumed for long 78 - under the risk of clogging other fifocmd users, so 79 - we treat reservations separtely from the way we treat 80 - other fallible KMS-atomic resources at prepare_fb */ 81 - cmd = VMW_CMD_RESERVE(dev_priv, cmd_size); 82 - 83 - if (unlikely(!cmd)) 84 - return; 85 - 86 - memset(cmd, 0, sizeof(*cmd)); 87 - 88 - memcpy(&cmd[1], image, image_size); 89 - 90 - cmd->cmd = SVGA_CMD_DEFINE_ALPHA_CURSOR; 91 - cmd->cursor.id = 0; 92 - cmd->cursor.width = width; 93 - cmd->cursor.height = height; 94 - cmd->cursor.hotspotX = hotspotX; 95 - cmd->cursor.hotspotY = hotspotY; 96 - 97 - vmw_cmd_commit_flush(dev_priv, cmd_size); 98 - } 99 - 100 - /** 101 - * vmw_cursor_update_image - update the cursor image on the provided plane 102 - * @dev_priv: the private driver struct 103 - * @vps: the plane state of the cursor plane 104 - * @image: buffer which holds the cursor image 105 - * @width: width of the mouse cursor image 106 - * @height: height of the mouse cursor image 107 - * @hotspotX: the horizontal position of mouse hotspot 108 - * @hotspotY: the vertical position of mouse hotspot 109 - */ 110 - static void vmw_cursor_update_image(struct vmw_private *dev_priv, 111 - struct vmw_plane_state *vps, 112 - u32 *image, u32 width, u32 height, 113 - u32 hotspotX, u32 hotspotY) 114 - { 115 - if (vps->cursor.bo) 116 - vmw_cursor_update_mob(dev_priv, vps, image, 117 - vps->base.crtc_w, vps->base.crtc_h, 118 - hotspotX, hotspotY); 119 - 120 - else 121 - vmw_send_define_cursor_cmd(dev_priv, image, width, height, 122 - hotspotX, hotspotY); 123 - } 124 - 125 - 126 - /** 127 - * vmw_cursor_update_mob - Update cursor vis CursorMob mechanism 128 - * 129 - * Called from inside vmw_du_cursor_plane_atomic_update to actually 130 - * make the cursor-image live. 131 - * 132 - * @dev_priv: device to work with 133 - * @vps: the plane state of the cursor plane 134 - * @image: cursor source data to fill the MOB with 135 - * @width: source data width 136 - * @height: source data height 137 - * @hotspotX: cursor hotspot x 138 - * @hotspotY: cursor hotspot Y 139 - */ 140 - static void vmw_cursor_update_mob(struct vmw_private *dev_priv, 141 - struct vmw_plane_state *vps, 142 - u32 *image, u32 width, u32 height, 143 - u32 hotspotX, u32 hotspotY) 144 - { 145 - SVGAGBCursorHeader *header; 146 - SVGAGBAlphaCursorHeader *alpha_header; 147 - const u32 image_size = width * height * sizeof(*image); 148 - 149 - header = vmw_bo_map_and_cache(vps->cursor.bo); 150 - alpha_header = &header->header.alphaHeader; 151 - 152 - memset(header, 0, sizeof(*header)); 153 - 154 - header->type = SVGA_ALPHA_CURSOR; 155 - header->sizeInBytes = image_size; 156 - 157 - alpha_header->hotspotX = hotspotX; 158 - alpha_header->hotspotY = hotspotY; 159 - alpha_header->width = width; 160 - alpha_header->height = height; 161 - 162 - memcpy(header + 1, image, image_size); 163 - vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, 164 - vps->cursor.bo->tbo.resource->start); 165 - } 166 - 167 - 168 - static u32 vmw_du_cursor_mob_size(u32 w, u32 h) 169 - { 170 - return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader); 171 - } 172 - 173 - /** 174 - * vmw_du_cursor_plane_acquire_image -- Acquire the image data 175 - * @vps: cursor plane state 176 - */ 177 - static u32 *vmw_du_cursor_plane_acquire_image(struct vmw_plane_state *vps) 178 - { 179 - struct vmw_surface *surf; 180 - 181 - if (vmw_user_object_is_null(&vps->uo)) 182 - return NULL; 183 - 184 - surf = vmw_user_object_surface(&vps->uo); 185 - if (surf && !vmw_user_object_is_mapped(&vps->uo)) 186 - return surf->snooper.image; 187 - 188 - return vmw_user_object_map(&vps->uo); 189 - } 190 - 191 - static bool vmw_du_cursor_plane_has_changed(struct vmw_plane_state *old_vps, 192 - struct vmw_plane_state *new_vps) 193 - { 194 - void *old_image; 195 - void *new_image; 196 - u32 size; 197 - bool changed; 198 - 199 - if (old_vps->base.crtc_w != new_vps->base.crtc_w || 200 - old_vps->base.crtc_h != new_vps->base.crtc_h) 201 - return true; 202 - 203 - if (old_vps->cursor.hotspot_x != new_vps->cursor.hotspot_x || 204 - old_vps->cursor.hotspot_y != new_vps->cursor.hotspot_y) 205 - return true; 206 - 207 - size = new_vps->base.crtc_w * new_vps->base.crtc_h * sizeof(u32); 208 - 209 - old_image = vmw_du_cursor_plane_acquire_image(old_vps); 210 - new_image = vmw_du_cursor_plane_acquire_image(new_vps); 211 - 212 - changed = false; 213 - if (old_image && new_image && old_image != new_image) 214 - changed = memcmp(old_image, new_image, size) != 0; 215 - 216 - return changed; 217 - } 218 - 219 - static void vmw_du_destroy_cursor_mob(struct vmw_bo **vbo) 220 - { 221 - if (!(*vbo)) 222 - return; 223 - 224 - ttm_bo_unpin(&(*vbo)->tbo); 225 - vmw_bo_unreference(vbo); 226 - } 227 - 228 - static void vmw_du_put_cursor_mob(struct vmw_cursor_plane *vcp, 229 - struct vmw_plane_state *vps) 230 - { 231 - u32 i; 232 - 233 - if (!vps->cursor.bo) 234 - return; 235 - 236 - vmw_du_cursor_plane_unmap_cm(vps); 237 - 238 - /* Look for a free slot to return this mob to the cache. */ 239 - for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 240 - if (!vcp->cursor_mobs[i]) { 241 - vcp->cursor_mobs[i] = vps->cursor.bo; 242 - vps->cursor.bo = NULL; 243 - return; 244 - } 245 - } 246 - 247 - /* Cache is full: See if this mob is bigger than an existing mob. */ 248 - for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 249 - if (vcp->cursor_mobs[i]->tbo.base.size < 250 - vps->cursor.bo->tbo.base.size) { 251 - vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]); 252 - vcp->cursor_mobs[i] = vps->cursor.bo; 253 - vps->cursor.bo = NULL; 254 - return; 255 - } 256 - } 257 - 258 - /* Destroy it if it's not worth caching. */ 259 - vmw_du_destroy_cursor_mob(&vps->cursor.bo); 260 - } 261 - 262 - static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp, 263 - struct vmw_plane_state *vps) 264 - { 265 - struct vmw_private *dev_priv = vmw_priv(vcp->base.dev); 266 - u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h); 267 - u32 i; 268 - u32 cursor_max_dim, mob_max_size; 269 - struct vmw_fence_obj *fence = NULL; 270 - int ret; 271 - 272 - if (!dev_priv->has_mob || 273 - (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0) 274 - return -EINVAL; 275 - 276 - mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); 277 - cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION); 278 - 279 - if (size > mob_max_size || vps->base.crtc_w > cursor_max_dim || 280 - vps->base.crtc_h > cursor_max_dim) 281 - return -EINVAL; 282 - 283 - if (vps->cursor.bo) { 284 - if (vps->cursor.bo->tbo.base.size >= size) 285 - return 0; 286 - vmw_du_put_cursor_mob(vcp, vps); 287 - } 288 - 289 - /* Look for an unused mob in the cache. */ 290 - for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 291 - if (vcp->cursor_mobs[i] && 292 - vcp->cursor_mobs[i]->tbo.base.size >= size) { 293 - vps->cursor.bo = vcp->cursor_mobs[i]; 294 - vcp->cursor_mobs[i] = NULL; 295 - return 0; 296 - } 297 - } 298 - /* Create a new mob if we can't find an existing one. */ 299 - ret = vmw_bo_create_and_populate(dev_priv, size, 300 - VMW_BO_DOMAIN_MOB, 301 - &vps->cursor.bo); 302 - 303 - if (ret != 0) 304 - return ret; 305 - 306 - /* Fence the mob creation so we are guarateed to have the mob */ 307 - ret = ttm_bo_reserve(&vps->cursor.bo->tbo, false, false, NULL); 308 - if (ret != 0) 309 - goto teardown; 310 - 311 - ret = vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 312 - if (ret != 0) { 313 - ttm_bo_unreserve(&vps->cursor.bo->tbo); 314 - goto teardown; 315 - } 316 - 317 - dma_fence_wait(&fence->base, false); 318 - dma_fence_put(&fence->base); 319 - 320 - ttm_bo_unreserve(&vps->cursor.bo->tbo); 321 - return 0; 322 - 323 - teardown: 324 - vmw_du_destroy_cursor_mob(&vps->cursor.bo); 325 - return ret; 326 - } 327 - 328 - 329 - static void vmw_cursor_update_position(struct vmw_private *dev_priv, 330 - bool show, int x, int y) 331 - { 332 - const uint32_t svga_cursor_on = show ? SVGA_CURSOR_ON_SHOW 333 - : SVGA_CURSOR_ON_HIDE; 334 - uint32_t count; 335 - 336 - spin_lock(&dev_priv->cursor_lock); 337 - if (dev_priv->capabilities2 & SVGA_CAP2_EXTRA_REGS) { 338 - vmw_write(dev_priv, SVGA_REG_CURSOR4_X, x); 339 - vmw_write(dev_priv, SVGA_REG_CURSOR4_Y, y); 340 - vmw_write(dev_priv, SVGA_REG_CURSOR4_SCREEN_ID, SVGA3D_INVALID_ID); 341 - vmw_write(dev_priv, SVGA_REG_CURSOR4_ON, svga_cursor_on); 342 - vmw_write(dev_priv, SVGA_REG_CURSOR4_SUBMIT, 1); 343 - } else if (vmw_is_cursor_bypass3_enabled(dev_priv)) { 344 - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, svga_cursor_on); 345 - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_X, x); 346 - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_Y, y); 347 - count = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CURSOR_COUNT); 348 - vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_COUNT, ++count); 349 - } else { 350 - vmw_write(dev_priv, SVGA_REG_CURSOR_X, x); 351 - vmw_write(dev_priv, SVGA_REG_CURSOR_Y, y); 352 - vmw_write(dev_priv, SVGA_REG_CURSOR_ON, svga_cursor_on); 353 - } 354 - spin_unlock(&dev_priv->cursor_lock); 355 - } 356 - 357 - void vmw_kms_cursor_snoop(struct vmw_surface *srf, 358 - struct ttm_object_file *tfile, 359 - struct ttm_buffer_object *bo, 360 - SVGA3dCmdHeader *header) 361 - { 362 - struct ttm_bo_kmap_obj map; 363 - unsigned long kmap_offset; 364 - unsigned long kmap_num; 365 - SVGA3dCopyBox *box; 366 - unsigned box_count; 367 - void *virtual; 368 - bool is_iomem; 369 - struct vmw_dma_cmd { 370 - SVGA3dCmdHeader header; 371 - SVGA3dCmdSurfaceDMA dma; 372 - } *cmd; 373 - int i, ret; 374 - const struct SVGA3dSurfaceDesc *desc = 375 - vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 376 - const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock; 377 - 378 - cmd = container_of(header, struct vmw_dma_cmd, header); 379 - 380 - /* No snooper installed, nothing to copy */ 381 - if (!srf->snooper.image) 382 - return; 383 - 384 - if (cmd->dma.host.face != 0 || cmd->dma.host.mipmap != 0) { 385 - DRM_ERROR("face and mipmap for cursors should never != 0\n"); 386 - return; 387 - } 388 - 389 - if (cmd->header.size < 64) { 390 - DRM_ERROR("at least one full copy box must be given\n"); 391 - return; 392 - } 393 - 394 - box = (SVGA3dCopyBox *)&cmd[1]; 395 - box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) / 396 - sizeof(SVGA3dCopyBox); 397 - 398 - if (cmd->dma.guest.ptr.offset % PAGE_SIZE || 399 - box->x != 0 || box->y != 0 || box->z != 0 || 400 - box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || 401 - box->d != 1 || box_count != 1 || 402 - box->w > VMW_CURSOR_SNOOP_WIDTH || box->h > VMW_CURSOR_SNOOP_HEIGHT) { 403 - /* TODO handle none page aligned offsets */ 404 - /* TODO handle more dst & src != 0 */ 405 - /* TODO handle more then one copy */ 406 - DRM_ERROR("Can't snoop dma request for cursor!\n"); 407 - DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n", 408 - box->srcx, box->srcy, box->srcz, 409 - box->x, box->y, box->z, 410 - box->w, box->h, box->d, box_count, 411 - cmd->dma.guest.ptr.offset); 412 - return; 413 - } 414 - 415 - kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT; 416 - kmap_num = (VMW_CURSOR_SNOOP_HEIGHT*image_pitch) >> PAGE_SHIFT; 417 - 418 - ret = ttm_bo_reserve(bo, true, false, NULL); 419 - if (unlikely(ret != 0)) { 420 - DRM_ERROR("reserve failed\n"); 421 - return; 422 - } 423 - 424 - ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map); 425 - if (unlikely(ret != 0)) 426 - goto err_unreserve; 427 - 428 - virtual = ttm_kmap_obj_virtual(&map, &is_iomem); 429 - 430 - if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) { 431 - memcpy(srf->snooper.image, virtual, 432 - VMW_CURSOR_SNOOP_HEIGHT*image_pitch); 433 - } else { 434 - /* Image is unsigned pointer. */ 435 - for (i = 0; i < box->h; i++) 436 - memcpy(srf->snooper.image + i * image_pitch, 437 - virtual + i * cmd->dma.guest.pitch, 438 - box->w * desc->pitchBytesPerBlock); 439 - } 440 - 441 - srf->snooper.age++; 442 - 443 - ttm_bo_kunmap(&map); 444 - err_unreserve: 445 - ttm_bo_unreserve(bo); 446 - } 447 - 448 - /** 449 - * vmw_kms_legacy_hotspot_clear - Clear legacy hotspots 450 - * 451 - * @dev_priv: Pointer to the device private struct. 452 - * 453 - * Clears all legacy hotspots. 454 - */ 455 - void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv) 456 - { 457 - struct drm_device *dev = &dev_priv->drm; 458 - struct vmw_display_unit *du; 459 - struct drm_crtc *crtc; 460 - 461 - drm_modeset_lock_all(dev); 462 - drm_for_each_crtc(crtc, dev) { 463 - du = vmw_crtc_to_du(crtc); 464 - 465 - du->hotspot_x = 0; 466 - du->hotspot_y = 0; 467 - } 468 - drm_modeset_unlock_all(dev); 469 - } 470 - 471 - void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) 472 - { 473 - struct drm_device *dev = &dev_priv->drm; 474 - struct vmw_display_unit *du; 475 - struct drm_crtc *crtc; 476 - 477 - mutex_lock(&dev->mode_config.mutex); 478 - 479 - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 480 - du = vmw_crtc_to_du(crtc); 481 - if (!du->cursor_surface || 482 - du->cursor_age == du->cursor_surface->snooper.age || 483 - !du->cursor_surface->snooper.image) 484 - continue; 485 - 486 - du->cursor_age = du->cursor_surface->snooper.age; 487 - vmw_send_define_cursor_cmd(dev_priv, 488 - du->cursor_surface->snooper.image, 489 - VMW_CURSOR_SNOOP_WIDTH, 490 - VMW_CURSOR_SNOOP_HEIGHT, 491 - du->hotspot_x + du->core_hotspot_x, 492 - du->hotspot_y + du->core_hotspot_y); 493 - } 494 - 495 - mutex_unlock(&dev->mode_config.mutex); 496 - } 497 - 498 - 499 - void vmw_du_cursor_plane_destroy(struct drm_plane *plane) 500 - { 501 - struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 502 - u32 i; 503 - 504 - vmw_cursor_update_position(vmw_priv(plane->dev), false, 0, 0); 505 - 506 - for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) 507 - vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]); 508 - 509 - drm_plane_cleanup(plane); 510 60 } 511 61 512 62 ··· 89 575 90 576 91 577 /** 92 - * vmw_du_cursor_plane_map_cm - Maps the cursor mobs. 93 - * 94 - * @vps: plane_state 95 - * 96 - * Returns 0 on success 97 - */ 98 - 99 - static int 100 - vmw_du_cursor_plane_map_cm(struct vmw_plane_state *vps) 101 - { 102 - int ret; 103 - u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h); 104 - struct ttm_buffer_object *bo; 105 - 106 - if (!vps->cursor.bo) 107 - return -EINVAL; 108 - 109 - bo = &vps->cursor.bo->tbo; 110 - 111 - if (bo->base.size < size) 112 - return -EINVAL; 113 - 114 - if (vps->cursor.bo->map.virtual) 115 - return 0; 116 - 117 - ret = ttm_bo_reserve(bo, false, false, NULL); 118 - if (unlikely(ret != 0)) 119 - return -ENOMEM; 120 - 121 - vmw_bo_map_and_cache(vps->cursor.bo); 122 - 123 - ttm_bo_unreserve(bo); 124 - 125 - if (unlikely(ret != 0)) 126 - return -ENOMEM; 127 - 128 - return 0; 129 - } 130 - 131 - 132 - /** 133 - * vmw_du_cursor_plane_unmap_cm - Unmaps the cursor mobs. 134 - * 135 - * @vps: state of the cursor plane 136 - * 137 - * Returns 0 on success 138 - */ 139 - 140 - static int 141 - vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps) 142 - { 143 - int ret = 0; 144 - struct vmw_bo *vbo = vps->cursor.bo; 145 - 146 - if (!vbo || !vbo->map.virtual) 147 - return 0; 148 - 149 - ret = ttm_bo_reserve(&vbo->tbo, true, false, NULL); 150 - if (likely(ret == 0)) { 151 - vmw_bo_unmap(vbo); 152 - ttm_bo_unreserve(&vbo->tbo); 153 - } 154 - 155 - return ret; 156 - } 157 - 158 - 159 - /** 160 - * vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface 161 - * 162 - * @plane: cursor plane 163 - * @old_state: contains the state to clean up 164 - * 165 - * Unmaps all cursor bo mappings and unpins the cursor surface 166 - * 167 - * Returns 0 on success 168 - */ 169 - void 170 - vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, 171 - struct drm_plane_state *old_state) 172 - { 173 - struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 174 - struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 175 - 176 - if (!vmw_user_object_is_null(&vps->uo)) 177 - vmw_user_object_unmap(&vps->uo); 178 - 179 - vmw_du_cursor_plane_unmap_cm(vps); 180 - vmw_du_put_cursor_mob(vcp, vps); 181 - 182 - vmw_du_plane_unpin_surf(vps); 183 - vmw_user_object_unref(&vps->uo); 184 - } 185 - 186 - 187 - /** 188 - * vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it 189 - * 190 - * @plane: display plane 191 - * @new_state: info on the new plane state, including the FB 192 - * 193 - * Returns 0 on success 194 - */ 195 - int 196 - vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, 197 - struct drm_plane_state *new_state) 198 - { 199 - struct drm_framebuffer *fb = new_state->fb; 200 - struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 201 - struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 202 - struct vmw_bo *bo = NULL; 203 - int ret = 0; 204 - 205 - if (!vmw_user_object_is_null(&vps->uo)) { 206 - vmw_user_object_unmap(&vps->uo); 207 - vmw_user_object_unref(&vps->uo); 208 - } 209 - 210 - if (fb) { 211 - if (vmw_framebuffer_to_vfb(fb)->bo) { 212 - vps->uo.buffer = vmw_framebuffer_to_vfbd(fb)->buffer; 213 - vps->uo.surface = NULL; 214 - } else { 215 - memcpy(&vps->uo, &vmw_framebuffer_to_vfbs(fb)->uo, sizeof(vps->uo)); 216 - } 217 - vmw_user_object_ref(&vps->uo); 218 - } 219 - 220 - bo = vmw_user_object_buffer(&vps->uo); 221 - if (bo) { 222 - struct ttm_operation_ctx ctx = {false, false}; 223 - 224 - ret = ttm_bo_reserve(&bo->tbo, true, false, NULL); 225 - if (ret != 0) 226 - return -ENOMEM; 227 - 228 - ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 229 - if (ret != 0) 230 - return -ENOMEM; 231 - 232 - vmw_bo_pin_reserved(bo, true); 233 - if (vmw_framebuffer_to_vfb(fb)->bo) { 234 - const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32); 235 - 236 - (void)vmw_bo_map_and_cache_size(bo, size); 237 - } else { 238 - vmw_bo_map_and_cache(bo); 239 - } 240 - ttm_bo_unreserve(&bo->tbo); 241 - } 242 - 243 - if (!vmw_user_object_is_null(&vps->uo)) { 244 - vmw_du_get_cursor_mob(vcp, vps); 245 - vmw_du_cursor_plane_map_cm(vps); 246 - } 247 - 248 - return 0; 249 - } 250 - 251 - 252 - void 253 - vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, 254 - struct drm_atomic_state *state) 255 - { 256 - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 257 - plane); 258 - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 259 - plane); 260 - struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc; 261 - struct vmw_private *dev_priv = vmw_priv(crtc->dev); 262 - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 263 - struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 264 - struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state); 265 - struct vmw_bo *old_bo = NULL; 266 - struct vmw_bo *new_bo = NULL; 267 - struct ww_acquire_ctx ctx; 268 - s32 hotspot_x, hotspot_y; 269 - int ret; 270 - 271 - hotspot_x = du->hotspot_x + new_state->hotspot_x; 272 - hotspot_y = du->hotspot_y + new_state->hotspot_y; 273 - 274 - du->cursor_surface = vmw_user_object_surface(&vps->uo); 275 - 276 - if (vmw_user_object_is_null(&vps->uo)) { 277 - vmw_cursor_update_position(dev_priv, false, 0, 0); 278 - return; 279 - } 280 - 281 - vps->cursor.hotspot_x = hotspot_x; 282 - vps->cursor.hotspot_y = hotspot_y; 283 - 284 - if (du->cursor_surface) 285 - du->cursor_age = du->cursor_surface->snooper.age; 286 - 287 - ww_acquire_init(&ctx, &reservation_ww_class); 288 - 289 - if (!vmw_user_object_is_null(&old_vps->uo)) { 290 - old_bo = vmw_user_object_buffer(&old_vps->uo); 291 - ret = ttm_bo_reserve(&old_bo->tbo, false, false, &ctx); 292 - if (ret != 0) 293 - return; 294 - } 295 - 296 - if (!vmw_user_object_is_null(&vps->uo)) { 297 - new_bo = vmw_user_object_buffer(&vps->uo); 298 - if (old_bo != new_bo) { 299 - ret = ttm_bo_reserve(&new_bo->tbo, false, false, &ctx); 300 - if (ret != 0) { 301 - if (old_bo) { 302 - ttm_bo_unreserve(&old_bo->tbo); 303 - ww_acquire_fini(&ctx); 304 - } 305 - return; 306 - } 307 - } else { 308 - new_bo = NULL; 309 - } 310 - } 311 - if (!vmw_du_cursor_plane_has_changed(old_vps, vps)) { 312 - /* 313 - * If it hasn't changed, avoid making the device do extra 314 - * work by keeping the old cursor active. 315 - */ 316 - struct vmw_cursor_plane_state tmp = old_vps->cursor; 317 - old_vps->cursor = vps->cursor; 318 - vps->cursor = tmp; 319 - } else { 320 - void *image = vmw_du_cursor_plane_acquire_image(vps); 321 - if (image) 322 - vmw_cursor_update_image(dev_priv, vps, image, 323 - new_state->crtc_w, 324 - new_state->crtc_h, 325 - hotspot_x, hotspot_y); 326 - } 327 - 328 - if (new_bo) 329 - ttm_bo_unreserve(&new_bo->tbo); 330 - if (old_bo) 331 - ttm_bo_unreserve(&old_bo->tbo); 332 - 333 - ww_acquire_fini(&ctx); 334 - 335 - du->cursor_x = new_state->crtc_x + du->set_gui_x; 336 - du->cursor_y = new_state->crtc_y + du->set_gui_y; 337 - 338 - vmw_cursor_update_position(dev_priv, true, 339 - du->cursor_x + hotspot_x, 340 - du->cursor_y + hotspot_y); 341 - 342 - du->core_hotspot_x = hotspot_x - du->hotspot_x; 343 - du->core_hotspot_y = hotspot_y - du->hotspot_y; 344 - } 345 - 346 - 347 - /** 348 578 * vmw_du_primary_plane_atomic_check - check if the new state is okay 349 579 * 350 580 * @plane: display plane ··· 130 872 false, true); 131 873 return ret; 132 874 } 133 - 134 - 135 - /** 136 - * vmw_du_cursor_plane_atomic_check - check if the new state is okay 137 - * 138 - * @plane: cursor plane 139 - * @state: info on the new plane state 140 - * 141 - * This is a chance to fail if the new cursor state does not fit 142 - * our requirements. 143 - * 144 - * Returns 0 on success 145 - */ 146 - int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, 147 - struct drm_atomic_state *state) 148 - { 149 - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 150 - plane); 151 - int ret = 0; 152 - struct drm_crtc_state *crtc_state = NULL; 153 - struct vmw_surface *surface = NULL; 154 - struct drm_framebuffer *fb = new_state->fb; 155 - 156 - if (new_state->crtc) 157 - crtc_state = drm_atomic_get_new_crtc_state(new_state->state, 158 - new_state->crtc); 159 - 160 - ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, 161 - DRM_PLANE_NO_SCALING, 162 - DRM_PLANE_NO_SCALING, 163 - true, true); 164 - if (ret) 165 - return ret; 166 - 167 - /* Turning off */ 168 - if (!fb) 169 - return 0; 170 - 171 - /* A lot of the code assumes this */ 172 - if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { 173 - DRM_ERROR("Invalid cursor dimensions (%d, %d)\n", 174 - new_state->crtc_w, new_state->crtc_h); 175 - return -EINVAL; 176 - } 177 - 178 - if (!vmw_framebuffer_to_vfb(fb)->bo) { 179 - surface = vmw_user_object_surface(&vmw_framebuffer_to_vfbs(fb)->uo); 180 - 181 - WARN_ON(!surface); 182 - 183 - if (!surface || 184 - (!surface->snooper.image && !surface->res.guest_memory_bo)) { 185 - DRM_ERROR("surface not suitable for cursor\n"); 186 - return -EINVAL; 187 - } 188 - } 189 - 190 - return 0; 191 - } 192 - 193 875 194 876 int vmw_du_crtc_atomic_check(struct drm_crtc *crtc, 195 877 struct drm_atomic_state *state) ··· 274 1076 vps->pinned = 0; 275 1077 vps->cpp = 0; 276 1078 277 - memset(&vps->cursor, 0, sizeof(vps->cursor)); 1079 + vps->cursor.mob = NULL; 278 1080 279 1081 /* Each ref counted resource needs to be acquired again */ 280 1082 vmw_user_object_ref(&vps->uo); ··· 419 1221 { 420 1222 struct vmw_framebuffer_surface *vfbs = 421 1223 vmw_framebuffer_to_vfbs(framebuffer); 1224 + struct vmw_bo *bo = vmw_user_object_buffer(&vfbs->uo); 1225 + struct vmw_surface *surf = vmw_user_object_surface(&vfbs->uo); 422 1226 1227 + if (bo) { 1228 + vmw_bo_dirty_release(bo); 1229 + /* 1230 + * bo->dirty is reference counted so it being NULL 1231 + * means that the surface wasn't coherent to begin 1232 + * with and so we have to free the dirty tracker 1233 + * in the vmw_resource 1234 + */ 1235 + if (!bo->dirty && surf && surf->res.dirty) 1236 + surf->res.func->dirty_free(&surf->res); 1237 + } 423 1238 drm_framebuffer_cleanup(framebuffer); 424 1239 vmw_user_object_unref(&vfbs->uo); 425 1240 ··· 586 1375 struct vmw_framebuffer_bo *vfbd = 587 1376 vmw_framebuffer_to_vfbd(framebuffer); 588 1377 1378 + vmw_bo_dirty_release(vfbd->buffer); 589 1379 drm_framebuffer_cleanup(framebuffer); 590 1380 vmw_bo_unreference(&vfbd->buffer); 591 1381 ··· 717 1505 struct vmw_private *dev_priv = vmw_priv(dev); 718 1506 struct vmw_framebuffer *vfb = NULL; 719 1507 struct vmw_user_object uo = {0}; 1508 + struct vmw_bo *bo; 1509 + struct vmw_surface *surface; 720 1510 int ret; 721 1511 722 1512 /* returns either a bo or surface */ ··· 748 1534 } 749 1535 750 1536 err_out: 1537 + bo = vmw_user_object_buffer(&uo); 1538 + surface = vmw_user_object_surface(&uo); 751 1539 /* vmw_user_object_lookup takes one ref so does new_fb */ 752 1540 vmw_user_object_unref(&uo); 753 1541 ··· 757 1541 DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); 758 1542 return ERR_PTR(ret); 759 1543 } 1544 + 1545 + ttm_bo_reserve(&bo->tbo, false, false, NULL); 1546 + ret = vmw_bo_dirty_add(bo); 1547 + if (!ret && surface && surface->res.func->dirty_alloc) { 1548 + surface->res.coherent = true; 1549 + ret = surface->res.func->dirty_alloc(&surface->res); 1550 + } 1551 + ttm_bo_unreserve(&bo->tbo); 760 1552 761 1553 return &vfb->base; 762 1554 } ··· 1194 1970 drm_mode_config_cleanup(&dev_priv->drm); 1195 1971 if (dev_priv->active_display_unit == vmw_du_legacy) 1196 1972 ret = vmw_kms_ldu_close_display(dev_priv); 1197 - 1198 - return ret; 1199 - } 1200 - 1201 - int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, 1202 - struct drm_file *file_priv) 1203 - { 1204 - struct drm_vmw_cursor_bypass_arg *arg = data; 1205 - struct vmw_display_unit *du; 1206 - struct drm_crtc *crtc; 1207 - int ret = 0; 1208 - 1209 - mutex_lock(&dev->mode_config.mutex); 1210 - if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) { 1211 - 1212 - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 1213 - du = vmw_crtc_to_du(crtc); 1214 - du->hotspot_x = arg->xhot; 1215 - du->hotspot_y = arg->yhot; 1216 - } 1217 - 1218 - mutex_unlock(&dev->mode_config.mutex); 1219 - return 0; 1220 - } 1221 - 1222 - crtc = drm_crtc_find(dev, file_priv, arg->crtc_id); 1223 - if (!crtc) { 1224 - ret = -ENOENT; 1225 - goto out; 1226 - } 1227 - 1228 - du = vmw_crtc_to_du(crtc); 1229 - 1230 - du->hotspot_x = arg->xhot; 1231 - du->hotspot_y = arg->yhot; 1232 - 1233 - out: 1234 - mutex_unlock(&dev->mode_config.mutex); 1235 1973 1236 1974 return ret; 1237 1975 }
+4 -67
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 2 /************************************************************************** 3 3 * 4 - * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 4 + * Copyright (c) 2009-2025 Broadcom. All Rights Reserved. The term 5 5 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 6 - * 7 - * Permission is hereby granted, free of charge, to any person obtaining a 8 - * copy of this software and associated documentation files (the 9 - * "Software"), to deal in the Software without restriction, including 10 - * without limitation the rights to use, copy, modify, merge, publish, 11 - * distribute, sub license, and/or sell copies of the Software, and to 12 - * permit persons to whom the Software is furnished to do so, subject to 13 - * the following conditions: 14 - * 15 - * The above copyright notice and this permission notice (including the 16 - * next paragraph) shall be included in all copies or substantial portions 17 - * of the Software. 18 - * 19 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 6 * 27 7 **************************************************************************/ 28 8 29 9 #ifndef VMWGFX_KMS_H_ 30 10 #define VMWGFX_KMS_H_ 31 11 12 + #include "vmwgfx_cursor_plane.h" 13 + #include "vmwgfx_drv.h" 14 + 32 15 #include <drm/drm_encoder.h> 33 16 #include <drm/drm_framebuffer.h> 34 17 #include <drm/drm_probe_helper.h> 35 - 36 - #include "vmwgfx_drv.h" 37 18 38 19 /** 39 20 * struct vmw_du_update_plane - Closure structure for vmw_du_helper_plane_update ··· 216 235 DRM_FORMAT_XRGB1555, 217 236 }; 218 237 219 - static const uint32_t __maybe_unused vmw_cursor_plane_formats[] = { 220 - DRM_FORMAT_ARGB8888, 221 - }; 222 - 223 238 224 239 #define vmw_crtc_state_to_vcs(x) container_of(x, struct vmw_crtc_state, base) 225 240 #define vmw_plane_state_to_vps(x) container_of(x, struct vmw_plane_state, base) 226 241 #define vmw_connector_state_to_vcs(x) \ 227 242 container_of(x, struct vmw_connector_state, base) 228 - #define vmw_plane_to_vcp(x) container_of(x, struct vmw_cursor_plane, base) 229 243 230 244 /** 231 245 * Derived class for crtc state object ··· 231 255 struct drm_crtc_state base; 232 256 }; 233 257 234 - struct vmw_cursor_plane_state { 235 - struct vmw_bo *bo; 236 - s32 hotspot_x; 237 - s32 hotspot_y; 238 - }; 239 258 240 259 /** 241 260 * Derived class for plane state object ··· 254 283 /* For CPU Blit */ 255 284 unsigned int cpp; 256 285 257 - bool surf_mapped; 258 286 struct vmw_cursor_plane_state cursor; 259 287 }; 260 288 ··· 287 317 int gui_y; 288 318 }; 289 319 290 - /** 291 - * Derived class for cursor plane object 292 - * 293 - * @base DRM plane object 294 - * @cursor.cursor_mobs Cursor mobs available for re-use 295 - */ 296 - struct vmw_cursor_plane { 297 - struct drm_plane base; 298 - 299 - struct vmw_bo *cursor_mobs[3]; 300 - }; 301 320 302 321 /** 303 322 * Base class display unit. ··· 301 342 struct drm_connector connector; 302 343 struct drm_plane primary; 303 344 struct vmw_cursor_plane cursor; 304 - 305 - struct vmw_surface *cursor_surface; 306 - size_t cursor_age; 307 - 308 - int cursor_x; 309 - int cursor_y; 310 - 311 - int hotspot_x; 312 - int hotspot_y; 313 - s32 core_hotspot_x; 314 - s32 core_hotspot_y; 315 345 316 346 unsigned unit; 317 347 ··· 351 403 */ 352 404 void vmw_du_init(struct vmw_display_unit *du); 353 405 void vmw_du_cleanup(struct vmw_display_unit *du); 354 - void vmw_du_crtc_save(struct drm_crtc *crtc); 355 - void vmw_du_crtc_restore(struct drm_crtc *crtc); 356 406 int vmw_du_crtc_gamma_set(struct drm_crtc *crtc, 357 407 u16 *r, u16 *g, u16 *b, 358 408 uint32_t size, ··· 406 460 407 461 /* Universal Plane Helpers */ 408 462 void vmw_du_primary_plane_destroy(struct drm_plane *plane); 409 - void vmw_du_cursor_plane_destroy(struct drm_plane *plane); 410 463 411 464 /* Atomic Helpers */ 412 465 int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, 413 466 struct drm_atomic_state *state); 414 - int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, 415 - struct drm_atomic_state *state); 416 - void vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, 417 - struct drm_atomic_state *state); 418 - int vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, 419 - struct drm_plane_state *new_state); 420 - void vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, 421 - struct drm_plane_state *old_state); 422 467 void vmw_du_plane_cleanup_fb(struct drm_plane *plane, 423 468 struct drm_plane_state *old_state); 424 469 void vmw_du_plane_reset(struct drm_plane *plane);
+5 -5
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
··· 372 372 static const struct drm_plane_funcs vmw_ldu_cursor_funcs = { 373 373 .update_plane = drm_atomic_helper_update_plane, 374 374 .disable_plane = drm_atomic_helper_disable_plane, 375 - .destroy = vmw_du_cursor_plane_destroy, 375 + .destroy = vmw_cursor_plane_destroy, 376 376 .reset = vmw_du_plane_reset, 377 377 .atomic_duplicate_state = vmw_du_plane_duplicate_state, 378 378 .atomic_destroy_state = vmw_du_plane_destroy_state, ··· 383 383 */ 384 384 static const struct 385 385 drm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = { 386 - .atomic_check = vmw_du_cursor_plane_atomic_check, 387 - .atomic_update = vmw_du_cursor_plane_atomic_update, 388 - .prepare_fb = vmw_du_cursor_plane_prepare_fb, 389 - .cleanup_fb = vmw_du_cursor_plane_cleanup_fb, 386 + .atomic_check = vmw_cursor_plane_atomic_check, 387 + .atomic_update = vmw_cursor_plane_atomic_update, 388 + .prepare_fb = vmw_cursor_plane_prepare_fb, 389 + .cleanup_fb = vmw_cursor_plane_cleanup_fb, 390 390 }; 391 391 392 392 static const struct
+42 -21
drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2019-2023 VMware, Inc., Palo Alto, CA., USA 5 - * 6 - * Permission is hereby granted, free of charge, to any person obtaining a 7 - * copy of this software and associated documentation files (the 8 - * "Software"), to deal in the Software without restriction, including 9 - * without limitation the rights to use, copy, modify, merge, publish, 10 - * distribute, sub license, and/or sell copies of the Software, and to 11 - * permit persons to whom the Software is furnished to do so, subject to 12 - * the following conditions: 13 - * 14 - * The above copyright notice and this permission notice (including the 15 - * next paragraph) shall be included in all copies or substantial portions 16 - * of the Software. 17 - * 18 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 4 + * Copyright (c) 2019-2025 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 25 6 * 26 7 **************************************************************************/ 27 8 #include "vmwgfx_bo.h" ··· 51 70 unsigned long bitmap_size; 52 71 unsigned long bitmap[]; 53 72 }; 73 + 74 + bool vmw_bo_is_dirty(struct vmw_bo *vbo) 75 + { 76 + return vbo->dirty && (vbo->dirty->start < vbo->dirty->end); 77 + } 54 78 55 79 /** 56 80 * vmw_bo_dirty_scan_pagetable - Perform a pagetable scan for dirty bits ··· 319 333 num = end - start; 320 334 bitmap_clear(&dirty->bitmap[0], start, num); 321 335 vmw_resource_dirty_update(res, start, end); 336 + } 337 + 338 + if (res_start <= dirty->start && res_end > dirty->start) 339 + dirty->start = res_end; 340 + if (res_start < dirty->end && res_end >= dirty->end) 341 + dirty->end = res_start; 342 + } 343 + 344 + void vmw_bo_dirty_clear(struct vmw_bo *vbo) 345 + { 346 + struct vmw_bo_dirty *dirty = vbo->dirty; 347 + pgoff_t start, cur, end; 348 + unsigned long res_start = 0; 349 + unsigned long res_end = vbo->tbo.base.size; 350 + 351 + WARN_ON_ONCE(res_start & ~PAGE_MASK); 352 + res_start >>= PAGE_SHIFT; 353 + res_end = DIV_ROUND_UP(res_end, PAGE_SIZE); 354 + 355 + if (res_start >= dirty->end || res_end <= dirty->start) 356 + return; 357 + 358 + cur = max(res_start, dirty->start); 359 + res_end = max(res_end, dirty->end); 360 + while (cur < res_end) { 361 + unsigned long num; 362 + 363 + start = find_next_bit(&dirty->bitmap[0], res_end, cur); 364 + if (start >= res_end) 365 + break; 366 + 367 + end = find_next_zero_bit(&dirty->bitmap[0], res_end, start + 1); 368 + cur = end + 1; 369 + num = end - start; 370 + bitmap_clear(&dirty->bitmap[0], start, num); 322 371 } 323 372 324 373 if (res_start <= dirty->start && res_end > dirty->start)
+5 -5
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
··· 764 764 static const struct drm_plane_funcs vmw_sou_cursor_funcs = { 765 765 .update_plane = drm_atomic_helper_update_plane, 766 766 .disable_plane = drm_atomic_helper_disable_plane, 767 - .destroy = vmw_du_cursor_plane_destroy, 767 + .destroy = vmw_cursor_plane_destroy, 768 768 .reset = vmw_du_plane_reset, 769 769 .atomic_duplicate_state = vmw_du_plane_duplicate_state, 770 770 .atomic_destroy_state = vmw_du_plane_destroy_state, ··· 775 775 */ 776 776 static const struct 777 777 drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = { 778 - .atomic_check = vmw_du_cursor_plane_atomic_check, 779 - .atomic_update = vmw_du_cursor_plane_atomic_update, 780 - .prepare_fb = vmw_du_cursor_plane_prepare_fb, 781 - .cleanup_fb = vmw_du_cursor_plane_cleanup_fb, 778 + .atomic_check = vmw_cursor_plane_atomic_check, 779 + .atomic_update = vmw_cursor_plane_atomic_update, 780 + .prepare_fb = vmw_cursor_plane_prepare_fb, 781 + .cleanup_fb = vmw_cursor_plane_cleanup_fb, 782 782 }; 783 783 784 784 static const struct
+6 -5
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
··· 1482 1482 static const struct drm_plane_funcs vmw_stdu_cursor_funcs = { 1483 1483 .update_plane = drm_atomic_helper_update_plane, 1484 1484 .disable_plane = drm_atomic_helper_disable_plane, 1485 - .destroy = vmw_du_cursor_plane_destroy, 1485 + .destroy = vmw_cursor_plane_destroy, 1486 1486 .reset = vmw_du_plane_reset, 1487 1487 .atomic_duplicate_state = vmw_du_plane_duplicate_state, 1488 1488 .atomic_destroy_state = vmw_du_plane_destroy_state, ··· 1494 1494 */ 1495 1495 static const struct 1496 1496 drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = { 1497 - .atomic_check = vmw_du_cursor_plane_atomic_check, 1498 - .atomic_update = vmw_du_cursor_plane_atomic_update, 1499 - .prepare_fb = vmw_du_cursor_plane_prepare_fb, 1500 - .cleanup_fb = vmw_du_cursor_plane_cleanup_fb, 1497 + .atomic_check = vmw_cursor_plane_atomic_check, 1498 + .atomic_update = vmw_cursor_plane_atomic_update, 1499 + .prepare_fb = vmw_cursor_plane_prepare_fb, 1500 + .cleanup_fb = vmw_cursor_plane_cleanup_fb, 1501 1501 }; 1502 1502 1503 1503 static const struct ··· 1584 1584 } 1585 1585 1586 1586 drm_plane_helper_add(&cursor->base, &vmw_stdu_cursor_plane_helper_funcs); 1587 + drm_plane_enable_fb_damage_clips(&cursor->base); 1587 1588 1588 1589 ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, 1589 1590 DRM_MODE_CONNECTOR_VIRTUAL);
+7 -40
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 4 + * Copyright (c) 2009-2025 Broadcom. All Rights Reserved. The term 5 5 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 6 - * 7 - * Permission is hereby granted, free of charge, to any person obtaining a 8 - * copy of this software and associated documentation files (the 9 - * "Software"), to deal in the Software without restriction, including 10 - * without limitation the rights to use, copy, modify, merge, publish, 11 - * distribute, sub license, and/or sell copies of the Software, and to 12 - * permit persons to whom the Software is furnished to do so, subject to 13 - * the following conditions: 14 - * 15 - * The above copyright notice and this permission notice (including the 16 - * next paragraph) shall be included in all copies or substantial portions 17 - * of the Software. 18 - * 19 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 6 * 27 7 **************************************************************************/ 28 8 29 9 #include "vmwgfx_bo.h" 10 + #include "vmwgfx_cursor_plane.h" 30 11 #include "vmwgfx_drv.h" 31 12 #include "vmwgfx_resource_priv.h" 32 13 #include "vmwgfx_so.h" ··· 799 818 } 800 819 } 801 820 res->guest_memory_size = cur_bo_offset; 802 - if (!file_priv->atomic && 803 - metadata->scanout && 804 - metadata->num_sizes == 1 && 805 - metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH && 806 - metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT && 807 - metadata->format == VMW_CURSOR_SNOOP_FORMAT) { 808 - const struct SVGA3dSurfaceDesc *desc = 809 - vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 810 - const u32 cursor_size_bytes = VMW_CURSOR_SNOOP_WIDTH * 811 - VMW_CURSOR_SNOOP_HEIGHT * 812 - desc->pitchBytesPerBlock; 813 - srf->snooper.image = kzalloc(cursor_size_bytes, GFP_KERNEL); 814 - if (!srf->snooper.image) { 815 - DRM_ERROR("Failed to allocate cursor_image\n"); 816 - ret = -ENOMEM; 817 - goto out_no_copy; 818 - } 819 - } else { 820 - srf->snooper.image = NULL; 821 + 822 + srf->snooper.image = vmw_cursor_snooper_create(file_priv, metadata); 823 + if (IS_ERR(srf->snooper.image)) { 824 + ret = PTR_ERR(srf->snooper.image); 825 + goto out_no_copy; 821 826 } 822 827 823 828 if (drm_is_primary_client(file_priv))