drm/radeon: make indirect register access concurrency-safe
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Sun, 2 Dec 2012 13:06:15 +0000 (14:06 +0100)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 14 Dec 2012 15:45:23 +0000 (10:45 -0500)
With the new per-crtc locking mutliple set-cursor calls could happen
in parallel. Out of sheer paranoia I've opted for an irqsave spinlock.
But if there's indeed an access from interrupt contexts to these regs
it's already broken with the old code, so this can likely just be
reduced to a normal spinlock. Otoh the pageflip completion happens
from the vblank irq handler ...

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_device.c

index ae4c857fb173df531d4e6c2f554f015073965670..8ff7cac222dce7ccba37e5318adea5773571cd6f 100644 (file)
@@ -4141,8 +4141,15 @@ uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg,
        if (reg < rdev->rmmio_size && !always_indirect)
                return readl(((void __iomem *)rdev->rmmio) + reg);
        else {
+               unsigned long flags;
+               uint32_t ret;
+
+               spin_lock_irqsave(&rdev->mmio_idx_lock, flags);
                writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
-               return readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
+               ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
+               spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags);
+
+               return ret;
        }
 }
 
@@ -4152,8 +4159,12 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
        if (reg < rdev->rmmio_size && !always_indirect)
                writel(v, ((void __iomem *)rdev->rmmio) + reg);
        else {
+               unsigned long flags;
+
+               spin_lock_irqsave(&rdev->mmio_idx_lock, flags);
                writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
                writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
+               spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags);
        }
 }
 
index 609bb18d09f180068adcb2a31f020d76e0999b93..285fb3f203af947fe918d7d8f42df91a1d98af48 100644 (file)
@@ -1556,6 +1556,8 @@ struct radeon_device {
        /* Register mmio */
        resource_size_t                 rmmio_base;
        resource_size_t                 rmmio_size;
+       /* protects concurrent MM_INDEX/DATA based register access */
+       spinlock_t mmio_idx_lock;
        void __iomem                    *rmmio;
        radeon_rreg_t                   mc_rreg;
        radeon_wreg_t                   mc_wreg;
index e2f5f888c374cc29b2f8658a5e0ba9d91325827d..49b06590001e1a30ca65761cfab2e20d901bc215 100644 (file)
@@ -1059,6 +1059,7 @@ int radeon_device_init(struct radeon_device *rdev,
 
        /* Registers mapping */
        /* TODO: block userspace mapping of io register */
+       spin_lock_init(&rdev->mmio_idx_lock);
        rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
        rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
        rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size);