aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Widawsky <benjamin.widawsky@intel.com>2013-09-19 14:13:41 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-09-19 14:37:04 -0400
commit35a85ac60618521d41cfdb14f3fbfc8ad7329e9e (patch)
treeb9e3edb84f5c5a65cfc59179bdaf903b013f2a73
parent1c966dd26b2e46a9d089fcb7e36f649000670e64 (diff)
drm/i915: Add second slice l3 remapping
Certain HSW SKUs have a second bank of L3. This L3 remapping has a separate register set, and interrupt from the first "slice". A slice is simply a term to define some subset of the GPU's l3 cache. This patch implements both the interrupt handler, and ability to communicate with userspace about this second slice. v2: Remove redundant check about non-existent slice. Change warning about interrupts of unknown slices to WARN_ON_ONCE Handle the case where we get 2 slice interrupts concurrently, and switch the tracking of interrupts to be non-destructive (all Ville) Don't enable/mask the second slice parity interrupt for ivb/vlv (even though all docs I can find claim it's rsvd) (Ville + Bryan) Keep BYT excluded from L3 parity v3: Fix the slice = ffs to be decremented by one (found by Ville). When I initially did my testing on the series, I was using 1-based slice counting, so this code was correct. Not sure why my simpler tests that I've been running since then didn't pick it up sooner. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Ben Widawsky <ben@bwidawsk.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h7
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c26
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c89
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h7
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c34
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c7
-rw-r--r--include/uapi/drm/i915_drm.h8
7 files changed, 117 insertions, 61 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8b16d47280f9..c6e8df737566 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -917,9 +917,11 @@ struct i915_ums_state {
917 int mm_suspended; 917 int mm_suspended;
918}; 918};
919 919
920#define MAX_L3_SLICES 2
920struct intel_l3_parity { 921struct intel_l3_parity {
921 u32 *remap_info; 922 u32 *remap_info[MAX_L3_SLICES];
922 struct work_struct error_work; 923 struct work_struct error_work;
924 int which_slice;
923}; 925};
924 926
925struct i915_gem_mm { 927struct i915_gem_mm {
@@ -1686,6 +1688,7 @@ struct drm_i915_file_private {
1686#define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) 1688#define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake)
1687 1689
1688#define HAS_L3_GPU_CACHE(dev) (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) 1690#define HAS_L3_GPU_CACHE(dev) (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
1691#define NUM_L3_SLICES(dev) (IS_HSW_GT3(dev) ? 2 : HAS_L3_GPU_CACHE(dev))
1689 1692
1690#define GT_FREQUENCY_MULTIPLIER 50 1693#define GT_FREQUENCY_MULTIPLIER 50
1691 1694
@@ -1946,7 +1949,7 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
1946int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj); 1949int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
1947int __must_check i915_gem_init(struct drm_device *dev); 1950int __must_check i915_gem_init(struct drm_device *dev);
1948int __must_check i915_gem_init_hw(struct drm_device *dev); 1951int __must_check i915_gem_init_hw(struct drm_device *dev);
1949void i915_gem_l3_remap(struct drm_device *dev); 1952void i915_gem_l3_remap(struct drm_device *dev, int slice);
1950void i915_gem_init_swizzling(struct drm_device *dev); 1953void i915_gem_init_swizzling(struct drm_device *dev);
1951void i915_gem_cleanup_ringbuffer(struct drm_device *dev); 1954void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
1952int __must_check i915_gpu_idle(struct drm_device *dev); 1955int __must_check i915_gpu_idle(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d00d24f7a976..21a3d69679ee 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4222,16 +4222,15 @@ i915_gem_idle(struct drm_device *dev)
4222 return 0; 4222 return 0;
4223} 4223}
4224 4224
4225void i915_gem_l3_remap(struct drm_device *dev) 4225void i915_gem_l3_remap(struct drm_device *dev, int slice)
4226{ 4226{
4227 drm_i915_private_t *dev_priv = dev->dev_private; 4227 drm_i915_private_t *dev_priv = dev->dev_private;
4228 u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200);
4229 u32 *remap_info = dev_priv->l3_parity.remap_info[slice];
4228 u32 misccpctl; 4230 u32 misccpctl;
4229 int i; 4231 int i;
4230 4232
4231 if (!HAS_L3_GPU_CACHE(dev)) 4233 if (!HAS_L3_GPU_CACHE(dev) || !remap_info)
4232 return;
4233
4234 if (!dev_priv->l3_parity.remap_info)
4235 return; 4234 return;
4236 4235
4237 misccpctl = I915_READ(GEN7_MISCCPCTL); 4236 misccpctl = I915_READ(GEN7_MISCCPCTL);
@@ -4239,17 +4238,17 @@ void i915_gem_l3_remap(struct drm_device *dev)
4239 POSTING_READ(GEN7_MISCCPCTL); 4238 POSTING_READ(GEN7_MISCCPCTL);
4240 4239
4241 for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) { 4240 for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
4242 u32 remap = I915_READ(GEN7_L3LOG_BASE + i); 4241 u32 remap = I915_READ(reg_base + i);
4243 if (remap && remap != dev_priv->l3_parity.remap_info[i/4]) 4242 if (remap && remap != remap_info[i/4])
4244 DRM_DEBUG("0x%x was already programmed to %x\n", 4243 DRM_DEBUG("0x%x was already programmed to %x\n",
4245 GEN7_L3LOG_BASE + i, remap); 4244 reg_base + i, remap);
4246 if (remap && !dev_priv->l3_parity.remap_info[i/4]) 4245 if (remap && !remap_info[i/4])
4247 DRM_DEBUG_DRIVER("Clearing remapped register\n"); 4246 DRM_DEBUG_DRIVER("Clearing remapped register\n");
4248 I915_WRITE(GEN7_L3LOG_BASE + i, dev_priv->l3_parity.remap_info[i/4]); 4247 I915_WRITE(reg_base + i, remap_info[i/4]);
4249 } 4248 }
4250 4249
4251 /* Make sure all the writes land before disabling dop clock gating */ 4250 /* Make sure all the writes land before disabling dop clock gating */
4252 POSTING_READ(GEN7_L3LOG_BASE); 4251 POSTING_READ(reg_base);
4253 4252
4254 I915_WRITE(GEN7_MISCCPCTL, misccpctl); 4253 I915_WRITE(GEN7_MISCCPCTL, misccpctl);
4255} 4254}
@@ -4343,7 +4342,7 @@ int
4343i915_gem_init_hw(struct drm_device *dev) 4342i915_gem_init_hw(struct drm_device *dev)
4344{ 4343{
4345 drm_i915_private_t *dev_priv = dev->dev_private; 4344 drm_i915_private_t *dev_priv = dev->dev_private;
4346 int ret; 4345 int ret, i;
4347 4346
4348 if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) 4347 if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
4349 return -EIO; 4348 return -EIO;
@@ -4362,7 +4361,8 @@ i915_gem_init_hw(struct drm_device *dev)
4362 I915_WRITE(GEN7_MSG_CTL, temp); 4361 I915_WRITE(GEN7_MSG_CTL, temp);
4363 } 4362 }
4364 4363
4365 i915_gem_l3_remap(dev); 4364 for (i = 0; i < NUM_L3_SLICES(dev); i++)
4365 i915_gem_l3_remap(dev, i);
4366 4366
4367 i915_gem_init_swizzling(dev); 4367 i915_gem_init_swizzling(dev);
4368 4368
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index a610f5abcc41..60a7bac4fc3b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -888,9 +888,10 @@ static void ivybridge_parity_work(struct work_struct *work)
888 drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 888 drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
889 l3_parity.error_work); 889 l3_parity.error_work);
890 u32 error_status, row, bank, subbank; 890 u32 error_status, row, bank, subbank;
891 char *parity_event[5]; 891 char *parity_event[6];
892 uint32_t misccpctl; 892 uint32_t misccpctl;
893 unsigned long flags; 893 unsigned long flags;
894 uint8_t slice = 0;
894 895
895 /* We must turn off DOP level clock gating to access the L3 registers. 896 /* We must turn off DOP level clock gating to access the L3 registers.
896 * In order to prevent a get/put style interface, acquire struct mutex 897 * In order to prevent a get/put style interface, acquire struct mutex
@@ -898,45 +899,64 @@ static void ivybridge_parity_work(struct work_struct *work)
898 */ 899 */
899 mutex_lock(&dev_priv->dev->struct_mutex); 900 mutex_lock(&dev_priv->dev->struct_mutex);
900 901
902 /* If we've screwed up tracking, just let the interrupt fire again */
903 if (WARN_ON(!dev_priv->l3_parity.which_slice))
904 goto out;
905
901 misccpctl = I915_READ(GEN7_MISCCPCTL); 906 misccpctl = I915_READ(GEN7_MISCCPCTL);
902 I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); 907 I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
903 POSTING_READ(GEN7_MISCCPCTL); 908 POSTING_READ(GEN7_MISCCPCTL);
904 909
905 error_status = I915_READ(GEN7_L3CDERRST1); 910 while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
906 row = GEN7_PARITY_ERROR_ROW(error_status); 911 u32 reg;
907 bank = GEN7_PARITY_ERROR_BANK(error_status);
908 subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
909 912
910 I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID | 913 slice--;
911 GEN7_L3CDERRST1_ENABLE); 914 if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev)))
912 POSTING_READ(GEN7_L3CDERRST1); 915 break;
913 916
914 I915_WRITE(GEN7_MISCCPCTL, misccpctl); 917 dev_priv->l3_parity.which_slice &= ~(1<<slice);
915 918
916 spin_lock_irqsave(&dev_priv->irq_lock, flags); 919 reg = GEN7_L3CDERRST1 + (slice * 0x200);
917 ilk_enable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
918