diff options
| author | Ben Widawsky <benjamin.widawsky@intel.com> | 2013-09-19 14:13:41 -0400 |
|---|---|---|
| committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-09-19 14:37:04 -0400 |
| commit | 35a85ac60618521d41cfdb14f3fbfc8ad7329e9e (patch) | |
| tree | b9e3edb84f5c5a65cfc59179bdaf903b013f2a73 | |
| parent | 1c966dd26b2e46a9d089fcb7e36f649000670e64 (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.h | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 26 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 89 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_sysfs.c | 34 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 7 | ||||
| -rw-r--r-- | include/uapi/drm/i915_drm.h | 8 |
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 | ||
| 920 | struct intel_l3_parity { | 921 | struct 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 | ||
| 925 | struct i915_gem_mm { | 927 | struct 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); | |||
| 1946 | int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj); | 1949 | int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj); |
| 1947 | int __must_check i915_gem_init(struct drm_device *dev); | 1950 | int __must_check i915_gem_init(struct drm_device *dev); |
| 1948 | int __must_check i915_gem_init_hw(struct drm_device *dev); | 1951 | int __must_check i915_gem_init_hw(struct drm_device *dev); |
| 1949 | void i915_gem_l3_remap(struct drm_device *dev); | 1952 | void i915_gem_l3_remap(struct drm_device *dev, int slice); |
| 1950 | void i915_gem_init_swizzling(struct drm_device *dev); | 1953 | void i915_gem_init_swizzling(struct drm_device *dev); |
| 1951 | void i915_gem_cleanup_ringbuffer(struct drm_device *dev); | 1954 | void i915_gem_cleanup_ringbuffer(struct drm_device *dev); |
| 1952 | int __must_check i915_gpu_idle(struct drm_device *dev); | 1955 | int __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 | ||
| 4225 | void i915_gem_l3_remap(struct drm_device *dev) | 4225 | void 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 | |||
| 4343 | i915_gem_init_hw(struct drm_device *dev) | 4342 | i915_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 | |||
