Commit d2e8851a authored by Thomas Hellstrom's avatar Thomas Hellstrom

drm/vmwgfx: Relax irq locking somewhat

Relax locking with the goal of reducing the number of locking cycles and
time spent with irqs disabled.
Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: default avatarSinclair Yeh <syeh@vmware.com>
parent 4e0858a6
...@@ -643,7 +643,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) ...@@ -643,7 +643,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
init_waitqueue_head(&dev_priv->fence_queue); init_waitqueue_head(&dev_priv->fence_queue);
init_waitqueue_head(&dev_priv->fifo_queue); init_waitqueue_head(&dev_priv->fifo_queue);
dev_priv->fence_queue_waiters = 0; dev_priv->fence_queue_waiters = 0;
atomic_set(&dev_priv->fifo_queue_waiters, 0); dev_priv->fifo_queue_waiters = 0;
dev_priv->used_memory_size = 0; dev_priv->used_memory_size = 0;
......
...@@ -440,13 +440,12 @@ struct vmw_private { ...@@ -440,13 +440,12 @@ struct vmw_private {
spinlock_t waiter_lock; spinlock_t waiter_lock;
int fence_queue_waiters; /* Protected by waiter_lock */ int fence_queue_waiters; /* Protected by waiter_lock */
int goal_queue_waiters; /* Protected by waiter_lock */ int goal_queue_waiters; /* Protected by waiter_lock */
int cmdbuf_waiters; /* Protected by irq_lock */ int cmdbuf_waiters; /* Protected by waiter_lock */
int error_waiters; /* Protected by irq_lock */ int error_waiters; /* Protected by waiter_lock */
atomic_t fifo_queue_waiters; int fifo_queue_waiters; /* Protected by waiter_lock */
uint32_t last_read_seqno; uint32_t last_read_seqno;
spinlock_t irq_lock;
struct vmw_fence_manager *fman; struct vmw_fence_manager *fman;
uint32_t irq_mask; uint32_t irq_mask; /* Updates protected by waiter_lock */
/* /*
* Device state * Device state
......
...@@ -252,7 +252,6 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv, ...@@ -252,7 +252,6 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
unsigned long timeout) unsigned long timeout)
{ {
long ret = 1L; long ret = 1L;
unsigned long irq_flags;
if (likely(!vmw_fifo_is_full(dev_priv, bytes))) if (likely(!vmw_fifo_is_full(dev_priv, bytes)))
return 0; return 0;
...@@ -262,16 +261,8 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv, ...@@ -262,16 +261,8 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
return vmw_fifo_wait_noirq(dev_priv, bytes, return vmw_fifo_wait_noirq(dev_priv, bytes,
interruptible, timeout); interruptible, timeout);
spin_lock(&dev_priv->waiter_lock); vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FIFO_PROGRESS,
if (atomic_add_return(1, &dev_priv->fifo_queue_waiters) > 0) { &dev_priv->fifo_queue_waiters);
spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
outl(SVGA_IRQFLAG_FIFO_PROGRESS,
dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
dev_priv->irq_mask |= SVGA_IRQFLAG_FIFO_PROGRESS;
vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
}
spin_unlock(&dev_priv->waiter_lock);
if (interruptible) if (interruptible)
ret = wait_event_interruptible_timeout ret = wait_event_interruptible_timeout
...@@ -287,14 +278,8 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv, ...@@ -287,14 +278,8 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
else if (likely(ret > 0)) else if (likely(ret > 0))
ret = 0; ret = 0;
spin_lock(&dev_priv->waiter_lock); vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FIFO_PROGRESS,
if (atomic_dec_and_test(&dev_priv->fifo_queue_waiters)) { &dev_priv->fifo_queue_waiters);
spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
dev_priv->irq_mask &= ~SVGA_IRQFLAG_FIFO_PROGRESS;
vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
}
spin_unlock(&dev_priv->waiter_lock);
return ret; return ret;
} }
......
...@@ -36,15 +36,13 @@ irqreturn_t vmw_irq_handler(int irq, void *arg) ...@@ -36,15 +36,13 @@ irqreturn_t vmw_irq_handler(int irq, void *arg)
struct vmw_private *dev_priv = vmw_priv(dev); struct vmw_private *dev_priv = vmw_priv(dev);
uint32_t status, masked_status; uint32_t status, masked_status;
spin_lock(&dev_priv->irq_lock);
status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
masked_status = status & dev_priv->irq_mask; masked_status = status & READ_ONCE(dev_priv->irq_mask);
spin_unlock(&dev_priv->irq_lock);
if (likely(status)) if (likely(status))
outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
if (!masked_status) if (!status)
return IRQ_NONE; return IRQ_NONE;
if (masked_status & (SVGA_IRQFLAG_ANY_FENCE | if (masked_status & (SVGA_IRQFLAG_ANY_FENCE |
...@@ -190,65 +188,51 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, ...@@ -190,65 +188,51 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
return ret; return ret;
} }
void vmw_seqno_waiter_add(struct vmw_private *dev_priv) void vmw_generic_waiter_add(struct vmw_private *dev_priv,
u32 flag, int *waiter_count)
{ {
spin_lock(&dev_priv->waiter_lock); spin_lock_bh(&dev_priv->waiter_lock);
if (dev_priv->fence_queue_waiters++ == 0) { if ((*waiter_count)++ == 0) {
unsigned long irq_flags; outl(flag, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
dev_priv->irq_mask |= flag;
spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
outl(SVGA_IRQFLAG_ANY_FENCE,
dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
dev_priv->irq_mask |= SVGA_IRQFLAG_ANY_FENCE;
vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
} }
spin_unlock(&dev_priv->waiter_lock); spin_unlock_bh(&dev_priv->waiter_lock);
} }
void vmw_seqno_waiter_remove(struct vmw_private *dev_priv) void vmw_generic_waiter_remove(struct vmw_private *dev_priv,
u32 flag, int *waiter_count)
{ {
spin_lock(&dev_priv->waiter_lock); spin_lock_bh(&dev_priv->waiter_lock);
if (--dev_priv->fence_queue_waiters == 0) { if (--(*waiter_count) == 0) {
unsigned long irq_flags; dev_priv->irq_mask &= ~flag;
spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
dev_priv->irq_mask &= ~SVGA_IRQFLAG_ANY_FENCE;
vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
} }
spin_unlock(&dev_priv->waiter_lock); spin_unlock_bh(&dev_priv->waiter_lock);
} }
void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
{
vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_ANY_FENCE,
&dev_priv->fence_queue_waiters);
}
void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
{
vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_ANY_FENCE,
&dev_priv->fence_queue_waiters);
}
void vmw_goal_waiter_add(struct vmw_private *dev_priv) void vmw_goal_waiter_add(struct vmw_private *dev_priv)
{ {
spin_lock(&dev_priv->waiter_lock); vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
if (dev_priv->goal_queue_waiters++ == 0) { &dev_priv->goal_queue_waiters);
unsigned long irq_flags;
spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
outl(SVGA_IRQFLAG_FENCE_GOAL,
dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
dev_priv->irq_mask |= SVGA_IRQFLAG_FENCE_GOAL;
vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
}
spin_unlock(&dev_priv->waiter_lock);
} }
void vmw_goal_waiter_remove(struct vmw_private *dev_priv) void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
{ {
spin_lock(&dev_priv->waiter_lock); vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
if (--dev_priv->goal_queue_waiters == 0) { &dev_priv->goal_queue_waiters);
unsigned long irq_flags;
spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
dev_priv->irq_mask &= ~SVGA_IRQFLAG_FENCE_GOAL;
vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
}
spin_unlock(&dev_priv->waiter_lock);
} }
int vmw_wait_seqno(struct vmw_private *dev_priv, int vmw_wait_seqno(struct vmw_private *dev_priv,
...@@ -305,7 +289,6 @@ void vmw_irq_preinstall(struct drm_device *dev) ...@@ -305,7 +289,6 @@ void vmw_irq_preinstall(struct drm_device *dev)
if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
return; return;
spin_lock_init(&dev_priv->irq_lock);
status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
} }
...@@ -328,30 +311,3 @@ void vmw_irq_uninstall(struct drm_device *dev) ...@@ -328,30 +311,3 @@ void vmw_irq_uninstall(struct drm_device *dev)
status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
} }
void vmw_generic_waiter_add(struct vmw_private *dev_priv,
u32 flag, int *waiter_count)
{
unsigned long irq_flags;
spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
if ((*waiter_count)++ == 0) {
outl(flag, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
dev_priv->irq_mask |= flag;
vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
}
spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
}
void vmw_generic_waiter_remove(struct vmw_private *dev_priv,
u32 flag, int *waiter_count)
{
unsigned long irq_flags;
spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
if (--(*waiter_count) == 0) {
dev_priv->irq_mask &= ~flag;
vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
}
spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment