80,7 → 80,56 |
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS |
}; |
|
/* IIR can theoretically queue up two events. Be paranoid. */ |
#define GEN8_IRQ_RESET_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); \ |
POSTING_READ(GEN8_##type##_IIR(which)); \ |
} while (0) |
|
#define GEN5_IRQ_RESET(type) do { \ |
I915_WRITE(type##IMR, 0xffffffff); \ |
POSTING_READ(type##IMR); \ |
I915_WRITE(type##IER, 0); \ |
I915_WRITE(type##IIR, 0xffffffff); \ |
POSTING_READ(type##IIR); \ |
I915_WRITE(type##IIR, 0xffffffff); \ |
POSTING_READ(type##IIR); \ |
} while (0) |
|
/* |
* We should clear IMR at preinstall/uninstall, and just check at postinstall. |
*/ |
#define GEN5_ASSERT_IIR_IS_ZERO(reg) do { \ |
u32 val = I915_READ(reg); \ |
if (val) { \ |
WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n", \ |
(reg), val); \ |
I915_WRITE((reg), 0xffffffff); \ |
POSTING_READ(reg); \ |
I915_WRITE((reg), 0xffffffff); \ |
POSTING_READ(reg); \ |
} \ |
} while (0) |
|
#define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \ |
GEN5_ASSERT_IIR_IS_ZERO(GEN8_##type##_IIR(which)); \ |
I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \ |
I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \ |
POSTING_READ(GEN8_##type##_IER(which)); \ |
} while (0) |
|
#define GEN5_IRQ_INIT(type, imr_val, ier_val) do { \ |
GEN5_ASSERT_IIR_IS_ZERO(type##IIR); \ |
I915_WRITE(type##IMR, (imr_val)); \ |
I915_WRITE(type##IER, (ier_val)); \ |
POSTING_READ(type##IER); \ |
} while (0) |
|
#define pr_err(fmt, ...) \ |
printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
|
94,15 → 143,12 |
|
/* For display hotplug interrupt */ |
static void |
ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) |
ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask) |
{ |
assert_spin_locked(&dev_priv->irq_lock); |
|
if (dev_priv->pc8.irqs_disabled) { |
WARN(1, "IRQs disabled\n"); |
dev_priv->pc8.regsave.deimr &= ~mask; |
if (WARN_ON(!intel_irqs_enabled(dev_priv))) |
return; |
} |
|
if ((dev_priv->irq_mask & mask) != 0) { |
dev_priv->irq_mask &= ~mask; |
112,15 → 158,12 |
} |
|
static void |
ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) |
ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask) |
{ |
assert_spin_locked(&dev_priv->irq_lock); |
|
if (dev_priv->pc8.irqs_disabled) { |
WARN(1, "IRQs disabled\n"); |
dev_priv->pc8.regsave.deimr |= mask; |
if (!intel_irqs_enabled(dev_priv)) |
return; |
} |
|
if ((dev_priv->irq_mask & mask) != mask) { |
dev_priv->irq_mask |= mask; |
141,13 → 184,8 |
{ |
assert_spin_locked(&dev_priv->irq_lock); |
|
if (dev_priv->pc8.irqs_disabled) { |
WARN(1, "IRQs disabled\n"); |
dev_priv->pc8.regsave.gtimr &= ~interrupt_mask; |
dev_priv->pc8.regsave.gtimr |= (~enabled_irq_mask & |
interrupt_mask); |
if (WARN_ON(!intel_irqs_enabled(dev_priv))) |
return; |
} |
|
dev_priv->gt_irq_mask &= ~interrupt_mask; |
dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask); |
155,12 → 193,12 |
POSTING_READ(GTIMR); |
} |
|
void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
{ |
ilk_update_gt_irq(dev_priv, mask, mask); |
} |
|
void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
{ |
ilk_update_gt_irq(dev_priv, mask, 0); |
} |
179,13 → 217,8 |
|
assert_spin_locked(&dev_priv->irq_lock); |
|
if (dev_priv->pc8.irqs_disabled) { |
WARN(1, "IRQs disabled\n"); |
dev_priv->pc8.regsave.gen6_pmimr &= ~interrupt_mask; |
dev_priv->pc8.regsave.gen6_pmimr |= (~enabled_irq_mask & |
interrupt_mask); |
if (WARN_ON(!intel_irqs_enabled(dev_priv))) |
return; |
} |
|
new_val = dev_priv->pm_irq_mask; |
new_val &= ~interrupt_mask; |
198,12 → 231,12 |
} |
} |
|
void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
{ |
snb_update_pm_irq(dev_priv, mask, mask); |
} |
|
void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
{ |
snb_update_pm_irq(dev_priv, mask, 0); |
} |
226,6 → 259,46 |
return true; |
} |
|
/** |
* bdw_update_pm_irq - update GT interrupt 2 |
* @dev_priv: driver private |
* @interrupt_mask: mask of interrupt bits to update |
* @enabled_irq_mask: mask of interrupt bits to enable |
* |
* Copied from the snb function, updated with relevant register offsets |
*/ |
static void bdw_update_pm_irq(struct drm_i915_private *dev_priv, |
uint32_t interrupt_mask, |
uint32_t enabled_irq_mask) |
{ |
uint32_t new_val; |
|
assert_spin_locked(&dev_priv->irq_lock); |
|
if (WARN_ON(!intel_irqs_enabled(dev_priv))) |
return; |
|
new_val = dev_priv->pm_irq_mask; |
new_val &= ~interrupt_mask; |
new_val |= (~enabled_irq_mask & interrupt_mask); |
|
if (new_val != dev_priv->pm_irq_mask) { |
dev_priv->pm_irq_mask = new_val; |
I915_WRITE(GEN8_GT_IMR(2), dev_priv->pm_irq_mask); |
POSTING_READ(GEN8_GT_IMR(2)); |
} |
} |
|
void gen8_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
{ |
bdw_update_pm_irq(dev_priv, mask, mask); |
} |
|
void gen8_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
{ |
bdw_update_pm_irq(dev_priv, mask, 0); |
} |
|
static bool cpt_can_enable_serr_int(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
244,6 → 317,53 |
return true; |
} |
|
void i9xx_check_fifo_underruns(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *crtc; |
unsigned long flags; |
|
spin_lock_irqsave(&dev_priv->irq_lock, flags); |
|
for_each_intel_crtc(dev, crtc) { |
u32 reg = PIPESTAT(crtc->pipe); |
u32 pipestat; |
|
if (crtc->cpu_fifo_underrun_disabled) |
continue; |
|
pipestat = I915_READ(reg) & 0xffff0000; |
if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0) |
continue; |
|
I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); |
POSTING_READ(reg); |
|
DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe)); |
} |
|
spin_unlock_irqrestore(&dev_priv->irq_lock, flags); |
} |
|
static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev, |
enum pipe pipe, |
bool enable, bool old) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 reg = PIPESTAT(pipe); |
u32 pipestat = I915_READ(reg) & 0xffff0000; |
|
assert_spin_locked(&dev_priv->irq_lock); |
|
if (enable) { |
I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); |
POSTING_READ(reg); |
} else { |
if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS) |
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); |
} |
} |
|
static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, |
enum pipe pipe, bool enable) |
{ |
258,7 → 378,8 |
} |
|
static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, |
enum pipe pipe, bool enable) |
enum pipe pipe, |
bool enable, bool old) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
if (enable) { |
269,14 → 390,11 |
|
ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); |
} else { |
bool was_enabled = !(I915_READ(DEIMR) & DE_ERR_INT_IVB); |
|
/* Change the state _after_ we've read out the current one. */ |
ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); |
|
if (!was_enabled && |
(I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe))) { |
DRM_DEBUG_KMS("uncleared fifo underrun on pipe %c\n", |
if (old && |
I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) { |
DRM_ERROR("uncleared fifo underrun on pipe %c\n", |
pipe_name(pipe)); |
} |
} |
313,14 → 431,8 |
|
assert_spin_locked(&dev_priv->irq_lock); |
|
if (dev_priv->pc8.irqs_disabled && |
(interrupt_mask & SDE_HOTPLUG_MASK_CPT)) { |
WARN(1, "IRQs disabled\n"); |
dev_priv->pc8.regsave.sdeimr &= ~interrupt_mask; |
dev_priv->pc8.regsave.sdeimr |= (~enabled_irq_mask & |
interrupt_mask); |
if (WARN_ON(!intel_irqs_enabled(dev_priv))) |
return; |
} |
|
I915_WRITE(SDEIMR, sdeimr); |
POSTING_READ(SDEIMR); |
346,7 → 458,7 |
|
static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, |
enum transcoder pch_transcoder, |
bool enable) |
bool enable, bool old) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
359,15 → 471,11 |
|
ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT); |
} else { |
uint32_t tmp = I915_READ(SERR_INT); |
bool was_enabled = !(I915_READ(SDEIMR) & SDE_ERROR_CPT); |
|
/* Change the state _after_ we've read out the current one. */ |
ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT); |
|
if (!was_enabled && |
(tmp & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder))) { |
DRM_DEBUG_KMS("uncleared pch fifo underrun on pch transcoder %c\n", |
if (old && I915_READ(SERR_INT) & |
SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) { |
DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n", |
transcoder_name(pch_transcoder)); |
} |
} |
387,36 → 495,55 |
* |
* Returns the previous state of underrun reporting. |
*/ |
bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, |
static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, |
enum pipe pipe, bool enable) |
{ |
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); |
unsigned long flags; |
bool ret; |
bool old; |
|
spin_lock_irqsave(&dev_priv->irq_lock, flags); |
assert_spin_locked(&dev_priv->irq_lock); |
|
ret = !intel_crtc->cpu_fifo_underrun_disabled; |
|
if (enable == ret) |
goto done; |
|
old = !intel_crtc->cpu_fifo_underrun_disabled; |
intel_crtc->cpu_fifo_underrun_disabled = !enable; |
|
if (IS_GEN5(dev) || IS_GEN6(dev)) |
if (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)) |
i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old); |
else if (IS_GEN5(dev) || IS_GEN6(dev)) |
ironlake_set_fifo_underrun_reporting(dev, pipe, enable); |
else if (IS_GEN7(dev)) |
ivybridge_set_fifo_underrun_reporting(dev, pipe, enable); |
ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old); |
else if (IS_GEN8(dev)) |
broadwell_set_fifo_underrun_reporting(dev, pipe, enable); |
|
done: |
return old; |
} |
|
bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, |
enum pipe pipe, bool enable) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long flags; |
bool ret; |
|
spin_lock_irqsave(&dev_priv->irq_lock, flags); |
ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable); |
spin_unlock_irqrestore(&dev_priv->irq_lock, flags); |
|
return ret; |
} |
|
static bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev, |
enum pipe pipe) |
{ |
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); |
|
return !intel_crtc->cpu_fifo_underrun_disabled; |
} |
|
/** |
* intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages |
* @dev: drm device |
439,7 → 566,7 |
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; |
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
unsigned long flags; |
bool ret; |
bool old; |
|
/* |
* NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT |
452,63 → 579,132 |
|
spin_lock_irqsave(&dev_priv->irq_lock, flags); |
|
ret = !intel_crtc->pch_fifo_underrun_disabled; |
|
if (enable == ret) |
goto done; |
|
old = !intel_crtc->pch_fifo_underrun_disabled; |
intel_crtc->pch_fifo_underrun_disabled = !enable; |
|
if (HAS_PCH_IBX(dev)) |
ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable); |
else |
cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable); |
cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old); |
|
done: |
spin_unlock_irqrestore(&dev_priv->irq_lock, flags); |
return ret; |
return old; |
} |
|
|
void |
i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask) |
static void |
__i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, |
u32 enable_mask, u32 status_mask) |
{ |
u32 reg = PIPESTAT(pipe); |
u32 pipestat = I915_READ(reg) & 0x7fff0000; |
u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK; |
|
assert_spin_locked(&dev_priv->irq_lock); |
|
if ((pipestat & mask) == mask) |
if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK || |
status_mask & ~PIPESTAT_INT_STATUS_MASK, |
"pipe %c: enable_mask=0x%x, status_mask=0x%x\n", |
pipe_name(pipe), enable_mask, status_mask)) |
return; |
|
if ((pipestat & enable_mask) == enable_mask) |
return; |
|
dev_priv->pipestat_irq_mask[pipe] |= status_mask; |
|
/* Enable the interrupt, clear any pending status */ |
pipestat |= mask | (mask >> 16); |
pipestat |= enable_mask | status_mask; |
I915_WRITE(reg, pipestat); |
POSTING_READ(reg); |
} |
|
void |
i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask) |
static void |
__i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, |
u32 enable_mask, u32 status_mask) |
{ |
u32 reg = PIPESTAT(pipe); |
u32 pipestat = I915_READ(reg) & 0x7fff0000; |
u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK; |
|
assert_spin_locked(&dev_priv->irq_lock); |
|
if ((pipestat & mask) == 0) |
if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK || |
status_mask & ~PIPESTAT_INT_STATUS_MASK, |
"pipe %c: enable_mask=0x%x, status_mask=0x%x\n", |
pipe_name(pipe), enable_mask, status_mask)) |
return; |
|
pipestat &= ~mask; |
if ((pipestat & enable_mask) == 0) |
return; |
|
dev_priv->pipestat_irq_mask[pipe] &= ~status_mask; |
|
pipestat &= ~enable_mask; |
I915_WRITE(reg, pipestat); |
POSTING_READ(reg); |
} |
|
static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask) |
{ |
u32 enable_mask = status_mask << 16; |
|
/* |
* On pipe A we don't support the PSR interrupt yet, |
* on pipe B and C the same bit MBZ. |
*/ |
if (WARN_ON_ONCE(status_mask & PIPE_A_PSR_STATUS_VLV)) |
return 0; |
/* |
* On pipe B and C we don't support the PSR interrupt yet, on pipe |
* A the same bit is for perf counters which we don't use either. |
*/ |
if (WARN_ON_ONCE(status_mask & PIPE_B_PSR_STATUS_VLV)) |
return 0; |
|
enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS | |
SPRITE0_FLIP_DONE_INT_EN_VLV | |
SPRITE1_FLIP_DONE_INT_EN_VLV); |
if (status_mask & SPRITE0_FLIP_DONE_INT_STATUS_VLV) |
enable_mask |= SPRITE0_FLIP_DONE_INT_EN_VLV; |
if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV) |
enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV; |
|
return enable_mask; |
} |
|
void |
i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, |
u32 status_mask) |
{ |
u32 enable_mask; |
|
if (IS_VALLEYVIEW(dev_priv->dev)) |
enable_mask = vlv_get_pipestat_enable_mask(dev_priv->dev, |
status_mask); |
else |
enable_mask = status_mask << 16; |
__i915_enable_pipestat(dev_priv, pipe, enable_mask, status_mask); |
} |
|
void |
i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, |
u32 status_mask) |
{ |
u32 enable_mask; |
|
if (IS_VALLEYVIEW(dev_priv->dev)) |
enable_mask = vlv_get_pipestat_enable_mask(dev_priv->dev, |
status_mask); |
else |
enable_mask = status_mask << 16; |
__i915_disable_pipestat(dev_priv, pipe, enable_mask, status_mask); |
} |
|
/** |
* i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion |
*/ |
static void i915_enable_asle_pipestat(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
|
if (!dev_priv->opregion.asle || !IS_MOBILE(dev)) |
516,10 → 712,10 |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
|
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS); |
if (INTEL_INFO(dev)->gen >= 4) |
i915_enable_pipestat(dev_priv, PIPE_A, |
PIPE_LEGACY_BLC_EVENT_ENABLE); |
PIPE_LEGACY_BLC_EVENT_STATUS); |
|
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
} |
536,7 → 732,7 |
static int |
i915_pipe_enabled(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
/* Locking is horribly broken here, but whatever. */ |
549,6 → 745,56 |
} |
} |
|
/* |
* This timing diagram depicts the video signal in and |
* around the vertical blanking period. |
* |
* Assumptions about the fictitious mode used in this example: |
* vblank_start >= 3 |
* vsync_start = vblank_start + 1 |
* vsync_end = vblank_start + 2 |
* vtotal = vblank_start + 3 |
* |
* start of vblank: |
* latch double buffered registers |
* increment frame counter (ctg+) |
* generate start of vblank interrupt (gen4+) |
* | |
* | frame start: |
* | generate frame start interrupt (aka. vblank interrupt) (gmch) |
* | may be shifted forward 1-3 extra lines via PIPECONF |
* | | |
* | | start of vsync: |
* | | generate vsync interrupt |
* | | | |
* ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx |
* . \hs/ . \hs/ \hs/ \hs/ . \hs/ |
* ----va---> <-----------------vb--------------------> <--------va------------- |
* | | <----vs-----> | |
* -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2) |
* -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+) |
* -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi) |
* | | | |
* last visible pixel first visible pixel |
* | increment frame counter (gen3/4) |
* pixel counter = vblank_start * htotal pixel counter = 0 (gen3/4) |
* |
* x = horizontal active |
* _ = horizontal blanking |
* hs = horizontal sync |
* va = vertical active |
* vb = vertical blanking |
* vs = vertical sync |
* vbs = vblank_start (number) |
* |
* Summary: |
* - most events happen at the start of horizontal sync |
* - frame start happens at the start of horizontal blank, 1-4 lines |
* (depending on PIPECONF settings) after the start of vblank |
* - gen3/4 pixel and frame counter are synchronized with the start |
* of horizontal active on the first line of vertical active |
*/ |
|
static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe) |
{ |
/* Gen2 doesn't have a hardware frame counter */ |
560,10 → 806,10 |
*/ |
static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long high_frame; |
unsigned long low_frame; |
u32 high1, high2, low, pixel, vbl_start; |
u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal; |
|
if (!i915_pipe_enabled(dev, pipe)) { |
DRM_DEBUG_DRIVER("trying to get vblank count for disabled " |
577,18 → 823,28 |
const struct drm_display_mode *mode = |
&intel_crtc->config.adjusted_mode; |
|
vbl_start = mode->crtc_vblank_start * mode->crtc_htotal; |
htotal = mode->crtc_htotal; |
hsync_start = mode->crtc_hsync_start; |
vbl_start = mode->crtc_vblank_start; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
vbl_start = DIV_ROUND_UP(vbl_start, 2); |
} else { |
enum transcoder cpu_transcoder = |
intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
u32 htotal; |
enum transcoder cpu_transcoder = (enum transcoder) pipe; |
|
htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1; |
hsync_start = (I915_READ(HSYNC(cpu_transcoder)) & 0x1fff) + 1; |
vbl_start = (I915_READ(VBLANK(cpu_transcoder)) & 0x1fff) + 1; |
if ((I915_READ(PIPECONF(cpu_transcoder)) & |
PIPECONF_INTERLACE_MASK) != PIPECONF_PROGRESSIVE) |
vbl_start = DIV_ROUND_UP(vbl_start, 2); |
} |
|
/* Convert to pixel count */ |
vbl_start *= htotal; |
} |
|
/* Start of vblank event occurs at start of hsync */ |
vbl_start -= htotal - hsync_start; |
|
high_frame = PIPEFRAME(pipe); |
low_frame = PIPEFRAMEPIXEL(pipe); |
|
617,7 → 873,7 |
|
static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int reg = PIPE_FRMCOUNT_GM45(pipe); |
|
if (!i915_pipe_enabled(dev, pipe)) { |
631,33 → 887,29 |
|
/* 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) |
static int __intel_get_crtc_scanline(struct intel_crtc *crtc) |
{ |
struct drm_device *dev = crtc->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t status; |
const struct drm_display_mode *mode = &crtc->config.adjusted_mode; |
enum pipe pipe = crtc->pipe; |
int position, vtotal; |
|
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; |
} |
} |
vtotal = mode->crtc_vtotal; |
if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
vtotal /= 2; |
|
return __raw_i915_read32(dev_priv, DEISR) & status; |
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; |
|
/* |
* See update_scanline_offset() for the details on the |
* scanline_offset adjustment. |
*/ |
return (position + crtc->scanline_offset) % vtotal; |
} |
|
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, |
669,7 → 921,7 |
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; |
int vbl_start, vbl_end, hsync_start, htotal, vtotal; |
bool in_vbl = true; |
int ret = 0; |
unsigned long irqflags; |
681,6 → 933,7 |
} |
|
htotal = mode->crtc_htotal; |
hsync_start = mode->crtc_hsync_start; |
vtotal = mode->crtc_vtotal; |
vbl_start = mode->crtc_vblank_start; |
vbl_end = mode->crtc_vblank_end; |
707,48 → 960,8 |
/* No obvious pixelcount register. Only query vertical |
* scanout position from Display scan line register. |
*/ |
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; |
|
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. |
*/ |
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; |
position = __intel_get_crtc_scanline(intel_crtc); |
} 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. |
759,6 → 972,29 |
vbl_start *= htotal; |
vbl_end *= htotal; |
vtotal *= htotal; |
|
/* |
* In interlaced modes, the pixel counter counts all pixels, |
* so one field will have htotal more pixels. In order to avoid |
* the reported position from jumping backwards when the pixel |
* counter is beyond the length of the shorter field, just |
* clamp the position the length of the shorter field. This |
* matches how the scanline counter based position works since |
* the scanline counter doesn't count the two half lines. |
*/ |
if (position >= vtotal) |
position = vtotal - 1; |
|
/* |
* Start of vblank interrupt is triggered at start of hsync, |
* just prior to the first active line of vblank. However we |
* consider lines to start at the leading edge of horizontal |
* active. So, should we get here before we've crossed into |
* the horizontal active of the first line in vblank, we would |
* not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that, |
* always add htotal-hsync_start to the current pixel position. |
*/ |
position = (position + htotal - hsync_start) % vtotal; |
} |
|
|
794,6 → 1030,19 |
return ret; |
} |
|
int intel_get_crtc_scanline(struct intel_crtc *crtc) |
{ |
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; |
unsigned long irqflags; |
int position; |
|
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); |
position = __intel_get_crtc_scanline(crtc); |
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); |
|
return position; |
} |
|
static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, |
int *max_error, |
struct timeval *vblank_time, |
839,7 → 1088,7 |
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", |
connector->base.id, |
drm_get_connector_name(connector), |
connector->name, |
drm_get_connector_status_name(old_status), |
drm_get_connector_status_name(connector->status)); |
|
853,8 → 1102,8 |
|
static void i915_hotplug_work_func(struct work_struct *work) |
{ |
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, |
hotplug_work); |
struct drm_i915_private *dev_priv = |
container_of(work, struct drm_i915_private, hotplug_work); |
struct drm_device *dev = dev_priv->dev; |
struct drm_mode_config *mode_config = &dev->mode_config; |
struct intel_connector *intel_connector; |
865,10 → 1114,6 |
bool changed = false; |
u32 hpd_event_bits; |
|
/* HPD irq before everything is fully set up. */ |
if (!dev_priv->enable_hotplug_processing) |
return; |
|
mutex_lock(&mode_config->mutex); |
DRM_DEBUG_KMS("running encoder hotplug functions\n"); |
|
878,6 → 1123,8 |
dev_priv->hpd_event_bits = 0; |
list_for_each_entry(connector, &mode_config->connector_list, head) { |
intel_connector = to_intel_connector(connector); |
if (!intel_connector->encoder) |
continue; |
intel_encoder = intel_connector->encoder; |
if (intel_encoder->hpd_pin > HPD_NONE && |
dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED && |
884,7 → 1131,7 |
connector->polled == DRM_CONNECTOR_POLL_HPD) { |
DRM_INFO("HPD interrupt storm detected on connector %s: " |
"switching from hotplug detection to polling\n", |
drm_get_connector_name(connector)); |
connector->name); |
dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED; |
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
| DRM_CONNECTOR_POLL_DISCONNECT; |
892,22 → 1139,19 |
} |
if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { |
DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", |
drm_get_connector_name(connector), intel_encoder->hpd_pin); |
connector->name, intel_encoder->hpd_pin); |
} |
} |
/* if there were no outputs to poll, poll was disabled, |
* therefore make sure it's enabled when disabling HPD on |
* some connectors */ |
if (hpd_disabled) { |
drm_kms_helper_poll_enable(dev); |
mod_timer(&dev_priv->hotplug_reenable_timer, |
GetTimerTicks() + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); |
} |
|
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
list_for_each_entry(connector, &mode_config->connector_list, head) { |
intel_connector = to_intel_connector(connector); |
if (!intel_connector->encoder) |
continue; |
intel_encoder = intel_connector->encoder; |
if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { |
if (intel_encoder->hot_plug) |
918,13 → 1162,11 |
} |
mutex_unlock(&mode_config->mutex); |
|
if (changed) |
drm_kms_helper_hotplug_event(dev); |
} |
|
static void ironlake_rps_change_irq_handler(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 busy_up, busy_down, max_avg, min_avg; |
u8 new_delay; |
|
962,9 → 1204,9 |
} |
|
static void notify_ring(struct drm_device *dev, |
struct intel_ring_buffer *ring) |
struct intel_engine_cs *ring) |
{ |
if (ring->obj == NULL) |
if (!intel_ring_initialized(ring)) |
return; |
|
trace_i915_gem_request_complete(ring); |
972,10 → 1214,135 |
wake_up_all(&ring->irq_queue); |
} |
|
static u32 vlv_c0_residency(struct drm_i915_private *dev_priv, |
struct intel_rps_ei *rps_ei) |
{ |
u32 cz_ts, cz_freq_khz; |
u32 render_count, media_count; |
u32 elapsed_render, elapsed_media, elapsed_time; |
u32 residency = 0; |
|
cz_ts = vlv_punit_read(dev_priv, PUNIT_REG_CZ_TIMESTAMP); |
cz_freq_khz = DIV_ROUND_CLOSEST(dev_priv->mem_freq * 1000, 4); |
|
render_count = I915_READ(VLV_RENDER_C0_COUNT_REG); |
media_count = I915_READ(VLV_MEDIA_C0_COUNT_REG); |
|
if (rps_ei->cz_clock == 0) { |
rps_ei->cz_clock = cz_ts; |
rps_ei->render_c0 = render_count; |
rps_ei->media_c0 = media_count; |
|
return dev_priv->rps.cur_freq; |
} |
|
elapsed_time = cz_ts - rps_ei->cz_clock; |
rps_ei->cz_clock = cz_ts; |
|
elapsed_render = render_count - rps_ei->render_c0; |
rps_ei->render_c0 = render_count; |
|
elapsed_media = media_count - rps_ei->media_c0; |
rps_ei->media_c0 = media_count; |
|
/* Convert all the counters into common unit of milli sec */ |
elapsed_time /= VLV_CZ_CLOCK_TO_MILLI_SEC; |
elapsed_render /= cz_freq_khz; |
elapsed_media /= cz_freq_khz; |
|
/* |
* Calculate overall C0 residency percentage |
* only if elapsed time is non zero |
*/ |
if (elapsed_time) { |
residency = |
((max(elapsed_render, elapsed_media) * 100) |
/ elapsed_time); |
} |
|
return residency; |
} |
|
/** |
* vlv_calc_delay_from_C0_counters - Increase/Decrease freq based on GPU |
* busy-ness calculated from C0 counters of render & media power wells |
* @dev_priv: DRM device private |
* |
*/ |
static u32 vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv) |
{ |
u32 residency_C0_up = 0, residency_C0_down = 0; |
u8 new_delay, adj; |
|
dev_priv->rps.ei_interrupt_count++; |
|
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); |
|
|
if (dev_priv->rps.up_ei.cz_clock == 0) { |
vlv_c0_residency(dev_priv, &dev_priv->rps.up_ei); |
vlv_c0_residency(dev_priv, &dev_priv->rps.down_ei); |
return dev_priv->rps.cur_freq; |
} |
|
|
/* |
* To down throttle, C0 residency should be less than down threshold |
* for continous EI intervals. So calculate down EI counters |
* once in VLV_INT_COUNT_FOR_DOWN_EI |
*/ |
if (dev_priv->rps.ei_interrupt_count == VLV_INT_COUNT_FOR_DOWN_EI) { |
|
dev_priv->rps.ei_interrupt_count = 0; |
|
residency_C0_down = vlv_c0_residency(dev_priv, |
&dev_priv->rps.down_ei); |
} else { |
residency_C0_up = vlv_c0_residency(dev_priv, |
&dev_priv->rps.up_ei); |
} |
|
new_delay = dev_priv->rps.cur_freq; |
|
adj = dev_priv->rps.last_adj; |
/* C0 residency is greater than UP threshold. Increase Frequency */ |
if (residency_C0_up >= VLV_RP_UP_EI_THRESHOLD) { |
if (adj > 0) |
adj *= 2; |
else |
adj = 1; |
|
if (dev_priv->rps.cur_freq < dev_priv->rps.max_freq_softlimit) |
new_delay = dev_priv->rps.cur_freq + adj; |
|
/* |
* For better performance, jump directly |
* to RPe if we're below it. |
*/ |
if (new_delay < dev_priv->rps.efficient_freq) |
new_delay = dev_priv->rps.efficient_freq; |
|
} else if (!dev_priv->rps.ei_interrupt_count && |
(residency_C0_down < VLV_RP_DOWN_EI_THRESHOLD)) { |
if (adj < 0) |
adj *= 2; |
else |
adj = -1; |
/* |
* This means, C0 residency is less than down threshold over |
* a period of VLV_INT_COUNT_FOR_DOWN_EI. So, reduce the freq |
*/ |
if (dev_priv->rps.cur_freq > dev_priv->rps.min_freq_softlimit) |
new_delay = dev_priv->rps.cur_freq + adj; |
} |
|
return new_delay; |
} |
|
static void gen6_pm_rps_work(struct work_struct *work) |
{ |
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, |
rps.work); |
struct drm_i915_private *dev_priv = |
container_of(work, struct drm_i915_private, rps.work); |
u32 pm_iir; |
int new_delay, adj; |
|
982,14 → 1349,18 |
spin_lock_irq(&dev_priv->irq_lock); |
pm_iir = dev_priv->rps.pm_iir; |
dev_priv->rps.pm_iir = 0; |
/* Make sure not to corrupt PMIMR state used by ringbuffer code */ |
snb_enable_pm_irq(dev_priv, GEN6_PM_RPS_EVENTS); |
if (INTEL_INFO(dev_priv->dev)->gen >= 8) |
gen8_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); |
else { |
/* Make sure not to corrupt PMIMR state used by ringbuffer */ |
gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); |
} |
spin_unlock_irq(&dev_priv->irq_lock); |
|
/* Make sure we didn't queue anything we're not going to process. */ |
WARN_ON(pm_iir & ~GEN6_PM_RPS_EVENTS); |
WARN_ON(pm_iir & ~dev_priv->pm_rps_events); |
|
if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0) |
if ((pm_iir & dev_priv->pm_rps_events) == 0) |
return; |
|
mutex_lock(&dev_priv->rps.hw_lock); |
998,30 → 1369,36 |
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { |
if (adj > 0) |
adj *= 2; |
else |
adj = 1; |
new_delay = dev_priv->rps.cur_delay + adj; |
else { |
/* CHV needs even encode values */ |
adj = IS_CHERRYVIEW(dev_priv->dev) ? 2 : 1; |
} |
new_delay = dev_priv->rps.cur_freq + adj; |
|
/* |
* For better performance, jump directly |
* to RPe if we're below it. |
*/ |
if (new_delay < dev_priv->rps.rpe_delay) |
new_delay = dev_priv->rps.rpe_delay; |
if (new_delay < dev_priv->rps.efficient_freq) |
new_delay = dev_priv->rps.efficient_freq; |
} 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; |
if (dev_priv->rps.cur_freq > dev_priv->rps.efficient_freq) |
new_delay = dev_priv->rps.efficient_freq; |
else |
new_delay = dev_priv->rps.min_delay; |
new_delay = dev_priv->rps.min_freq_softlimit; |
adj = 0; |
} else if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) { |
new_delay = vlv_calc_delay_from_C0_counters(dev_priv); |
} 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 { |
/* CHV needs even encode values */ |
adj = IS_CHERRYVIEW(dev_priv->dev) ? -2 : -1; |
} |
new_delay = dev_priv->rps.cur_freq + adj; |
} else { /* unknown event */ |
new_delay = dev_priv->rps.cur_delay; |
new_delay = dev_priv->rps.cur_freq; |
} |
|
/* sysfs frequency interfaces may have snuck in while servicing the |
1028,9 → 1405,11 |
* interrupt |
*/ |
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; |
dev_priv->rps.min_freq_softlimit, |
dev_priv->rps.max_freq_softlimit); |
|
dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_freq; |
|
if (IS_VALLEYVIEW(dev_priv->dev)) |
valleyview_set_rps(dev_priv->dev, new_delay); |
else |
1051,8 → 1430,8 |
*/ |
static void ivybridge_parity_work(struct work_struct *work) |
{ |
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, |
l3_parity.error_work); |
struct drm_i915_private *dev_priv = |
container_of(work, struct drm_i915_private, l3_parity.error_work); |
u32 error_status, row, bank, subbank; |
char *parity_event[6]; |
uint32_t misccpctl; |
1102,7 → 1481,7 |
out: |
WARN_ON(dev_priv->l3_parity.which_slice); |
spin_lock_irqsave(&dev_priv->irq_lock, flags); |
ilk_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev)); |
gen5_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); |
1110,13 → 1489,13 |
|
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; |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
if (!HAS_L3_DPF(dev)) |
return; |
|
spin_lock(&dev_priv->irq_lock); |
ilk_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev)); |
gen5_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev)); |
spin_unlock(&dev_priv->irq_lock); |
|
iir &= GT_PARITY_ERROR(dev); |
1156,8 → 1535,8 |
if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT | |
GT_BSD_CS_ERROR_INTERRUPT | |
GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) { |
DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir); |
i915_handle_error(dev, false); |
i915_handle_error(dev, false, "GT error interrupt 0x%08x", |
gt_iir); |
} |
|
if (gt_iir & GT_PARITY_ERROR(dev)) |
1164,6 → 1543,19 |
ivybridge_parity_error_irq_handler(dev, gt_iir); |
} |
|
static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) |
{ |
if ((pm_iir & dev_priv->pm_rps_events) == 0) |
return; |
|
spin_lock(&dev_priv->irq_lock); |
dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events; |
gen8_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events); |
spin_unlock(&dev_priv->irq_lock); |
|
queue_work(dev_priv->wq, &dev_priv->rps.work); |
} |
|
static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, |
struct drm_i915_private *dev_priv, |
u32 master_ctl) |
1175,6 → 1567,7 |
if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { |
tmp = I915_READ(GEN8_GT_IIR(0)); |
if (tmp) { |
I915_WRITE(GEN8_GT_IIR(0), tmp); |
ret = IRQ_HANDLED; |
rcs = tmp >> GEN8_RCS_IRQ_SHIFT; |
bcs = tmp >> GEN8_BCS_IRQ_SHIFT; |
1182,31 → 1575,44 |
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) { |
if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) { |
tmp = I915_READ(GEN8_GT_IIR(1)); |
if (tmp) { |
I915_WRITE(GEN8_GT_IIR(1), 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); |
vcs = tmp >> GEN8_VCS2_IRQ_SHIFT; |
if (vcs & GT_RENDER_USER_INTERRUPT) |
notify_ring(dev, &dev_priv->ring[VCS2]); |
} else |
DRM_ERROR("The master control interrupt lied (GT1)!\n"); |
} |
|
if (master_ctl & GEN8_GT_PM_IRQ) { |
tmp = I915_READ(GEN8_GT_IIR(2)); |
if (tmp & dev_priv->pm_rps_events) { |
I915_WRITE(GEN8_GT_IIR(2), |
tmp & dev_priv->pm_rps_events); |
ret = IRQ_HANDLED; |
gen8_rps_irq_handler(dev_priv, tmp); |
} else |
DRM_ERROR("The master control interrupt lied (PM)!\n"); |
} |
|
if (master_ctl & GEN8_GT_VECS_IRQ) { |
tmp = I915_READ(GEN8_GT_IIR(3)); |
if (tmp) { |
I915_WRITE(GEN8_GT_IIR(3), 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"); |
} |
1217,34 → 1623,132 |
#define HPD_STORM_DETECT_PERIOD 1000 |
#define HPD_STORM_THRESHOLD 5 |
|
static int ilk_port_to_hotplug_shift(enum port port) |
{ |
switch (port) { |
case PORT_A: |
case PORT_E: |
default: |
return -1; |
case PORT_B: |
return 0; |
case PORT_C: |
return 8; |
case PORT_D: |
return 16; |
} |
} |
|
static int g4x_port_to_hotplug_shift(enum port port) |
{ |
switch (port) { |
case PORT_A: |
case PORT_E: |
default: |
return -1; |
case PORT_B: |
return 17; |
case PORT_C: |
return 19; |
case PORT_D: |
return 21; |
} |
} |
|
static inline enum port get_port_from_pin(enum hpd_pin pin) |
{ |
switch (pin) { |
case HPD_PORT_B: |
return PORT_B; |
case HPD_PORT_C: |
return PORT_C; |
case HPD_PORT_D: |
return PORT_D; |
default: |
return PORT_A; /* no hpd */ |
} |
} |
|
static inline void intel_hpd_irq_handler(struct drm_device *dev, |
u32 hotplug_trigger, |
u32 dig_hotplug_reg, |
const u32 *hpd) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int i; |
enum port port; |
bool storm_detected = false; |
bool queue_dig = false, queue_hp = false; |
u32 dig_shift; |
u32 dig_port_mask = 0; |
|
if (!hotplug_trigger) |
return; |
|
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x\n", |
hotplug_trigger, dig_hotplug_reg); |
|
spin_lock(&dev_priv->irq_lock); |
for (i = 1; i < HPD_NUM_PINS; i++) { |
if (!(hpd[i] & hotplug_trigger)) |
continue; |
|
WARN_ONCE(hpd[i] & hotplug_trigger && |
dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED, |
port = get_port_from_pin(i); |
if (port && dev_priv->hpd_irq_port[port]) { |
bool long_hpd; |
|
if (IS_G4X(dev)) { |
dig_shift = g4x_port_to_hotplug_shift(port); |
long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; |
} else { |
dig_shift = ilk_port_to_hotplug_shift(port); |
long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; |
} |
|
DRM_DEBUG_DRIVER("digital hpd port %d %d\n", port, long_hpd); |
/* for long HPD pulses we want to have the digital queue happen, |
but we still want HPD storm detection to function. */ |
if (long_hpd) { |
dev_priv->long_hpd_port_mask |= (1 << port); |
dig_port_mask |= hpd[i]; |
} else { |
/* for short HPD just trigger the digital queue */ |
dev_priv->short_hpd_port_mask |= (1 << port); |
hotplug_trigger &= ~hpd[i]; |
} |
queue_dig = true; |
} |
} |
|
for (i = 1; i < HPD_NUM_PINS; i++) { |
if (hpd[i] & hotplug_trigger && |
dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED) { |
/* |
* On GMCH platforms the interrupt mask bits only |
* prevent irq generation, not the setting of the |
* hotplug bits itself. So only WARN about unexpected |
* interrupts on saner platforms. |
*/ |
WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), |
"Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", |
hotplug_trigger, i, hpd[i]); |
|
continue; |
} |
|
if (!(hpd[i] & hotplug_trigger) || |
dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) |
continue; |
|
if (!(dig_port_mask & hpd[i])) { |
dev_priv->hpd_event_bits |= (1 << i); |
if (!time_in_range(GetTimerTicks(), dev_priv->hpd_stats[i].hpd_last_jiffies, |
queue_hp = true; |
} |
|
if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, |
dev_priv->hpd_stats[i].hpd_last_jiffies |
+ msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { |
dev_priv->hpd_stats[i].hpd_last_jiffies = GetTimerTicks(); |
dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies; |
dev_priv->hpd_stats[i].hpd_cnt = 0; |
DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i); |
} else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { |
1269,12 → 1773,13 |
* queue for otherwise the flush_work in the pageflip code will |
* deadlock. |
*/ |
if (queue_hp) |
schedule_work(&dev_priv->hotplug_work); |
} |
|
static void gmbus_irq_handler(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
wake_up_all(&dev_priv->gmbus_wait_queue); |
} |
1281,7 → 1786,7 |
|
static void dp_aux_irq_handler(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
wake_up_all(&dev_priv->gmbus_wait_queue); |
} |
1387,10 → 1892,10 |
* the work queue. */ |
static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) |
{ |
if (pm_iir & GEN6_PM_RPS_EVENTS) { |
if (pm_iir & dev_priv->pm_rps_events) { |
spin_lock(&dev_priv->irq_lock); |
dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS; |
snb_disable_pm_irq(dev_priv, pm_iir & GEN6_PM_RPS_EVENTS); |
dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events; |
gen6_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events); |
spin_unlock(&dev_priv->irq_lock); |
|
queue_work(dev_priv->wq, &dev_priv->rps.work); |
1401,58 → 1906,70 |
notify_ring(dev_priv->dev, &dev_priv->ring[VECS]); |
|
if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) { |
DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir); |
i915_handle_error(dev_priv->dev, false); |
i915_handle_error(dev_priv->dev, false, |
"VEBOX CS error interrupt 0x%08x", |
pm_iir); |
} |
} |
} |
|
static irqreturn_t valleyview_irq_handler(int irq, void *arg) |
static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) |
{ |
struct drm_device *dev = (struct drm_device *) arg; |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
u32 iir, gt_iir, pm_iir; |
irqreturn_t ret = IRQ_NONE; |
unsigned long irqflags; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 pipe_stats[I915_MAX_PIPES] = { }; |
int pipe; |
u32 pipe_stats[I915_MAX_PIPES]; |
|
atomic_inc(&dev_priv->irq_received); |
spin_lock(&dev_priv->irq_lock); |
for_each_pipe(pipe) { |
int reg; |
u32 mask, iir_bit = 0; |
|
while (true) { |
iir = I915_READ(VLV_IIR); |
gt_iir = I915_READ(GTIIR); |
pm_iir = I915_READ(GEN6_PMIIR); |
/* |
* PIPESTAT bits get signalled even when the interrupt is |
* disabled with the mask bits, and some of the status bits do |
* not generate interrupts at all (like the underrun bit). Hence |
* we need to be careful that we only handle what we want to |
* handle. |
*/ |
mask = 0; |
if (__cpu_fifo_underrun_reporting_enabled(dev, pipe)) |
mask |= PIPE_FIFO_UNDERRUN_STATUS; |
|
if (gt_iir == 0 && pm_iir == 0 && iir == 0) |
goto out; |
switch (pipe) { |
case PIPE_A: |
iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; |
break; |
case PIPE_B: |
iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; |
break; |
case PIPE_C: |
iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; |
break; |
} |
if (iir & iir_bit) |
mask |= dev_priv->pipestat_irq_mask[pipe]; |
|
ret = IRQ_HANDLED; |
if (!mask) |
continue; |
|
snb_gt_irq_handler(dev, dev_priv, gt_iir); |
reg = PIPESTAT(pipe); |
mask |= PIPESTAT_INT_ENABLE_MASK; |
pipe_stats[pipe] = I915_READ(reg) & mask; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
for_each_pipe(pipe) { |
int reg = PIPESTAT(pipe); |
pipe_stats[pipe] = I915_READ(reg); |
|
/* |
* Clear the PIPE*STAT regs before the IIR |
*/ |
if (pipe_stats[pipe] & 0x8000ffff) { |
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) |
DRM_DEBUG_DRIVER("pipe %c underrun\n", |
pipe_name(pipe)); |
if (pipe_stats[pipe] & (PIPE_FIFO_UNDERRUN_STATUS | |
PIPESTAT_INT_STATUS_MASK)) |
I915_WRITE(reg, pipe_stats[pipe]); |
} |
} |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
spin_unlock(&dev_priv->irq_lock); |
|
for_each_pipe(pipe) { |
// if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS) |
// drm_handle_vblank(dev, pipe); |
|
if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) { |
if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) { |
// intel_prepare_page_flip(dev, pipe); |
// intel_finish_page_flip(dev, pipe); |
} |
1459,48 → 1976,141 |
|
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
|
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && |
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) |
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); |
} |
|
/* Consume port. Then clear IIR or we'll miss events */ |
if (iir & I915_DISPLAY_PORT_INTERRUPT) { |
if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) |
gmbus_irq_handler(dev); |
} |
|
static void i9xx_hpd_irq_handler(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); |
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; |
|
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", |
hotplug_status); |
if (hotplug_status) { |
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); |
/* |
* Make sure hotplug status is cleared before we clear IIR, or else we |
* may miss hotplug events. |
*/ |
POSTING_READ(PORT_HOTPLUG_STAT); |
|
intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); |
if (IS_G4X(dev)) { |
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; |
|
if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) |
dp_aux_irq_handler(dev); |
intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); |
} else { |
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; |
|
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); |
I915_READ(PORT_HOTPLUG_STAT); |
intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); |
} |
|
if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) |
gmbus_irq_handler(dev); |
if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && |
hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) |
dp_aux_irq_handler(dev); |
} |
} |
|
if (pm_iir) |
gen6_rps_irq_handler(dev_priv, pm_iir); |
static irqreturn_t valleyview_irq_handler(int irq, void *arg) |
{ |
struct drm_device *dev = arg; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 iir, gt_iir, pm_iir; |
irqreturn_t ret = IRQ_NONE; |
|
while (true) { |
/* Find, clear, then process each source of interrupt */ |
|
gt_iir = I915_READ(GTIIR); |
if (gt_iir) |
I915_WRITE(GTIIR, gt_iir); |
|
pm_iir = I915_READ(GEN6_PMIIR); |
if (pm_iir) |
I915_WRITE(GEN6_PMIIR, pm_iir); |
|
iir = I915_READ(VLV_IIR); |
if (iir) { |
/* Consume port before clearing IIR or we'll miss events */ |
if (iir & I915_DISPLAY_PORT_INTERRUPT) |
i9xx_hpd_irq_handler(dev); |
I915_WRITE(VLV_IIR, iir); |
} |
|
if (gt_iir == 0 && pm_iir == 0 && iir == 0) |
goto out; |
|
ret = IRQ_HANDLED; |
|
if (gt_iir) |
snb_gt_irq_handler(dev, dev_priv, gt_iir); |
if (pm_iir) |
gen6_rps_irq_handler(dev_priv, pm_iir); |
/* Call regardless, as some status bits might not be |
* signalled in iir */ |
valleyview_pipestat_irq_handler(dev, iir); |
} |
|
out: |
return ret; |
} |
|
static irqreturn_t cherryview_irq_handler(int irq, void *arg) |
{ |
struct drm_device *dev = arg; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 master_ctl, iir; |
irqreturn_t ret = IRQ_NONE; |
|
for (;;) { |
master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL; |
iir = I915_READ(VLV_IIR); |
|
if (master_ctl == 0 && iir == 0) |
break; |
|
ret = IRQ_HANDLED; |
|
I915_WRITE(GEN8_MASTER_IRQ, 0); |
|
/* Find, clear, then process each source of interrupt */ |
|
if (iir) { |
/* Consume port before clearing IIR or we'll miss events */ |
if (iir & I915_DISPLAY_PORT_INTERRUPT) |
i9xx_hpd_irq_handler(dev); |
I915_WRITE(VLV_IIR, iir); |
} |
|
gen8_gt_irq_handler(dev, dev_priv, master_ctl); |
|
/* Call regardless, as some status bits might not be |
* signalled in iir */ |
valleyview_pipestat_irq_handler(dev, iir); |
|
I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL); |
POSTING_READ(GEN8_MASTER_IRQ); |
} |
|
return ret; |
} |
|
static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; |
u32 dig_hotplug_reg; |
|
intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx); |
dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); |
I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); |
|
intel_hpd_irq_handler(dev, hotplug_trigger, dig_hotplug_reg, hpd_ibx); |
|
if (pch_iir & SDE_AUDIO_POWER_MASK) { |
int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> |
SDE_AUDIO_POWER_SHIFT); |
1538,12 → 2148,12 |
if (pch_iir & SDE_TRANSA_FIFO_UNDER) |
if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, |
false)) |
DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); |
DRM_ERROR("PCH transcoder A FIFO underrun\n"); |
|
if (pch_iir & SDE_TRANSB_FIFO_UNDER) |
if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, |
false)) |
DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); |
DRM_ERROR("PCH transcoder B FIFO underrun\n"); |
} |
|
static void ivb_err_int_handler(struct drm_device *dev) |
1559,7 → 2169,7 |
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", |
DRM_ERROR("Pipe %c FIFO underrun\n", |
pipe_name(pipe)); |
} |
|
1585,17 → 2195,17 |
if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN) |
if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, |
false)) |
DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); |
DRM_ERROR("PCH transcoder A FIFO underrun\n"); |
|
if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN) |
if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, |
false)) |
DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); |
DRM_ERROR("PCH transcoder B FIFO underrun\n"); |
|
if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN) |
if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C, |
false)) |
DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n"); |
DRM_ERROR("PCH transcoder C FIFO underrun\n"); |
|
I915_WRITE(SERR_INT, serr_int); |
} |
1602,12 → 2212,16 |
|
static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; |
u32 dig_hotplug_reg; |
|
intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt); |
dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); |
I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); |
|
intel_hpd_irq_handler(dev, hotplug_trigger, dig_hotplug_reg, hpd_cpt); |
|
if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { |
int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> |
SDE_AUDIO_POWER_SHIFT_CPT); |
1657,7 → 2271,7 |
|
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", |
DRM_ERROR("Pipe %c FIFO underrun\n", |
pipe_name(pipe)); |
|
if (de_iir & DE_PIPE_CRC_DONE(pipe)) |
1690,7 → 2304,7 |
static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
enum pipe i; |
enum pipe pipe; |
|
if (de_iir & DE_ERR_INT_IVB) |
ivb_err_int_handler(dev); |
1701,14 → 2315,14 |
if (de_iir & DE_GSE_IVB) |
intel_opregion_asle_intr(dev); |
|
for_each_pipe(i) { |
// if (de_iir & (DE_PIPE_VBLANK_IVB(i))) |
// drm_handle_vblank(dev, i); |
for_each_pipe(pipe) { |
// if (de_iir & (DE_PIPE_VBLANK_IVB(pipe))) |
// drm_handle_vblank(dev, pipe); |
|
/* 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); |
if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) { |
// intel_prepare_page_flip(dev, pipe); |
// intel_finish_page_flip_plane(dev, pipe); |
} |
} |
|
1723,15 → 2337,21 |
} |
} |
|
/* |
* To handle irqs with the minimum potential races with fresh interrupts, we: |
* 1 - Disable Master Interrupt Control. |
* 2 - Find the source(s) of the interrupt. |
* 3 - Clear the Interrupt Identity bits (IIR). |
* 4 - Process the interrupt(s) that had bits set in the IIRs. |
* 5 - Re-enable Master Interrupt Control. |
*/ |
static irqreturn_t ironlake_irq_handler(int irq, void *arg) |
{ |
struct drm_device *dev = (struct drm_device *) arg; |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_device *dev = arg; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 de_iir, gt_iir, de_ier, sde_ier = 0; |
irqreturn_t ret = IRQ_NONE; |
|
atomic_inc(&dev_priv->irq_received); |
|
/* We get interrupts on unclaimed registers, so check for this before we |
* do any I915_{READ,WRITE}. */ |
intel_uncore_check_errors(dev); |
1752,32 → 2372,34 |
POSTING_READ(SDEIER); |
} |
|
/* Find, clear, then process each source of interrupt */ |
|
gt_iir = I915_READ(GTIIR); |
if (gt_iir) { |
I915_WRITE(GTIIR, gt_iir); |
ret = IRQ_HANDLED; |
if (INTEL_INFO(dev)->gen >= 6) |
snb_gt_irq_handler(dev, dev_priv, gt_iir); |
else |
ilk_gt_irq_handler(dev, dev_priv, gt_iir); |
I915_WRITE(GTIIR, gt_iir); |
ret = IRQ_HANDLED; |
} |
|
de_iir = I915_READ(DEIIR); |
if (de_iir) { |
I915_WRITE(DEIIR, de_iir); |
ret = IRQ_HANDLED; |
if (INTEL_INFO(dev)->gen >= 7) |
ivb_display_irq_handler(dev, de_iir); |
else |
ilk_display_irq_handler(dev, de_iir); |
I915_WRITE(DEIIR, de_iir); |
ret = IRQ_HANDLED; |
} |
|
if (INTEL_INFO(dev)->gen >= 6) { |
u32 pm_iir = I915_READ(GEN6_PMIIR); |
if (pm_iir) { |
gen6_rps_irq_handler(dev_priv, pm_iir); |
I915_WRITE(GEN6_PMIIR, pm_iir); |
ret = IRQ_HANDLED; |
gen6_rps_irq_handler(dev_priv, pm_iir); |
} |
} |
|
1800,8 → 2422,6 |
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) |
1810,37 → 2430,37 |
I915_WRITE(GEN8_MASTER_IRQ, 0); |
POSTING_READ(GEN8_MASTER_IRQ); |
|
/* Find, clear, then process each source of interrupt */ |
|
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) { |
I915_WRITE(GEN8_DE_MISC_IIR, tmp); |
ret = IRQ_HANDLED; |
if (tmp & GEN8_DE_MISC_GSE) |
intel_opregion_asle_intr(dev); |
else if (tmp) |
else |
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) { |
I915_WRITE(GEN8_DE_PORT_IIR, tmp); |
ret = IRQ_HANDLED; |
if (tmp & GEN8_AUX_CHANNEL_A) |
dp_aux_irq_handler(dev); |
else if (tmp) |
else |
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; |
1849,10 → 2469,13 |
continue; |
|
pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe)); |
if (pipe_iir) { |
ret = IRQ_HANDLED; |
I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir); |
// if (pipe_iir & GEN8_PIPE_VBLANK) |
// drm_handle_vblank(dev, pipe); |
// intel_pipe_handle_vblank(dev, pipe); |
|
if (pipe_iir & GEN8_PIPE_FLIP_DONE) { |
if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) { |
// intel_prepare_page_flip(dev, pipe); |
// intel_finish_page_flip_plane(dev, pipe); |
} |
1863,7 → 2486,7 |
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", |
DRM_ERROR("Pipe %c FIFO underrun\n", |
pipe_name(pipe)); |
} |
|
1872,10 → 2495,6 |
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"); |
} |
1887,14 → 2506,14 |
* 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; |
cpt_irq_handler(dev, pch_iir); |
} else |
DRM_ERROR("The master control interrupt lied (SDE)!\n"); |
|
} |
} |
|
I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); |
POSTING_READ(GEN8_MASTER_IRQ); |
1905,7 → 2524,7 |
static void i915_error_wake_up(struct drm_i915_private *dev_priv, |
bool reset_completed) |
{ |
struct intel_ring_buffer *ring; |
struct intel_engine_cs *ring; |
int i; |
|
/* |
1939,8 → 2558,8 |
{ |
struct i915_gpu_error *error = container_of(work, struct i915_gpu_error, |
work); |
drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t, |
gpu_error); |
struct drm_i915_private *dev_priv = |
container_of(error, struct drm_i915_private, gpu_error); |
struct drm_device *dev = dev_priv->dev; |
char *error_event[] = { I915_ERROR_UEVENT "=1", NULL }; |
char *reset_event[] = { I915_RESET_UEVENT "=1", NULL }; |
2097,10 → 2716,17 |
* so userspace knows something bad happened (should trigger collection |
* of a ring dump etc.). |
*/ |
void i915_handle_error(struct drm_device *dev, bool wedged) |
void i915_handle_error(struct drm_device *dev, bool wedged, |
const char *fmt, ...) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
va_list args; |
char error_msg[80]; |
|
va_start(args, fmt); |
vscnprintf(error_msg, sizeof(error_msg), fmt, args); |
va_end(args); |
|
// i915_capture_error_state(dev); |
i915_report_and_clear_eir(dev); |
|
2136,7 → 2762,7 |
#if 0 |
static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
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); |
struct drm_i915_gem_object *obj; |
2168,8 → 2794,8 |
} else { |
int dspaddr = DSPADDR(intel_crtc->plane); |
stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) + |
crtc->y * crtc->fb->pitches[0] + |
crtc->x * crtc->fb->bits_per_pixel/8); |
crtc->y * crtc->primary->fb->pitches[0] + |
crtc->x * crtc->primary->fb->bits_per_pixel/8); |
} |
|
spin_unlock_irqrestore(&dev->event_lock, flags); |
2187,7 → 2813,7 |
*/ |
static int i915_enable_vblank(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
|
if (!i915_pipe_enabled(dev, pipe)) |
2196,14 → 2822,10 |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
if (INTEL_INFO(dev)->gen >= 4) |
i915_enable_pipestat(dev_priv, pipe, |
PIPE_START_VBLANK_INTERRUPT_ENABLE); |
PIPE_START_VBLANK_INTERRUPT_STATUS); |
else |
i915_enable_pipestat(dev_priv, pipe, |
PIPE_VBLANK_INTERRUPT_ENABLE); |
|
/* maintain vblank delivery even in deep C-states */ |
if (dev_priv->info->gen == 3) |
I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS)); |
PIPE_VBLANK_INTERRUPT_STATUS); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
return 0; |
2211,7 → 2833,7 |
|
static int ironlake_enable_vblank(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) : |
DE_PIPE_VBLANK(pipe); |
2228,22 → 2850,15 |
|
static int valleyview_enable_vblank(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
u32 imr; |
|
if (!i915_pipe_enabled(dev, pipe)) |
return -EINVAL; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
imr = I915_READ(VLV_IMR); |
if (pipe == PIPE_A) |
imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; |
else |
imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; |
I915_WRITE(VLV_IMR, imr); |
i915_enable_pipestat(dev_priv, pipe, |
PIPE_START_VBLANK_INTERRUPT_ENABLE); |
PIPE_START_VBLANK_INTERRUPT_STATUS); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
return 0; |
2270,22 → 2885,19 |
*/ |
static void i915_disable_vblank(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
if (dev_priv->info->gen == 3) |
I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS)); |
|
i915_disable_pipestat(dev_priv, pipe, |
PIPE_VBLANK_INTERRUPT_ENABLE | |
PIPE_START_VBLANK_INTERRUPT_ENABLE); |
PIPE_VBLANK_INTERRUPT_STATUS | |
PIPE_START_VBLANK_INTERRUPT_STATUS); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
} |
|
static void ironlake_disable_vblank(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) : |
DE_PIPE_VBLANK(pipe); |
2297,19 → 2909,12 |
|
static void valleyview_disable_vblank(struct drm_device *dev, int pipe) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
u32 imr; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
i915_disable_pipestat(dev_priv, pipe, |
PIPE_START_VBLANK_INTERRUPT_ENABLE); |
imr = I915_READ(VLV_IMR); |
if (pipe == PIPE_A) |
imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT; |
else |
imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; |
I915_WRITE(VLV_IMR, imr); |
PIPE_START_VBLANK_INTERRUPT_STATUS); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
} |
|
2329,7 → 2934,7 |
} |
|
static u32 |
ring_last_seqno(struct intel_ring_buffer *ring) |
ring_last_seqno(struct intel_engine_cs *ring) |
{ |
return list_entry(ring->request_list.prev, |
struct drm_i915_gem_request, list)->seqno; |
2336,81 → 2941,160 |
} |
|
static bool |
ring_idle(struct intel_ring_buffer *ring, u32 seqno) |
ring_idle(struct intel_engine_cs *ring, u32 seqno) |
{ |
return (list_empty(&ring->request_list) || |
i915_seqno_passed(seqno, ring_last_seqno(ring))); |
} |
|
static struct intel_ring_buffer * |
semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno) |
static bool |
ipehr_is_semaphore_wait(struct drm_device *dev, u32 ipehr) |
{ |
if (INTEL_INFO(dev)->gen >= 8) { |
return (ipehr >> 23) == 0x1c; |
} else { |
ipehr &= ~MI_SEMAPHORE_SYNC_MASK; |
return ipehr == (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | |
MI_SEMAPHORE_REGISTER); |
} |
} |
|
static struct intel_engine_cs * |
semaphore_wait_to_signaller_ring(struct intel_engine_cs *ring, u32 ipehr, u64 offset) |
{ |
struct drm_i915_private *dev_priv = ring->dev->dev_private; |
u32 cmd, ipehr, acthd, acthd_min; |
struct intel_engine_cs *signaller; |
int i; |
|
if (INTEL_INFO(dev_priv->dev)->gen >= 8) { |
for_each_ring(signaller, dev_priv, i) { |
if (ring == signaller) |
continue; |
|
if (offset == signaller->semaphore.signal_ggtt[ring->id]) |
return signaller; |
} |
} else { |
u32 sync_bits = ipehr & MI_SEMAPHORE_SYNC_MASK; |
|
for_each_ring(signaller, dev_priv, i) { |
if(ring == signaller) |
continue; |
|
if (sync_bits == signaller->semaphore.mbox.wait[ring->id]) |
return signaller; |
} |
} |
|
DRM_ERROR("No signaller ring found for ring %i, ipehr 0x%08x, offset 0x%016llx\n", |
ring->id, ipehr, offset); |
|
return NULL; |
} |
|
static struct intel_engine_cs * |
semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno) |
{ |
struct drm_i915_private *dev_priv = ring->dev->dev_private; |
u32 cmd, ipehr, head; |
u64 offset = 0; |
int i, backwards; |
|
ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); |
if ((ipehr & ~(0x3 << 16)) != |
(MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER)) |
if (!ipehr_is_semaphore_wait(ring->dev, ipehr)) |
return NULL; |
|
/* ACTHD is likely pointing to the dword after the actual command, |
* so scan backwards until we find the MBOX. |
/* |
* HEAD is likely pointing to the dword after the actual command, |
* so scan backwards until we find the MBOX. But limit it to just 3 |
* or 4 dwords depending on the semaphore wait command size. |
* Note that we don't care about ACTHD here since that might |
* point at at batch, and semaphores are always emitted into the |
* ringbuffer itself. |
*/ |
acthd = intel_ring_get_active_head(ring) & HEAD_ADDR; |
acthd_min = max((int)acthd - 3 * 4, 0); |
do { |
cmd = ioread32(ring->virtual_start + acthd); |
head = I915_READ_HEAD(ring) & HEAD_ADDR; |
backwards = (INTEL_INFO(ring->dev)->gen >= 8) ? 5 : 4; |
|
for (i = backwards; i; --i) { |
/* |
* Be paranoid and presume the hw has gone off into the wild - |
* our ring is smaller than what the hardware (and hence |
* HEAD_ADDR) allows. Also handles wrap-around. |
*/ |
head &= ring->buffer->size - 1; |
|
/* This here seems to blow up */ |
cmd = ioread32(ring->buffer->virtual_start + head); |
if (cmd == ipehr) |
break; |
|
acthd -= 4; |
if (acthd < acthd_min) |
head -= 4; |
} |
|
if (!i) |
return NULL; |
} while (1); |
|
*seqno = ioread32(ring->virtual_start+acthd+4)+1; |
return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; |
*seqno = ioread32(ring->buffer->virtual_start + head + 4) + 1; |
if (INTEL_INFO(ring->dev)->gen >= 8) { |
offset = ioread32(ring->buffer->virtual_start + head + 12); |
offset <<= 32; |
offset = ioread32(ring->buffer->virtual_start + head + 8); |
} |
return semaphore_wait_to_signaller_ring(ring, ipehr, offset); |
} |
|
static int semaphore_passed(struct intel_ring_buffer *ring) |
static int semaphore_passed(struct intel_engine_cs *ring) |
{ |
struct drm_i915_private *dev_priv = ring->dev->dev_private; |
struct intel_ring_buffer *signaller; |
u32 seqno, ctl; |
struct intel_engine_cs *signaller; |
u32 seqno; |
|
ring->hangcheck.deadlock = true; |
ring->hangcheck.deadlock++; |
|
signaller = semaphore_waits_for(ring, &seqno); |
if (signaller == NULL || signaller->hangcheck.deadlock) |
if (signaller == NULL) |
return -1; |
|
/* Prevent pathological recursion due to driver bugs */ |
if (signaller->hangcheck.deadlock >= I915_NUM_RINGS) |
return -1; |
|
if (i915_seqno_passed(signaller->get_seqno(signaller, false), seqno)) |
return 1; |
|
/* cursory check for an unkickable deadlock */ |
ctl = I915_READ_CTL(signaller); |
if (ctl & RING_WAIT_SEMAPHORE && semaphore_passed(signaller) < 0) |
if (I915_READ_CTL(signaller) & RING_WAIT_SEMAPHORE && |
semaphore_passed(signaller) < 0) |
return -1; |
|
return i915_seqno_passed(signaller->get_seqno(signaller, false), seqno); |
return 0; |
} |
|
static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv) |
{ |
struct intel_ring_buffer *ring; |
struct intel_engine_cs *ring; |
int i; |
|
for_each_ring(ring, dev_priv, i) |
ring->hangcheck.deadlock = false; |
ring->hangcheck.deadlock = 0; |
} |
|
static enum intel_ring_hangcheck_action |
ring_stuck(struct intel_ring_buffer *ring, u32 acthd) |
ring_stuck(struct intel_engine_cs *ring, u64 acthd) |
{ |
struct drm_device *dev = ring->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 tmp; |
|
if (ring->hangcheck.acthd != acthd) |
if (acthd != ring->hangcheck.acthd) { |
if (acthd > ring->hangcheck.max_acthd) { |
ring->hangcheck.max_acthd = acthd; |
return HANGCHECK_ACTIVE; |
} |
|
return HANGCHECK_ACTIVE_LOOP; |
} |
|
if (IS_GEN2(dev)) |
return HANGCHECK_HUNG; |
|
2421,7 → 3105,8 |
*/ |
tmp = I915_READ_CTL(ring); |
if (tmp & RING_WAIT) { |
DRM_ERROR("Kicking stuck wait on %s\n", |
i915_handle_error(dev, false, |
"Kicking stuck wait on %s", |
ring->name); |
I915_WRITE_CTL(ring, tmp); |
return HANGCHECK_KICK; |
2432,7 → 3117,8 |
default: |
return HANGCHECK_HUNG; |
case 1: |
DRM_ERROR("Kicking stuck semaphore on %s\n", |
i915_handle_error(dev, false, |
"Kicking stuck semaphore on %s", |
ring->name); |
I915_WRITE_CTL(ring, tmp); |
return HANGCHECK_KICK; |
2455,8 → 3141,8 |
static void i915_hangcheck_elapsed(unsigned long data) |
{ |
struct drm_device *dev = (struct drm_device *)data; |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct intel_ring_buffer *ring; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_engine_cs *ring; |
int i; |
int busy_count = 0, rings_hung = 0; |
bool stuck[I915_NUM_RINGS] = { 0 }; |
2463,13 → 3149,13 |
#define BUSY 1 |
#define KICK 5 |
#define HUNG 20 |
#define FIRE 30 |
|
if (!i915_enable_hangcheck) |
if (!i915.enable_hangcheck) |
return; |
|
for_each_ring(ring, dev_priv, i) { |
u32 seqno, acthd; |
u64 acthd; |
u32 seqno; |
bool busy = true; |
|
semaphore_clear_deadlocks(dev_priv); |
2479,6 → 3165,8 |
|
if (ring->hangcheck.seqno == seqno) { |
if (ring_idle(ring, seqno)) { |
ring->hangcheck.action = HANGCHECK_IDLE; |
|
// if (waitqueue_active(&ring->irq_queue)) { |
/* Issue a wake-up to catch stuck h/w. */ |
// DRM_ERROR("Hangcheck timer elapsed... %s idle\n", |
2508,8 → 3196,9 |
switch (ring->hangcheck.action) { |
case HANGCHECK_IDLE: |
case HANGCHECK_WAIT: |
case HANGCHECK_ACTIVE: |
break; |
case HANGCHECK_ACTIVE: |
case HANGCHECK_ACTIVE_LOOP: |
ring->hangcheck.score += BUSY; |
break; |
case HANGCHECK_KICK: |
2529,6 → 3218,8 |
*/ |
if (ring->hangcheck.score > 0) |
ring->hangcheck.score--; |
|
ring->hangcheck.acthd = ring->hangcheck.max_acthd = 0; |
} |
|
ring->hangcheck.seqno = seqno; |
2537,7 → 3228,7 |
} |
|
for_each_ring(ring, dev_priv, i) { |
if (ring->hangcheck.score > FIRE) { |
if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) { |
DRM_INFO("%s on %s\n", |
stuck[i] ? "stuck" : "no progress", |
ring->name); |
2549,8 → 3240,7 |
// return i915_handle_error(dev, true); |
|
} |
|
static void ibx_irq_preinstall(struct drm_device *dev) |
static void ibx_irq_reset(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
2557,61 → 3247,63 |
if (HAS_PCH_NOP(dev)) |
return; |
|
/* south display irq */ |
I915_WRITE(SDEIMR, 0xffffffff); |
GEN5_IRQ_RESET(SDE); |
|
if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev)) |
I915_WRITE(SERR_INT, 0xffffffff); |
} |
|
/* |
* SDEIER is also touched by the interrupt handler to work around missed |
* PCH interrupts. Hence we can't update it after the interrupt handler |
* is enabled - instead we unconditionally enable all PCH interrupt |
* sources here, but then only unmask them as needed with SDEIMR. |
* SDEIER is also touched by the interrupt handler to work around missed PCH |
* interrupts. Hence we can't update it after the interrupt handler is enabled - |
* instead we unconditionally enable all PCH interrupt sources here, but then |
* only unmask them as needed with SDEIMR. |
* |
* This function needs to be called before interrupts are enabled. |
*/ |
static void ibx_irq_pre_postinstall(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
if (HAS_PCH_NOP(dev)) |
return; |
|
WARN_ON(I915_READ(SDEIER) != 0); |
I915_WRITE(SDEIER, 0xffffffff); |
POSTING_READ(SDEIER); |
} |
|
static void gen5_gt_irq_preinstall(struct drm_device *dev) |
static void gen5_gt_irq_reset(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
/* and GT */ |
I915_WRITE(GTIMR, 0xffffffff); |
I915_WRITE(GTIER, 0x0); |
POSTING_READ(GTIER); |
|
if (INTEL_INFO(dev)->gen >= 6) { |
/* and PM */ |
I915_WRITE(GEN6_PMIMR, 0xffffffff); |
I915_WRITE(GEN6_PMIER, 0x0); |
POSTING_READ(GEN6_PMIER); |
GEN5_IRQ_RESET(GT); |
if (INTEL_INFO(dev)->gen >= 6) |
GEN5_IRQ_RESET(GEN6_PM); |
} |
} |
|
/* drm_dma.h hooks |
*/ |
static void ironlake_irq_preinstall(struct drm_device *dev) |
static void ironlake_irq_reset(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
atomic_set(&dev_priv->irq_received, 0); |
I915_WRITE(HWSTAM, 0xffffffff); |
|
I915_WRITE(HWSTAM, 0xeffe); |
GEN5_IRQ_RESET(DE); |
if (IS_GEN7(dev)) |
I915_WRITE(GEN7_ERR_INT, 0xffffffff); |
|
I915_WRITE(DEIMR, 0xffffffff); |
I915_WRITE(DEIER, 0x0); |
POSTING_READ(DEIER); |
gen5_gt_irq_reset(dev); |
|
gen5_gt_irq_preinstall(dev); |
|
ibx_irq_preinstall(dev); |
ibx_irq_reset(dev); |
} |
|
static void valleyview_irq_preinstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
atomic_set(&dev_priv->irq_received, 0); |
|
/* VLV magic */ |
I915_WRITE(VLV_IMR, 0); |
I915_WRITE(RING_IMR(RENDER_RING_BASE), 0); |
2622,7 → 3314,7 |
I915_WRITE(GTIIR, I915_READ(GTIIR)); |
I915_WRITE(GTIIR, I915_READ(GTIIR)); |
|
gen5_gt_irq_preinstall(dev); |
gen5_gt_irq_reset(dev); |
|
I915_WRITE(DPINVGTT, 0xff); |
|
2636,58 → 3328,79 |
POSTING_READ(VLV_IER); |
} |
|
static void gen8_irq_preinstall(struct drm_device *dev) |
static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv) |
{ |
GEN8_IRQ_RESET_NDX(GT, 0); |
GEN8_IRQ_RESET_NDX(GT, 1); |
GEN8_IRQ_RESET_NDX(GT, 2); |
GEN8_IRQ_RESET_NDX(GT, 3); |
} |
|
static void gen8_irq_reset(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) |
gen8_gt_irq_reset(dev_priv); |
|
#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) |
for_each_pipe(pipe) |
if (intel_display_power_enabled(dev_priv, |
POWER_DOMAIN_PIPE(pipe))) |
GEN8_IRQ_RESET_NDX(DE_PIPE, pipe); |
|
GEN8_IRQ_INIT_NDX(GT, 0); |
GEN8_IRQ_INIT_NDX(GT, 1); |
GEN8_IRQ_INIT_NDX(GT, 2); |
GEN8_IRQ_INIT_NDX(GT, 3); |
GEN5_IRQ_RESET(GEN8_DE_PORT_); |
GEN5_IRQ_RESET(GEN8_DE_MISC_); |
GEN5_IRQ_RESET(GEN8_PCU_); |
|
for_each_pipe(pipe) { |
GEN8_IRQ_INIT_NDX(DE_PIPE, pipe); |
ibx_irq_reset(dev); |
} |
|
GEN8_IRQ_INIT(DE_PORT); |
GEN8_IRQ_INIT(DE_MISC); |
GEN8_IRQ_INIT(PCU); |
#undef GEN8_IRQ_INIT |
#undef GEN8_IRQ_INIT_NDX |
void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv) |
{ |
unsigned long irqflags; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_B, dev_priv->de_irq_mask[PIPE_B], |
~dev_priv->de_irq_mask[PIPE_B]); |
GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_C, dev_priv->de_irq_mask[PIPE_C], |
~dev_priv->de_irq_mask[PIPE_C]); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
} |
|
static void cherryview_irq_preinstall(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
I915_WRITE(GEN8_MASTER_IRQ, 0); |
POSTING_READ(GEN8_MASTER_IRQ); |
|
gen8_gt_irq_reset(dev_priv); |
|
GEN5_IRQ_RESET(GEN8_PCU_); |
|
POSTING_READ(GEN8_PCU_IIR); |
|
ibx_irq_preinstall(dev); |
I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV); |
|
I915_WRITE(PORT_HOTPLUG_EN, 0); |
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |
|
for_each_pipe(pipe) |
I915_WRITE(PIPESTAT(pipe), 0xffff); |
|
I915_WRITE(VLV_IMR, 0xffffffff); |
I915_WRITE(VLV_IER, 0x0); |
I915_WRITE(VLV_IIR, 0xffffffff); |
POSTING_READ(VLV_IIR); |
} |
|
static void ibx_hpd_irq_setup(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_mode_config *mode_config = &dev->mode_config; |
struct intel_encoder *intel_encoder; |
u32 hotplug_irqs, hotplug, enabled_irqs = 0; |
2722,22 → 3435,18 |
|
static void ibx_irq_postinstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 mask; |
|
if (HAS_PCH_NOP(dev)) |
return; |
|
if (HAS_PCH_IBX(dev)) { |
mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER | |
SDE_TRANSA_FIFO_UNDER | SDE_POISON; |
} else { |
mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT; |
if (HAS_PCH_IBX(dev)) |
mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON; |
else |
mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; |
|
I915_WRITE(SERR_INT, I915_READ(SERR_INT)); |
} |
|
I915_WRITE(SDEIIR, I915_READ(SDEIIR)); |
GEN5_ASSERT_IIR_IS_ZERO(SDEIIR); |
I915_WRITE(SDEIMR, ~mask); |
} |
|
2763,22 → 3472,16 |
gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; |
} |
|
I915_WRITE(GTIIR, I915_READ(GTIIR)); |
I915_WRITE(GTIMR, dev_priv->gt_irq_mask); |
I915_WRITE(GTIER, gt_irqs); |
POSTING_READ(GTIER); |
GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs); |
|
if (INTEL_INFO(dev)->gen >= 6) { |
pm_irqs |= GEN6_PM_RPS_EVENTS; |
pm_irqs |= dev_priv->pm_rps_events; |
|
if (HAS_VEBOX(dev)) |
pm_irqs |= PM_VEBOX_USER_INTERRUPT; |
|
dev_priv->pm_irq_mask = 0xffffffff; |
I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); |
I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask); |
I915_WRITE(GEN6_PMIER, pm_irqs); |
POSTING_READ(GEN6_PMIER); |
GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_irq_mask, pm_irqs); |
} |
} |
|
2785,7 → 3488,7 |
static int ironlake_irq_postinstall(struct drm_device *dev) |
{ |
unsigned long irqflags; |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 display_mask, extra_mask; |
|
if (INTEL_INFO(dev)->gen >= 7) { |
2792,30 → 3495,27 |
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | |
DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB | |
DE_PLANEB_FLIP_DONE_IVB | |
DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB | |
DE_ERR_INT_IVB); |
DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB); |
extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB | |
DE_PIPEA_VBLANK_IVB); |
|
I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); |
DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB); |
} 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_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE | |
DE_POISON); |
extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT; |
extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT | |
DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN; |
} |
|
dev_priv->irq_mask = ~display_mask; |
|
/* should always can generate irq */ |
I915_WRITE(DEIIR, I915_READ(DEIIR)); |
I915_WRITE(DEIMR, dev_priv->irq_mask); |
I915_WRITE(DEIER, display_mask | extra_mask); |
POSTING_READ(DEIER); |
I915_WRITE(HWSTAM, 0xeffe); |
|
ibx_irq_pre_postinstall(dev); |
|
GEN5_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask); |
|
gen5_gt_irq_postinstall(dev); |
|
ibx_irq_postinstall(dev); |
2834,44 → 3534,113 |
return 0; |
} |
|
static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv) |
{ |
u32 pipestat_mask; |
u32 iir_mask; |
|
pipestat_mask = PIPESTAT_INT_STATUS_MASK | |
PIPE_FIFO_UNDERRUN_STATUS; |
|
I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask); |
I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask); |
POSTING_READ(PIPESTAT(PIPE_A)); |
|
pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | |
PIPE_CRC_DONE_INTERRUPT_STATUS; |
|
i915_enable_pipestat(dev_priv, PIPE_A, pipestat_mask | |
PIPE_GMBUS_INTERRUPT_STATUS); |
i915_enable_pipestat(dev_priv, PIPE_B, pipestat_mask); |
|
iir_mask = I915_DISPLAY_PORT_INTERRUPT | |
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | |
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; |
dev_priv->irq_mask &= ~iir_mask; |
|
I915_WRITE(VLV_IIR, iir_mask); |
I915_WRITE(VLV_IIR, iir_mask); |
I915_WRITE(VLV_IMR, dev_priv->irq_mask); |
I915_WRITE(VLV_IER, ~dev_priv->irq_mask); |
POSTING_READ(VLV_IER); |
} |
|
static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv) |
{ |
u32 pipestat_mask; |
u32 iir_mask; |
|
iir_mask = I915_DISPLAY_PORT_INTERRUPT | |
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | |
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; |
|
dev_priv->irq_mask |= iir_mask; |
I915_WRITE(VLV_IER, ~dev_priv->irq_mask); |
I915_WRITE(VLV_IMR, dev_priv->irq_mask); |
I915_WRITE(VLV_IIR, iir_mask); |
I915_WRITE(VLV_IIR, iir_mask); |
POSTING_READ(VLV_IIR); |
|
pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | |
PIPE_CRC_DONE_INTERRUPT_STATUS; |
|
i915_disable_pipestat(dev_priv, PIPE_A, pipestat_mask | |
PIPE_GMBUS_INTERRUPT_STATUS); |
i915_disable_pipestat(dev_priv, PIPE_B, pipestat_mask); |
|
pipestat_mask = PIPESTAT_INT_STATUS_MASK | |
PIPE_FIFO_UNDERRUN_STATUS; |
I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask); |
I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask); |
POSTING_READ(PIPESTAT(PIPE_A)); |
} |
|
void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv) |
{ |
assert_spin_locked(&dev_priv->irq_lock); |
|
if (dev_priv->display_irqs_enabled) |
return; |
|
dev_priv->display_irqs_enabled = true; |
|
if (dev_priv->dev->irq_enabled) |
valleyview_display_irqs_install(dev_priv); |
} |
|
void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv) |
{ |
assert_spin_locked(&dev_priv->irq_lock); |
|
if (!dev_priv->display_irqs_enabled) |
return; |
|
dev_priv->display_irqs_enabled = false; |
|
if (dev_priv->dev->irq_enabled) |
valleyview_display_irqs_uninstall(dev_priv); |
} |
|
static int valleyview_irq_postinstall(struct drm_device *dev) |
{ |
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 | |
PIPE_CRC_DONE_ENABLE; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
|
enable_mask = I915_DISPLAY_PORT_INTERRUPT; |
enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | |
I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | |
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | |
I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; |
dev_priv->irq_mask = ~0; |
|
/* |
*Leave vblank interrupts masked initially. enable/disable will |
* toggle them based on usage. |
*/ |
dev_priv->irq_mask = (~enable_mask) | |
I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | |
I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; |
|
I915_WRITE(PORT_HOTPLUG_EN, 0); |
POSTING_READ(PORT_HOTPLUG_EN); |
|
I915_WRITE(VLV_IMR, dev_priv->irq_mask); |
I915_WRITE(VLV_IER, enable_mask); |
I915_WRITE(VLV_IER, ~dev_priv->irq_mask); |
I915_WRITE(VLV_IIR, 0xffffffff); |
I915_WRITE(PIPESTAT(0), 0xffff); |
I915_WRITE(PIPESTAT(1), 0xffff); |
POSTING_READ(VLV_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, pipestat_enable); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE); |
i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable); |
if (dev_priv->display_irqs_enabled) |
valleyview_display_irqs_install(dev_priv); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
I915_WRITE(VLV_IIR, 0xffffffff); |
2905,43 → 3674,33 |
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]); |
for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) |
GEN8_IRQ_INIT_NDX(GT, i, ~gt_interrupts[i], gt_interrupts[i]); |
|
dev_priv->pm_irq_mask = 0xffffffff; |
} |
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 | |
uint32_t de_pipe_masked = GEN8_PIPE_PRIMARY_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; |
uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | |
GEN8_PIPE_FIFO_UNDERRUN; |
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)); |
for_each_pipe(pipe) |
if (intel_display_power_enabled(dev_priv, |
POWER_DOMAIN_PIPE(pipe))) |
GEN8_IRQ_INIT_NDX(DE_PIPE, pipe, |
dev_priv->de_irq_mask[pipe], |
de_pipe_enables); |
|
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); |
GEN5_IRQ_INIT(GEN8_DE_PORT_, ~GEN8_AUX_CHANNEL_A, GEN8_AUX_CHANNEL_A); |
} |
|
static int gen8_irq_postinstall(struct drm_device *dev) |
2948,6 → 3707,8 |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
ibx_irq_pre_postinstall(dev); |
|
gen8_gt_irq_postinstall(dev_priv); |
gen8_de_irq_postinstall(dev_priv); |
|
2959,57 → 3720,65 |
return 0; |
} |
|
static void gen8_irq_uninstall(struct drm_device *dev) |
static int cherryview_irq_postinstall(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 enable_mask = I915_DISPLAY_PORT_INTERRUPT | |
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | |
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | |
I915_DISPLAY_PIPE_C_EVENT_INTERRUPT; |
u32 pipestat_enable = PLANE_FLIP_DONE_INT_STATUS_VLV | |
PIPE_CRC_DONE_INTERRUPT_STATUS; |
unsigned long irqflags; |
int pipe; |
|
if (!dev_priv) |
return; |
/* |
* Leave vblank interrupts masked initially. enable/disable will |
* toggle them based on usage. |
*/ |
dev_priv->irq_mask = ~enable_mask; |
|
atomic_set(&dev_priv->irq_received, 0); |
for_each_pipe(pipe) |
I915_WRITE(PIPESTAT(pipe), 0xffff); |
|
I915_WRITE(GEN8_MASTER_IRQ, 0); |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); |
for_each_pipe(pipe) |
i915_enable_pipestat(dev_priv, pipe, pipestat_enable); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
#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) |
I915_WRITE(VLV_IIR, 0xffffffff); |
I915_WRITE(VLV_IMR, dev_priv->irq_mask); |
I915_WRITE(VLV_IER, enable_mask); |
|
#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_gt_irq_postinstall(dev_priv); |
|
GEN8_IRQ_FINI_NDX(GT, 0); |
GEN8_IRQ_FINI_NDX(GT, 1); |
GEN8_IRQ_FINI_NDX(GT, 2); |
GEN8_IRQ_FINI_NDX(GT, 3); |
I915_WRITE(GEN8_MASTER_IRQ, MASTER_INTERRUPT_ENABLE); |
POSTING_READ(GEN8_MASTER_IRQ); |
|
for_each_pipe(pipe) { |
GEN8_IRQ_FINI_NDX(DE_PIPE, pipe); |
return 0; |
} |
|
GEN8_IRQ_FINI(DE_PORT); |
GEN8_IRQ_FINI(DE_MISC); |
GEN8_IRQ_FINI(PCU); |
#undef GEN8_IRQ_FINI |
#undef GEN8_IRQ_FINI_NDX |
static void gen8_irq_uninstall(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
POSTING_READ(GEN8_PCU_IIR); |
if (!dev_priv) |
return; |
|
gen8_irq_reset(dev); |
} |
|
static void valleyview_irq_uninstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
int pipe; |
|
if (!dev_priv) |
return; |
|
del_timer_sync(&dev_priv->hotplug_reenable_timer); |
I915_WRITE(VLV_MASTER_IER, 0); |
|
for_each_pipe(pipe) |
I915_WRITE(PIPESTAT(pipe), 0xffff); |
3017,8 → 3786,14 |
I915_WRITE(HWSTAM, 0xffffffff); |
I915_WRITE(PORT_HOTPLUG_EN, 0); |
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |
for_each_pipe(pipe) |
I915_WRITE(PIPESTAT(pipe), 0xffff); |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
if (dev_priv->display_irqs_enabled) |
valleyview_display_irqs_uninstall(dev_priv); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
dev_priv->irq_mask = 0; |
|
I915_WRITE(VLV_IIR, 0xffffffff); |
I915_WRITE(VLV_IMR, 0xffffffff); |
I915_WRITE(VLV_IER, 0x0); |
3025,35 → 3800,65 |
POSTING_READ(VLV_IER); |
} |
|
static void ironlake_irq_uninstall(struct drm_device *dev) |
static void cherryview_irq_uninstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
if (!dev_priv) |
return; |
|
del_timer_sync(&dev_priv->hotplug_reenable_timer); |
I915_WRITE(GEN8_MASTER_IRQ, 0); |
POSTING_READ(GEN8_MASTER_IRQ); |
|
I915_WRITE(HWSTAM, 0xffffffff); |
#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); \ |
POSTING_READ(GEN8_##type##_IIR(which)); \ |
I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \ |
} while (0) |
|
I915_WRITE(DEIMR, 0xffffffff); |
I915_WRITE(DEIER, 0x0); |
I915_WRITE(DEIIR, I915_READ(DEIIR)); |
if (IS_GEN7(dev)) |
I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); |
#define GEN8_IRQ_FINI(type) \ |
do { \ |
I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \ |
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) |
|
I915_WRITE(GTIMR, 0xffffffff); |
I915_WRITE(GTIER, 0x0); |
I915_WRITE(GTIIR, I915_READ(GTIIR)); |
GEN8_IRQ_FINI_NDX(GT, 0); |
GEN8_IRQ_FINI_NDX(GT, 1); |
GEN8_IRQ_FINI_NDX(GT, 2); |
GEN8_IRQ_FINI_NDX(GT, 3); |
|
if (HAS_PCH_NOP(dev)) |
GEN8_IRQ_FINI(PCU); |
|
#undef GEN8_IRQ_FINI |
#undef GEN8_IRQ_FINI_NDX |
|
I915_WRITE(PORT_HOTPLUG_EN, 0); |
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |
|
for_each_pipe(pipe) |
I915_WRITE(PIPESTAT(pipe), 0xffff); |
|
I915_WRITE(VLV_IMR, 0xffffffff); |
I915_WRITE(VLV_IER, 0x0); |
I915_WRITE(VLV_IIR, 0xffffffff); |
POSTING_READ(VLV_IIR); |
} |
|
static void ironlake_irq_uninstall(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
if (!dev_priv) |
return; |
|
I915_WRITE(SDEIMR, 0xffffffff); |
I915_WRITE(SDEIER, 0x0); |
I915_WRITE(SDEIIR, I915_READ(SDEIIR)); |
if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev)) |
I915_WRITE(SERR_INT, I915_READ(SERR_INT)); |
ironlake_irq_reset(dev); |
} |
|
#if 0 |
3060,11 → 3865,9 |
|
static void i8xx_irq_preinstall(struct drm_device * dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
atomic_set(&dev_priv->irq_received, 0); |
|
for_each_pipe(pipe) |
I915_WRITE(PIPESTAT(pipe), 0); |
I915_WRITE16(IMR, 0xffff); |
3074,7 → 3877,7 |
|
static int i8xx_irq_postinstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
|
I915_WRITE16(EMR, |
3099,8 → 3902,8 |
/* 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); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS); |
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
return 0; |
3112,7 → 3915,7 |
static bool i8xx_handle_vblank(struct drm_device *dev, |
int plane, int pipe, u32 iir) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); |
|
// if (!drm_handle_vblank(dev, pipe)) |
3139,8 → 3942,8 |
|
static irqreturn_t i8xx_irq_handler(int irq, void *arg) |
{ |
struct drm_device *dev = (struct drm_device *) arg; |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_device *dev = arg; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u16 iir, new_iir; |
u32 pipe_stats[2]; |
unsigned long irqflags; |
3149,8 → 3952,6 |
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; |
|
atomic_inc(&dev_priv->irq_received); |
|
iir = I915_READ16(IIR); |
if (iir == 0) |
return IRQ_NONE; |
3163,7 → 3964,9 |
*/ |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) |
i915_handle_error(dev, false); |
i915_handle_error(dev, false, |
"Command parser error, iir 0x%08x", |
iir); |
|
for_each_pipe(pipe) { |
int reg = PIPESTAT(pipe); |
3172,13 → 3975,9 |
/* |
* Clear the PIPE*STAT regs before the IIR |
*/ |
if (pipe_stats[pipe] & 0x8000ffff) { |
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) |
DRM_DEBUG_DRIVER("pipe %c underrun\n", |
pipe_name(pipe)); |
if (pipe_stats[pipe] & 0x8000ffff) |
I915_WRITE(reg, pipe_stats[pipe]); |
} |
} |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
I915_WRITE16(IIR, iir & ~flip_mask); |
3200,6 → 3999,10 |
|
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
|
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && |
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) |
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); |
} |
|
iir = new_iir; |
3210,7 → 4013,7 |
|
static void i8xx_irq_uninstall(struct drm_device * dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
for_each_pipe(pipe) { |
3227,11 → 4030,9 |
|
static void i915_irq_preinstall(struct drm_device * dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
atomic_set(&dev_priv->irq_received, 0); |
|
if (I915_HAS_HOTPLUG(dev)) { |
I915_WRITE(PORT_HOTPLUG_EN, 0); |
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |
3247,7 → 4048,7 |
|
static int i915_irq_postinstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 enable_mask; |
unsigned long irqflags; |
|
3288,8 → 4089,8 |
/* 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); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS); |
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
return 0; |
3301,7 → 4102,7 |
static bool i915_handle_vblank(struct drm_device *dev, |
int plane, int pipe, u32 iir) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); |
|
// if (!drm_handle_vblank(dev, pipe)) |
3328,8 → 4129,8 |
|
static irqreturn_t i915_irq_handler(int irq, void *arg) |
{ |
struct drm_device *dev = (struct drm_device *) arg; |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_device *dev = arg; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 iir, new_iir, pipe_stats[I915_MAX_PIPES]; |
unsigned long irqflags; |
u32 flip_mask = |
3337,8 → 4138,6 |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; |
int pipe, ret = IRQ_NONE; |
|
atomic_inc(&dev_priv->irq_received); |
|
iir = I915_READ(IIR); |
do { |
bool irq_received = (iir & ~flip_mask) != 0; |
3351,7 → 4150,9 |
*/ |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) |
i915_handle_error(dev, false); |
i915_handle_error(dev, false, |
"Command parser error, iir 0x%08x", |
iir); |
|
for_each_pipe(pipe) { |
int reg = PIPESTAT(pipe); |
3359,9 → 4160,6 |
|
/* Clear the PIPE*STAT regs before the IIR */ |
if (pipe_stats[pipe] & 0x8000ffff) { |
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) |
DRM_DEBUG_DRIVER("pipe %c underrun\n", |
pipe_name(pipe)); |
I915_WRITE(reg, pipe_stats[pipe]); |
irq_received = true; |
} |
3372,20 → 4170,10 |
break; |
|
/* Consume port. Then clear IIR or we'll miss events */ |
if ((I915_HAS_HOTPLUG(dev)) && |
(iir & I915_DISPLAY_PORT_INTERRUPT)) { |
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); |
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; |
if (I915_HAS_HOTPLUG(dev) && |
iir & I915_DISPLAY_PORT_INTERRUPT) |
i9xx_hpd_irq_handler(dev); |
|
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", |
hotplug_status); |
|
intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); |
|
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); |
POSTING_READ(PORT_HOTPLUG_STAT); |
} |
|
I915_WRITE(IIR, iir & ~flip_mask); |
new_iir = I915_READ(IIR); /* Flush posted writes */ |
|
3406,6 → 4194,10 |
|
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
|
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && |
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) |
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); |
} |
|
if (blc_event || (iir & I915_ASLE_INTERRUPT)) |
3437,11 → 4229,9 |
|
static void i915_irq_uninstall(struct drm_device * dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
del_timer_sync(&dev_priv->hotplug_reenable_timer); |
|
if (I915_HAS_HOTPLUG(dev)) { |
I915_WRITE(PORT_HOTPLUG_EN, 0); |
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |
3461,11 → 4251,9 |
|
static void i965_irq_preinstall(struct drm_device * dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
atomic_set(&dev_priv->irq_received, 0); |
|
I915_WRITE(PORT_HOTPLUG_EN, 0); |
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |
|
3479,7 → 4267,7 |
|
static int i965_irq_postinstall(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 enable_mask; |
u32 error_mask; |
unsigned long irqflags; |
3504,9 → 4292,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, 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); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS); |
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS); |
i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS); |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
|
/* |
3538,7 → 4326,7 |
|
static void i915_hpd_irq_setup(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_mode_config *mode_config = &dev->mode_config; |
struct intel_encoder *intel_encoder; |
u32 hotplug_en; |
3569,26 → 4357,22 |
|
static irqreturn_t i965_irq_handler(int irq, void *arg) |
{ |
struct drm_device *dev = (struct drm_device *) arg; |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_device *dev = arg; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 iir, new_iir; |
u32 pipe_stats[I915_MAX_PIPES]; |
unsigned long irqflags; |
int irq_received; |
int ret = IRQ_NONE, pipe; |
u32 flip_mask = |
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; |
|
atomic_inc(&dev_priv->irq_received); |
|
iir = I915_READ(IIR); |
|
for (;;) { |
bool irq_received = (iir & ~flip_mask) != 0; |
bool blc_event = false; |
|
irq_received = (iir & ~flip_mask) != 0; |
|
/* Can't rely on pipestat interrupt bit in iir as it might |
* have been cleared after the pipestat interrupt was received. |
* It doesn't set the bit in iir again, but it still produces |
3596,7 → 4380,9 |
*/ |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) |
i915_handle_error(dev, false); |
i915_handle_error(dev, false, |
"Command parser error, iir 0x%08x", |
iir); |
|
for_each_pipe(pipe) { |
int reg = PIPESTAT(pipe); |
3606,11 → 4392,8 |
* Clear the PIPE*STAT regs before the IIR |
*/ |
if (pipe_stats[pipe] & 0x8000ffff) { |
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) |
DRM_DEBUG_DRIVER("pipe %c underrun\n", |
pipe_name(pipe)); |
I915_WRITE(reg, pipe_stats[pipe]); |
irq_received = 1; |
irq_received = true; |
} |
} |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
3621,26 → 4404,9 |
ret = IRQ_HANDLED; |
|
/* Consume port. Then clear IIR or we'll miss events */ |
if (iir & I915_DISPLAY_PORT_INTERRUPT) { |
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); |
u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? |
HOTPLUG_INT_STATUS_G4X : |
HOTPLUG_INT_STATUS_I915); |
if (iir & I915_DISPLAY_PORT_INTERRUPT) |
i9xx_hpd_irq_handler(dev); |
|
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", |
hotplug_status); |
|
intel_hpd_irq_handler(dev, hotplug_trigger, |
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); |
} |
|
I915_WRITE(IIR, iir & ~flip_mask); |
new_iir = I915_READ(IIR); /* Flush posted writes */ |
|
3659,9 → 4425,12 |
|
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) |
i9xx_pipe_crc_irq_handler(dev, pipe); |
|
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS && |
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false)) |
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); |
} |
|
|
if (blc_event || (iir & I915_ASLE_INTERRUPT)) |
intel_opregion_asle_intr(dev); |
|
3693,14 → 4462,12 |
|
static void i965_irq_uninstall(struct drm_device * dev) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
struct drm_i915_private *dev_priv = dev->dev_private; |
int pipe; |
|
if (!dev_priv) |
return; |
|
del_timer_sync(&dev_priv->hotplug_reenable_timer); |
|
I915_WRITE(PORT_HOTPLUG_EN, 0); |
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); |
|
3716,9 → 4483,11 |
I915_WRITE(IIR, I915_READ(IIR)); |
} |
|
static void i915_reenable_hotplug_timer_func(unsigned long data) |
static void intel_hpd_irq_reenable(struct work_struct *work) |
{ |
drm_i915_private_t *dev_priv = (drm_i915_private_t *)data; |
struct drm_i915_private *dev_priv = |
container_of(work, typeof(*dev_priv), |
hotplug_reenable_work.work); |
struct drm_device *dev = dev_priv->dev; |
struct drm_mode_config *mode_config = &dev->mode_config; |
unsigned long irqflags; |
3739,7 → 4508,7 |
if (intel_connector->encoder->hpd_pin == i) { |
if (connector->polled != intel_connector->polled) |
DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", |
drm_get_connector_name(connector)); |
connector->name); |
connector->polled = intel_connector->polled; |
if (!connector->polled) |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
3760,9 → 4529,15 |
INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); |
INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); |
|
setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func, |
(unsigned long) dev_priv); |
/* Let's track the enabled rps events */ |
if (IS_VALLEYVIEW(dev)) |
/* WaGsvRC0ResidenncyMethod:VLV */ |
dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED; |
else |
dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS; |
|
/* Haven't installed the IRQ handler yet */ |
dev_priv->pm._irqs_disabled = true; |
|
if (IS_GEN2(dev)) { |
dev->max_vblank_count = 0; |
3780,7 → 4555,15 |
dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; |
} |
|
if (IS_VALLEYVIEW(dev)) { |
if (IS_CHERRYVIEW(dev)) { |
dev->driver->irq_handler = cherryview_irq_handler; |
dev->driver->irq_preinstall = cherryview_irq_preinstall; |
dev->driver->irq_postinstall = cherryview_irq_postinstall; |
dev->driver->irq_uninstall = cherryview_irq_uninstall; |
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_VALLEYVIEW(dev)) { |
dev->driver->irq_handler = valleyview_irq_handler; |
dev->driver->irq_preinstall = valleyview_irq_preinstall; |
dev->driver->irq_postinstall = valleyview_irq_postinstall; |
3790,7 → 4573,7 |
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_preinstall = gen8_irq_reset; |
dev->driver->irq_postinstall = gen8_irq_postinstall; |
dev->driver->irq_uninstall = gen8_irq_uninstall; |
dev->driver->enable_vblank = gen8_enable_vblank; |
3798,7 → 4581,7 |
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; |
dev->driver->irq_preinstall = ironlake_irq_reset; |
dev->driver->irq_postinstall = ironlake_irq_postinstall; |
dev->driver->irq_uninstall = ironlake_irq_uninstall; |
dev->driver->enable_vblank = ironlake_enable_vblank; |
3839,8 → 4622,10 |
list_for_each_entry(connector, &mode_config->connector_list, head) { |
struct intel_connector *intel_connector = to_intel_connector(connector); |
connector->polled = intel_connector->polled; |
if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) |
if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
if (intel_connector->mst_port) |
connector->polled = DRM_CONNECTOR_POLL_HPD; |
} |
|
/* Interrupt setup is already guaranteed to be single-threaded, this is |
3851,60 → 4636,23 |
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
} |
|
/* Disable interrupts so we can allow Package C8+. */ |
void hsw_pc8_disable_interrupts(struct drm_device *dev) |
/* Disable interrupts so we can allow runtime PM. */ |
void intel_runtime_pm_disable_interrupts(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
|
dev_priv->pc8.regsave.deimr = I915_READ(DEIMR); |
dev_priv->pc8.regsave.sdeimr = I915_READ(SDEIMR); |
dev_priv->pc8.regsave.gtimr = I915_READ(GTIMR); |
dev_priv->pc8.regsave.gtier = I915_READ(GTIER); |
dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR); |
|
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); |
|
dev_priv->pc8.irqs_disabled = true; |
|
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
dev->driver->irq_uninstall(dev); |
dev_priv->pm._irqs_disabled = true; |
} |
|
/* Restore interrupts so we can recover from Package C8+. */ |
void hsw_pc8_restore_interrupts(struct drm_device *dev) |
/* Restore interrupts so we can recover from runtime PM. */ |
void intel_runtime_pm_restore_interrupts(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned long irqflags; |
uint32_t val; |
|
spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
|
val = I915_READ(DEIMR); |
WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val); |
|
val = I915_READ(SDEIMR); |
WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val); |
|
val = I915_READ(GTIMR); |
WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val); |
|
val = I915_READ(GEN6_PMIMR); |
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); |
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); |
|
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
dev_priv->pm._irqs_disabled = false; |
dev->driver->irq_preinstall(dev); |
dev->driver->irq_postinstall(dev); |
} |
|
|