Skip to content

Commit

Permalink
drm/vmwgfx: Fix fencing on SVGAv3
Browse files Browse the repository at this point in the history
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: 2cd80db ("drm/vmwgfx: Add basic support for SVGA3")
Signed-off-by: Zack Rusin <[email protected]>
Reviewed-by: Martin Krastev <[email protected]>
Reviewed-by: Maaz Mombasawala <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
zackr committed May 13, 2022
1 parent 5005e98 commit 1d6595b
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 19 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno)
*seqno = atomic_add_return(1, &dev_priv->marker_seq);
} while (*seqno == 0);

if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE)) {
if (!vmw_has_fences(dev_priv)) {

/*
* Don't request hardware to send a fence. The
Expand Down
8 changes: 8 additions & 0 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1679,4 +1679,12 @@ static inline void vmw_irq_status_write(struct vmw_private *vmw,
outl(status, vmw->io_start + SVGA_IRQSTATUS_PORT);
}

static inline bool vmw_has_fences(struct vmw_private *vmw)
{
if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
SVGA_CAP_CMD_BUFFERS_2)) != 0)
return true;
return (vmw_fifo_caps(vmw) & SVGA_FIFO_CAP_FENCE) != 0;
}

#endif
28 changes: 21 additions & 7 deletions drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,22 @@ fman_from_fence(struct vmw_fence_obj *fence)
return container_of(fence->base.lock, struct vmw_fence_manager, lock);
}

static u32 vmw_fence_goal_read(struct vmw_private *vmw)
{
if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
return vmw_read(vmw, SVGA_REG_FENCE_GOAL);
else
return vmw_fifo_mem_read(vmw, SVGA_FIFO_FENCE_GOAL);
}

static void vmw_fence_goal_write(struct vmw_private *vmw, u32 value)
{
if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
vmw_write(vmw, SVGA_REG_FENCE_GOAL, value);
else
vmw_fifo_mem_write(vmw, SVGA_FIFO_FENCE_GOAL, value);
}

/*
* Note on fencing subsystem usage of irqs:
* Typically the vmw_fences_update function is called
Expand Down Expand Up @@ -392,17 +408,16 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
if (likely(!fman->seqno_valid))
return false;

goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL);
goal_seqno = vmw_fence_goal_read(fman->dev_priv);
if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP))
return false;

fman->seqno_valid = false;
list_for_each_entry(fence, &fman->fence_list, head) {
if (!list_empty(&fence->seq_passed_actions)) {
fman->seqno_valid = true;
vmw_fifo_mem_write(fman->dev_priv,
SVGA_FIFO_FENCE_GOAL,
fence->base.seqno);
vmw_fence_goal_write(fman->dev_priv,
fence->base.seqno);
break;
}
}
Expand Down Expand Up @@ -434,13 +449,12 @@ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
if (dma_fence_is_signaled_locked(&fence->base))
return false;

goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL);
goal_seqno = vmw_fence_goal_read(fman->dev_priv);
if (likely(fman->seqno_valid &&
goal_seqno - fence->base.seqno < VMW_FENCE_WRAP))
return false;

vmw_fifo_mem_write(fman->dev_priv, SVGA_FIFO_FENCE_GOAL,
fence->base.seqno);
vmw_fence_goal_write(fman->dev_priv, fence->base.seqno);
fman->seqno_valid = true;

return true;
Expand Down
26 changes: 18 additions & 8 deletions drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@

#define VMW_FENCE_WRAP (1 << 24)

static u32 vmw_irqflag_fence_goal(struct vmw_private *vmw)
{
if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
return SVGA_IRQFLAG_REG_FENCE_GOAL;
else
return SVGA_IRQFLAG_FENCE_GOAL;
}

/**
* vmw_thread_fn - Deferred (process context) irq handler
*
Expand Down Expand Up @@ -96,7 +104,7 @@ static irqreturn_t vmw_irq_handler(int irq, void *arg)
wake_up_all(&dev_priv->fifo_queue);

if ((masked_status & (SVGA_IRQFLAG_ANY_FENCE |
SVGA_IRQFLAG_FENCE_GOAL)) &&
vmw_irqflag_fence_goal(dev_priv))) &&
!test_and_set_bit(VMW_IRQTHREAD_FENCE, dev_priv->irqthread_pending))
ret = IRQ_WAKE_THREAD;

Expand Down Expand Up @@ -137,8 +145,7 @@ bool vmw_seqno_passed(struct vmw_private *dev_priv,
if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
return true;

if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE) &&
vmw_fifo_idle(dev_priv, seqno))
if (!vmw_has_fences(dev_priv) && vmw_fifo_idle(dev_priv, seqno))
return true;

/**
Expand All @@ -160,6 +167,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
unsigned long timeout)
{
struct vmw_fifo_state *fifo_state = dev_priv->fifo;
bool fifo_down = false;

uint32_t count = 0;
uint32_t signal_seq;
Expand All @@ -176,12 +184,14 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
*/

if (fifo_idle) {
down_read(&fifo_state->rwsem);
if (dev_priv->cman) {
ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible,
10*HZ);
if (ret)
goto out_err;
} else if (fifo_state) {
down_read(&fifo_state->rwsem);
fifo_down = true;
}
}

Expand Down Expand Up @@ -218,12 +228,12 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
}
}
finish_wait(&dev_priv->fence_queue, &__wait);
if (ret == 0 && fifo_idle)
if (ret == 0 && fifo_idle && fifo_state)
vmw_fence_write(dev_priv, signal_seq);

wake_up_all(&dev_priv->fence_queue);
out_err:
if (fifo_idle)
if (fifo_down)
up_read(&fifo_state->rwsem);

return ret;
Expand Down Expand Up @@ -266,13 +276,13 @@ void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)

void vmw_goal_waiter_add(struct vmw_private *dev_priv)
{
vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
vmw_generic_waiter_add(dev_priv, vmw_irqflag_fence_goal(dev_priv),
&dev_priv->goal_queue_waiters);
}

void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
{
vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
vmw_generic_waiter_remove(dev_priv, vmw_irqflag_fence_goal(dev_priv),
&dev_priv->goal_queue_waiters);
}

Expand Down
8 changes: 5 additions & 3 deletions drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -1344,7 +1344,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
mode_cmd,
is_bo_proxy);

/*
* vmw_create_bo_proxy() adds a reference that is no longer
* needed
Expand Down Expand Up @@ -1385,13 +1384,16 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
ret = vmw_user_lookup_handle(dev_priv, file_priv,
mode_cmd->handles[0],
&surface, &bo);
if (ret)
if (ret) {
DRM_ERROR("Invalid buffer object handle %u (0x%x).\n",
mode_cmd->handles[0], mode_cmd->handles[0]);
goto err_out;
}


if (!bo &&
!vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) {
DRM_ERROR("Surface size cannot exceed %dx%d",
DRM_ERROR("Surface size cannot exceed %dx%d\n",
dev_priv->texture_max_width,
dev_priv->texture_max_height);
goto err_out;
Expand Down

0 comments on commit 1d6595b

Please sign in to comment.