aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2013-07-12 16:43:26 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-07-16 02:58:12 -0400
commit0a9a8c91a5f9617d6fa319fe052de38691fb29cb (patch)
tree0eb74af571c64cec4f6b6eeb0a4a650d5661e5d8 /drivers/gpu/drm/i915/i915_irq.c
parentd18ea1b58a5003eb6fca03aff03c4c01321e6cb1 (diff)
drm/i915: unify GT/PM irq postinstall code
Again extract a common helper. For the postinstall hook things are a bit more complicated since we have more cases on ilk-hsw/vlv here. But since vlv was clearly broken by failing to initialize dev_priv->gt_irq_mask correctly the shared code is clearly justified. Also kill the PMIER setting in the async rps enable work. I should have been save, but also clearly looked rather fragile. PMIER setup is now all down in the irq pre/postinstall hooks. With this we now have the usual interrupt register sequence for GT/PM irq registers: - IER is setup once with all the interrupts we ever need in the postinstall hook and never touched again. Exceptions are SDEIER, which is touched in the preinstall hook (when the irq handler isn't enabled) and then only from the irq handler. And DEIER/VLV_IER with is used in the irq handler but also written to once in the postinstall hook. But since that write is essentially what enables the interrupt and we should always have MSI interrupts we should be save. In case we ever have non-MSI interrupts we'd be screwed. - IIR is cleared in the postinstall hook before we enable/unmask the respective interrupt sources. Hence we can't steal an interrupt event an accidentally trigger the spurious interrupt logic in the core kernel. Note that after some discussion with Ben Widawsky we think that we actually should clear the IIR registers in the preinstall hook. But doing that is a much larger patch series. - IMR regs are (usually) all masked off. Those are the only regs changed at runtime, which is all protected by dev_priv->irq_lock. This unification also kills the cargo-culted read-modify-write PM register setup for VECS. Interrupt setup is done without userspace being able to interfere, so we better know what values we want to put into those registers. RMW cycles otoh are really good at papering over races, until stuff magically blows up and no one has a clue why. v2: Touch the gen6+ PM interrupt registers only on gen6+. v3: Improve the commit message to more clearly spell out why we want to unify the code and what exactly changes. Cc: Ben Widawsky <ben@bwidawsk.net> Cc: Paulo Zanoni <przanoni@gmail.com> Reviewed-by: Ben Widawsky <ben@bwidawsk.net> [danvet: Add a comment to explain why the l3 parity interrupt is special.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c93
1 files changed, 43 insertions, 50 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 0d54a550ec6d..b388641e0606 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2196,6 +2196,46 @@ static void ibx_irq_postinstall(struct drm_device *dev)
2196 I915_WRITE(SDEIMR, ~mask); 2196 I915_WRITE(SDEIMR, ~mask);
2197} 2197}
2198 2198
2199static void gen5_gt_irq_postinstall(struct drm_device *dev)
2200{
2201 struct drm_i915_private *dev_priv = dev->dev_private;
2202 u32 pm_irqs, gt_irqs;
2203
2204 pm_irqs = gt_irqs = 0;
2205
2206 dev_priv->gt_irq_mask = ~0;
2207 if (HAS_L3_GPU_CACHE(dev)) {
2208 /* L3 parity interrupt is always unmasked. */
2209 dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
2210 gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
2211 }
2212
2213 gt_irqs |= GT_RENDER_USER_INTERRUPT;
2214 if (IS_GEN5(dev)) {
2215 gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT |
2216 ILK_BSD_USER_INTERRUPT;
2217 } else {
2218 gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
2219 }
2220
2221 I915_WRITE(GTIIR, I915_READ(GTIIR));
2222 I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
2223 I915_WRITE(GTIER, gt_irqs);
2224 POSTING_READ(GTIER);
2225
2226 if (INTEL_INFO(dev)->gen >= 6) {
2227 pm_irqs |= GEN6_PM_RPS_EVENTS;
2228
2229 if (HAS_VEBOX(dev))
2230 pm_irqs |= PM_VEBOX_USER_INTERRUPT;
2231
2232 I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
2233 I915_WRITE(GEN6_PMIMR, 0xffffffff);
2234 I915_WRITE(GEN6_PMIER, pm_irqs);
2235 POSTING_READ(GEN6_PMIER);
2236 }
2237}
2238
2199static int ironlake_irq_postinstall(struct drm_device *dev) 2239static int ironlake_irq_postinstall(struct drm_device *dev)
2200{ 2240{
2201 unsigned long irqflags; 2241 unsigned long irqflags;
@@ -2206,7 +2246,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
2206 DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | 2246 DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
2207 DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN | 2247 DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
2208 DE_PIPEA_FIFO_UNDERRUN | DE_POISON; 2248 DE_PIPEA_FIFO_UNDERRUN | DE_POISON;
2209 u32 gt_irqs;
2210 2249
2211 dev_priv->irq_mask = ~display_mask; 2250 dev_priv->irq_mask = ~display_mask;
2212 2251
@@ -2217,21 +2256,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
2217 DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT); 2256 DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
2218 POSTING_READ(DEIER); 2257 POSTING_READ(DEIER);
2219 2258
2220 dev_priv->gt_irq_mask = ~0; 2259 gen5_gt_irq_postinstall(dev);
2221
2222 I915_WRITE(GTIIR, I915_READ(GTIIR));
2223 I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
2224
2225 gt_irqs = GT_RENDER_USER_INTERRUPT;
2226
2227 if (IS_GEN6(dev))
2228 gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
2229 else
2230 gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT |
2231 ILK_BSD_USER_INTERRUPT;
2232
2233 I915_WRITE(GTIER, gt_irqs);
2234 POSTING_READ(GTIER);
2235 2260
2236 ibx_irq_postinstall(dev); 2261 ibx_irq_postinstall(dev);
2237 2262
@@ -2260,8 +2285,6 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
2260 DE_PLANEA_FLIP_DONE_IVB | 2285 DE_PLANEA_FLIP_DONE_IVB |
2261 DE_AUX_CHANNEL_A_IVB | 2286 DE_AUX_CHANNEL_A_IVB |
2262 DE_ERR_INT_IVB; 2287 DE_ERR_INT_IVB;
2263 u32 pm_irqs = GEN6_PM_RPS_EVENTS;
2264 u32 gt_irqs;
2265 2288
2266 dev_priv->irq_mask = ~display_mask; 2289 dev_priv->irq_mask = ~display_mask;
2267 2290
@@ -2276,30 +2299,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
2276 DE_PIPEA_VBLANK_IVB); 2299 DE_PIPEA_VBLANK_IVB);
2277 POSTING_READ(DEIER); 2300 POSTING_READ(DEIER);
2278 2301
2279 dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT; 2302 gen5_gt_irq_postinstall(dev);
2280
2281 I915_WRITE(GTIIR, I915_READ(GTIIR));
2282 I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
2283
2284 gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
2285 GT_BLT_USER_INTERRUPT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
2286 I915_WRITE(GTIER, gt_irqs);
2287 POSTING_READ(GTIER);
2288
2289 I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
2290 if (HAS_VEBOX(dev))
2291 pm_irqs |= PM_VEBOX_USER_INTERRUPT;
2292
2293 /* Our enable/disable rps functions may touch these registers so
2294 * make sure to set a known state for only the non-RPS bits.
2295 * The RMW is extra paranoia since this should be called after being set
2296 * to a known state in preinstall.
2297 * */
2298 I915_WRITE(GEN6_PMIMR,
2299 (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs);
2300 I915_WRITE(GEN6_PMIER,
2301 (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs);
2302 POSTING_READ(GEN6_PMIER);
2303 2303
2304 ibx_irq_postinstall(dev); 2304 ibx_irq_postinstall(dev);
2305 2305
@@ -2309,7 +2309,6 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
2309static int valleyview_irq_postinstall(struct drm_device *dev) 2309static int valleyview_irq_postinstall(struct drm_device *dev)
2310{ 2310{
2311 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2311 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2312 u32 gt_irqs;
2313 u32 enable_mask; 2312 u32 enable_mask;
2314 u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; 2313 u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
2315 unsigned long irqflags; 2314 unsigned long irqflags;
@@ -2349,13 +2348,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
2349 I915_WRITE(VLV_IIR, 0xffffffff); 2348 I915_WRITE(VLV_IIR, 0xffffffff);
2350 I915_WRITE(VLV_IIR, 0xffffffff); 2349 I915_WRITE(VLV_IIR, 0xffffffff);
2351 2350
2352 I915_WRITE(GTIIR, I915_READ(GTIIR)); 2351 gen5_gt_irq_postinstall(dev);
2353 I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
2354
2355 gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
2356 GT_BLT_USER_INTERRUPT;
2357 I915_WRITE(GTIER, gt_irqs);
2358 POSTING_READ(GTIER);
2359 2352
2360 /* ack & enable invalid PTE error interrupts */ 2353 /* ack & enable invalid PTE error interrupts */
2361#if 0 /* FIXME: add support to irq handler for checking these bits */ 2354#if 0 /* FIXME: add support to irq handler for checking these bits */