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 else 104 return VMW_CURSOR_UPDATE_GB_ONLY; 105 } 106 drm_warn_once(&vmw->drm, "Unknown Cursor Type!\n"); 107 return VMW_CURSOR_UPDATE_NONE; 108 } 109 110 static void vmw_cursor_update_mob(struct vmw_private *vmw, 111 struct vmw_plane_state *vps) 112 { 113 SVGAGBCursorHeader *header; 114 SVGAGBAlphaCursorHeader *alpha_header; 115 struct vmw_bo *bo = vmw_user_object_buffer(&vps->uo); 116 u32 *image = vmw_bo_map_and_cache(bo); 117 const u32 image_size = vps->base.crtc_w * vps->base.crtc_h * sizeof(*image); 118 119 header = vmw_bo_map_and_cache(vps->cursor.mob); 120 alpha_header = &header->header.alphaHeader; 121 122 memset(header, 0, sizeof(*header)); 123 124 header->type = SVGA_ALPHA_CURSOR; 125 header->sizeInBytes = image_size; 126 127 alpha_header->hotspotX = vps->cursor.legacy.hotspot_x + vps->base.hotspot_x; 128 alpha_header->hotspotY = vps->cursor.legacy.hotspot_y + vps->base.hotspot_y; 129 alpha_header->width = vps->base.crtc_w; 130 alpha_header->height = vps->base.crtc_h; 131 132 memcpy(header + 1, image, image_size); 133 vmw_write(vmw, SVGA_REG_CURSOR_MOBID, vmw_bo_mobid(vps->cursor.mob)); 134 135 vmw_bo_unmap(bo); 136 vmw_bo_unmap(vps->cursor.mob); 137 } 138 139 static u32 vmw_cursor_mob_size(enum vmw_cursor_update_type update_type, 140 u32 w, u32 h) 141 { 142 switch (update_type) { 143 case VMW_CURSOR_UPDATE_LEGACY: 144 case VMW_CURSOR_UPDATE_GB_ONLY: 145 case VMW_CURSOR_UPDATE_NONE: 146 return 0; 147 case VMW_CURSOR_UPDATE_MOB: 148 return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader); 149 } 150 return 0; 151 } 152 153 static void vmw_cursor_mob_destroy(struct vmw_bo **vbo) 154 { 155 if (!(*vbo)) 156 return; 157 158 ttm_bo_unpin(&(*vbo)->tbo); 159 vmw_bo_unreference(vbo); 160 } 161 162 /** 163 * vmw_cursor_mob_unmap - Unmaps the cursor mobs. 164 * 165 * @vps: state of the cursor plane 166 * 167 * Returns 0 on success 168 */ 169 170 static int 171 vmw_cursor_mob_unmap(struct vmw_plane_state *vps) 172 { 173 int ret = 0; 174 struct vmw_bo *vbo = vps->cursor.mob; 175 176 if (!vbo || !vbo->map.virtual) 177 return 0; 178 179 ret = ttm_bo_reserve(&vbo->tbo, true, false, NULL); 180 if (likely(ret == 0)) { 181 vmw_bo_unmap(vbo); 182 ttm_bo_unreserve(&vbo->tbo); 183 } 184 185 return ret; 186 } 187 188 static void vmw_cursor_mob_put(struct vmw_cursor_plane *vcp, 189 struct vmw_plane_state *vps) 190 { 191 u32 i; 192 193 if (!vps->cursor.mob) 194 return; 195 196 vmw_cursor_mob_unmap(vps); 197 198 /* Look for a free slot to return this mob to the cache. */ 199 for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 200 if (!vcp->cursor_mobs[i]) { 201 vcp->cursor_mobs[i] = vps->cursor.mob; 202 vps->cursor.mob = NULL; 203 return; 204 } 205 } 206 207 /* Cache is full: See if this mob is bigger than an existing mob. */ 208 for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 209 if (vcp->cursor_mobs[i]->tbo.base.size < 210 vps->cursor.mob->tbo.base.size) { 211 vmw_cursor_mob_destroy(&vcp->cursor_mobs[i]); 212 vcp->cursor_mobs[i] = vps->cursor.mob; 213 vps->cursor.mob = NULL; 214 return; 215 } 216 } 217 218 /* Destroy it if it's not worth caching. */ 219 vmw_cursor_mob_destroy(&vps->cursor.mob); 220 } 221 222 static int vmw_cursor_mob_get(struct vmw_cursor_plane *vcp, 223 struct vmw_plane_state *vps) 224 { 225 struct vmw_private *dev_priv = vmw_priv(vcp->base.dev); 226 u32 size = vmw_cursor_mob_size(vps->cursor.update_type, 227 vps->base.crtc_w, vps->base.crtc_h); 228 u32 i; 229 u32 cursor_max_dim, mob_max_size; 230 struct vmw_fence_obj *fence = NULL; 231 int ret; 232 233 if (!dev_priv->has_mob || 234 (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0) 235 return -EINVAL; 236 237 mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); 238 cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION); 239 240 if (size > mob_max_size || vps->base.crtc_w > cursor_max_dim || 241 vps->base.crtc_h > cursor_max_dim) 242 return -EINVAL; 243 244 if (vps->cursor.mob) { 245 if (vps->cursor.mob->tbo.base.size >= size) 246 return 0; 247 vmw_cursor_mob_put(vcp, vps); 248 } 249 250 /* Look for an unused mob in the cache. */ 251 for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 252 if (vcp->cursor_mobs[i] && 253 vcp->cursor_mobs[i]->tbo.base.size >= size) { 254 vps->cursor.mob = vcp->cursor_mobs[i]; 255 vcp->cursor_mobs[i] = NULL; 256 return 0; 257 } 258 } 259 /* Create a new mob if we can't find an existing one. */ 260 ret = vmw_bo_create_and_populate(dev_priv, size, VMW_BO_DOMAIN_MOB, 261 &vps->cursor.mob); 262 263 if (ret != 0) 264 return ret; 265 266 /* Fence the mob creation so we are guarateed to have the mob */ 267 ret = ttm_bo_reserve(&vps->cursor.mob->tbo, false, false, NULL); 268 if (ret != 0) 269 goto teardown; 270 271 ret = vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); 272 if (ret != 0) { 273 ttm_bo_unreserve(&vps->cursor.mob->tbo); 274 goto teardown; 275 } 276 277 dma_fence_wait(&fence->base, false); 278 dma_fence_put(&fence->base); 279 280 ttm_bo_unreserve(&vps->cursor.mob->tbo); 281 282 return 0; 283 284 teardown: 285 vmw_cursor_mob_destroy(&vps->cursor.mob); 286 return ret; 287 } 288 289 static void vmw_cursor_update_position(struct vmw_private *dev_priv, 290 bool show, int x, int y) 291 { 292 const u32 svga_cursor_on = show ? SVGA_CURSOR_ON_SHOW 293 : SVGA_CURSOR_ON_HIDE; 294 u32 count; 295 296 spin_lock(&dev_priv->cursor_lock); 297 if (dev_priv->capabilities2 & SVGA_CAP2_EXTRA_REGS) { 298 vmw_write(dev_priv, SVGA_REG_CURSOR4_X, x); 299 vmw_write(dev_priv, SVGA_REG_CURSOR4_Y, y); 300 vmw_write(dev_priv, SVGA_REG_CURSOR4_SCREEN_ID, SVGA3D_INVALID_ID); 301 vmw_write(dev_priv, SVGA_REG_CURSOR4_ON, svga_cursor_on); 302 vmw_write(dev_priv, SVGA_REG_CURSOR4_SUBMIT, 1); 303 } else if (vmw_is_cursor_bypass3_enabled(dev_priv)) { 304 vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_ON, svga_cursor_on); 305 vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_X, x); 306 vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_Y, y); 307 count = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CURSOR_COUNT); 308 vmw_fifo_mem_write(dev_priv, SVGA_FIFO_CURSOR_COUNT, ++count); 309 } else { 310 vmw_write(dev_priv, SVGA_REG_CURSOR_X, x); 311 vmw_write(dev_priv, SVGA_REG_CURSOR_Y, y); 312 vmw_write(dev_priv, SVGA_REG_CURSOR_ON, svga_cursor_on); 313 } 314 spin_unlock(&dev_priv->cursor_lock); 315 } 316 317 void vmw_kms_cursor_snoop(struct vmw_surface *srf, 318 struct ttm_object_file *tfile, 319 struct ttm_buffer_object *bo, 320 SVGA3dCmdHeader *header) 321 { 322 struct ttm_bo_kmap_obj map; 323 unsigned long kmap_offset; 324 unsigned long kmap_num; 325 SVGA3dCopyBox *box; 326 u32 box_count; 327 void *virtual; 328 bool is_iomem; 329 struct vmw_dma_cmd { 330 SVGA3dCmdHeader header; 331 SVGA3dCmdSurfaceDMA dma; 332 } *cmd; 333 int i, ret; 334 const struct SVGA3dSurfaceDesc *desc = 335 vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 336 const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock; 337 338 cmd = container_of(header, struct vmw_dma_cmd, header); 339 340 /* No snooper installed, nothing to copy */ 341 if (!srf->snooper.image) 342 return; 343 344 if (cmd->dma.host.face != 0 || cmd->dma.host.mipmap != 0) { 345 DRM_ERROR("face and mipmap for cursors should never != 0\n"); 346 return; 347 } 348 349 if (cmd->header.size < 64) { 350 DRM_ERROR("at least one full copy box must be given\n"); 351 return; 352 } 353 354 box = (SVGA3dCopyBox *)&cmd[1]; 355 box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) / 356 sizeof(SVGA3dCopyBox); 357 358 if (cmd->dma.guest.ptr.offset % PAGE_SIZE || 359 box->x != 0 || box->y != 0 || box->z != 0 || 360 box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || 361 box->d != 1 || box_count != 1 || 362 box->w > VMW_CURSOR_SNOOP_WIDTH || box->h > VMW_CURSOR_SNOOP_HEIGHT) { 363 /* TODO handle none page aligned offsets */ 364 /* TODO handle more dst & src != 0 */ 365 /* TODO handle more then one copy */ 366 DRM_ERROR("Can't snoop dma request for cursor!\n"); 367 DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n", 368 box->srcx, box->srcy, box->srcz, 369 box->x, box->y, box->z, 370 box->w, box->h, box->d, box_count, 371 cmd->dma.guest.ptr.offset); 372 return; 373 } 374 375 kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT; 376 kmap_num = (VMW_CURSOR_SNOOP_HEIGHT * image_pitch) >> PAGE_SHIFT; 377 378 ret = ttm_bo_reserve(bo, true, false, NULL); 379 if (unlikely(ret != 0)) { 380 DRM_ERROR("reserve failed\n"); 381 return; 382 } 383 384 ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map); 385 if (unlikely(ret != 0)) 386 goto err_unreserve; 387 388 virtual = ttm_kmap_obj_virtual(&map, &is_iomem); 389 390 if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) { 391 memcpy(srf->snooper.image, virtual, 392 VMW_CURSOR_SNOOP_HEIGHT * image_pitch); 393 } else { 394 /* Image is unsigned pointer. */ 395 for (i = 0; i < box->h; i++) 396 memcpy(srf->snooper.image + i * image_pitch, 397 virtual + i * cmd->dma.guest.pitch, 398 box->w * desc->pitchBytesPerBlock); 399 } 400 srf->snooper.id++; 401 402 ttm_bo_kunmap(&map); 403 err_unreserve: 404 ttm_bo_unreserve(bo); 405 } 406 407 void vmw_cursor_plane_destroy(struct drm_plane *plane) 408 { 409 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 410 u32 i; 411 412 vmw_cursor_update_position(vmw_priv(plane->dev), false, 0, 0); 413 414 for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) 415 vmw_cursor_mob_destroy(&vcp->cursor_mobs[i]); 416 417 drm_plane_cleanup(plane); 418 } 419 420 /** 421 * vmw_cursor_mob_map - Maps the cursor mobs. 422 * 423 * @vps: plane_state 424 * 425 * Returns 0 on success 426 */ 427 428 static int 429 vmw_cursor_mob_map(struct vmw_plane_state *vps) 430 { 431 int ret; 432 u32 size = vmw_cursor_mob_size(vps->cursor.update_type, 433 vps->base.crtc_w, vps->base.crtc_h); 434 struct vmw_bo *vbo = vps->cursor.mob; 435 void *map; 436 437 if (!vbo) 438 return -EINVAL; 439 440 if (vbo->tbo.base.size < size) 441 return -EINVAL; 442 443 if (vbo->map.virtual) 444 return 0; 445 446 ret = ttm_bo_reserve(&vbo->tbo, false, false, NULL); 447 if (unlikely(ret != 0)) 448 return -ENOMEM; 449 450 map = vmw_bo_map_and_cache(vbo); 451 if (!map) { 452 vmw_bo_unmap(vbo); 453 ret = -ENOMEM; 454 } 455 456 ttm_bo_unreserve(&vbo->tbo); 457 458 return ret; 459 } 460 461 /** 462 * vmw_cursor_plane_cleanup_fb - Unpins the plane surface 463 * 464 * @plane: cursor plane 465 * @old_state: contains the state to clean up 466 * 467 * Unmaps all cursor bo mappings and unpins the cursor surface 468 * 469 * Returns 0 on success 470 */ 471 void 472 vmw_cursor_plane_cleanup_fb(struct drm_plane *plane, 473 struct drm_plane_state *old_state) 474 { 475 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 476 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 477 478 if (!vmw_user_object_is_null(&vps->uo)) 479 vmw_user_object_unmap(&vps->uo); 480 481 vmw_cursor_mob_unmap(vps); 482 vmw_cursor_mob_put(vcp, vps); 483 484 vmw_du_plane_unpin_surf(vps); 485 vmw_user_object_unref(&vps->uo); 486 } 487 488 static bool 489 vmw_cursor_buffer_changed(struct vmw_plane_state *new_vps, 490 struct vmw_plane_state *old_vps) 491 { 492 struct vmw_bo *new_bo = vmw_user_object_buffer(&new_vps->uo); 493 struct vmw_bo *old_bo = vmw_user_object_buffer(&old_vps->uo); 494 struct vmw_surface *surf; 495 bool dirty = false; 496 int ret; 497 498 if (new_bo != old_bo) 499 return true; 500 501 if (new_bo) { 502 if (!old_bo) { 503 return true; 504 } else if (new_bo->dirty) { 505 vmw_bo_dirty_scan(new_bo); 506 dirty = vmw_bo_is_dirty(new_bo); 507 if (dirty) { 508 surf = vmw_user_object_surface(&new_vps->uo); 509 if (surf) 510 vmw_bo_dirty_transfer_to_res(&surf->res); 511 else 512 vmw_bo_dirty_clear(new_bo); 513 } 514 return dirty; 515 } else if (new_bo != old_bo) { 516 /* 517 * Currently unused because the top exits right away. 518 * In most cases buffer being different will mean 519 * that the contents is different. For the few percent 520 * of cases where that's not true the cost of doing 521 * the memcmp on all other seems to outweight the 522 * benefits. Leave the conditional to be able to 523 * trivially validate it by removing the initial 524 * if (new_bo != old_bo) at the start. 525 */ 526 void *old_image; 527 void *new_image; 528 bool changed = false; 529 struct ww_acquire_ctx ctx; 530 const u32 size = new_vps->base.crtc_w * 531 new_vps->base.crtc_h * sizeof(u32); 532 533 ww_acquire_init(&ctx, &reservation_ww_class); 534 535 ret = ttm_bo_reserve(&old_bo->tbo, false, false, &ctx); 536 if (ret != 0) { 537 ww_acquire_fini(&ctx); 538 return true; 539 } 540 541 ret = ttm_bo_reserve(&new_bo->tbo, false, false, &ctx); 542 if (ret != 0) { 543 ttm_bo_unreserve(&old_bo->tbo); 544 ww_acquire_fini(&ctx); 545 return true; 546 } 547 548 old_image = vmw_bo_map_and_cache(old_bo); 549 new_image = vmw_bo_map_and_cache(new_bo); 550 551 if (old_image && new_image && old_image != new_image) 552 changed = memcmp(old_image, new_image, size) != 553 0; 554 555 ttm_bo_unreserve(&new_bo->tbo); 556 ttm_bo_unreserve(&old_bo->tbo); 557 558 ww_acquire_fini(&ctx); 559 560 return changed; 561 } 562 return false; 563 } 564 565 return false; 566 } 567 568 static bool 569 vmw_cursor_plane_changed(struct vmw_plane_state *new_vps, 570 struct vmw_plane_state *old_vps) 571 { 572 if (old_vps->base.crtc_w != new_vps->base.crtc_w || 573 old_vps->base.crtc_h != new_vps->base.crtc_h) 574 return true; 575 576 if (old_vps->base.hotspot_x != new_vps->base.hotspot_x || 577 old_vps->base.hotspot_y != new_vps->base.hotspot_y) 578 return true; 579 580 if (old_vps->cursor.legacy.hotspot_x != 581 new_vps->cursor.legacy.hotspot_x || 582 old_vps->cursor.legacy.hotspot_y != 583 new_vps->cursor.legacy.hotspot_y) 584 return true; 585 586 if (old_vps->base.fb != new_vps->base.fb) 587 return true; 588 589 return false; 590 } 591 592 /** 593 * vmw_cursor_plane_prepare_fb - Readies the cursor by referencing it 594 * 595 * @plane: display plane 596 * @new_state: info on the new plane state, including the FB 597 * 598 * Returns 0 on success 599 */ 600 int vmw_cursor_plane_prepare_fb(struct drm_plane *plane, 601 struct drm_plane_state *new_state) 602 { 603 struct drm_framebuffer *fb = new_state->fb; 604 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 605 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 606 struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(plane->state); 607 struct vmw_private *vmw = vmw_priv(plane->dev); 608 struct vmw_bo *bo = NULL; 609 struct vmw_surface *surface; 610 int ret = 0; 611 612 if (!vmw_user_object_is_null(&vps->uo)) { 613 vmw_user_object_unmap(&vps->uo); 614 vmw_user_object_unref(&vps->uo); 615 } 616 617 if (fb) { 618 if (vmw_framebuffer_to_vfb(fb)->bo) { 619 vps->uo.buffer = vmw_framebuffer_to_vfbd(fb)->buffer; 620 vps->uo.surface = NULL; 621 } else { 622 memcpy(&vps->uo, &vmw_framebuffer_to_vfbs(fb)->uo, sizeof(vps->uo)); 623 } 624 vmw_user_object_ref(&vps->uo); 625 } 626 627 vps->cursor.update_type = vmw_cursor_update_type(vmw, vps); 628 switch (vps->cursor.update_type) { 629 case VMW_CURSOR_UPDATE_LEGACY: 630 surface = vmw_user_object_surface(&vps->uo); 631 if (!surface || vps->cursor.legacy.id == surface->snooper.id) 632 vps->cursor.update_type = VMW_CURSOR_UPDATE_NONE; 633 break; 634 case VMW_CURSOR_UPDATE_GB_ONLY: 635 case VMW_CURSOR_UPDATE_MOB: { 636 bo = vmw_user_object_buffer(&vps->uo); 637 if (bo) { 638 struct ttm_operation_ctx ctx = { false, false }; 639 640 ret = ttm_bo_reserve(&bo->tbo, true, false, NULL); 641 if (ret != 0) 642 return -ENOMEM; 643 644 ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 645 if (ret != 0) 646 return -ENOMEM; 647 648 /* 649 * vmw_bo_pin_reserved also validates, so to skip 650 * the extra validation use ttm_bo_pin directly 651 */ 652 if (!bo->tbo.pin_count) 653 ttm_bo_pin(&bo->tbo); 654 655 if (vmw_framebuffer_to_vfb(fb)->bo) { 656 const u32 size = new_state->crtc_w * 657 new_state->crtc_h * 658 sizeof(u32); 659 660 (void)vmw_bo_map_and_cache_size(bo, size); 661 } else { 662 vmw_bo_map_and_cache(bo); 663 } 664 ttm_bo_unreserve(&bo->tbo); 665 } 666 if (!vmw_user_object_is_null(&vps->uo)) { 667 if (!vmw_cursor_plane_changed(vps, old_vps) && 668 !vmw_cursor_buffer_changed(vps, old_vps)) { 669 vps->cursor.update_type = 670 VMW_CURSOR_UPDATE_NONE; 671 } else if (vps->cursor.update_type == 672 VMW_CURSOR_UPDATE_MOB && 673 (vmw_cursor_mob_get(vcp, vps) || 674 vmw_cursor_mob_map(vps))) { 675 /* 676 * Reset the cursor to avoid crashes later. 677 */ 678 vps->cursor.update_type = 679 VMW_CURSOR_UPDATE_NONE; 680 } 681 } 682 } 683 break; 684 case VMW_CURSOR_UPDATE_NONE: 685 /* do nothing */ 686 break; 687 } 688 689 return 0; 690 } 691 692 /** 693 * vmw_cursor_plane_atomic_check - check if the new state is okay 694 * 695 * @plane: cursor plane 696 * @state: info on the new plane state 697 * 698 * This is a chance to fail if the new cursor state does not fit 699 * our requirements. 700 * 701 * Returns 0 on success 702 */ 703 int vmw_cursor_plane_atomic_check(struct drm_plane *plane, 704 struct drm_atomic_commit *state) 705 { 706 struct drm_plane_state *new_state = 707 drm_atomic_get_new_plane_state(state, plane); 708 struct vmw_private *vmw = vmw_priv(plane->dev); 709 int ret = 0; 710 struct drm_crtc_state *crtc_state = NULL; 711 struct vmw_surface *surface = NULL; 712 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 713 enum vmw_cursor_update_type update_type; 714 struct drm_framebuffer *fb = new_state->fb; 715 716 if (new_state->crtc) 717 crtc_state = drm_atomic_get_new_crtc_state(new_state->state, 718 new_state->crtc); 719 720 ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, 721 DRM_PLANE_NO_SCALING, 722 DRM_PLANE_NO_SCALING, true, 723 true); 724 if (ret) 725 return ret; 726 727 /* Turning off */ 728 if (!fb) 729 return 0; 730 731 update_type = vmw_cursor_update_type(vmw, vps); 732 if (update_type == VMW_CURSOR_UPDATE_LEGACY) { 733 if (new_state->crtc_w != VMW_CURSOR_SNOOP_WIDTH || 734 new_state->crtc_h != VMW_CURSOR_SNOOP_HEIGHT) { 735 drm_warn(&vmw->drm, 736 "Invalid cursor dimensions (%d, %d)\n", 737 new_state->crtc_w, new_state->crtc_h); 738 return -EINVAL; 739 } 740 surface = vmw_user_object_surface(&vps->uo); 741 if (!surface || !surface->snooper.image) { 742 drm_warn(&vmw->drm, 743 "surface not suitable for cursor\n"); 744 return -EINVAL; 745 } 746 } else if (update_type == VMW_CURSOR_UPDATE_GB_ONLY || 747 update_type == VMW_CURSOR_UPDATE_MOB) { 748 u32 cursor_max_dim = 749 vmw_read(vmw, SVGA_REG_CURSOR_MAX_DIMENSION); 750 751 if (new_state->crtc_w > cursor_max_dim || 752 new_state->crtc_h > cursor_max_dim) { 753 drm_warn(&vmw->drm, 754 "Cursor dimensions (%d, %d) exceed device max %u\n", 755 new_state->crtc_w, new_state->crtc_h, 756 cursor_max_dim); 757 return -EINVAL; 758 } 759 760 if (update_type == VMW_CURSOR_UPDATE_MOB) { 761 u32 mob_max_size = 762 vmw_read(vmw, SVGA_REG_MOB_MAX_SIZE); 763 u64 mob_size = (u64)new_state->crtc_w * 764 new_state->crtc_h * sizeof(u32) + 765 sizeof(SVGAGBCursorHeader); 766 767 if (mob_size > mob_max_size) { 768 drm_warn(&vmw->drm, 769 "Cursor MOB size %llu exceeds device max %u\n", 770 mob_size, mob_max_size); 771 return -EINVAL; 772 } 773 } 774 } 775 776 return 0; 777 } 778 779 void 780 vmw_cursor_plane_atomic_update(struct drm_plane *plane, 781 struct drm_atomic_commit *state) 782 { 783 struct vmw_bo *bo; 784 struct drm_plane_state *new_state = 785 drm_atomic_get_new_plane_state(state, plane); 786 struct drm_plane_state *old_state = 787 drm_atomic_get_old_plane_state(state, plane); 788 struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc; 789 struct vmw_private *dev_priv = vmw_priv(plane->dev); 790 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 791 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 792 s32 hotspot_x, hotspot_y, cursor_x, cursor_y; 793 794 /* 795 * Hide the cursor if the new bo is null 796 */ 797 if (vmw_user_object_is_null(&vps->uo)) { 798 vmw_cursor_update_position(dev_priv, false, 0, 0); 799 return; 800 } 801 802 switch (vps->cursor.update_type) { 803 case VMW_CURSOR_UPDATE_LEGACY: 804 vmw_cursor_plane_update_legacy(dev_priv, vps); 805 break; 806 case VMW_CURSOR_UPDATE_MOB: 807 vmw_cursor_update_mob(dev_priv, vps); 808 break; 809 case VMW_CURSOR_UPDATE_GB_ONLY: 810 bo = vmw_user_object_buffer(&vps->uo); 811 if (bo) 812 vmw_send_define_cursor_cmd(dev_priv, bo->map.virtual, 813 vps->base.crtc_w, 814 vps->base.crtc_h, 815 vps->base.hotspot_x, 816 vps->base.hotspot_y); 817 break; 818 case VMW_CURSOR_UPDATE_NONE: 819 /* do nothing */ 820 break; 821 } 822 823 /* 824 * For all update types update the cursor position 825 */ 826 cursor_x = new_state->crtc_x + du->set_gui_x; 827 cursor_y = new_state->crtc_y + du->set_gui_y; 828 829 hotspot_x = vps->cursor.legacy.hotspot_x + new_state->hotspot_x; 830 hotspot_y = vps->cursor.legacy.hotspot_y + new_state->hotspot_y; 831 832 vmw_cursor_update_position(dev_priv, true, cursor_x + hotspot_x, 833 cursor_y + hotspot_y); 834 } 835 836 int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, 837 struct drm_file *file_priv) 838 { 839 struct drm_vmw_cursor_bypass_arg *arg = data; 840 struct vmw_display_unit *du; 841 struct vmw_plane_state *vps; 842 struct drm_crtc *crtc; 843 int ret = 0; 844 845 mutex_lock(&dev->mode_config.mutex); 846 if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) { 847 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 848 du = vmw_crtc_to_du(crtc); 849 vps = vmw_plane_state_to_vps(du->cursor.base.state); 850 vps->cursor.legacy.hotspot_x = arg->xhot; 851 vps->cursor.legacy.hotspot_y = arg->yhot; 852 } 853 854 mutex_unlock(&dev->mode_config.mutex); 855 return 0; 856 } 857 858 crtc = drm_crtc_find(dev, file_priv, arg->crtc_id); 859 if (!crtc) { 860 ret = -ENOENT; 861 goto out; 862 } 863 864 du = vmw_crtc_to_du(crtc); 865 vps = vmw_plane_state_to_vps(du->cursor.base.state); 866 vps->cursor.legacy.hotspot_x = arg->xhot; 867 vps->cursor.legacy.hotspot_y = arg->yhot; 868 869 out: 870 mutex_unlock(&dev->mode_config.mutex); 871 872 return ret; 873 } 874 875 void *vmw_cursor_snooper_create(struct drm_file *file_priv, 876 struct vmw_surface_metadata *metadata) 877 { 878 if (!file_priv->atomic && metadata->scanout && 879 metadata->num_sizes == 1 && 880 metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH && 881 metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT && 882 metadata->format == VMW_CURSOR_SNOOP_FORMAT) { 883 const struct SVGA3dSurfaceDesc *desc = 884 vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 885 const u32 cursor_size_bytes = VMW_CURSOR_SNOOP_WIDTH * 886 VMW_CURSOR_SNOOP_HEIGHT * 887 desc->pitchBytesPerBlock; 888 void *image = kzalloc(cursor_size_bytes, GFP_KERNEL); 889 890 if (!image) { 891 DRM_ERROR("Failed to allocate cursor_image\n"); 892 return ERR_PTR(-ENOMEM); 893 } 894 return image; 895 } 896 return NULL; 897 } 898