Dumb binary interfaces which allow root-only updates of our cache remapping registers. See intel-gpu-tools for how this can/should be used. Signed-off-by: Ben Widawsky <benjamin.widawsky at intel.com> --- drivers/gpu/drm/i915/i915_reg.h | 10 ++++ drivers/gpu/drm/i915/i915_sysfs.c | 103 ++++++++++++++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index de1685e..1a93395 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4007,6 +4007,16 @@ #define GEN7_PARITY_ERROR_SUBBANK(reg) \ ((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8) +#define GEN7_L3LOG_BASE 0xB070 +#define GEN7_L3LOG_SIZE 0x80 +#if 0 +#define GEN7_L3LOG_ROW1(reg) ((reg>>21) & IVYBRDIGE_L3_ROW_MASK) +#define GEN7_L3LOG_VLDERR1 (1<<16) +#define GEN7_L3LOG_ROW0(reg) ((reg>>5) & IVYBRDIGE_L3_ROW_MASK) +#define GEN7_L3LOG_VLDERR0 (1<<0) +#endif + + #define G4X_AUD_VID_DID 0x62020 #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index f1b5108..fe37960 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -92,20 +92,119 @@ static struct attribute_group rc6_attr_group = { .attrs = rc6_attrs }; +static bool is_l3_access_valid(struct drm_device *dev, loff_t offset) +{ + if (!IS_IVYBRIDGE(dev)) + return false; + + if (offset >= GEN7_L3LOG_SIZE) + return false; + + if (offset % 4 != 0) + return false; + + return true; +} + +static ssize_t +i915_l3_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t offset, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + struct drm_device *drm_dev = dminor->dev; + struct drm_i915_private *dev_priv = drm_dev->dev_private; + int i; + + if (is_l3_access_valid(drm_dev, offset)) + return 0; + + if (i915_mutex_lock_interruptible(drm_dev)) + return 0; + + I915_WRITE(GEN7_MISCCPCTL, + I915_READ(GEN7_MISCCPCTL) & ~GEN7_DOP_CLOCK_GATE_ENABLE); + POSTING_READ(GEN7_MISCCPCTL); + + for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4) + buf[i] = I915_READ(GEN7_L3LOG_BASE + i); + + I915_WRITE(GEN7_MISCCPCTL, + I915_READ(GEN7_MISCCPCTL) | GEN7_DOP_CLOCK_GATE_ENABLE); + POSTING_READ(GEN7_MISCCPCTL); + + mutex_unlock(&drm_dev->struct_mutex); + + return i - offset; +} + +static ssize_t +i915_l3_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t offset, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + struct drm_device *drm_dev = dminor->dev; + struct drm_i915_private *dev_priv = drm_dev->dev_private; + int i; + + if (is_l3_access_valid(drm_dev, offset)) + return 0; + + if (i915_mutex_lock_interruptible(drm_dev)) + return 0; + + I915_WRITE(GEN7_MISCCPCTL, + I915_READ(GEN7_MISCCPCTL) & ~GEN7_DOP_CLOCK_GATE_ENABLE); + POSTING_READ(GEN7_MISCCPCTL); + + + for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4) { + uint32_t data = *(uint32_t *)(&buf[i]); + I915_WRITE(GEN7_L3LOG_BASE + i, data); + } + + I915_WRITE(GEN7_MISCCPCTL, + I915_READ(GEN7_MISCCPCTL) | GEN7_DOP_CLOCK_GATE_ENABLE); + POSTING_READ(GEN7_MISCCPCTL); + + mutex_unlock(&drm_dev->struct_mutex); + + return 0; +} + +static struct bin_attribute dpf_attrs = { + .attr = {.name = "l3_parity", .mode = (S_IRWXU)}, + .size = GEN7_L3LOG_SIZE, + .read = i915_l3_read, + .write = i915_l3_write, + .mmap = NULL +}; + void i915_setup_sysfs(struct drm_device *dev) { int ret; - /* ILK doesn't have any residency information */ + /* ILK and below don't yet have relevant sysfs files */ if (INTEL_INFO(dev)->gen < 6) return; ret = sysfs_merge_group(&dev->primary->kdev.kobj, &rc6_attr_group); if (ret) - DRM_ERROR("sysfs setup failed\n"); + DRM_ERROR("RC6 residency sysfs setup failed\n"); + + if (!IS_IVYBRIDGE(dev)) + return; + + ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs); + if (ret) + DRM_ERROR("l3 parity sysfs setup failed\n"); } void i915_teardown_sysfs(struct drm_device *dev) { + device_remove_bin_file(&dev->primary->kdev, &dpf_attrs); sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group); } -- 1.7.10