62,7 → 62,7 |
[HPD_PORT_D] = PORTD_HOTPLUG_INT_EN |
}; |
|
static const u32 hpd_status_gen4[] = { |
static const u32 hpd_status_g4x[] = { |
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS, |
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, |
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, |
282,6 → 282,21 |
} |
} |
|
static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev, |
enum pipe pipe, bool enable) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
assert_spin_locked(&dev_priv->irq_lock); |
|
if (enable) |
dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN; |
else |
dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN; |
I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); |
POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); |
} |
|
/** |
* ibx_display_interrupt_update - update SDEIMR |
* @dev_priv: driver private |
394,6 → 409,8 |
ironlake_set_fifo_underrun_reporting(dev, pipe, enable); |
else if (IS_GEN7(dev)) |
ivybridge_set_fifo_underrun_reporting(dev, pipe, enable); |
else if (IS_GEN8(dev)) |
broadwell_set_fifo_underrun_reporting(dev, pipe, enable); |
|
done: |
spin_unlock_irqrestore(&dev_priv->irq_lock, flags); |
454,7 → 471,7 |
|
|
void |
i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) |
i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask) |
{ |
u32 reg = PIPESTAT(pipe); |
u32 pipestat = I915_READ(reg) & 0x7fff0000; |
471,7 → 488,7 |
} |
|
void |
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) |
i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask) |
{ |
u32 reg = PIPESTAT(pipe); |
u32 pipestat = I915_READ(reg) & 0x7fff0000; |
499,9 → 516,10 |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
|
i915_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_ENABLE); |
if (INTEL_INFO(dev)->gen >= 4) |
i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_A, |
PIPE_LEGACY_BLC_EVENT_ENABLE); |
|
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
} |
531,6 → 549,12 |
} |
} |
|
static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe) |
{ |
/* Gen2 doesn't have a hardware frame counter */ |
return 0; |
} |
|
/* Called from drm generic code, passed a 'crtc', which |
* we use as a pipe index |
*/ |
539,7 → 563,7 |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
unsigned long high_frame; |
unsigned long low_frame; |
u32 high1, high2, low; |
u32 high1, high2, low, pixel, vbl_start; |
|
if (!i915_pipe_enabled(dev, pipe)) { |
DRM_DEBUG_DRIVER("trying to get vblank count for disabled " |
547,6 → 571,24 |
return 0; |
} |
|
if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
struct intel_crtc *intel_crtc = |
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); |
const struct drm_display_mode *mode = |
&intel_crtc->config.adjusted_mode; |
|
vbl_start = mode->crtc_vblank_start * mode->crtc_htotal; |
} else { |
enum transcoder cpu_transcoder = |
intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
u32 htotal; |
|
htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1; |
vbl_start = (I915_READ(VBLANK(cpu_transcoder)) & 0x1fff) + 1; |
|
vbl_start *= htotal; |
} |
|
high_frame = PIPEFRAME(pipe); |
low_frame = PIPEFRAMEPIXEL(pipe); |
|
557,13 → 599,20 |
*/ |
do { |
high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; |
low = I915_READ(low_frame) & PIPE_FRAME_LOW_MASK; |
low = I915_READ(low_frame); |
high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; |
} while (high1 != high2); |
|
high1 >>= PIPE_FRAME_HIGH_SHIFT; |
pixel = low & PIPE_PIXEL_MASK; |
low >>= PIPE_FRAME_LOW_SHIFT; |
return (high1 << 8) | low; |
|
/* |
* The frame counter increments at beginning of active. |
* Cook up a vblank counter by also checking the pixel |
* counter against vblank start. |
*/ |
return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff; |
} |
|
static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) |
580,67 → 629,164 |
return I915_READ(reg); |
} |
|
/* raw reads, only for fast reads of display block, no need for forcewake etc. */ |
#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) |
#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__)) |
|
static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t status; |
|
if (INTEL_INFO(dev)->gen < 7) { |
status = pipe == PIPE_A ? |
DE_PIPEA_VBLANK : |
DE_PIPEB_VBLANK; |
} else { |
switch (pipe) { |
default: |
case PIPE_A: |
status = DE_PIPEA_VBLANK_IVB; |
break; |
case PIPE_B: |
status = DE_PIPEB_VBLANK_IVB; |
break; |
case PIPE_C: |
status = DE_PIPEC_VBLANK_IVB; |
break; |
} |
} |
|
return __raw_i915_read32(dev_priv, DEISR) & status; |
} |
|
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, |
int *vpos, int *hpos) |
unsigned int flags, int *vpos, int *hpos, |
void *stime, void *etime) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 vbl = 0, position = 0; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; |
int position; |
int vbl_start, vbl_end, htotal, vtotal; |
bool in_vbl = true; |
int ret = 0; |
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, |
pipe); |
unsigned long irqflags; |
|
if (!i915_pipe_enabled(dev, pipe)) { |
if (!intel_crtc->active) { |
DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " |
"pipe %c\n", pipe_name(pipe)); |
return 0; |
} |
|
/* Get vtotal. */ |
vtotal = 1 + ((I915_READ(VTOTAL(cpu_transcoder)) >> 16) & 0x1fff); |
htotal = mode->crtc_htotal; |
vtotal = mode->crtc_vtotal; |
vbl_start = mode->crtc_vblank_start; |
vbl_end = mode->crtc_vblank_end; |
|
if (INTEL_INFO(dev)->gen >= 4) { |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) { |
vbl_start = DIV_ROUND_UP(vbl_start, 2); |
vbl_end /= 2; |
vtotal /= 2; |
} |
|
ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; |
|
/* |
* Lock uncore.lock, as we will do multiple timing critical raw |
* register reads, potentially with preemption disabled, so the |
* following code must not block on uncore.lock. |
*/ |
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); |
|
/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ |
|
|
if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { |
/* No obvious pixelcount register. Only query vertical |
* scanout position from Display scan line register. |
*/ |
position = I915_READ(PIPEDSL(pipe)); |
if (IS_GEN2(dev)) |
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; |
else |
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; |
|
/* Decode into vertical scanout position. Don't have |
* horizontal scanout position. |
if (HAS_PCH_SPLIT(dev)) { |
/* |
* The scanline counter increments at the leading edge |
* of hsync, ie. it completely misses the active portion |
* of the line. Fix up the counter at both edges of vblank |
* to get a more accurate picture whether we're in vblank |
* or not. |
*/ |
*vpos = position & 0x1fff; |
*hpos = 0; |
in_vbl = ilk_pipe_in_vblank_locked(dev, pipe); |
if ((in_vbl && position == vbl_start - 1) || |
(!in_vbl && position == vbl_end - 1)) |
position = (position + 1) % vtotal; |
} else { |
/* |
* ISR vblank status bits don't work the way we'd want |
* them to work on non-PCH platforms (for |
* ilk_pipe_in_vblank_locked()), and there doesn't |
* appear any other way to determine if we're currently |
* in vblank. |
* |
* Instead let's assume that we're already in vblank if |
* we got called from the vblank interrupt and the |
* scanline counter value indicates that we're on the |
* line just prior to vblank start. This should result |
* in the correct answer, unless the vblank interrupt |
* delivery really got delayed for almost exactly one |
* full frame/field. |
*/ |
if (flags & DRM_CALLED_FROM_VBLIRQ && |
position == vbl_start - 1) { |
position = (position + 1) % vtotal; |
|
/* Signal this correction as "applied". */ |
ret |= 0x8; |
} |
} |
} else { |
/* Have access to pixelcount since start of frame. |
* We can split this into vertical and horizontal |
* scanout position. |
*/ |
position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; |
position = (__raw_i915_read32(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; |
|
htotal = 1 + ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff); |
*vpos = position / htotal; |
*hpos = position - (*vpos * htotal); |
/* convert to pixel counts */ |
vbl_start *= htotal; |
vbl_end *= htotal; |
vtotal *= htotal; |
} |
|
/* Query vblank area. */ |
vbl = I915_READ(VBLANK(cpu_transcoder)); |
|
/* Test position against vblank region. */ |
vbl_start = vbl & 0x1fff; |
vbl_end = (vbl >> 16) & 0x1fff; |
/* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ |
|
if ((*vpos < vbl_start) || (*vpos > vbl_end)) |
in_vbl = false; |
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); |
|
/* Inside "upper part" of vblank area? Apply corrective offset: */ |
if (in_vbl && (*vpos >= vbl_start)) |
*vpos = *vpos - vtotal; |
in_vbl = position >= vbl_start && position < vbl_end; |
|
/* Readouts valid? */ |
if (vbl > 0) |
ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; |
/* |
* While in vblank, position will be negative |
* counting up towards 0 at vbl_end. And outside |
* vblank, position will be positive counting |
* up since vbl_end. |
*/ |
if (position >= vbl_start) |
position -= vbl_end; |
else |
position += vtotal - vbl_end; |
|
if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { |
*vpos = position; |
*hpos = 0; |
} else { |
*vpos = position / htotal; |
*hpos = position - (*vpos * htotal); |
} |
|
/* In vblank? */ |
if (in_vbl) |
ret |= DRM_SCANOUTPOS_INVBL; |
675,10 → 821,12 |
/* Helper routine in DRM core does all the work: */ |
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, |
vblank_time, flags, |
crtc); |
crtc, |
&to_intel_crtc(crtc)->config.adjusted_mode); |
} |
|
static int intel_hpd_irq_event(struct drm_device *dev, struct drm_connector *connector) |
static bool intel_hpd_irq_event(struct drm_device *dev, |
struct drm_connector *connector) |
{ |
enum drm_connector_status old_status; |
|
686,11 → 834,16 |
old_status = connector->status; |
|
connector->status = connector->funcs->detect(connector, false); |
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", |
if (old_status == connector->status) |
return false; |
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", |
connector->base.id, |
drm_get_connector_name(connector), |
old_status, connector->status); |
return (old_status != connector->status); |
drm_get_connector_status_name(old_status), |
drm_get_connector_status_name(connector->status)); |
|
return true; |
} |
|
/* |
814,7 → 967,7 |
if (ring->obj == NULL) |
return; |
|
trace_i915_gem_request_complete(ring, ring->get_seqno(ring, false)); |
trace_i915_gem_request_complete(ring); |
|
wake_up_all(&ring->irq_queue); |
} |
824,7 → 977,7 |
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, |
rps.work); |
u32 pm_iir; |
u8 new_delay; |
int new_delay, adj; |
|
spin_lock_irq(&dev_priv->irq_lock); |
pm_iir = dev_priv->rps.pm_iir; |
841,41 → 994,48 |
|
mutex_lock(&dev_priv->rps.hw_lock); |
|
adj = dev_priv->rps.last_adj; |
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { |
new_delay = dev_priv->rps.cur_delay + 1; |
if (adj > 0) |
adj *= 2; |
else |
adj = 1; |
new_delay = dev_priv->rps.cur_delay + adj; |
|
/* |
* For better performance, jump directly |
* to RPe if we're below it. |
*/ |
if (IS_VALLEYVIEW(dev_priv->dev) && |
dev_priv->rps.cur_delay < dev_priv->rps.rpe_delay) |
if (new_delay < dev_priv->rps.rpe_delay) |
new_delay = dev_priv->rps.rpe_delay; |
} else |
new_delay = dev_priv->rps.cur_delay - 1; |
} else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) { |
if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay) |
new_delay = dev_priv->rps.rpe_delay; |
else |
new_delay = dev_priv->rps.min_delay; |
adj = 0; |
} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) { |
if (adj < 0) |
adj *= 2; |
else |
adj = -1; |
new_delay = dev_priv->rps.cur_delay + adj; |
} else { /* unknown event */ |
new_delay = dev_priv->rps.cur_delay; |
} |
|
/* sysfs frequency interfaces may have snuck in while servicing the |
* interrupt |
*/ |
if (new_delay >= dev_priv->rps.min_delay && |
new_delay <= dev_priv->rps.max_delay) { |
new_delay = clamp_t(int, new_delay, |
dev_priv->rps.min_delay, dev_priv->rps.max_delay); |
dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay; |
|
if (IS_VALLEYVIEW(dev_priv->dev)) |
valleyview_set_rps(dev_priv->dev, new_delay); |
else |
gen6_set_rps(dev_priv->dev, new_delay); |
} |
|
if (IS_VALLEYVIEW(dev_priv->dev)) { |
/* |
* On VLV, when we enter RC6 we may not be at the minimum |
* voltage level, so arm a timer to check. It should only |
* fire when there's activity or once after we've entered |
* RC6, and then won't be re-armed until the next RPS interrupt. |
*/ |
// mod_delayed_work(dev_priv->wq, &dev_priv->rps.vlv_work, |
// msecs_to_jiffies(100)); |
} |
|
mutex_unlock(&dev_priv->rps.hw_lock); |
} |
|
894,9 → 1054,10 |
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, |
l3_parity.error_work); |
u32 error_status, row, bank, subbank; |
char *parity_event[5]; |
char *parity_event[6]; |
uint32_t misccpctl; |
unsigned long flags; |
uint8_t slice = 0; |
|
/* We must turn off DOP level clock gating to access the L3 registers. |
* In order to prevent a get/put style interface, acquire struct mutex |
904,43 → 1065,67 |
*/ |
mutex_lock(&dev_priv->dev->struct_mutex); |
|
/* If we've screwed up tracking, just let the interrupt fire again */ |
if (WARN_ON(!dev_priv->l3_parity.which_slice)) |
goto out; |
|
misccpctl = I915_READ(GEN7_MISCCPCTL); |
I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); |
POSTING_READ(GEN7_MISCCPCTL); |
|
error_status = I915_READ(GEN7_L3CDERRST1); |
while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) { |
u32 reg; |
|
slice--; |
if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev))) |
break; |
|
dev_priv->l3_parity.which_slice &= ~(1<<slice); |
|
reg = GEN7_L3CDERRST1 + (slice * 0x200); |
|
error_status = I915_READ(reg); |
row = GEN7_PARITY_ERROR_ROW(error_status); |
bank = GEN7_PARITY_ERROR_BANK(error_status); |
subbank = GEN7_PARITY_ERROR_SUBBANK(error_status); |
|
I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID | |
GEN7_L3CDERRST1_ENABLE); |
POSTING_READ(GEN7_L3CDERRST1); |
I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE); |
POSTING_READ(reg); |
|
DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n", |
slice, row, bank, subbank); |
|
} |
|
I915_WRITE(GEN7_MISCCPCTL, misccpctl); |
|
out: |
WARN_ON(dev_priv->l3_parity.which_slice); |
spin_lock_irqsave(&dev_priv->irq_lock, flags); |
ilk_enable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT); |
ilk_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev)); |
spin_unlock_irqrestore(&dev_priv->irq_lock, flags); |
|
mutex_unlock(&dev_priv->dev->struct_mutex); |
|
DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n", |
row, bank, subbank); |
|
} |
|
static void ivybridge_parity_error_irq_handler(struct drm_device *dev) |
static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
|
if (!HAS_L3_GPU_CACHE(dev)) |
if (!HAS_L3_DPF(dev)) |
return; |
|
spin_lock(&dev_priv->irq_lock); |
ilk_disable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT); |
ilk_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev)); |
spin_unlock(&dev_priv->irq_lock); |
|
iir &= GT_PARITY_ERROR(dev); |
if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1) |
dev_priv->l3_parity.which_slice |= 1 << 1; |
|
if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT) |
dev_priv->l3_parity.which_slice |= 1 << 0; |
|
queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work); |
} |
|
975,10 → 1160,60 |
i915_handle_error(dev, false); |
} |
|
if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT) |
ivybridge_parity_error_irq_handler(dev); |
if (gt_iir & GT_PARITY_ERROR(dev)) |
ivybridge_parity_error_irq_handler(dev, gt_iir); |
} |
|
static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, |
struct drm_i915_private *dev_priv, |
u32 master_ctl) |
{ |
u32 rcs, bcs, vcs; |
uint32_t tmp = 0; |
irqreturn_t ret = IRQ_NONE; |
|
if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { |
tmp = I915_READ(GEN8_GT_IIR(0)); |
if (tmp) { |
ret = IRQ_HANDLED; |
rcs = tmp >> GEN8_RCS_IRQ_SHIFT; |
bcs = tmp >> GEN8_BCS_IRQ_SHIFT; |
if (rcs & GT_RENDER_USER_INTERRUPT) |
notify_ring(dev, &dev_priv->ring[RCS]); |
if (bcs & GT_RENDER_USER_INTERRUPT) |
notify_ring(dev, &dev_priv->ring[BCS]); |
I915_WRITE(GEN8_GT_IIR(0), tmp); |
} else |
DRM_ERROR("The master control interrupt lied (GT0)!\n"); |
} |
|
if (master_ctl & GEN8_GT_VCS1_IRQ) { |
tmp = I915_READ(GEN8_GT_IIR(1)); |
if (tmp) { |
ret = IRQ_HANDLED; |
vcs = tmp >> GEN8_VCS1_IRQ_SHIFT; |
if (vcs & GT_RENDER_USER_INTERRUPT) |
notify_ring(dev, &dev_priv->ring[VCS]); |
I915_WRITE(GEN8_GT_IIR(1), tmp); |
} else |
DRM_ERROR("The master control interrupt lied (GT1)!\n"); |
} |
|
if (master_ctl & GEN8_GT_VECS_IRQ) { |
tmp = I915_READ(GEN8_GT_IIR(3)); |
if (tmp) { |
ret = IRQ_HANDLED; |
vcs = tmp >> GEN8_VECS_IRQ_SHIFT; |
if (vcs & GT_RENDER_USER_INTERRUPT) |
notify_ring(dev, &dev_priv->ring[VECS]); |
I915_WRITE(GEN8_GT_IIR(3), tmp); |
} else |
DRM_ERROR("The master control interrupt lied (GT3)!\n"); |
} |
|
return ret; |
} |
|
#define HPD_STORM_DETECT_PERIOD 1000 |
#define HPD_STORM_THRESHOLD 5 |
|
996,9 → 1231,10 |
spin_lock(&dev_priv->irq_lock); |
for (i = 1; i < HPD_NUM_PINS; i++) { |
|
WARN(((hpd[i] & hotplug_trigger) && |
dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED), |
"Received HPD interrupt although disabled\n"); |
WARN_ONCE(hpd[i] & hotplug_trigger && |
dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED, |
"Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", |
hotplug_trigger, i, hpd[i]); |
|
if (!(hpd[i] & hotplug_trigger) || |
dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) |
1050,6 → 1286,102 |
wake_up_all(&dev_priv->gmbus_wait_queue); |
} |
|
#if defined(CONFIG_DEBUG_FS) |
static void display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe, |
uint32_t crc0, uint32_t crc1, |
uint32_t crc2, uint32_t crc3, |
uint32_t crc4) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; |
struct intel_pipe_crc_entry *entry; |
int head, tail; |
|
spin_lock(&pipe_crc->lock); |
|
if (!pipe_crc->entries) { |
spin_unlock(&pipe_crc->lock); |
DRM_ERROR("spurious interrupt\n"); |
return; |
} |
|
head = pipe_crc->head; |
tail = pipe_crc->tail; |
|
if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) { |
spin_unlock(&pipe_crc->lock); |
DRM_ERROR("CRC buffer overflowing\n"); |
return; |
} |
|
entry = &pipe_crc->entries[head]; |
|
entry->frame = dev->driver->get_vblank_counter(dev, pipe); |
entry->crc[0] = crc0; |
entry->crc[1] = crc1; |
entry->crc[2] = crc2; |
entry->crc[3] = crc3; |
entry->crc[4] = crc4; |
|
head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); |
pipe_crc->head = head; |
|
spin_unlock(&pipe_crc->lock); |
|
wake_up_interruptible(&pipe_crc->wq); |
} |
#else |
static inline void |
display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe, |
uint32_t crc0, uint32_t crc1, |
uint32_t crc2, uint32_t crc3, |
uint32_t crc4) {} |
#endif |
|
|
static void hsw_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
display_pipe_crc_irq_handler(dev, pipe, |
I915_READ(PIPE_CRC_RES_1_IVB(pipe)), |
0, 0, 0, 0); |
} |
|
static void ivb_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
display_pipe_crc_irq_handler(dev, pipe, |
I915_READ(PIPE_CRC_RES_1_IVB(pipe)), |
I915_READ(PIPE_CRC_RES_2_IVB(pipe)), |
I915_READ(PIPE_CRC_RES_3_IVB(pipe)), |
I915_READ(PIPE_CRC_RES_4_IVB(pipe)), |
I915_READ(PIPE_CRC_RES_5_IVB(pipe))); |
} |
|
static void i9xx_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t res1, res2; |
|
if (INTEL_INFO(dev)->gen >= 3) |
res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe)); |
else |
res1 = 0; |
|
if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev)) |
res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe)); |
else |
res2 = 0; |
|
display_pipe_crc_irq_handler(dev, pipe, |
I915_READ(PIPE_CRC_RES_RED(pipe)), |
I915_READ(PIPE_CRC_RES_GREEN(pipe)), |
I915_READ(PIPE_CRC_RES_BLUE(pipe)), |
res1, res2); |
} |
|
/* The RPS events need forcewake, so we add them to a work queue and mask their |
* IMR bits until the work is done. Other interrupts can be processed without |
* the work queue. */ |
1116,17 → 1448,18 |
} |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
#if 0 |
for_each_pipe(pipe) { |
if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS) |
drm_handle_vblank(dev, pipe); |
// if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) |
// drm_handle_vblank(dev, pipe); |
|
if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) { |
intel_prepare_page_flip(dev, pipe); |
intel_finish_page_flip(dev, pipe); |
// intel_prepare_page_flip(dev, pipe); |
// intel_finish_page_flip(dev, pipe); |
} |
|
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
} |
#endif |
|
/* Consume port. Then clear IIR or we'll miss events */ |
if (iir & I915_DISPLAY_PORT_INTERRUPT) { |
1138,6 → 1471,9 |
|
intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); |
|
if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) |
dp_aux_irq_handler(dev); |
|
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); |
I915_READ(PORT_HOTPLUG_STAT); |
} |
1214,22 → 1550,27 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 err_int = I915_READ(GEN7_ERR_INT); |
enum pipe pipe; |
|
if (err_int & ERR_INT_POISON) |
DRM_ERROR("Poison interrupt\n"); |
|
if (err_int & ERR_INT_FIFO_UNDERRUN_A) |
if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) |
DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); |
for_each_pipe(pipe) { |
if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) { |
if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, |
false)) |
DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", |
pipe_name(pipe)); |
} |
|
if (err_int & ERR_INT_FIFO_UNDERRUN_B) |
if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false)) |
DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n"); |
if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) { |
if (IS_IVYBRIDGE(dev)) |
ivb_pipe_crc_irq_handler(dev, pipe); |
else |
hsw_pipe_crc_irq_handler(dev, pipe); |
} |
} |
|
if (err_int & ERR_INT_FIFO_UNDERRUN_C) |
if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false)) |
DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n"); |
|
I915_WRITE(GEN7_ERR_INT, err_int); |
} |
|
1299,6 → 1640,7 |
static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
enum pipe pipe; |
|
if (de_iir & DE_AUX_CHANNEL_A) |
dp_aux_irq_handler(dev); |
1306,35 → 1648,27 |
if (de_iir & DE_GSE) |
intel_opregion_asle_intr(dev); |
|
#if 0 |
if (de_iir & DE_PIPEA_VBLANK) |
drm_handle_vblank(dev, 0); |
|
if (de_iir & DE_PIPEB_VBLANK) |
drm_handle_vblank(dev, 1); |
#endif |
|
if (de_iir & DE_POISON) |
DRM_ERROR("Poison interrupt\n"); |
|
if (de_iir & DE_PIPEA_FIFO_UNDERRUN) |
if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) |
DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); |
for_each_pipe(pipe) { |
// if (de_iir & DE_PIPE_VBLANK(pipe)) |
// drm_handle_vblank(dev, pipe); |
|
if (de_iir & DE_PIPEB_FIFO_UNDERRUN) |
if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false)) |
DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n"); |
#if 0 |
if (de_iir & DE_PLANEA_FLIP_DONE) { |
intel_prepare_page_flip(dev, 0); |
intel_finish_page_flip_plane(dev, 0); |
} |
if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe)) |
if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) |
DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", |
pipe_name(pipe)); |
|
if (de_iir & DE_PLANEB_FLIP_DONE) { |
intel_prepare_page_flip(dev, 1); |
intel_finish_page_flip_plane(dev, 1); |
if (de_iir & DE_PIPE_CRC_DONE(pipe)) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
|
/* plane/pipes map 1:1 on ilk+ */ |
if (de_iir & DE_PLANE_FLIP_DONE(pipe)) { |
// intel_prepare_page_flip(dev, pipe); |
// intel_finish_page_flip_plane(dev, pipe); |
} |
#endif |
} |
|
/* check event from PCH */ |
if (de_iir & DE_PCH_EVENT) { |
1356,7 → 1690,7 |
static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int i; |
enum pipe i; |
|
if (de_iir & DE_ERR_INT_IVB) |
ivb_err_int_handler(dev); |
1366,16 → 1700,17 |
|
if (de_iir & DE_GSE_IVB) |
intel_opregion_asle_intr(dev); |
#if 0 |
for (i = 0; i < 3; i++) { |
if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) |
drm_handle_vblank(dev, i); |
if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) { |
intel_prepare_page_flip(dev, i); |
intel_finish_page_flip_plane(dev, i); |
|
for_each_pipe(i) { |
// if (de_iir & (DE_PIPE_VBLANK_IVB(i))) |
// drm_handle_vblank(dev, i); |
|
/* plane/pipes map 1:1 on ilk+ */ |
if (de_iir & DE_PLANE_FLIP_DONE_IVB(i)) { |
// intel_prepare_page_flip(dev, i); |
// intel_finish_page_flip_plane(dev, i); |
} |
} |
#endif |
|
/* check event from PCH */ |
if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) { |
1394,7 → 1729,6 |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 de_iir, gt_iir, de_ier, sde_ier = 0; |
irqreturn_t ret = IRQ_NONE; |
bool err_int_reenable = false; |
|
atomic_inc(&dev_priv->irq_received); |
|
1418,17 → 1752,6 |
POSTING_READ(SDEIER); |
} |
|
/* On Haswell, also mask ERR_INT because we don't want to risk |
* generating "unclaimed register" interrupts from inside the interrupt |
* handler. */ |
if (IS_HASWELL(dev)) { |
spin_lock(&dev_priv->irq_lock); |
err_int_reenable = ~dev_priv->irq_mask & DE_ERR_INT_IVB; |
if (err_int_reenable) |
ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); |
spin_unlock(&dev_priv->irq_lock); |
} |
|
gt_iir = I915_READ(GTIIR); |
if (gt_iir) { |
if (INTEL_INFO(dev)->gen >= 6) |
1458,13 → 1781,6 |
} |
} |
|
if (err_int_reenable) { |
spin_lock(&dev_priv->irq_lock); |
if (ivb_can_enable_err_int(dev)) |
ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); |
spin_unlock(&dev_priv->irq_lock); |
} |
|
I915_WRITE(DEIER, de_ier); |
POSTING_READ(DEIER); |
if (!HAS_PCH_NOP(dev)) { |
1475,6 → 1791,117 |
return ret; |
} |
|
static irqreturn_t gen8_irq_handler(int irq, void *arg) |
{ |
struct drm_device *dev = arg; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 master_ctl; |
irqreturn_t ret = IRQ_NONE; |
uint32_t tmp = 0; |
enum pipe pipe; |
|
atomic_inc(&dev_priv->irq_received); |
|
master_ctl = I915_READ(GEN8_MASTER_IRQ); |
master_ctl &= ~GEN8_MASTER_IRQ_CONTROL; |
if (!master_ctl) |
return IRQ_NONE; |
|
I915_WRITE(GEN8_MASTER_IRQ, 0); |
POSTING_READ(GEN8_MASTER_IRQ); |
|
ret = gen8_gt_irq_handler(dev, dev_priv, master_ctl); |
|
if (master_ctl & GEN8_DE_MISC_IRQ) { |
tmp = I915_READ(GEN8_DE_MISC_IIR); |
if (tmp & GEN8_DE_MISC_GSE) |
intel_opregion_asle_intr(dev); |
else if (tmp) |
DRM_ERROR("Unexpected DE Misc interrupt\n"); |
else |
DRM_ERROR("The master control interrupt lied (DE MISC)!\n"); |
|
if (tmp) { |
I915_WRITE(GEN8_DE_MISC_IIR, tmp); |
ret = IRQ_HANDLED; |
} |
} |
|
if (master_ctl & GEN8_DE_PORT_IRQ) { |
tmp = I915_READ(GEN8_DE_PORT_IIR); |
if (tmp & GEN8_AUX_CHANNEL_A) |
dp_aux_irq_handler(dev); |
else if (tmp) |
DRM_ERROR("Unexpected DE Port interrupt\n"); |
else |
DRM_ERROR("The master control interrupt lied (DE PORT)!\n"); |
|
if (tmp) { |
I915_WRITE(GEN8_DE_PORT_IIR, tmp); |
ret = IRQ_HANDLED; |
} |
} |
|
for_each_pipe(pipe) { |
uint32_t pipe_iir; |
|
if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe))) |
continue; |
|
pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe)); |
// if (pipe_iir & GEN8_PIPE_VBLANK) |
// drm_handle_vblank(dev, pipe); |
|
if (pipe_iir & GEN8_PIPE_FLIP_DONE) { |
// intel_prepare_page_flip(dev, pipe); |
// intel_finish_page_flip_plane(dev, pipe); |
} |
|
if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE) |
hsw_pipe_crc_irq_handler(dev, pipe); |
|
if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) { |
if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, |
false)) |
DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n", |
pipe_name(pipe)); |
} |
|
if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) { |
DRM_ERROR("Fault errors on pipe %c\n: 0x%08x", |
pipe_name(pipe), |
pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS); |
} |
|
if (pipe_iir) { |
ret = IRQ_HANDLED; |
I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir); |
} else |
DRM_ERROR("The master control interrupt lied (DE PIPE)!\n"); |
} |
|
if (!HAS_PCH_NOP(dev) && master_ctl & GEN8_DE_PCH_IRQ) { |
/* |
* FIXME(BDW): Assume for now that the new interrupt handling |
* scheme also closed the SDE interrupt handling race we've seen |
* on older pch-split platforms. But this needs testing. |
*/ |
u32 pch_iir = I915_READ(SDEIIR); |
|
cpt_irq_handler(dev, pch_iir); |
|
if (pch_iir) { |
I915_WRITE(SDEIIR, pch_iir); |
ret = IRQ_HANDLED; |
} |
} |
|
I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); |
POSTING_READ(GEN8_MASTER_IRQ); |
|
return ret; |
} |
|
static void i915_error_wake_up(struct drm_i915_private *dev_priv, |
bool reset_completed) |
{ |
1557,7 → 1984,7 |
atomic_inc(&dev_priv->gpu_error.reset_counter); |
|
} else { |
atomic_set(&error->reset_counter, I915_WEDGED); |
atomic_set_mask(I915_WEDGED, &error->reset_counter); |
} |
|
/* |
1787,7 → 2214,7 |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
unsigned long irqflags; |
uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) : |
DE_PIPE_VBLANK_ILK(pipe); |
DE_PIPE_VBLANK(pipe); |
|
if (!i915_pipe_enabled(dev, pipe)) |
return -EINVAL; |
1810,7 → 2237,7 |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
imr = I915_READ(VLV_IMR); |
if (pipe == 0) |
if (pipe == PIPE_A) |
imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; |
else |
imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; |
1822,6 → 2249,22 |
return 0; |
} |
|
static int gen8_enable_vblank(struct drm_device *dev, int pipe) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
|
if (!i915_pipe_enabled(dev, pipe)) |
return -EINVAL; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_VBLANK; |
I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); |
POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
return 0; |
} |
|
/* Called from drm generic code, passed 'crtc' which |
* we use as a pipe index |
*/ |
1845,7 → 2288,7 |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
unsigned long irqflags; |
uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) : |
DE_PIPE_VBLANK_ILK(pipe); |
DE_PIPE_VBLANK(pipe); |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
ironlake_disable_display_irq(dev_priv, bit); |
1862,7 → 2305,7 |
i915_disable_pipestat(dev_priv, pipe, |
PIPE_START_VBLANK_INTERRUPT_ENABLE); |
imr = I915_READ(VLV_IMR); |
if (pipe == 0) |
if (pipe == PIPE_A) |
imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; |
else |
imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; |
1870,6 → 2313,21 |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
} |
|
static void gen8_disable_vblank(struct drm_device *dev, int pipe) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
|
if (!i915_pipe_enabled(dev, pipe)) |
return; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_VBLANK; |
I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); |
POSTING_READ(GEN8_DE_PIPE_IMR(pipe)); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
} |
|
static u32 |
ring_last_seqno(struct intel_ring_buffer *ring) |
{ |
2048,6 → 2506,7 |
acthd); |
|
switch (ring->hangcheck.action) { |
case HANGCHECK_IDLE: |
case HANGCHECK_WAIT: |
break; |
case HANGCHECK_ACTIVE: |
2063,6 → 2522,8 |
} |
} |
} else { |
ring->hangcheck.action = HANGCHECK_ACTIVE; |
|
/* Gradually reduce the count so that we catch DoS |
* attempts across multiple batches. |
*/ |
2175,6 → 2636,55 |
POSTING_READ(VLV_IER); |
} |
|
static void gen8_irq_preinstall(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
atomic_set(&dev_priv->irq_received, 0); |
|
I915_WRITE(GEN8_MASTER_IRQ, 0); |
POSTING_READ(GEN8_MASTER_IRQ); |
|
/* IIR can theoretically queue up two events. Be paranoid */ |
#define GEN8_IRQ_INIT_NDX(type, which) do { \ |
I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ |
POSTING_READ(GEN8_##type##_IMR(which)); \ |
I915_WRITE(GEN8_##type##_IER(which), 0); \ |
I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ |
POSTING_READ(GEN8_##type##_IIR(which)); \ |
I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ |
} while (0) |
|
#define GEN8_IRQ_INIT(type) do { \ |
I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ |
POSTING_READ(GEN8_##type##_IMR); \ |
I915_WRITE(GEN8_##type##_IER, 0); \ |
I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ |
POSTING_READ(GEN8_##type##_IIR); \ |
I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ |
} while (0) |
|
GEN8_IRQ_INIT_NDX(GT, 0); |
GEN8_IRQ_INIT_NDX(GT, 1); |
GEN8_IRQ_INIT_NDX(GT, 2); |
GEN8_IRQ_INIT_NDX(GT, 3); |
|
for_each_pipe(pipe) { |
GEN8_IRQ_INIT_NDX(DE_PIPE, pipe); |
} |
|
GEN8_IRQ_INIT(DE_PORT); |
GEN8_IRQ_INIT(DE_MISC); |
GEN8_IRQ_INIT(PCU); |
#undef GEN8_IRQ_INIT |
#undef GEN8_IRQ_INIT_NDX |
|
POSTING_READ(GEN8_PCU_IIR); |
|
ibx_irq_preinstall(dev); |
} |
|
static void ibx_hpd_irq_setup(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
2239,10 → 2749,10 |
pm_irqs = gt_irqs = 0; |
|
dev_priv->gt_irq_mask = ~0; |
if (HAS_L3_GPU_CACHE(dev)) { |
if (HAS_L3_DPF(dev)) { |
/* L3 parity interrupt is always unmasked. */ |
dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT; |
gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; |
dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev); |
gt_irqs |= GT_PARITY_ERROR(dev); |
} |
|
gt_irqs |= GT_RENDER_USER_INTERRUPT; |
2291,8 → 2801,10 |
} else { |
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | |
DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN | |
DE_PIPEA_FIFO_UNDERRUN | DE_POISON); |
DE_AUX_CHANNEL_A | |
DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN | |
DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE | |
DE_POISON); |
extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT; |
} |
|
2326,7 → 2838,8 |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 enable_mask; |
u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; |
u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV | |
PIPE_CRC_DONE_ENABLE; |
unsigned long irqflags; |
|
enable_mask = I915_DISPLAY_PORT_INTERRUPT; |
2356,9 → 2869,9 |
/* Interrupt setup is already guaranteed to be single-threaded, this is |
* just to make the assert_spin_locked check happy. */ |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
i915_enable_pipestat(dev_priv, 0, pipestat_enable); |
i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); |
i915_enable_pipestat(dev_priv, 1, pipestat_enable); |
i915_enable_pipestat(dev_priv, PIPE_A, pipestat_enable); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
I915_WRITE(VLV_IIR, 0xffffffff); |
2377,6 → 2890,117 |
return 0; |
} |
|
static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) |
{ |
int i; |
|
/* These are interrupts we'll toggle with the ring mask register */ |
uint32_t gt_interrupts[] = { |
GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | |
GT_RENDER_L3_PARITY_ERROR_INTERRUPT | |
GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT, |
GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT | |
GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT, |
0, |
GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT |
}; |
|
for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) { |
u32 tmp = I915_READ(GEN8_GT_IIR(i)); |
if (tmp) |
DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", |
i, tmp); |
I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]); |
I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]); |
} |
POSTING_READ(GEN8_GT_IER(0)); |
} |
|
static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) |
{ |
struct drm_device *dev = dev_priv->dev; |
uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE | |
GEN8_PIPE_CDCLK_CRC_DONE | |
GEN8_PIPE_FIFO_UNDERRUN | |
GEN8_DE_PIPE_IRQ_FAULT_ERRORS; |
uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK; |
int pipe; |
dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked; |
dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked; |
dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked; |
|
for_each_pipe(pipe) { |
u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe)); |
if (tmp) |
DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n", |
pipe, tmp); |
I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]); |
I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables); |
} |
POSTING_READ(GEN8_DE_PIPE_ISR(0)); |
|
I915_WRITE(GEN8_DE_PORT_IMR, ~GEN8_AUX_CHANNEL_A); |
I915_WRITE(GEN8_DE_PORT_IER, GEN8_AUX_CHANNEL_A); |
POSTING_READ(GEN8_DE_PORT_IER); |
} |
|
static int gen8_irq_postinstall(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
gen8_gt_irq_postinstall(dev_priv); |
gen8_de_irq_postinstall(dev_priv); |
|
ibx_irq_postinstall(dev); |
|
I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL); |
POSTING_READ(GEN8_MASTER_IRQ); |
|
return 0; |
} |
|
static void gen8_irq_uninstall(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
if (!dev_priv) |
return; |
|
atomic_set(&dev_priv->irq_received, 0); |
|
I915_WRITE(GEN8_MASTER_IRQ, 0); |
|
#define GEN8_IRQ_FINI_NDX(type, which) do { \ |
I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ |
I915_WRITE(GEN8_##type##_IER(which), 0); \ |
I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ |
} while (0) |
|
#define GEN8_IRQ_FINI(type) do { \ |
I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ |
I915_WRITE(GEN8_##type##_IER, 0); \ |
I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \ |
} while (0) |
|
GEN8_IRQ_FINI_NDX(GT, 0); |
GEN8_IRQ_FINI_NDX(GT, 1); |
GEN8_IRQ_FINI_NDX(GT, 2); |
GEN8_IRQ_FINI_NDX(GT, 3); |
|
for_each_pipe(pipe) { |
GEN8_IRQ_FINI_NDX(DE_PIPE, pipe); |
} |
|
GEN8_IRQ_FINI(DE_PORT); |
GEN8_IRQ_FINI(DE_MISC); |
GEN8_IRQ_FINI(PCU); |
#undef GEN8_IRQ_FINI |
#undef GEN8_IRQ_FINI_NDX |
|
POSTING_READ(GEN8_PCU_IIR); |
} |
|
static void valleyview_irq_uninstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
2451,6 → 3075,7 |
static int i8xx_irq_postinstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
unsigned long irqflags; |
|
I915_WRITE16(EMR, |
~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); |
2471,6 → 3096,13 |
I915_USER_INTERRUPT); |
POSTING_READ16(IER); |
|
/* Interrupt setup is already guaranteed to be single-threaded, this is |
* just to make the assert_spin_locked check happy. */ |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
return 0; |
} |
|
2478,10 → 3110,10 |
* Returns true when a page flip has completed. |
*/ |
static bool i8xx_handle_vblank(struct drm_device *dev, |
int pipe, u16 iir) |
int plane, int pipe, u32 iir) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe); |
u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); |
|
// if (!drm_handle_vblank(dev, pipe)) |
return false; |
2557,14 → 3189,19 |
if (iir & I915_USER_INTERRUPT) |
notify_ring(dev, &dev_priv->ring[RCS]); |
|
if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS && |
i8xx_handle_vblank(dev, 0, iir)) |
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0); |
for_each_pipe(pipe) { |
int plane = pipe; |
if (HAS_FBC(dev)) |
plane = !plane; |
|
if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS && |
i8xx_handle_vblank(dev, 1, iir)) |
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1); |
if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && |
i8xx_handle_vblank(dev, plane, pipe, iir)) |
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); |
|
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
} |
|
iir = new_iir; |
} |
|
2612,6 → 3249,7 |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 enable_mask; |
unsigned long irqflags; |
|
I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); |
|
2647,6 → 3285,13 |
|
i915_enable_asle_pipestat(dev); |
|
/* Interrupt setup is already guaranteed to be single-threaded, this is |
* just to make the assert_spin_locked check happy. */ |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
return 0; |
} |
|
2749,7 → 3394,7 |
|
for_each_pipe(pipe) { |
int plane = pipe; |
if (IS_MOBILE(dev)) |
if (HAS_FBC(dev)) |
plane = !plane; |
|
if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && |
2758,6 → 3403,9 |
|
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) |
blc_event = true; |
|
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
} |
|
if (blc_event || (iir & I915_ASLE_INTERRUPT)) |
2856,7 → 3504,9 |
/* Interrupt setup is already guaranteed to be single-threaded, this is |
* just to make the assert_spin_locked check happy. */ |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
/* |
2981,8 → 3631,12 |
hotplug_status); |
|
intel_hpd_irq_handler(dev, hotplug_trigger, |
IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915); |
IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915); |
|
if (IS_G4X(dev) && |
(hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)) |
dp_aux_irq_handler(dev); |
|
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); |
I915_READ(PORT_HOTPLUG_STAT); |
} |
3002,6 → 3656,9 |
|
if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) |
blc_event = true; |
|
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
} |
|
|
3106,18 → 3763,22 |
setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func, |
(unsigned long) dev_priv); |
|
|
if (IS_GEN2(dev)) { |
dev->max_vblank_count = 0; |
dev->driver->get_vblank_counter = i8xx_get_vblank_counter; |
} else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { |
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ |
dev->driver->get_vblank_counter = gm45_get_vblank_counter; |
} else { |
dev->driver->get_vblank_counter = i915_get_vblank_counter; |
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ |
if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { |
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ |
dev->driver->get_vblank_counter = gm45_get_vblank_counter; |
} |
|
if (drm_core_check_feature(dev, DRIVER_MODESET)) |
if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; |
else |
dev->driver->get_vblank_timestamp = NULL; |
dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; |
} |
|
if (IS_VALLEYVIEW(dev)) { |
dev->driver->irq_handler = valleyview_irq_handler; |
3127,6 → 3788,14 |
dev->driver->enable_vblank = valleyview_enable_vblank; |
dev->driver->disable_vblank = valleyview_disable_vblank; |
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; |
} else if (IS_GEN8(dev)) { |
dev->driver->irq_handler = gen8_irq_handler; |
dev->driver->irq_preinstall = gen8_irq_preinstall; |
dev->driver->irq_postinstall = gen8_irq_postinstall; |
dev->driver->irq_uninstall = gen8_irq_uninstall; |
dev->driver->enable_vblank = gen8_enable_vblank; |
dev->driver->disable_vblank = gen8_disable_vblank; |
dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; |
} else if (HAS_PCH_SPLIT(dev)) { |
dev->driver->irq_handler = ironlake_irq_handler; |
dev->driver->irq_preinstall = ironlake_irq_preinstall; |
3196,8 → 3865,8 |
dev_priv->pc8.regsave.gtier = I915_READ(GTIER); |
dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR); |
|
ironlake_disable_display_irq(dev_priv, ~DE_PCH_EVENT_IVB); |
ibx_disable_display_interrupt(dev_priv, ~SDE_HOTPLUG_MASK_CPT); |
ironlake_disable_display_irq(dev_priv, 0xffffffff); |
ibx_disable_display_interrupt(dev_priv, 0xffffffff); |
ilk_disable_gt_irq(dev_priv, 0xffffffff); |
snb_disable_pm_irq(dev_priv, 0xffffffff); |
|
3211,34 → 3880,26 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
uint32_t val, expected; |
uint32_t val; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
|
val = I915_READ(DEIMR); |
expected = ~DE_PCH_EVENT_IVB; |
WARN(val != expected, "DEIMR is 0x%08x, not 0x%08x\n", val, expected); |
WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val); |
|
val = I915_READ(SDEIMR) & ~SDE_HOTPLUG_MASK_CPT; |
expected = ~SDE_HOTPLUG_MASK_CPT; |
WARN(val != expected, "SDEIMR non-HPD bits are 0x%08x, not 0x%08x\n", |
val, expected); |
val = I915_READ(SDEIMR); |
WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val); |
|
val = I915_READ(GTIMR); |
expected = 0xffffffff; |
WARN(val != expected, "GTIMR is 0x%08x, not 0x%08x\n", val, expected); |
WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val); |
|
val = I915_READ(GEN6_PMIMR); |
expected = 0xffffffff; |
WARN(val != expected, "GEN6_PMIMR is 0x%08x, not 0x%08x\n", val, |
expected); |
WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val); |
|
dev_priv->pc8.irqs_disabled = false; |
|
ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr); |
ibx_enable_display_interrupt(dev_priv, |
~dev_priv->pc8.regsave.sdeimr & |
~SDE_HOTPLUG_MASK_CPT); |
ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr); |
ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr); |
snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr); |
I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier); |