diff options
author | Eric Anholt <eric@anholt.net> | 2015-06-16 16:18:38 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2015-06-17 17:20:19 -0700 |
commit | fefaa64b6faf8bd7bac610758cefe3c405962fe1 (patch) | |
tree | afccec90b8e3ca17b9fa8ec11be7987d2364a4bd | |
parent | 8d102f7a302db39539ce780875f88ea62270818b (diff) | |
download | linux-fefaa64b6faf8bd7bac610758cefe3c405962fe1.tar.gz |
drm/vc4: Clean up V3D interrupt handling, and document how it works.
My surprise about having to set INTENA for OUTOMEM when I hadn't
cleared anything in it now makes sense, having found that there is
just one set of underlying enable bits behind the INTENA/INTDIS
registers.
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_irq.c | 50 |
1 files changed, 37 insertions, 13 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index b5a1a273f83f..2d0b91a9bd93 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -21,6 +21,25 @@ * IN THE SOFTWARE. */ +/** DOC: Interrupt management for the V3D engine. + * + * We have an interrupt status register (V3D_INTCTL) which reports + * interrupts, and where writing 1 bits clears those interrupts. + * There are also a pair of interrupt registers + * (V3D_INTENA/V3D_INTDIS) where writing a 1 to their bits enables or + * disables that specific interrupt, and 0s written are ignored + * (reading either one returns the set of enabled interrupts). + * + * When we take a render frame interrupt, we need to wake the + * processes waiting for some frame to be done, and get the next frame + * submitted ASAP (so the hardware doesn't sit idle when there's work + * to do). + * + * When we take the binner out of memory interrupt, we need to + * allocate some new memory and pass it to the binner so that the + * current job can make progress. + */ + #include "vc4_drv.h" #include "vc4_regs.h" @@ -77,9 +96,8 @@ vc4_overflow_mem_work(struct work_struct *work) V3D_WRITE(V3D_BPOA, bo->base.paddr); V3D_WRITE(V3D_BPOS, bo->base.base.size); - V3D_WRITE(V3D_INTDIS, 0); - V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); + V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); } static void @@ -109,9 +127,15 @@ vc4_irq(int irq, void *arg) barrier(); intctl = V3D_READ(V3D_INTCTL); + + /* Acknowledge the interrupts we're handling here. The render + * frame done interrupt will be cleared, while OUTOMEM will + * stay high until the underlying cause is cleared. + */ V3D_WRITE(V3D_INTCTL, intctl); if (intctl & V3D_INT_OUTOMEM) { + /* Disable OUTOMEM until the work is done. */ V3D_WRITE(V3D_INTDIS, V3D_INT_OUTOMEM); schedule_work(&vc4->overflow_mem_work); status = IRQ_HANDLED; @@ -146,16 +170,9 @@ vc4_irq_postinstall(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); - /* Enable both the bin and render done interrupts, as well as - * out of memory. Eventually, we'll have the bin use internal - * semaphores with render to sync between the two, but for now - * we're driving that from the ARM. - */ + /* Enable both the render done and out of memory interrupts. */ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); - /* No interrupts disabled. */ - V3D_WRITE(V3D_INTDIS, 0); - return 0; } @@ -164,8 +181,8 @@ vc4_irq_uninstall(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); - V3D_WRITE(V3D_INTENA, 0); - V3D_WRITE(V3D_INTDIS, 0); + /* Disable sending interrupts for our driver's IRQs. */ + V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS); /* Clear any pending interrupts we might have left. */ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); @@ -179,8 +196,15 @@ void vc4_irq_reset(struct drm_device *dev) struct vc4_dev *vc4 = to_vc4_dev(dev); unsigned long irqflags; + /* Acknowledge any stale IRQs. */ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); - V3D_WRITE(V3D_INTDIS, 0); + + /* + * Turn all our interrupts on. Binner out of memory is the + * only one we expect to trigger at this point, since we've + * just come from poweron and haven't supplied any overflow + * memory yet. + */ V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); spin_lock_irqsave(&vc4->job_lock, irqflags); |