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 u64 src_extent; 328 void *virtual; 329 bool is_iomem; 330 struct vmw_dma_cmd { 331 SVGA3dCmdHeader header; 332 SVGA3dCmdSurfaceDMA dma; 333 } *cmd; 334 int i, ret; 335 const struct SVGA3dSurfaceDesc *desc = 336 vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 337 const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock; 338 339 BUILD_BUG_ON(sizeof(*srf->snooper.image) != desc->pitchBytesPerBlock); 340 341 cmd = container_of(header, struct vmw_dma_cmd, header); 342 343 /* No snooper installed, nothing to copy */ 344 if (!srf->snooper.image) 345 return; 346 347 if (cmd->dma.host.face != 0 || cmd->dma.host.mipmap != 0) { 348 DRM_ERROR("face and mipmap for cursors should never != 0\n"); 349 return; 350 } 351 352 if (cmd->header.size < 64) { 353 DRM_ERROR("at least one full copy box must be given\n"); 354 return; 355 } 356 357 box = (SVGA3dCopyBox *)&cmd[1]; 358 box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) / 359 sizeof(SVGA3dCopyBox); 360 361 if (cmd->dma.guest.ptr.offset % PAGE_SIZE || 362 box->x != 0 || box->y != 0 || box->z != 0 || 363 box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || 364 box->d != 1 || box_count != 1 || 365 box->w > VMW_CURSOR_SNOOP_WIDTH || box->h > VMW_CURSOR_SNOOP_HEIGHT) { 366 /* TODO handle none page aligned offsets */ 367 /* TODO handle more dst & src != 0 */ 368 /* TODO handle more then one copy */ 369 DRM_ERROR("Can't snoop dma request for cursor!\n"); 370 DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n", 371 box->srcx, box->srcy, box->srcz, 372 box->x, box->y, box->z, 373 box->w, box->h, box->d, box_count, 374 cmd->dma.guest.ptr.offset); 375 return; 376 } 377 378 if (box->w == 0 || box->h == 0) 379 return; 380 381 src_extent = (u64)(box->h - 1) * cmd->dma.guest.pitch + 382 (u64)box->w * desc->pitchBytesPerBlock; 383 if (src_extent > bo->base.size) { 384 DRM_ERROR("Cursor snoop source of %llu bytes exceeds the %zu byte buffer\n", 385 src_extent, bo->base.size); 386 return; 387 } 388 389 kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT; 390 kmap_num = PFN_UP(src_extent); 391 392 ret = ttm_bo_reserve(bo, true, false, NULL); 393 if (unlikely(ret != 0)) { 394 DRM_ERROR("reserve failed\n"); 395 return; 396 } 397 398 ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map); 399 if (unlikely(ret != 0)) 400 goto err_unreserve; 401 402 virtual = ttm_kmap_obj_virtual(&map, &is_iomem); 403 404 if (box->w == VMW_CURSOR_SNOOP_WIDTH && 405 box->h == VMW_CURSOR_SNOOP_HEIGHT && 406 cmd->dma.guest.pitch == image_pitch) { 407 memcpy(srf->snooper.image, virtual, 408 VMW_CURSOR_SNOOP_HEIGHT * image_pitch); 409 } else { 410 /* The destination stride is in pixels. */ 411 for (i = 0; i < box->h; i++) 412 memcpy(srf->snooper.image + i * VMW_CURSOR_SNOOP_WIDTH, 413 virtual + (size_t)i * cmd->dma.guest.pitch, 414 box->w * desc->pitchBytesPerBlock); 415 } 416 srf->snooper.id++; 417 418 ttm_bo_kunmap(&map); 419 err_unreserve: 420 ttm_bo_unreserve(bo); 421 } 422 423 void vmw_cursor_plane_destroy(struct drm_plane *plane) 424 { 425 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 426 u32 i; 427 428 vmw_cursor_update_position(vmw_priv(plane->dev), false, 0, 0); 429 430 for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) 431 vmw_cursor_mob_destroy(&vcp->cursor_mobs[i]); 432 433 drm_plane_cleanup(plane); 434 } 435 436 /** 437 * vmw_cursor_mob_map - Maps the cursor mobs. 438 * 439 * @vps: plane_state 440 * 441 * Returns 0 on success 442 */ 443 444 static int 445 vmw_cursor_mob_map(struct vmw_plane_state *vps) 446 { 447 int ret; 448 u32 size = vmw_cursor_mob_size(vps->cursor.update_type, 449 vps->base.crtc_w, vps->base.crtc_h); 450 struct vmw_bo *vbo = vps->cursor.mob; 451 void *map; 452 453 if (!vbo) 454 return -EINVAL; 455 456 if (vbo->tbo.base.size < size) 457 return -EINVAL; 458 459 if (vbo->map.virtual) 460 return 0; 461 462 ret = ttm_bo_reserve(&vbo->tbo, false, false, NULL); 463 if (unlikely(ret != 0)) 464 return -ENOMEM; 465 466 map = vmw_bo_map_and_cache(vbo); 467 if (!map) { 468 vmw_bo_unmap(vbo); 469 ret = -ENOMEM; 470 } 471 472 ttm_bo_unreserve(&vbo->tbo); 473 474 return ret; 475 } 476 477 /** 478 * vmw_cursor_plane_cleanup_fb - Unpins the plane surface 479 * 480 * @plane: cursor plane 481 * @old_state: contains the state to clean up 482 * 483 * Unmaps all cursor bo mappings and unpins the cursor surface 484 * 485 * Returns 0 on success 486 */ 487 void 488 vmw_cursor_plane_cleanup_fb(struct drm_plane *plane, 489 struct drm_plane_state *old_state) 490 { 491 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 492 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 493 494 if (!vmw_user_object_is_null(&vps->uo)) 495 vmw_user_object_unmap(&vps->uo); 496 497 vmw_cursor_mob_unmap(vps); 498 vmw_cursor_mob_put(vcp, vps); 499 500 vmw_du_plane_unpin_surf(vps); 501 vmw_user_object_unref(&vps->uo); 502 } 503 504 static bool 505 vmw_cursor_buffer_changed(struct vmw_plane_state *new_vps, 506 struct vmw_plane_state *old_vps) 507 { 508 struct vmw_bo *new_bo = vmw_user_object_buffer(&new_vps->uo); 509 struct vmw_bo *old_bo = vmw_user_object_buffer(&old_vps->uo); 510 struct vmw_surface *surf; 511 bool dirty = false; 512 int ret; 513 514 if (new_bo != old_bo) 515 return true; 516 517 if (new_bo) { 518 if (!old_bo) { 519 return true; 520 } else if (new_bo->dirty) { 521 vmw_bo_dirty_scan(new_bo); 522 dirty = vmw_bo_is_dirty(new_bo); 523 if (dirty) { 524 surf = vmw_user_object_surface(&new_vps->uo); 525 if (surf) 526 vmw_bo_dirty_transfer_to_res(&surf->res); 527 else 528 vmw_bo_dirty_clear(new_bo); 529 } 530 return dirty; 531 } else if (new_bo != old_bo) { 532 /* 533 * Currently unused because the top exits right away. 534 * In most cases buffer being different will mean 535 * that the contents is different. For the few percent 536 * of cases where that's not true the cost of doing 537 * the memcmp on all other seems to outweight the 538 * benefits. Leave the conditional to be able to 539 * trivially validate it by removing the initial 540 * if (new_bo != old_bo) at the start. 541 */ 542 void *old_image; 543 void *new_image; 544 bool changed = false; 545 struct ww_acquire_ctx ctx; 546 const u32 size = new_vps->base.crtc_w * 547 new_vps->base.crtc_h * sizeof(u32); 548 549 ww_acquire_init(&ctx, &reservation_ww_class); 550 551 ret = ttm_bo_reserve(&old_bo->tbo, false, false, &ctx); 552 if (ret != 0) { 553 ww_acquire_fini(&ctx); 554 return true; 555 } 556 557 ret = ttm_bo_reserve(&new_bo->tbo, false, false, &ctx); 558 if (ret != 0) { 559 ttm_bo_unreserve(&old_bo->tbo); 560 ww_acquire_fini(&ctx); 561 return true; 562 } 563 564 old_image = vmw_bo_map_and_cache(old_bo); 565 new_image = vmw_bo_map_and_cache(new_bo); 566 567 if (old_image && new_image && old_image != new_image) 568 changed = memcmp(old_image, new_image, size) != 569 0; 570 571 ttm_bo_unreserve(&new_bo->tbo); 572 ttm_bo_unreserve(&old_bo->tbo); 573 574 ww_acquire_fini(&ctx); 575 576 return changed; 577 } 578 return false; 579 } 580 581 return false; 582 } 583 584 static bool 585 vmw_cursor_plane_changed(struct vmw_plane_state *new_vps, 586 struct vmw_plane_state *old_vps) 587 { 588 if (old_vps->base.crtc_w != new_vps->base.crtc_w || 589 old_vps->base.crtc_h != new_vps->base.crtc_h) 590 return true; 591 592 if (old_vps->base.hotspot_x != new_vps->base.hotspot_x || 593 old_vps->base.hotspot_y != new_vps->base.hotspot_y) 594 return true; 595 596 if (old_vps->cursor.legacy.hotspot_x != 597 new_vps->cursor.legacy.hotspot_x || 598 old_vps->cursor.legacy.hotspot_y != 599 new_vps->cursor.legacy.hotspot_y) 600 return true; 601 602 if (old_vps->base.fb != new_vps->base.fb) 603 return true; 604 605 return false; 606 } 607 608 /** 609 * vmw_cursor_plane_prepare_fb - Readies the cursor by referencing it 610 * 611 * @plane: display plane 612 * @new_state: info on the new plane state, including the FB 613 * 614 * Returns 0 on success 615 */ 616 int vmw_cursor_plane_prepare_fb(struct drm_plane *plane, 617 struct drm_plane_state *new_state) 618 { 619 struct drm_framebuffer *fb = new_state->fb; 620 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 621 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 622 struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(plane->state); 623 struct vmw_private *vmw = vmw_priv(plane->dev); 624 struct vmw_bo *bo = NULL; 625 struct vmw_surface *surface; 626 int ret = 0; 627 628 if (!vmw_user_object_is_null(&vps->uo)) { 629 vmw_user_object_unmap(&vps->uo); 630 vmw_user_object_unref(&vps->uo); 631 } 632 633 if (fb) { 634 if (vmw_framebuffer_to_vfb(fb)->bo) { 635 vps->uo.buffer = vmw_framebuffer_to_vfbd(fb)->buffer; 636 vps->uo.surface = NULL; 637 } else { 638 memcpy(&vps->uo, &vmw_framebuffer_to_vfbs(fb)->uo, sizeof(vps->uo)); 639 } 640 vmw_user_object_ref(&vps->uo); 641 } 642 643 vps->cursor.update_type = vmw_cursor_update_type(vmw, vps); 644 switch (vps->cursor.update_type) { 645 case VMW_CURSOR_UPDATE_LEGACY: 646 surface = vmw_user_object_surface(&vps->uo); 647 if (!surface || vps->cursor.legacy.id == surface->snooper.id) 648 vps->cursor.update_type = VMW_CURSOR_UPDATE_NONE; 649 break; 650 case VMW_CURSOR_UPDATE_GB_ONLY: 651 case VMW_CURSOR_UPDATE_MOB: { 652 bo = vmw_user_object_buffer(&vps->uo); 653 if (bo) { 654 struct ttm_operation_ctx ctx = { false, false }; 655 656 ret = ttm_bo_reserve(&bo->tbo, true, false, NULL); 657 if (ret != 0) 658 return -ENOMEM; 659 660 ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 661 if (ret != 0) 662 return -ENOMEM; 663 664 /* 665 * vmw_bo_pin_reserved also validates, so to skip 666 * the extra validation use ttm_bo_pin directly 667 */ 668 if (!bo->tbo.pin_count) 669 ttm_bo_pin(&bo->tbo); 670 671 if (vmw_framebuffer_to_vfb(fb)->bo) { 672 const u32 size = new_state->crtc_w * 673 new_state->crtc_h * 674 sizeof(u32); 675 676 (void)vmw_bo_map_and_cache_size(bo, size); 677 } else { 678 vmw_bo_map_and_cache(bo); 679 } 680 ttm_bo_unreserve(&bo->tbo); 681 } 682 if (!vmw_user_object_is_null(&vps->uo)) { 683 if (!vmw_cursor_plane_changed(vps, old_vps) && 684 !vmw_cursor_buffer_changed(vps, old_vps)) { 685 vps->cursor.update_type = 686 VMW_CURSOR_UPDATE_NONE; 687 } else if (vps->cursor.update_type == 688 VMW_CURSOR_UPDATE_MOB && 689 (vmw_cursor_mob_get(vcp, vps) || 690 vmw_cursor_mob_map(vps))) { 691 /* 692 * Reset the cursor to avoid crashes later. 693 */ 694 vps->cursor.update_type = 695 VMW_CURSOR_UPDATE_NONE; 696 } 697 } 698 } 699 break; 700 case VMW_CURSOR_UPDATE_NONE: 701 /* do nothing */ 702 break; 703 } 704 705 return 0; 706 } 707 708 /** 709 * vmw_cursor_plane_atomic_check - check if the new state is okay 710 * 711 * @plane: cursor plane 712 * @state: info on the new plane state 713 * 714 * This is a chance to fail if the new cursor state does not fit 715 * our requirements. 716 * 717 * Returns 0 on success 718 */ 719 int vmw_cursor_plane_atomic_check(struct drm_plane *plane, 720 struct drm_atomic_commit *state) 721 { 722 struct drm_plane_state *new_state = 723 drm_atomic_get_new_plane_state(state, plane); 724 struct vmw_private *vmw = vmw_priv(plane->dev); 725 int ret = 0; 726 struct drm_crtc_state *crtc_state = NULL; 727 struct vmw_surface *surface = NULL; 728 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 729 enum vmw_cursor_update_type update_type; 730 struct drm_framebuffer *fb = new_state->fb; 731 732 if (new_state->crtc) 733 crtc_state = drm_atomic_get_new_crtc_state(new_state->state, 734 new_state->crtc); 735 736 ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, 737 DRM_PLANE_NO_SCALING, 738 DRM_PLANE_NO_SCALING, true, 739 true); 740 if (ret) 741 return ret; 742 743 /* Turning off */ 744 if (!fb) 745 return 0; 746 747 update_type = vmw_cursor_update_type(vmw, vps); 748 if (update_type == VMW_CURSOR_UPDATE_LEGACY) { 749 if (new_state->crtc_w != VMW_CURSOR_SNOOP_WIDTH || 750 new_state->crtc_h != VMW_CURSOR_SNOOP_HEIGHT) { 751 drm_warn(&vmw->drm, 752 "Invalid cursor dimensions (%d, %d)\n", 753 new_state->crtc_w, new_state->crtc_h); 754 return -EINVAL; 755 } 756 surface = vmw_user_object_surface(&vps->uo); 757 if (!surface || !surface->snooper.image) { 758 drm_warn(&vmw->drm, 759 "surface not suitable for cursor\n"); 760 return -EINVAL; 761 } 762 } else if (update_type == VMW_CURSOR_UPDATE_GB_ONLY || 763 update_type == VMW_CURSOR_UPDATE_MOB) { 764 u32 cursor_max_dim = 765 vmw_read(vmw, SVGA_REG_CURSOR_MAX_DIMENSION); 766 767 if (new_state->crtc_w > cursor_max_dim || 768 new_state->crtc_h > cursor_max_dim) { 769 drm_warn(&vmw->drm, 770 "Cursor dimensions (%d, %d) exceed device max %u\n", 771 new_state->crtc_w, new_state->crtc_h, 772 cursor_max_dim); 773 return -EINVAL; 774 } 775 776 if (update_type == VMW_CURSOR_UPDATE_MOB) { 777 u32 mob_max_size = 778 vmw_read(vmw, SVGA_REG_MOB_MAX_SIZE); 779 u64 mob_size = (u64)new_state->crtc_w * 780 new_state->crtc_h * sizeof(u32) + 781 sizeof(SVGAGBCursorHeader); 782 783 if (mob_size > mob_max_size) { 784 drm_warn(&vmw->drm, 785 "Cursor MOB size %llu exceeds device max %u\n", 786 mob_size, mob_max_size); 787 return -EINVAL; 788 } 789 } 790 } 791 792 return 0; 793 } 794 795 void 796 vmw_cursor_plane_atomic_update(struct drm_plane *plane, 797 struct drm_atomic_commit *state) 798 { 799 struct vmw_bo *bo; 800 struct drm_plane_state *new_state = 801 drm_atomic_get_new_plane_state(state, plane); 802 struct drm_plane_state *old_state = 803 drm_atomic_get_old_plane_state(state, plane); 804 struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc; 805 struct vmw_private *dev_priv = vmw_priv(plane->dev); 806 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 807 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 808 s32 hotspot_x, hotspot_y, cursor_x, cursor_y; 809 810 /* 811 * Hide the cursor if the new bo is null 812 */ 813 if (vmw_user_object_is_null(&vps->uo)) { 814 vmw_cursor_update_position(dev_priv, false, 0, 0); 815 return; 816 } 817 818 switch (vps->cursor.update_type) { 819 case VMW_CURSOR_UPDATE_LEGACY: 820 vmw_cursor_plane_update_legacy(dev_priv, vps); 821 break; 822 case VMW_CURSOR_UPDATE_MOB: 823 vmw_cursor_update_mob(dev_priv, vps); 824 break; 825 case VMW_CURSOR_UPDATE_GB_ONLY: 826 bo = vmw_user_object_buffer(&vps->uo); 827 if (bo) 828 vmw_send_define_cursor_cmd(dev_priv, bo->map.virtual, 829 vps->base.crtc_w, 830 vps->base.crtc_h, 831 vps->base.hotspot_x, 832 vps->base.hotspot_y); 833 break; 834 case VMW_CURSOR_UPDATE_NONE: 835 /* do nothing */ 836 break; 837 } 838 839 /* 840 * For all update types update the cursor position 841 */ 842 cursor_x = new_state->crtc_x + du->set_gui_x; 843 cursor_y = new_state->crtc_y + du->set_gui_y; 844 845 hotspot_x = vps->cursor.legacy.hotspot_x + new_state->hotspot_x; 846 hotspot_y = vps->cursor.legacy.hotspot_y + new_state->hotspot_y; 847 848 vmw_cursor_update_position(dev_priv, true, cursor_x + hotspot_x, 849 cursor_y + hotspot_y); 850 } 851 852 int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, 853 struct drm_file *file_priv) 854 { 855 struct drm_vmw_cursor_bypass_arg *arg = data; 856 struct vmw_display_unit *du; 857 struct vmw_plane_state *vps; 858 struct drm_crtc *crtc; 859 int ret = 0; 860 861 mutex_lock(&dev->mode_config.mutex); 862 if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) { 863 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 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 870 mutex_unlock(&dev->mode_config.mutex); 871 return 0; 872 } 873 874 crtc = drm_crtc_find(dev, file_priv, arg->crtc_id); 875 if (!crtc) { 876 ret = -ENOENT; 877 goto out; 878 } 879 880 du = vmw_crtc_to_du(crtc); 881 vps = vmw_plane_state_to_vps(du->cursor.base.state); 882 vps->cursor.legacy.hotspot_x = arg->xhot; 883 vps->cursor.legacy.hotspot_y = arg->yhot; 884 885 out: 886 mutex_unlock(&dev->mode_config.mutex); 887 888 return ret; 889 } 890 891 void *vmw_cursor_snooper_create(struct drm_file *file_priv, 892 struct vmw_surface_metadata *metadata) 893 { 894 if (!file_priv->atomic && metadata->scanout && 895 metadata->num_sizes == 1 && 896 metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH && 897 metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT && 898 metadata->format == VMW_CURSOR_SNOOP_FORMAT) { 899 const struct SVGA3dSurfaceDesc *desc = 900 vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); 901 const u32 cursor_size_bytes = VMW_CURSOR_SNOOP_WIDTH * 902 VMW_CURSOR_SNOOP_HEIGHT * 903 desc->pitchBytesPerBlock; 904 void *image = kzalloc(cursor_size_bytes, GFP_KERNEL); 905 906 if (!image) { 907 DRM_ERROR("Failed to allocate cursor_image\n"); 908 return ERR_PTR(-ENOMEM); 909 } 910 return image; 911 } 912 return NULL; 913 } 914