summaryrefslogtreecommitdiff
path: root/sys/dev/pci/drm
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2009-04-03 12:25:05 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2009-04-03 12:25:05 +0000
commit945edc728f8c2b49653ec54af3cae1e8af64d04c (patch)
treeabee386d65329147c3a0c2e2dc64b0edc66596da /sys/dev/pci/drm
parentd1c647af2ed78ba07cac9e32438c6f437239a56b (diff)
Add a lock to protect races for the software interrupt on radeon chips
(vblank is already protected by that subsystem). Also, do all checks for the correct software interrupt having fired inside DRM_WAIT_ON(), since it won't sleep if it's already passed it doesn't gain us much (skips one lock grab). Finally, establish the interrupt with only the main radeon irq handler, don't bother with drm_irq_wrap. bunch of knf while i'm in here.
Diffstat (limited to 'sys/dev/pci/drm')
-rw-r--r--sys/dev/pci/drm/radeon_drv.c1
-rw-r--r--sys/dev/pci/drm/radeon_drv.h7
-rw-r--r--sys/dev/pci/drm/radeon_irq.c85
3 files changed, 46 insertions, 47 deletions
diff --git a/sys/dev/pci/drm/radeon_drv.c b/sys/dev/pci/drm/radeon_drv.c
index 582e903d626..db9c3af263e 100644
--- a/sys/dev/pci/drm/radeon_drv.c
+++ b/sys/dev/pci/drm/radeon_drv.c
@@ -556,6 +556,7 @@ radeondrm_attach(struct device *parent, struct device *self, void *aux)
return;
}
printf(": %s\n", pci_intr_string(pa->pa_pc, dev_priv->ih));
+ mtx_init(&dev_priv->swi_lock, IPL_BIO);
switch (dev_priv->flags & RADEON_FAMILY_MASK) {
case CHIP_R100:
diff --git a/sys/dev/pci/drm/radeon_drv.h b/sys/dev/pci/drm/radeon_drv.h
index 706065dc107..82c23c3fd49 100644
--- a/sys/dev/pci/drm/radeon_drv.h
+++ b/sys/dev/pci/drm/radeon_drv.h
@@ -268,9 +268,10 @@ typedef struct drm_radeon_private {
struct drm_heap fb_heap;
/* SW interrupt */
- atomic_t swi_emitted;
- uint32_t irq_enable_reg;
- uint32_t r500_disp_irq_reg;
+ struct mutex swi_lock;
+ atomic_t swi_emitted;
+ uint32_t irq_enable_reg;
+ uint32_t r500_disp_irq_reg;
struct radeon_surface surfaces[RADEON_MAX_SURFACES];
struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
diff --git a/sys/dev/pci/drm/radeon_irq.c b/sys/dev/pci/drm/radeon_irq.c
index ec407aeeebc..374bb5eb98a 100644
--- a/sys/dev/pci/drm/radeon_irq.c
+++ b/sys/dev/pci/drm/radeon_irq.c
@@ -35,10 +35,10 @@
#include "radeon_drm.h"
#include "radeon_drv.h"
-void r500_vbl_irq_set_state(struct drm_device *, u32, int);
-u_int32_t radeon_acknowledge_irqs(drm_radeon_private_t *, u32 *);
-int radeon_emit_irq(struct drm_device *);
-int radeon_wait_irq(struct drm_device *, int);
+void r500_vbl_irq_set_state(struct drm_device *, u_int32_t, int);
+u_int32_t radeon_acknowledge_irqs(drm_radeon_private_t *, u_int32_t *);
+int radeon_emit_irq(struct drm_device *);
+int radeon_wait_irq(struct drm_device *, int);
void
radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
@@ -167,7 +167,7 @@ radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int)
if (irqs)
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
- return irqs;
+ return (irqs);
}
/* Interrupts - Used for device synchronization and flushing in the
@@ -188,26 +188,25 @@ radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int)
* tied to dma at all, this is just a hangover from dri prehistory.
*/
-irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t
+radeon_driver_irq_handler(DRM_IRQ_ARGS)
{
- struct drm_device *dev = (struct drm_device *) arg;
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- u32 stat;
- u32 r500_disp_int;
-
- /* Only consider the bits we're interested in - others could be used
- * outside the DRM
- */
+ struct drm_device *dev = arg;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ u_int32_t stat, r500_disp_int;
+
stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int);
if (!stat)
- return IRQ_NONE;
+ return (IRQ_NONE);
stat &= dev_priv->irq_enable_reg;
/* SW interrupt */
- if (stat & RADEON_SW_INT_TEST)
+ if (stat & RADEON_SW_INT_TEST) {
+ mtx_enter(&dev_priv->swi_lock);
wakeup(dev_priv);
+ mtx_leave(&dev_priv->swi_lock);
+ }
/* VBLANK interrupt */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
@@ -221,7 +220,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
if (stat & RADEON_CRTC2_VBLANK_STAT)
drm_handle_vblank(dev, 1);
}
- return IRQ_HANDLED;
+ return (IRQ_HANDLED);
}
int
@@ -239,7 +238,7 @@ radeon_emit_irq(struct drm_device * dev)
ADVANCE_RING();
COMMIT_RING();
- return ret;
+ return (ret);
}
int
@@ -248,27 +247,25 @@ radeon_wait_irq(struct drm_device * dev, int swi_nr)
drm_radeon_private_t *dev_priv = dev->dev_private;
int ret = 0;
- if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr)
- return 0;
-
- DRM_WAIT_ON(ret, dev_priv, &dev->irq_lock, 3 * hz, "rdnwt",
+ DRM_WAIT_ON(ret, dev_priv, &dev_priv->swi_lock, 3 * hz, "rdnwt",
RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr);
return (ret);
}
-u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
+u_int32_t
+radeon_get_vblank_counter(struct drm_device *dev, int crtc)
{
- drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
- return EINVAL;
+ return (EINVAL);
}
if (crtc < 0 || crtc > 1) {
DRM_ERROR("Invalid crtc %d\n", crtc);
- return EINVAL;
+ return (EINVAL);
}
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
@@ -286,42 +283,44 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
/* Needs the lock as it touches the ring.
*/
-int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int
+radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_irq_emit_t *emit = data;
- int result;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_radeon_irq_emit_t *emit = data;
+ int result;
LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
- return EINVAL;
+ return (EINVAL);
}
result = radeon_emit_irq(dev);
if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return EFAULT;
+ return (EFAULT);
}
- return 0;
+ return (0);
}
/* Doesn't need the hardware lock.
*/
-int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int
+radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_irq_wait_t *irqwait = data;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
- return EINVAL;
+ return (EINVAL);
}
- return radeon_wait_irq(dev, irqwait->irq_seq);
+ return (radeon_wait_irq(dev, irqwait->irq_seq));
}
/* drm_dma.h hooks
@@ -329,9 +328,8 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr
int
radeon_driver_irq_install(struct drm_device * dev)
{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- u32 dummy;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ u_int32_t dummy;
/* Disable *all* interrupts */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
@@ -342,7 +340,7 @@ radeon_driver_irq_install(struct drm_device * dev)
radeon_acknowledge_irqs(dev_priv, &dummy);
dev_priv->irqh = pci_intr_establish(dev_priv->pc, dev_priv->ih, IPL_BIO,
- drm_irq_handler_wrap, dev, dev_priv->dev.dv_xname);
+ radeon_driver_irq_handler, dev, dev_priv->dev.dv_xname);
if (dev_priv->irqh == NULL)
return (ENOENT);
@@ -352,14 +350,13 @@ radeon_driver_irq_install(struct drm_device * dev)
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
- return 0;
+ return (0);
}
void
radeon_driver_irq_uninstall(struct drm_device * dev)
{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
if (!dev_priv)
return;