Skip to content

Commit c2798b1

Browse files
ickledanvet
authored andcommitted
drm/i915: i8xx interrupt handler
gen2 hardware has some significant differences from the other interrupt routines that were glossed over and then forgotten about in the transition to KMS. Such as - 16bit IIR - PendingFlip status bit This patch reintroduces a handler specifically for gen2 for the purpose of handling pageflips correctly, simplifying code in the process. v2: Also fixup ring get/put irq to only access 16bit registers (Daniel) Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=24202 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41793 Signed-off-by: Chris Wilson <[email protected]> [danvet: use posting_read16 in intel_ringbuffer.c and kill _driver from the function names.] Signed-off-by: Daniel Vetter <[email protected]>
1 parent 1869b62 commit c2798b1

File tree

2 files changed

+206
-8
lines changed

2 files changed

+206
-8
lines changed

drivers/gpu/drm/i915/i915_irq.c

Lines changed: 157 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,6 +2446,152 @@ static void i915_driver_irq_uninstall(struct drm_device * dev)
24462446
I915_WRITE(IIR, I915_READ(IIR));
24472447
}
24482448

2449+
static void i8xx_irq_preinstall(struct drm_device * dev)
2450+
{
2451+
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2452+
int pipe;
2453+
2454+
atomic_set(&dev_priv->irq_received, 0);
2455+
2456+
for_each_pipe(pipe)
2457+
I915_WRITE(PIPESTAT(pipe), 0);
2458+
I915_WRITE16(IMR, 0xffff);
2459+
I915_WRITE16(IER, 0x0);
2460+
POSTING_READ16(IER);
2461+
}
2462+
2463+
static int i8xx_irq_postinstall(struct drm_device *dev)
2464+
{
2465+
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2466+
2467+
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
2468+
2469+
dev_priv->pipestat[0] = 0;
2470+
dev_priv->pipestat[1] = 0;
2471+
2472+
I915_WRITE16(EMR,
2473+
~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
2474+
2475+
/* Unmask the interrupts that we always want on. */
2476+
dev_priv->irq_mask =
2477+
~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2478+
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2479+
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2480+
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
2481+
I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
2482+
I915_WRITE16(IMR, dev_priv->irq_mask);
2483+
2484+
I915_WRITE16(IER,
2485+
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2486+
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2487+
I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
2488+
I915_USER_INTERRUPT);
2489+
POSTING_READ16(IER);
2490+
2491+
return 0;
2492+
}
2493+
2494+
static irqreturn_t i8xx_irq_handler(DRM_IRQ_ARGS)
2495+
{
2496+
struct drm_device *dev = (struct drm_device *) arg;
2497+
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2498+
struct drm_i915_master_private *master_priv;
2499+
u16 iir, new_iir;
2500+
u32 pipe_stats[2];
2501+
unsigned long irqflags;
2502+
int irq_received;
2503+
int pipe;
2504+
u16 flip_mask =
2505+
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2506+
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
2507+
2508+
atomic_inc(&dev_priv->irq_received);
2509+
2510+
iir = I915_READ16(IIR);
2511+
if (iir == 0)
2512+
return IRQ_NONE;
2513+
2514+
while (iir & ~flip_mask) {
2515+
/* Can't rely on pipestat interrupt bit in iir as it might
2516+
* have been cleared after the pipestat interrupt was received.
2517+
* It doesn't set the bit in iir again, but it still produces
2518+
* interrupts (for non-MSI).
2519+
*/
2520+
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
2521+
if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
2522+
i915_handle_error(dev, false);
2523+
2524+
for_each_pipe(pipe) {
2525+
int reg = PIPESTAT(pipe);
2526+
pipe_stats[pipe] = I915_READ(reg);
2527+
2528+
/*
2529+
* Clear the PIPE*STAT regs before the IIR
2530+
*/
2531+
if (pipe_stats[pipe] & 0x8000ffff) {
2532+
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
2533+
DRM_DEBUG_DRIVER("pipe %c underrun\n",
2534+
pipe_name(pipe));
2535+
I915_WRITE(reg, pipe_stats[pipe]);
2536+
irq_received = 1;
2537+
}
2538+
}
2539+
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
2540+
2541+
I915_WRITE16(IIR, iir & ~flip_mask);
2542+
new_iir = I915_READ16(IIR); /* Flush posted writes */
2543+
2544+
if (dev->primary->master) {
2545+
master_priv = dev->primary->master->driver_priv;
2546+
if (master_priv->sarea_priv)
2547+
master_priv->sarea_priv->last_dispatch =
2548+
READ_BREADCRUMB(dev_priv);
2549+
}
2550+
2551+
if (iir & I915_USER_INTERRUPT)
2552+
notify_ring(dev, &dev_priv->ring[RCS]);
2553+
2554+
if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
2555+
drm_handle_vblank(dev, 0)) {
2556+
if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
2557+
intel_prepare_page_flip(dev, 0);
2558+
intel_finish_page_flip(dev, 0);
2559+
flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
2560+
}
2561+
}
2562+
2563+
if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
2564+
drm_handle_vblank(dev, 1)) {
2565+
if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
2566+
intel_prepare_page_flip(dev, 1);
2567+
intel_finish_page_flip(dev, 1);
2568+
flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
2569+
}
2570+
}
2571+
2572+
iir = new_iir;
2573+
}
2574+
2575+
return IRQ_HANDLED;
2576+
}
2577+
2578+
static void i8xx_irq_uninstall(struct drm_device * dev)
2579+
{
2580+
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2581+
int pipe;
2582+
2583+
dev_priv->vblank_pipe = 0;
2584+
2585+
for_each_pipe(pipe) {
2586+
/* Clear enable bits; then clear status bits */
2587+
I915_WRITE(PIPESTAT(pipe), 0);
2588+
I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
2589+
}
2590+
I915_WRITE16(IMR, 0xffff);
2591+
I915_WRITE16(IER, 0x0);
2592+
I915_WRITE16(IIR, I915_READ16(IIR));
2593+
}
2594+
24492595
void intel_irq_init(struct drm_device *dev)
24502596
{
24512597
dev->driver->get_vblank_counter = i915_get_vblank_counter;
@@ -2485,10 +2631,17 @@ void intel_irq_init(struct drm_device *dev)
24852631
dev->driver->enable_vblank = ironlake_enable_vblank;
24862632
dev->driver->disable_vblank = ironlake_disable_vblank;
24872633
} else {
2488-
dev->driver->irq_preinstall = i915_driver_irq_preinstall;
2489-
dev->driver->irq_postinstall = i915_driver_irq_postinstall;
2490-
dev->driver->irq_uninstall = i915_driver_irq_uninstall;
2491-
dev->driver->irq_handler = i915_driver_irq_handler;
2634+
if (INTEL_INFO(dev)->gen == 2) {
2635+
dev->driver->irq_preinstall = i8xx_irq_preinstall;
2636+
dev->driver->irq_postinstall = i8xx_irq_postinstall;
2637+
dev->driver->irq_handler = i8xx_irq_handler;
2638+
dev->driver->irq_uninstall = i8xx_irq_uninstall;
2639+
} else {
2640+
dev->driver->irq_preinstall = i915_driver_irq_preinstall;
2641+
dev->driver->irq_postinstall = i915_driver_irq_postinstall;
2642+
dev->driver->irq_uninstall = i915_driver_irq_uninstall;
2643+
dev->driver->irq_handler = i915_driver_irq_handler;
2644+
}
24922645
dev->driver->enable_vblank = i915_enable_vblank;
24932646
dev->driver->disable_vblank = i915_disable_vblank;
24942647
}

