Skip to content

Commit

Permalink
drm/i915: Refactor gen2 to gen4 vblank interrupt handling
Browse files Browse the repository at this point in the history
The indentation is getting way too deep. Pull the vblank interupt
handling out to separate functions.

v2: Keep flip_mask handling in the main irq handler and
    flatten {i8xx,i915}_handle_vblank() even further.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Ville Syrjälä authored and Daniel Vetter committed Feb 20, 2013
1 parent 21ad833 commit 90a72f8
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 54 deletions.
125 changes: 71 additions & 54 deletions drivers/gpu/drm/i915/i915_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -2226,6 +2226,37 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
return 0;
}

/*
* Returns true when a page flip has completed.
*/
static bool i8xx_handle_vblank(struct drm_device *dev,
int pipe, u16 iir)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe);

if (!drm_handle_vblank(dev, pipe))
return false;

if ((iir & flip_pending) == 0)
return false;

intel_prepare_page_flip(dev, pipe);

/* We detect FlipDone by looking for the change in PendingFlip from '1'
* to '0' on the following vblank, i.e. IIR has the Pendingflip
* asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
* the flip is completed (no longer pending). Since this doesn't raise
* an interrupt per se, we watch for the change at vblank.
*/
if (I915_READ16(ISR) & flip_pending)
return false;

intel_finish_page_flip(dev, pipe);

return true;
}

static irqreturn_t i8xx_irq_handler(int irq, void *arg)
{
struct drm_device *dev = (struct drm_device *) arg;
Expand Down Expand Up @@ -2281,28 +2312,12 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
notify_ring(dev, &dev_priv->ring[RCS]);

if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
drm_handle_vblank(dev, 0)) {
if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
intel_prepare_page_flip(dev, 0);

if ((I915_READ16(ISR) & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) == 0) {
intel_finish_page_flip(dev, 0);
flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
}
}
}
i8xx_handle_vblank(dev, 0, iir))
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0);

if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
drm_handle_vblank(dev, 1)) {
if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
intel_prepare_page_flip(dev, 1);

if ((I915_READ16(ISR) & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) == 0) {
intel_finish_page_flip(dev, 1);
flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
}
}
}
i8xx_handle_vblank(dev, 1, iir))
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1);

iir = new_iir;
}
Expand Down Expand Up @@ -2419,6 +2434,37 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
}
}

/*
* Returns true when a page flip has completed.
*/
static bool i915_handle_vblank(struct drm_device *dev,
int plane, int pipe, u32 iir)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);

if (!drm_handle_vblank(dev, pipe))
return false;

if ((iir & flip_pending) == 0)
return false;

intel_prepare_page_flip(dev, plane);

/* We detect FlipDone by looking for the change in PendingFlip from '1'
* to '0' on the following vblank, i.e. IIR has the Pendingflip
* asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
* the flip is completed (no longer pending). Since this doesn't raise
* an interrupt per se, we watch for the change at vblank.
*/
if (I915_READ(ISR) & flip_pending)
return false;

intel_finish_page_flip(dev, pipe);

return true;
}

static irqreturn_t i915_irq_handler(int irq, void *arg)
{
struct drm_device *dev = (struct drm_device *) arg;
Expand All @@ -2428,10 +2474,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
u32 flip_mask =
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
u32 flip[2] = {
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT,
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT
};
int pipe, ret = IRQ_NONE;

atomic_inc(&dev_priv->irq_received);
Expand Down Expand Up @@ -2493,23 +2535,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
int plane = pipe;
if (IS_MOBILE(dev))
plane = !plane;

if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
drm_handle_vblank(dev, pipe)) {
if (iir & flip[plane]) {
intel_prepare_page_flip(dev, plane);

/* We detect FlipDone by looking for the change in PendingFlip from '1'
* to '0' on the following vblank, i.e. IIR has the Pendingflip
* asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
* the flip is completed (no longer pending). Since this doesn't raise an
* interrupt per se, we watch for the change at vblank.
*/
if ((I915_READ(ISR) & flip[plane]) == 0) {
intel_finish_page_flip(dev, pipe);
flip_mask &= ~flip[plane];
}
}
}
i915_handle_vblank(dev, plane, pipe, iir))
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);

if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
blc_event = true;
Expand Down Expand Up @@ -2686,10 +2715,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
unsigned long irqflags;
int irq_received;
int ret = IRQ_NONE, pipe;
u32 flip[2] = {
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT,
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT
};
u32 flip_mask =
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
Expand Down Expand Up @@ -2758,16 +2783,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)

for_each_pipe(pipe) {
if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
drm_handle_vblank(dev, pipe)) {
if (iir & flip[pipe]) {
intel_prepare_page_flip(dev, pipe);

if ((I915_READ(ISR) & flip[pipe]) == 0) {
intel_finish_page_flip(dev, pipe);
flip_mask &= ~flip[pipe];
}
}
}
i915_handle_vblank(dev, pipe, pipe, iir))
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);

if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
blc_event = true;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@
#define I915_USER_INTERRUPT (1<<1)
#define I915_ASLE_INTERRUPT (1<<0)
#define I915_BSD_USER_INTERRUPT (1<<25)
#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */
#define EIR 0x020b0
#define EMR 0x020b4
#define ESR 0x020b8
Expand Down

0 comments on commit 90a72f8

Please sign in to comment.