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 spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
919 920
920 mutex_unlock(&dev_priv->dev->struct_mutex); 921 error_status = I915_READ(reg);
922 row = GEN7_PARITY_ERROR_ROW(error_status);
923 bank = GEN7_PARITY_ERROR_BANK(error_status);
924 subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
925
926 I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE);
927 POSTING_READ(reg);
928
929 parity_event[0] = I915_L3_PARITY_UEVENT "=1";
930 parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
931 parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
932 parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
933 parity_event[4] = kasprintf(GFP_KERNEL, "SLICE=%d", slice);
934 parity_event[5] = NULL;
935
936 kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
937 KOBJ_CHANGE, parity_event);
921 938
922 parity_event[0] = I915_L3_PARITY_UEVENT "=1"; 939 DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
923 parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row); 940 slice, row, bank, subbank);
924 parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
925 parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
926 parity_event[4] = NULL;
927 941
928 kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj, 942 kfree(parity_event[4]);
929 KOBJ_CHANGE, parity_event); 943 kfree(parity_event[3]);
944 kfree(parity_event[2]);
945 kfree(parity_event[1]);
946 }
930 947
931 DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n", 948 I915_WRITE(GEN7_MISCCPCTL, misccpctl);
932 row, bank, subbank);
933 949
934 kfree(parity_event[3]); 950out:
935 kfree(parity_event[2]); 951 WARN_ON(dev_priv->l3_parity.which_slice);
936 kfree(parity_event[1]); 952 spin_lock_irqsave(&dev_priv->irq_lock, flags);
953 ilk_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev));
954 spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
955
956 mutex_unlock(&dev_priv->dev->struct_mutex);
937} 957}
938 958
939static void ivybridge_parity_error_irq_handler(struct drm_device *dev) 959static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir)
940{ 960{
941 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 961 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
942 962
@@ -944,9 +964,16 @@ static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
944 return; 964 return;
945 965
946 spin_lock(&dev_priv->irq_lock); 966 spin_lock(&dev_priv->irq_lock);
947 ilk_disable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT); 967 ilk_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev));
948 spin_unlock(&dev_priv->irq_lock); 968 spin_unlock(&dev_priv->irq_lock);
949 969
970 iir &= GT_PARITY_ERROR(dev);
971 if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1)
972 dev_priv->l3_parity.which_slice |= 1 << 1;
973
974 if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
975 dev_priv->l3_parity.which_slice |= 1 << 0;
976
950 queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work); 977 queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
951} 978}
952 979
@@ -981,8 +1008,8 @@ static void snb_gt_irq_handler(struct drm_device *dev,
981 i915_handle_error(dev, false); 1008 i915_handle_error(dev, false);
982 } 1009 }
983 1010
984 if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT) 1011 if (gt_iir & GT_PARITY_ERROR(dev))
985 ivybridge_parity_error_irq_handler(dev); 1012 ivybridge_parity_error_irq_handler(dev, gt_iir);
986} 1013}
987 1014
988#define HPD_STORM_DETECT_PERIOD 1000 1015#define HPD_STORM_DETECT_PERIOD 1000
@@ -2221,8 +2248,8 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
2221 dev_priv->gt_irq_mask = ~0; 2248 dev_priv->gt_irq_mask = ~0;
2222 if (HAS_L3_GPU_CACHE(dev)) { 2249 if (HAS_L3_GPU_CACHE(dev)) {
2223 /* L3 parity interrupt is always unmasked. */ 2250 /* L3 parity interrupt is always unmasked. */
2224 dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT; 2251 dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev);
2225 gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; 2252 gt_irqs |= GT_PARITY_ERROR(dev);
2226 } 2253 }
2227 2254
2228 gt_irqs |= GT_RENDER_USER_INTERRUPT; 2255 gt_irqs |= GT_RENDER_USER_INTERRUPT;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index af6f93ca7296..c4f9bef6d073 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -927,6 +927,7 @@
927#define GT_BLT_USER_INTERRUPT (1 << 22) 927#define GT_BLT_USER_INTERRUPT (1 << 22)
928#define GT_BSD_CS_ERROR_INTERRUPT (1 << 15) 928#define GT_BSD_CS_ERROR_INTERRUPT (1 << 15)
929#define GT_BSD_USER_INTERRUPT (1 << 12) 929#define GT_BSD_USER_INTERRUPT (1 << 12)
930#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 (1 << 11) /* hsw+; rsvd on snb, ivb, vlv */
930#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT (1 << 5) /* !snb */ 931#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT (1 << 5) /* !snb */
931#define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT (1 << 4) 932#define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT (1 << 4)
932#define GT_RENDER_CS_MASTER_ERROR_INTERRUPT (1 << 3) 933#define GT_RENDER_CS_MASTER_ERROR_INTERRUPT (1 << 3)
@@ -937,6 +938,10 @@
937#define PM_VEBOX_CS_ERROR_INTERRUPT (1 << 12) /* hsw+ */ 938#define PM_VEBOX_CS_ERROR_INTERRUPT (1 << 12) /* hsw+ */
938#define PM_VEBOX_USER_INTERRUPT (1 << 10) /* hsw+ */ 939#define PM_VEBOX_USER_INTERRUPT (1 << 10) /* hsw+ */
939 940
941#define GT_PARITY_ERROR(dev) \
942 (GT_RENDER_L3_PARITY_ERROR_INTERRUPT | \
943 IS_HASWELL(dev) ? GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 : 0)
944
940/* These are all the "old" interrupts */ 945/* These are all the "old" interrupts */
941#define ILK_BSD_USER_INTERRUPT (1<<5) 946#define ILK_BSD_USER_INTERRUPT (1<<5)
942#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) 947#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
@@ -4747,6 +4752,7 @@
4747 4752
4748/* IVYBRIDGE DPF */ 4753/* IVYBRIDGE DPF */
4749#define GEN7_L3CDERRST1 0xB008 /* L3CD Error Status 1 */ 4754#define GEN7_L3CDERRST1 0xB008 /* L3CD Error Status 1 */
4755#define HSW_L3CDERRST11 0xB208 /* L3CD Error Status register 1 slice 1 */
4750#define GEN7_L3CDERRST1_ROW_MASK (0x7ff<<14) 4756#define GEN7_L3CDERRST1_ROW_MASK (0x7ff<<14)
4751#define GEN7_PARITY_ERROR_VALID (1<<13) 4757#define GEN7_PARITY_ERROR_VALID (1<<13)
4752#define GEN7_L3CDERRST1_BANK_MASK (3<<11) 4758#define GEN7_L3CDERRST1_BANK_MASK (3<<11)
@@ -4760,6 +4766,7 @@
4760#define GEN7_L3CDERRST1_ENABLE (1<<7) 4766#define GEN7_L3CDERRST1_ENABLE (1<<7)
4761 4767
4762#define GEN7_L3LOG_BASE 0xB070 4768#define GEN7_L3LOG_BASE 0xB070
4769#define HSW_L3LOG_BASE_SLICE1 0xB270
4763#define GEN7_L3LOG_SIZE 0x80 4770#define GEN7_L3LOG_SIZE 0x80
4764 4771
4765#define GEN7_HALF_SLICE_CHICKEN1 0xe100 /* IVB GT1 + VLV */ 4772#define GEN7_HALF_SLICE_CHICKEN1 0xe100 /* IVB GT1 + VLV */
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 71f6de24444e..3a8bf0c9b5ce 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -119,6 +119,7 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
119 struct drm_device *drm_dev = dminor->dev; 119 struct drm_device *drm_dev = dminor->dev;
120 struct drm_i915_private *dev_priv = drm_dev->dev_private; 120 struct drm_i915_private *dev_priv = drm_dev->dev_private;
121 uint32_t misccpctl; 121 uint32_t misccpctl;
122 int slice = (int)(uintptr_t)attr->private;
122 int i, ret; 123 int i, ret;
123 124
124 count = round_down(count, 4); 125 count = round_down(count, 4);
@@ -134,9 +135,9 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
134 return ret; 135 return ret;
135 136
136 if (IS_HASWELL(drm_dev)) { 137 if (IS_HASWELL(drm_dev)) {
137 if (dev_priv->l3_parity.remap_info) 138 if (dev_priv->l3_parity.remap_info[slice])
138 memcpy(buf, 139 memcpy(buf,
139 dev_priv->l3_parity.remap_info + (offset/4), 140 dev_priv->l3_parity.remap_info[slice] + (offset/4),
140 count); 141 count);
141 else 142 else
142 memset(buf, 0, count); 143 memset(buf, 0, count);
@@ -168,6 +169,7 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
168 struct drm_device *drm_dev = dminor->dev; 169 struct drm_device *drm_dev = dminor->dev;
169 struct drm_i915_private *dev_priv = drm_dev->dev_private; 170 struct drm_i915_private *dev_priv = drm_dev->dev_private;
170 u32 *temp = NULL; /* Just here to make handling failures easy */ 171 u32 *temp = NULL; /* Just here to make handling failures easy */
172 int slice = (int)(uintptr_t)attr->private;
171 int ret; 173 int ret;
172 174
173 ret = l3_access_valid(drm_dev, offset); 175 ret = l3_access_valid(drm_dev, offset);
@@ -178,7 +180,7 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
178 if (ret) 180 if (ret)
179 return ret; 181 return ret;
180 182
181 if (!dev_priv->l3_parity.remap_info) { 183 if (!dev_priv->l3_parity.remap_info[slice]) {
182 temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL); 184 temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
183 if (!temp) { 185 if (!temp) {
184 mutex_unlock(&drm_dev->struct_mutex); 186 mutex_unlock(&drm_dev->struct_mutex);
@@ -198,11 +200,11 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
198 * at this point it is left as a TODO. 200 * at this point it is left as a TODO.
199 */ 201 */
200 if (temp) 202 if (temp)
201 dev_priv->l3_parity.remap_info = temp; 203 dev_priv->l3_parity.remap_info[slice] = temp;
202 204
203 memcpy(dev_priv->l3_parity.remap_info + (offset/4), buf, count); 205 memcpy(dev_priv->l3_parity.remap_info[slice] + (offset/4), buf, count);
204 206
205 i915_gem_l3_remap(drm_dev); 207 i915_gem_l3_remap(drm_dev, slice);
206 208
207 mutex_unlock(&drm_dev->struct_mutex); 209 mutex_unlock(&drm_dev->struct_mutex);
208 210
@@ -214,7 +216,17 @@ static struct bin_attribute dpf_attrs = {
214 .size = GEN7_L3LOG_SIZE, 216 .size = GEN7_L3LOG_SIZE,
215 .read = i915_l3_read, 217 .read = i915_l3_read,
216 .write = i915_l3_write, 218 .write = i915_l3_write,
217 .mmap = NULL 219 .mmap = NULL,
220 .private = (void *)0
221};
222
223static struct bin_attribute dpf_attrs_1 = {
224 .attr = {.name = "l3_parity_slice_1", .mode = (S_IRUSR | S_IWUSR)},
225 .size = GEN7_L3LOG_SIZE,
226 .read = i915_l3_read,
227 .write = i915_l3_write,
228 .mmap = NULL,
229 .private = (void *)1
218}; 230};
219 231
220static ssize_t gt_cur_freq_mhz_show(struct device *kdev, 232static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
@@ -525,6 +537,13 @@ void i915_setup_sysfs(struct drm_device *dev)
525 ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs); 537 ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs);
526 if (ret) 538 if (ret)
527 DRM_ERROR("l3 parity sysfs setup failed\n"); 539 DRM_ERROR("l3 parity sysfs setup failed\n");
540
541 if (NUM_L3_SLICES(dev) > 1) {
542 ret = device_create_bin_file(&dev->primary->kdev,
543 &dpf_attrs_1);
544 if (ret)
545 DRM_ERROR("l3 parity slice 1 setup failed\n");
546 }
528 } 547 }
529 548
530 ret = 0; 549 ret = 0;
@@ -548,6 +567,7 @@ void i915_teardown_sysfs(struct drm_device *dev)
548 sysfs_remove_files(&dev->primary->kdev.kobj, vlv_attrs); 567 sysfs_remove_files(&dev->primary->kdev.kobj, vlv_attrs);
549 else 568 else
550 sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs); 569 sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs);
570 device_remove_bin_file(&dev->primary->kdev, &dpf_attrs_1);
551 device_remove_bin_file(&dev->primary->kdev, &dpf_attrs); 571 device_remove_bin_file(&dev->primary->kdev, &dpf_attrs);
552#ifdef CONFIG_PM 572#ifdef CONFIG_PM
553 sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group); 573 sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 686e5b23481d..958b7d8fea8b 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -570,7 +570,7 @@ static int init_render_ring(struct intel_ring_buffer *ring)
570 I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); 570 I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
571 571
572 if (HAS_L3_GPU_CACHE(dev)) 572 if (HAS_L3_GPU_CACHE(dev))
573 I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT); 573 I915_WRITE_IMR(ring, ~GT_PARITY_ERROR(dev));
574 574
575 return ret; 575 return ret;
576} 576}
@@ -1000,7 +1000,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
1000 if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) 1000 if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
1001 I915_WRITE_IMR(ring, 1001 I915_WRITE_IMR(ring,
1002 ~(ring->irq_enable_mask | 1002 ~(ring->irq_enable_mask |
1003 GT_RENDER_L3_PARITY_ERROR_INTERRUPT)); 1003 GT_PARITY_ERROR(dev)));
1004 else 1004 else
1005 I915_WRITE_IMR(ring, ~ring->irq_enable_mask); 1005 I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
1006 ilk_enable_gt_irq(dev_priv, ring->irq_enable_mask); 1006 ilk_enable_gt_irq(dev_priv, ring->irq_enable_mask);
@@ -1020,8 +1020,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
1020 spin_lock_irqsave(&dev_priv->irq_lock, flags); 1020 spin_lock_irqsave(&dev_priv->irq_lock, flags);
1021 if (--ring->irq_refcount == 0) { 1021 if (--ring->irq_refcount == 0) {
1022 if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) 1022 if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
1023 I915_WRITE_IMR(ring, 1023 I915_WRITE_IMR(ring, ~GT_PARITY_ERROR(dev));
1024 ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
1025 else 1024 else
1026 I915_WRITE_IMR(ring, ~0); 1025 I915_WRITE_IMR(ring, ~0);
1027 ilk_disable_gt_irq(dev_priv, ring->irq_enable_mask); 1026 ilk_disable_gt_irq(dev_priv, ring->irq_enable_mask);
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 55bb5729bd78..3a4e97bd8607 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -38,10 +38,10 @@
38 * 38 *
39 * I915_L3_PARITY_UEVENT - Generated when the driver receives a parity mismatch 39 * I915_L3_PARITY_UEVENT - Generated when the driver receives a parity mismatch
40 * event from the gpu l3 cache. Additional information supplied is ROW, 40 * event from the gpu l3 cache. Additional information supplied is ROW,
41 * BANK, SUBBANK of the affected cacheline. Userspace should keep track of 41 * BANK, SUBBANK, SLICE of the affected cacheline. Userspace should keep
42 * these events and if a specific cache-line seems to have a persistent 42 * track of these events and if a specific cache-line seems to have a
43 * error remap it with the l3 remapping tool supplied in intel-gpu-tools. 43 * persistent error remap it with the l3 remapping tool supplied in
44 * The value supplied with the event is always 1. 44 * intel-gpu-tools. The value supplied with the event is always 1.
45 * 45 *
46 * I915_ERROR_UEVENT - Generated upon error detection, currently only via 46 * I915_ERROR_UEVENT - Generated upon error detection, currently only via
47 * hangcheck. The error detection event is a good indicator of when things 47 * hangcheck. The error detection event is a good indicator of when things