drivers/gpu/drm/i915/intel_ringbuffer.c

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,41 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring)
678678
spin_unlock(&ring->irq_lock);
679679
}
680680

681+
static bool
682+
i8xx_ring_get_irq(struct intel_ring_buffer *ring)
683+
{
684+
struct drm_device *dev = ring->dev;
685+
drm_i915_private_t *dev_priv = dev->dev_private;
686+
687+
if (!dev->irq_enabled)
688+
return false;
689+
690+
spin_lock(&ring->irq_lock);
691+
if (ring->irq_refcount++ == 0) {
692+
dev_priv->irq_mask &= ~ring->irq_enable_mask;
693+
I915_WRITE16(IMR, dev_priv->irq_mask);
694+
POSTING_READ16(IMR);
695+
}
696+
spin_unlock(&ring->irq_lock);
697+
698+
return true;
699+
}
700+
701+
static void
702+
i8xx_ring_put_irq(struct intel_ring_buffer *ring)
703+
{
704+
struct drm_device *dev = ring->dev;
705+
drm_i915_private_t *dev_priv = dev->dev_private;
706+
707+
spin_lock(&ring->irq_lock);
708+
if (--ring->irq_refcount == 0) {
709+
dev_priv->irq_mask |= ring->irq_enable_mask;
710+
I915_WRITE16(IMR, dev_priv->irq_mask);
711+
POSTING_READ16(IMR);
712+
}
713+
spin_unlock(&ring->irq_lock);
714+
}
715+
681716
void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
682717
{
683718
struct drm_device *dev = ring->dev;
@@ -1310,8 +1345,13 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
13101345
else
13111346
ring->flush = gen4_render_ring_flush;
13121347
ring->get_seqno = ring_get_seqno;
1313-
ring->irq_get = i9xx_ring_get_irq;
1314-
ring->irq_put = i9xx_ring_put_irq;
1348+
if (IS_GEN2(dev)) {
1349+
ring->irq_get = i8xx_ring_get_irq;
1350+
ring->irq_put = i8xx_ring_put_irq;
1351+
} else {
1352+
ring->irq_get = i9xx_ring_get_irq;
1353+
ring->irq_put = i9xx_ring_put_irq;
1354+
}
13151355
ring->irq_enable_mask = I915_USER_INTERRUPT;
13161356
}
13171357
ring->write_tail = ring_write_tail;
@@ -1358,8 +1398,13 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
13581398
else
13591399
ring->flush = gen4_render_ring_flush;
13601400
ring->get_seqno = ring_get_seqno;
1361-
ring->irq_get = i9xx_ring_get_irq;
1362-
ring->irq_put = i9xx_ring_put_irq;
1401+
if (IS_GEN2(dev)) {
1402+
ring->irq_get = i8xx_ring_get_irq;
1403+
ring->irq_put = i8xx_ring_put_irq;
1404+
} else {
1405+
ring->irq_get = i9xx_ring_get_irq;
1406+
ring->irq_put = i9xx_ring_put_irq;
1407+
}
13631408
ring->irq_enable_mask = I915_USER_INTERRUPT;
13641409
ring->write_tail = ring_write_tail;
13651410
if (INTEL_INFO(dev)->gen >= 4)

0 commit comments

Comments
 (0)