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

drm/vmwgfx: Fix fencing on SVGAv3

Port of the vmwgfx to SVGAv3 lacked support for fencing. SVGAv3 removed
FIFO's and replaced them with command buffers and extra registers.
The initial version of SVGAv3 lacked support for most advanced features
(e.g. 3D) which made fences unnecessary. That is no longer the case,
especially as 3D support is being turned on.

Switch from FIFO commands and capabilities to command buffers and extra
registers to enable fences on SVGAv3.

Fixes: 2cd80dbd3551 ("drm/vmwgfx: Add basic support for SVGA3")
Signed-off-by: Zack Rusin <zackr@vmware.com>
Reviewed-by: Martin Krastev <krastevm@vmware.com>
Reviewed-by: Maaz Mombasawala <mombasawalam@vmware.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220302152426.885214-5-zack@kde.org

+53 -19
+1 -1
drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
··· 528 528 *seqno = atomic_add_return(1, &dev_priv->marker_seq); 529 529 } while (*seqno == 0); 530 530 531 - if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE)) { 531 + if (!vmw_has_fences(dev_priv)) { 532 532 533 533 /* 534 534 * Don't request hardware to send a fence. The
+8
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
··· 1683 1683 outl(status, vmw->io_start + SVGA_IRQSTATUS_PORT); 1684 1684 } 1685 1685 1686 + static inline bool vmw_has_fences(struct vmw_private *vmw) 1687 + { 1688 + if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS | 1689 + SVGA_CAP_CMD_BUFFERS_2)) != 0) 1690 + return true; 1691 + return (vmw_fifo_caps(vmw) & SVGA_FIFO_CAP_FENCE) != 0; 1692 + } 1693 + 1686 1694 #endif
+21 -7
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
··· 82 82 return container_of(fence->base.lock, struct vmw_fence_manager, lock); 83 83 } 84 84 85 + static u32 vmw_fence_goal_read(struct vmw_private *vmw) 86 + { 87 + if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0) 88 + return vmw_read(vmw, SVGA_REG_FENCE_GOAL); 89 + else 90 + return vmw_fifo_mem_read(vmw, SVGA_FIFO_FENCE_GOAL); 91 + } 92 + 93 + static void vmw_fence_goal_write(struct vmw_private *vmw, u32 value) 94 + { 95 + if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0) 96 + vmw_write(vmw, SVGA_REG_FENCE_GOAL, value); 97 + else 98 + vmw_fifo_mem_write(vmw, SVGA_FIFO_FENCE_GOAL, value); 99 + } 100 + 85 101 /* 86 102 * Note on fencing subsystem usage of irqs: 87 103 * Typically the vmw_fences_update function is called ··· 408 392 if (likely(!fman->seqno_valid)) 409 393 return false; 410 394 411 - goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL); 395 + goal_seqno = vmw_fence_goal_read(fman->dev_priv); 412 396 if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP)) 413 397 return false; 414 398 ··· 416 400 list_for_each_entry(fence, &fman->fence_list, head) { 417 401 if (!list_empty(&fence->seq_passed_actions)) { 418 402 fman->seqno_valid = true; 419 - vmw_fifo_mem_write(fman->dev_priv, 420 - SVGA_FIFO_FENCE_GOAL, 421 - fence->base.seqno); 403 + vmw_fence_goal_write(fman->dev_priv, 404 + fence->base.seqno); 422 405 break; 423 406 } 424 407 } ··· 449 434 if (dma_fence_is_signaled_locked(&fence->base)) 450 435 return false; 451 436 452 - goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL); 437 + goal_seqno = vmw_fence_goal_read(fman->dev_priv); 453 438 if (likely(fman->seqno_valid && 454 439 goal_seqno - fence->base.seqno < VMW_FENCE_WRAP)) 455 440 return false; 456 441 457 - vmw_fifo_mem_write(fman->dev_priv, SVGA_FIFO_FENCE_GOAL, 458 - fence->base.seqno); 442 + vmw_fence_goal_write(fman->dev_priv, fence->base.seqno); 459 443 fman->seqno_valid = true; 460 444 461 445 return true;
+18 -8
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
··· 32 32 33 33 #define VMW_FENCE_WRAP (1 << 24) 34 34 35 + static u32 vmw_irqflag_fence_goal(struct vmw_private *vmw) 36 + { 37 + if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0) 38 + return SVGA_IRQFLAG_REG_FENCE_GOAL; 39 + else 40 + return SVGA_IRQFLAG_FENCE_GOAL; 41 + } 42 + 35 43 /** 36 44 * vmw_thread_fn - Deferred (process context) irq handler 37 45 * ··· 104 96 wake_up_all(&dev_priv->fifo_queue); 105 97 106 98 if ((masked_status & (SVGA_IRQFLAG_ANY_FENCE | 107 - SVGA_IRQFLAG_FENCE_GOAL)) && 99 + vmw_irqflag_fence_goal(dev_priv))) && 108 100 !test_and_set_bit(VMW_IRQTHREAD_FENCE, dev_priv->irqthread_pending)) 109 101 ret = IRQ_WAKE_THREAD; 110 102 ··· 145 137 if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) 146 138 return true; 147 139 148 - if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE) && 149 - vmw_fifo_idle(dev_priv, seqno)) 140 + if (!vmw_has_fences(dev_priv) && vmw_fifo_idle(dev_priv, seqno)) 150 141 return true; 151 142 152 143 /** ··· 167 160 unsigned long timeout) 168 161 { 169 162 struct vmw_fifo_state *fifo_state = dev_priv->fifo; 163 + bool fifo_down = false; 170 164 171 165 uint32_t count = 0; 172 166 uint32_t signal_seq; ··· 184 176 */ 185 177 186 178 if (fifo_idle) { 187 - down_read(&fifo_state->rwsem); 188 179 if (dev_priv->cman) { 189 180 ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible, 190 181 10*HZ); 191 182 if (ret) 192 183 goto out_err; 184 + } else if (fifo_state) { 185 + down_read(&fifo_state->rwsem); 186 + fifo_down = true; 193 187 } 194 188 } 195 189 ··· 228 218 } 229 219 } 230 220 finish_wait(&dev_priv->fence_queue, &__wait); 231 - if (ret == 0 && fifo_idle) 221 + if (ret == 0 && fifo_idle && fifo_state) 232 222 vmw_fence_write(dev_priv, signal_seq); 233 223 234 224 wake_up_all(&dev_priv->fence_queue); 235 225 out_err: 236 - if (fifo_idle) 226 + if (fifo_down) 237 227 up_read(&fifo_state->rwsem); 238 228 239 229 return ret; ··· 276 266 277 267 void vmw_goal_waiter_add(struct vmw_private *dev_priv) 278 268 { 279 - vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL, 269 + vmw_generic_waiter_add(dev_priv, vmw_irqflag_fence_goal(dev_priv), 280 270 &dev_priv->goal_queue_waiters); 281 271 } 282 272 283 273 void vmw_goal_waiter_remove(struct vmw_private *dev_priv) 284 274 { 285 - vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL, 275 + vmw_generic_waiter_remove(dev_priv, vmw_irqflag_fence_goal(dev_priv), 286 276 &dev_priv->goal_queue_waiters); 287 277 } 288 278
+5 -3
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
··· 1593 1593 ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, 1594 1594 mode_cmd, 1595 1595 is_bo_proxy); 1596 - 1597 1596 /* 1598 1597 * vmw_create_bo_proxy() adds a reference that is no longer 1599 1598 * needed ··· 1633 1634 ret = vmw_user_lookup_handle(dev_priv, file_priv, 1634 1635 mode_cmd->handles[0], 1635 1636 &surface, &bo); 1636 - if (ret) 1637 + if (ret) { 1638 + DRM_ERROR("Invalid buffer object handle %u (0x%x).\n", 1639 + mode_cmd->handles[0], mode_cmd->handles[0]); 1637 1640 goto err_out; 1641 + } 1638 1642 1639 1643 1640 1644 if (!bo && 1641 1645 !vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) { 1642 - DRM_ERROR("Surface size cannot exceed %dx%d", 1646 + DRM_ERROR("Surface size cannot exceed %dx%d\n", 1643 1647 dev_priv->texture_max_width, 1644 1648 dev_priv->texture_max_height); 1645 1649 goto err_out;