All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4 v2] drm/i915: Dynamic Parity Detection handling
@ 2012-05-25 23:56 Ben Widawsky
  2012-05-25 23:56 ` [PATCH 2/4] drm/i915: enable parity error interrupts Ben Widawsky
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Ben Widawsky @ 2012-05-25 23:56 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ben Widawsky

On IVB hardware we are given an interrupt whenever a L3 parity error
occurs in the L3 cache. The L3 cache is used by internal GPU clients
only.  This is a very rare occurrence (in fact to test this I need to
use specially instrumented silicon).

When a row in the L3 cache detects a parity error the HW generates an
interrupt. The interrupt is masked in GTIMR until we get a chance to
read some registers and alert userspace via a uevent. With this
information userspace can use a sysfs interface (follow-up patch) to
remap those rows.

Way above my level of understanding, but if a given row fails, it is
statistically more likely to fail again than a row which has not failed.
Therefore it is desirable for an operating system to maintain a lifelong
list of failing rows and always remap any bad rows on driver load.
Hardware limits the number of rows that are remappable per bank/subbank,
and should more than that many rows detect parity errors, software
should maintain a list of the most frequent errors, and remap those
rows.

V2: Drop WARN_ON(IS_GEN6) (Jesse)
DRM_DEBUG row/bank/subbank on errror (Jesse)
Comment updates (Jesse)

Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_drv.h |    2 +
 drivers/gpu/drm/i915/i915_irq.c |   86 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_reg.h |   17 ++++++++
 3 files changed, 105 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a17e31e..504f53e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -816,6 +816,8 @@ typedef struct drm_i915_private {
 
 	struct drm_property *broadcast_rgb_property;
 	struct drm_property *force_audio_property;
+
+	struct work_struct parity_error_work;
 } drm_i915_private_t;
 
 /* Iterate over initialised rings */
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 5134a62..c526635 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -398,6 +398,86 @@ static void gen6_pm_rps_work(struct work_struct *work)
 	mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
+
+/**
+ * ivybridge_parity_work - Workqueue called when a parity error interrupt
+ * occurred.
+ * @work: workqueue struct
+ *
+ * Doesn't actually do anything except notify userspace. As a consequence of
+ * this event, userspace should try to remap the bad rows since statistically
+ * it is likely the same row is more likely to go bad again.
+ */
+static void ivybridge_parity_work(struct work_struct *work)
+{
+	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+						    parity_error_work);
+	u32 error_status, row, bank, subbank;
+	char *parity_event[5];
+	uint32_t misccpctl;
+	unsigned long flags;
+
+	/* We must turn off DOP level clock gating to access the L3 registers.
+	 * In order to prevent a get/put style interface, acquire struct mutex
+	 * any time we access those registers.
+	 */
+	mutex_lock(&dev_priv->dev->struct_mutex);
+
+	misccpctl = I915_READ(GEN7_MISCCPCTL);
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+	POSTING_READ(GEN7_MISCCPCTL);
+
+	error_status = I915_READ(GEN7_L3CDERRST1);
+	row = GEN7_PARITY_ERROR_ROW(error_status);
+	bank = GEN7_PARITY_ERROR_BANK(error_status);
+	subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
+
+	I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID |
+				    GEN7_L3CDERRST1_ENABLE);
+	POSTING_READ(GEN7_L3CDERRST1);
+
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	dev_priv->gt_irq_mask &= ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+	mutex_unlock(&dev_priv->dev->struct_mutex);
+
+	parity_event[0] = "L3_PARITY_ERROR=1";
+	parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
+	parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
+	parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
+	parity_event[4] = NULL;
+
+	kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
+			   KOBJ_CHANGE, parity_event);
+
+	DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n",
+		  row, bank, subbank);
+
+	kfree(parity_event[3]);
+	kfree(parity_event[2]);
+	kfree(parity_event[1]);
+}
+
+void ivybridge_handle_parity_error(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	unsigned long flags;
+
+	if (!IS_IVYBRIDGE(dev))
+		return;
+
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	dev_priv->gt_irq_mask |= GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+	queue_work(dev_priv->wq, &dev_priv->parity_error_work);
+}
+
 static void snb_gt_irq_handler(struct drm_device *dev,
 			       struct drm_i915_private *dev_priv,
 			       u32 gt_iir)
@@ -417,6 +497,9 @@ static void snb_gt_irq_handler(struct drm_device *dev,
 		DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
 		i915_handle_error(dev, false);
 	}
+
+	if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT)
+		ivybridge_handle_parity_error(dev);
 }
 
 static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
@@ -1641,6 +1724,9 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
 	atomic_set(&dev_priv->irq_received, 0);
 
 
+	if (IS_IVYBRIDGE(dev))
+		INIT_WORK(&dev_priv->parity_error_work, ivybridge_parity_work);
+
 	I915_WRITE(HWSTAM, 0xeffe);
 
 	/* XXX hotplug from PCH */
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 0f45a18..4d53dbd 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -4088,6 +4088,23 @@
 #define   GEN6_RC6			3
 #define   GEN6_RC7			4
 
+#define GEN7_MISCCPCTL			(0x9424)
+#define   GEN7_DOP_CLOCK_GATE_ENABLE	(1<<0)
+
+/* IVYBRIDGE DPF */
+#define GEN7_L3CDERRST1			0xB008 /* L3CD Error Status 1 */
+#define   GEN7_L3CDERRST1_ROW_MASK	(0x7ff<<14)
+#define   GEN7_PARITY_ERROR_VALID	(1<<13)
+#define   GEN7_L3CDERRST1_BANK_MASK	(3<<11)
+#define   GEN7_L3CDERRST1_SUBBANK_MASK	(7<<8)
+#define GEN7_PARITY_ERROR_ROW(reg) \
+		((reg & GEN7_L3CDERRST1_ROW_MASK) >> 14)
+#define GEN7_PARITY_ERROR_BANK(reg) \
+		((reg & GEN7_L3CDERRST1_BANK_MASK) >> 11)
+#define GEN7_PARITY_ERROR_SUBBANK(reg) \
+		((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8)
+#define   GEN7_L3CDERRST1_ENABLE	(1<<7)
+
 #define G4X_AUD_VID_DID			0x62020
 #define INTEL_AUDIO_DEVCL		0x808629FB
 #define INTEL_AUDIO_DEVBLC		0x80862801
-- 
1.7.10.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/4] drm/i915: enable parity error interrupts
  2012-05-25 23:56 [PATCH 1/4 v2] drm/i915: Dynamic Parity Detection handling Ben Widawsky
@ 2012-05-25 23:56 ` Ben Widawsky
  2012-05-25 23:56 ` [PATCH 3/4 v2] drm/i915: remap l3 on hw init Ben Widawsky
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Ben Widawsky @ 2012-05-25 23:56 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ben Widawsky

The previous patch put all the code, and handlers in place. It should
now be safe to enable the parity error interrupt. The parity error must
be unmasked in both the GTIMR, and the CS IMR. Unfortunately, the docs
aren't clear about this; nevertheless it's the truth.

Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_irq.c         |    4 ++--
 drivers/gpu/drm/i915/intel_ringbuffer.c |   14 ++++++++++++--
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index c526635..4a45752 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1889,13 +1889,13 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
 		   DE_PIPEA_VBLANK_IVB);
 	POSTING_READ(DEIER);
 
-	dev_priv->gt_irq_mask = ~0;
+	dev_priv->gt_irq_mask = ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
 
 	I915_WRITE(GTIIR, I915_READ(GTIIR));
 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 
 	render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
-		GEN6_BLITTER_USER_INTERRUPT;
+		GEN6_BLITTER_USER_INTERRUPT | GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
 	I915_WRITE(GTIER, render_irqs);
 	POSTING_READ(GTIER);
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 1df1694..89a5e7f 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -427,6 +427,9 @@ static int init_render_ring(struct intel_ring_buffer *ring)
 	if (INTEL_INFO(dev)->gen >= 6)
 		I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
 
+	if (IS_IVYBRIDGE(dev))
+		I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+
 	return ret;
 }
 
@@ -814,7 +817,11 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
 	if (ring->irq_refcount++ == 0) {
-		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
+		if (IS_IVYBRIDGE(dev) && ring->id == RCS)
+			I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
+						GEN6_RENDER_L3_PARITY_ERROR));
+		else
+			I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
 		dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
 		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 		POSTING_READ(GTIMR);
@@ -833,7 +840,10 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
 
 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
 	if (--ring->irq_refcount == 0) {
-		I915_WRITE_IMR(ring, ~0);
+		if (IS_IVYBRIDGE(dev) && ring->id == RCS)
+			I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+		else
+			I915_WRITE_IMR(ring, ~0);
 		dev_priv->gt_irq_mask |= ring->irq_enable_mask;
 		I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
 		POSTING_READ(GTIMR);
-- 
1.7.10.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/4 v2] drm/i915: remap l3 on hw init
  2012-05-25 23:56 [PATCH 1/4 v2] drm/i915: Dynamic Parity Detection handling Ben Widawsky
  2012-05-25 23:56 ` [PATCH 2/4] drm/i915: enable parity error interrupts Ben Widawsky
@ 2012-05-25 23:56 ` Ben Widawsky
  2012-05-25 23:56 ` [PATCH 4/4] drm/i915: l3 parity sysfs interface Ben Widawsky
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Ben Widawsky @ 2012-05-25 23:56 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ben Widawsky

If any l3 rows have been previously remapped, we must remap them after
GPU reset/resume too.

v2: Just return (no warn) on remapping init if not IVB (Jesse)
Move the check of schizo userspace to i915_gem_l3_remap (Jesse)

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_drv.h |    3 +++
 drivers/gpu/drm/i915/i915_gem.c |   34 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_reg.h |    3 +++
 3 files changed, 40 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 504f53e..470c732 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -656,6 +656,8 @@ typedef struct drm_i915_private {
 		/** PPGTT used for aliasing the PPGTT with the GTT */
 		struct i915_hw_ppgtt *aliasing_ppgtt;
 
+		u32 *l3_remap_info;
+
 		struct shrinker inactive_shrinker;
 
 		/**
@@ -1309,6 +1311,7 @@ int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
+void i915_gem_l3_remap(struct drm_device *dev);
 void i915_gem_init_swizzling(struct drm_device *dev);
 void i915_gem_init_ppgtt(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d2eaa00..1c08e09 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3527,6 +3527,38 @@ i915_gem_idle(struct drm_device *dev)
 	return 0;
 }
 
+void i915_gem_l3_remap(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	u32 misccpctl;
+	int i;
+
+	if (!IS_IVYBRIDGE(dev))
+		return;
+
+	if (!dev_priv->mm.l3_remap_info)
+		return;
+
+	misccpctl = I915_READ(GEN7_MISCCPCTL);
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+	POSTING_READ(GEN7_MISCCPCTL);
+
+	for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
+		u32 remap = I915_READ(GEN7_L3LOG_BASE + i);
+		if (remap && remap != dev_priv->mm.l3_remap_info[i/4])
+			DRM_DEBUG("0x%x was already programmed to %x\n",
+				  GEN7_L3LOG_BASE + i, remap);
+		if (remap && !dev_priv->mm.l3_remap_info[i/4])
+			DRM_DEBUG_DRIVER("Clearing remapped register\n");
+		I915_WRITE(GEN7_L3LOG_BASE + i, dev_priv->mm.l3_remap_info[i/4]);
+	}
+
+	/* Make sure all the writes land before disabling dop clock gating */
+	POSTING_READ(GEN7_L3LOG_BASE);
+
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+}
+
 void i915_gem_init_swizzling(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -3616,6 +3648,8 @@ i915_gem_init_hw(struct drm_device *dev)
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret;
 
+	i915_gem_l3_remap(dev);
+
 	i915_gem_init_swizzling(dev);
 
 	ret = intel_init_render_ring_buffer(dev);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 4d53dbd..d48a067 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -4105,6 +4105,9 @@
 		((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8)
 #define   GEN7_L3CDERRST1_ENABLE	(1<<7)
 
+#define GEN7_L3LOG_BASE			0xB070
+#define GEN7_L3LOG_SIZE			0x80
+
 #define G4X_AUD_VID_DID			0x62020
 #define INTEL_AUDIO_DEVCL		0x808629FB
 #define INTEL_AUDIO_DEVBLC		0x80862801
-- 
1.7.10.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/4] drm/i915: l3 parity sysfs interface
  2012-05-25 23:56 [PATCH 1/4 v2] drm/i915: Dynamic Parity Detection handling Ben Widawsky
  2012-05-25 23:56 ` [PATCH 2/4] drm/i915: enable parity error interrupts Ben Widawsky
  2012-05-25 23:56 ` [PATCH 3/4 v2] drm/i915: remap l3 on hw init Ben Widawsky
@ 2012-05-25 23:56 ` Ben Widawsky
  2012-05-31 10:45   ` Daniel Vetter
  2012-07-27  4:19   ` Zhang, Xiong Y
  2012-05-25 23:56 ` [PATCH 5/6] tools/dpf: Tool to read and write l3 remap registers Ben Widawsky
  2012-05-25 23:56 ` [PATCH 6/6] tests/dpf: simple dpf test Ben Widawsky
  4 siblings, 2 replies; 11+ messages in thread
From: Ben Widawsky @ 2012-05-25 23:56 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ben Widawsky

Dumb binary interfaces which allow root-only updates of the cache
remapping registers. As mentioned in a previous patch, software using
this interface needs to know about HW limits, and other programming
considerations as the kernel interface does no checking for these things
on the root-only interface.

v1: Drop extra posting reads (Chris)
Return negative values in the sysfs interfaces on errors (Chris)

v2: Return -EINVAL for offset % 4 (Jesse)
Move schizo userspace check out (Jesse)
Cleaner sysfs item initializers (Daniel)

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_sysfs.c |  121 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 79f8344..c201327 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/stat.h>
 #include <linux/sysfs.h>
+#include "intel_drv.h"
 #include "i915_drv.h"
 
 static u32 calc_residency(struct drm_device *dev, const u32 reg)
@@ -92,20 +93,136 @@ static struct attribute_group rc6_attr_group = {
 	.attrs =  rc6_attrs
 };
 
+static int l3_access_valid(struct drm_device *dev, loff_t offset)
+{
+	if (!IS_IVYBRIDGE(dev))
+		return -EPERM;
+
+	if (offset % 4 != 0)
+		return -EINVAL;
+
+	if (offset >= GEN7_L3LOG_SIZE)
+		return -ENXIO;
+
+	return 0;
+}
+
+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;
+	uint32_t misccpctl;
+	int i, ret;
+
+	ret = l3_access_valid(drm_dev, offset);
+	if (ret)
+		return ret;
+
+	ret = i915_mutex_lock_interruptible(drm_dev);
+	if (ret)
+		return ret;
+
+	misccpctl = I915_READ(GEN7_MISCCPCTL);
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+
+	for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4)
+		*((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + i);
+
+	I915_WRITE(GEN7_MISCCPCTL, 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;
+	u32 *temp = NULL; /* Just here to make handling failures easy */
+	int ret;
+
+	ret = l3_access_valid(drm_dev, offset);
+	if (ret)
+		return ret;
+
+	ret = i915_mutex_lock_interruptible(drm_dev);
+	if (ret)
+		return ret;
+
+	if (!dev_priv->mm.l3_remap_info) {
+		temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
+		if (!temp) {
+			mutex_unlock(&drm_dev->struct_mutex);
+			return -ENOMEM;
+		}
+	}
+
+	ret = i915_gpu_idle(drm_dev);
+	if (ret) {
+		kfree(temp);
+		mutex_unlock(&drm_dev->struct_mutex);
+		return ret;
+	}
+
+	/* TODO: Ideally we really want a GPU reset here to make sure errors
+	 * aren't propagated. Since I cannot find a stable way to reset the GPU
+	 * at this point it is left as a TODO.
+	*/
+	if (temp)
+		dev_priv->mm.l3_remap_info = temp;
+
+	memcpy(dev_priv->mm.l3_remap_info + (offset/4),
+	       buf + (offset/4),
+	       count);
+
+	i915_gem_l3_remap(drm_dev);
+
+	mutex_unlock(&drm_dev->struct_mutex);
+
+	return count;
+}
+
+static struct bin_attribute dpf_attrs = {
+	.attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
+	.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.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/6] tools/dpf: Tool to read and write l3 remap registers.
  2012-05-25 23:56 [PATCH 1/4 v2] drm/i915: Dynamic Parity Detection handling Ben Widawsky
                   ` (2 preceding siblings ...)
  2012-05-25 23:56 ` [PATCH 4/4] drm/i915: l3 parity sysfs interface Ben Widawsky
@ 2012-05-25 23:56 ` Ben Widawsky
  2012-05-28 20:16   ` Paul Menzel
  2012-05-25 23:56 ` [PATCH 6/6] tests/dpf: simple dpf test Ben Widawsky
  4 siblings, 1 reply; 11+ messages in thread
From: Ben Widawsky @ 2012-05-25 23:56 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ben Widawsky

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 tests/dpf_test          |    8 +++
 tools/Makefile.am       |    3 +-
 tools/intel_l3_parity.c |  159 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 169 insertions(+), 1 deletion(-)
 create mode 100755 tests/dpf_test
 create mode 100644 tools/intel_l3_parity.c

diff --git a/tests/dpf_test b/tests/dpf_test
new file mode 100755
index 0000000..7d431ac
--- /dev/null
+++ b/tests/dpf_test
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
+. $SOURCE_DIR/drm_lib.sh
+
+$SOURCE_DIR/../tools/intel_l3_parity -c 2>&1
+$SOURCE_DIR/../tools/intel_l3_parity 0,0,0 2>&1
+$SOURCE_DIR/../tools/intel_l3_parity 2>&1
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 2e4128b..d461f38 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -14,7 +14,8 @@ bin_PROGRAMS = 				\
 	intel_reg_snapshot 		\
 	intel_reg_write 		\
 	intel_reg_read 			\
-	intel_forcewaked
+	intel_forcewaked		\
+	intel_l3_parity
 
 noinst_PROGRAMS = 			\
 	intel_dump_decode 		\
diff --git a/tools/intel_l3_parity.c b/tools/intel_l3_parity.c
new file mode 100644
index 0000000..260c3d0
--- /dev/null
+++ b/tools/intel_l3_parity.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "intel_chipset.h"
+#include "intel_gpu_tools.h"
+#include "drmtest.h"
+
+#define NUM_BANKS 4
+#define NUM_SUBBANKS 8
+#define NUM_REGS (NUM_BANKS * NUM_SUBBANKS)
+
+struct __attribute__ ((__packed__)) l3_log_register {
+	uint32_t row0_enable	: 1;
+	uint32_t rsvd2		: 4;
+	uint32_t row0		: 11;
+	uint32_t row1_enable	: 1;
+	uint32_t rsvd1		: 4;
+	uint32_t row1		: 11;
+} l3log[NUM_BANKS][NUM_SUBBANKS];
+
+static void dumpit(void)
+{
+	int i, j;
+
+	for (i = 0; i < NUM_BANKS; i++) {
+		for (j = 0; j < NUM_SUBBANKS; j++) {
+			struct l3_log_register *reg = &l3log[i][j];
+
+		if (reg->row0_enable)
+			printf("Row %d, Bank %d, Subbank %d is disabled\n",
+			       reg->row0, i, j);
+		if (reg->row1_enable)
+			printf("Row %d, Bank %d, Subbank %d is disabled\n",
+			       reg->row1, i, j);
+		}
+	}
+}
+
+static int disable_rbs(int row, int bank, int sbank)
+{
+	struct l3_log_register *reg = &l3log[bank][sbank];
+
+	// can't map more than 2 rows
+	if (reg->row0_enable && reg->row1_enable)
+		return -1;
+
+	// can't remap the same row twice
+	if ((reg->row0_enable && reg->row0 == row) ||
+	    (reg->row1_enable && reg->row1 == row)) {
+		return -1;
+	}
+
+	if (reg->row0_enable) {
+		reg->row1 = row;
+		reg->row1_enable = 1;
+	} else {
+		reg->row0 = row;
+		reg->row0_enable = 1;
+	}
+
+	return 0;
+}
+
+static int do_parse(int argc, char *argv[])
+{
+	int row, bank, sbank, i, ret;
+
+	for (i = 1; i < argc; i++) {
+		ret = sscanf(argv[i], "%d,%d,%d", &row, &bank, &sbank);
+		if (ret != 3)
+			return i;
+		assert(disable_rbs(row, bank, sbank) == 0);
+	}
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	const int device = drm_get_card(0);
+	char *path;
+	unsigned int devid;
+	int drm_fd, fd, ret;
+
+	drm_fd = drm_open_any();
+	devid = intel_get_drm_devid(drm_fd);
+
+	ret = asprintf(&path, "/sys/class/drm/card%d/l3_parity", device);
+	assert(ret != -1);
+
+	fd = open(path, O_RDWR);
+	if (fd == -1 && IS_IVYBRIDGE(devid)) {
+		perror("Opening sysfs");
+		exit(EXIT_FAILURE);
+	} else if (fd == -1)
+		exit(EXIT_SUCCESS);
+
+	ret = read(fd, l3log, NUM_REGS * sizeof(uint32_t));
+	if (ret == -1) {
+		perror("Reading sysfs");
+		exit(EXIT_FAILURE);
+	}
+
+	assert(lseek(fd, 0, SEEK_SET) == 0);
+
+	if (argc == 1) {
+		dumpit();
+		exit(EXIT_SUCCESS);
+	} else if (!strncmp("-c", argv[1], 2)) {
+		memset(l3log, 0, sizeof(l3log));
+	} else {
+		ret = do_parse(argc, argv);
+		if (ret != 0) {
+			fprintf(stderr, "Malformed command line at %s\n", argv[ret]);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	ret = write(fd, l3log, NUM_REGS * sizeof(uint32_t));
+	if (ret == -1) {
+		perror("Writing sysfs");
+		exit(EXIT_FAILURE);
+	}
+
+	close(fd);
+
+	exit(EXIT_SUCCESS);
+}
-- 
1.7.10.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/6] tests/dpf: simple dpf test
  2012-05-25 23:56 [PATCH 1/4 v2] drm/i915: Dynamic Parity Detection handling Ben Widawsky
                   ` (3 preceding siblings ...)
  2012-05-25 23:56 ` [PATCH 5/6] tools/dpf: Tool to read and write l3 remap registers Ben Widawsky
@ 2012-05-25 23:56 ` Ben Widawsky
  4 siblings, 0 replies; 11+ messages in thread
From: Ben Widawsky @ 2012-05-25 23:56 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ben Widawsky

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 tests/Makefile.am |    1 +
 tests/dpf_test    |    9 ++++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/tests/Makefile.am b/tests/Makefile.am
index c7f4f73..3eec64f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -70,6 +70,7 @@ TESTS_progs = \
 TESTS_scripts = \
 	debugfs_reader \
 	debugfs_emon_crash \
+	dpf_test \
 	sysfs_edid_timing \
 	module_reload \
 	ZZ_check_dmesg \
diff --git a/tests/dpf_test b/tests/dpf_test
index 7d431ac..f62e341 100755
--- a/tests/dpf_test
+++ b/tests/dpf_test
@@ -4,5 +4,12 @@ SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
 . $SOURCE_DIR/drm_lib.sh
 
 $SOURCE_DIR/../tools/intel_l3_parity -c 2>&1
+
+#Check that we can remap a row
 $SOURCE_DIR/../tools/intel_l3_parity 0,0,0 2>&1
-$SOURCE_DIR/../tools/intel_l3_parity 2>&1
+disabled=`$SOURCE_DIR/../tools/intel_l3_parity | grep -c 'Row 0, Bank 0, Subbank 0 is disabled'`
+[ "$disabled" = "1" ] || echo "Fail" && exit -1
+$SOURCE_DIR/../tools/intel_l3_parity -c 2>&1
+
+#Check that we can clear remaps
+[ `$SOURCE_DIR/../tools/intel_l3_parity | wc -c` = "0" ] || echo "Fail" && exit -1
-- 
1.7.10.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 5/6] tools/dpf: Tool to read and write l3 remap registers.
  2012-05-25 23:56 ` [PATCH 5/6] tools/dpf: Tool to read and write l3 remap registers Ben Widawsky
@ 2012-05-28 20:16   ` Paul Menzel
  0 siblings, 0 replies; 11+ messages in thread
From: Paul Menzel @ 2012-05-28 20:16 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 606 bytes --]

Dear Ben,


Am Freitag, den 25.05.2012, 16:56 -0700 schrieb Ben Widawsky:

an output of a working run of `dpf_test` with some explanation pasted
into the commit message would be nice as there is no manual page.

> Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> ---
>  tests/dpf_test          |    8 +++
>  tools/Makefile.am       |    3 +-
>  tools/intel_l3_parity.c |  159 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 169 insertions(+), 1 deletion(-)
>  create mode 100755 tests/dpf_test
>  create mode 100644 tools/intel_l3_parity.c

[…]


Thanks,

Paul

[-- Attachment #1.2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/4] drm/i915: l3 parity sysfs interface
  2012-05-25 23:56 ` [PATCH 4/4] drm/i915: l3 parity sysfs interface Ben Widawsky
@ 2012-05-31 10:45   ` Daniel Vetter
  2012-05-31 15:55     ` Ben Widawsky
  2012-07-27  4:19   ` Zhang, Xiong Y
  1 sibling, 1 reply; 11+ messages in thread
From: Daniel Vetter @ 2012-05-31 10:45 UTC (permalink / raw)
  To: Ben Widawsky; +Cc: intel-gfx

On Fri, May 25, 2012 at 04:56:25PM -0700, Ben Widawsky wrote:
> Dumb binary interfaces which allow root-only updates of the cache
> remapping registers. As mentioned in a previous patch, software using
> this interface needs to know about HW limits, and other programming
> considerations as the kernel interface does no checking for these things
> on the root-only interface.
> 
> v1: Drop extra posting reads (Chris)
> Return negative values in the sysfs interfaces on errors (Chris)
> 
> v2: Return -EINVAL for offset % 4 (Jesse)
> Move schizo userspace check out (Jesse)
> Cleaner sysfs item initializers (Daniel)
> 
> Signed-off-by: Ben Widawsky <ben@bwidawsk.net>

I've queued this series for -next. Although you haven't fixed up the one
issue in patch 2 I've noticed and I also don't see my bikeshed for this
patch (despite that you claim to have done so). Whatever, I'll follow up
with patches.
-Daniel
-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/4] drm/i915: l3 parity sysfs interface
  2012-05-31 10:45   ` Daniel Vetter
@ 2012-05-31 15:55     ` Ben Widawsky
  0 siblings, 0 replies; 11+ messages in thread
From: Ben Widawsky @ 2012-05-31 15:55 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Thu, 31 May 2012 12:45:56 +0200
Daniel Vetter <daniel@ffwll.ch> wrote:

> On Fri, May 25, 2012 at 04:56:25PM -0700, Ben Widawsky wrote:
> > Dumb binary interfaces which allow root-only updates of the cache
> > remapping registers. As mentioned in a previous patch, software using
> > this interface needs to know about HW limits, and other programming
> > considerations as the kernel interface does no checking for these things
> > on the root-only interface.
> > 
> > v1: Drop extra posting reads (Chris)
> > Return negative values in the sysfs interfaces on errors (Chris)
> > 
> > v2: Return -EINVAL for offset % 4 (Jesse)
> > Move schizo userspace check out (Jesse)
> > Cleaner sysfs item initializers (Daniel)
> > 
> > Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> 
> I've queued this series for -next. Although you haven't fixed up the one
> issue in patch 2 I've noticed and I also don't see my bikeshed for this
> patch (despite that you claim to have done so). Whatever, I'll follow up
> with patches.
> -Daniel

Thanks for moving the patches forward, I'll review your fixes to them
shortly. The fixes are somewhere; I am not sure how they got lost.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/4] drm/i915: l3 parity sysfs interface
  2012-05-25 23:56 ` [PATCH 4/4] drm/i915: l3 parity sysfs interface Ben Widawsky
  2012-05-31 10:45   ` Daniel Vetter
@ 2012-07-27  4:19   ` Zhang, Xiong Y
  2012-07-27 16:50     ` Ben Widawsky
  1 sibling, 1 reply; 11+ messages in thread
From: Zhang, Xiong Y @ 2012-07-27  4:19 UTC (permalink / raw)
  To: Ben Widawsky, intel-gfx

   
   Who will monitor this sysfs interface, 2D driver or 3D driver or other application ?
   Now, I don't find any user of this sysfs interface in 2D driver or 3D driver.

thanks

-----Original Message-----
From: intel-gfx-bounces+xiong.y.zhang=intel.com@lists.freedesktop.org [mailto:intel-gfx-bounces+xiong.y.zhang=intel.com@lists.freedesktop.org] On Behalf Of Ben Widawsky
Sent: Saturday, May 26, 2012 7:56 AM
To: intel-gfx@lists.freedesktop.org
Cc: Ben Widawsky
Subject: [Intel-gfx] [PATCH 4/4] drm/i915: l3 parity sysfs interface

Dumb binary interfaces which allow root-only updates of the cache remapping registers. As mentioned in a previous patch, software using this interface needs to know about HW limits, and other programming considerations as the kernel interface does no checking for these things on the root-only interface.

v1: Drop extra posting reads (Chris)
Return negative values in the sysfs interfaces on errors (Chris)

v2: Return -EINVAL for offset % 4 (Jesse) Move schizo userspace check out (Jesse) Cleaner sysfs item initializers (Daniel)

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_sysfs.c |  121 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 79f8344..c201327 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/stat.h>
 #include <linux/sysfs.h>
+#include "intel_drv.h"
 #include "i915_drv.h"
 
 static u32 calc_residency(struct drm_device *dev, const u32 reg) @@ -92,20 +93,136 @@ static struct attribute_group rc6_attr_group = {
 	.attrs =  rc6_attrs
 };
 
+static int l3_access_valid(struct drm_device *dev, loff_t offset) {
+	if (!IS_IVYBRIDGE(dev))
+		return -EPERM;
+
+	if (offset % 4 != 0)
+		return -EINVAL;
+
+	if (offset >= GEN7_L3LOG_SIZE)
+		return -ENXIO;
+
+	return 0;
+}
+
+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;
+	uint32_t misccpctl;
+	int i, ret;
+
+	ret = l3_access_valid(drm_dev, offset);
+	if (ret)
+		return ret;
+
+	ret = i915_mutex_lock_interruptible(drm_dev);
+	if (ret)
+		return ret;
+
+	misccpctl = I915_READ(GEN7_MISCCPCTL);
+	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
+
+	for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4)
+		*((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + i);
+
+	I915_WRITE(GEN7_MISCCPCTL, 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;
+	u32 *temp = NULL; /* Just here to make handling failures easy */
+	int ret;
+
+	ret = l3_access_valid(drm_dev, offset);
+	if (ret)
+		return ret;
+
+	ret = i915_mutex_lock_interruptible(drm_dev);
+	if (ret)
+		return ret;
+
+	if (!dev_priv->mm.l3_remap_info) {
+		temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
+		if (!temp) {
+			mutex_unlock(&drm_dev->struct_mutex);
+			return -ENOMEM;
+		}
+	}
+
+	ret = i915_gpu_idle(drm_dev);
+	if (ret) {
+		kfree(temp);
+		mutex_unlock(&drm_dev->struct_mutex);
+		return ret;
+	}
+
+	/* TODO: Ideally we really want a GPU reset here to make sure errors
+	 * aren't propagated. Since I cannot find a stable way to reset the GPU
+	 * at this point it is left as a TODO.
+	*/
+	if (temp)
+		dev_priv->mm.l3_remap_info = temp;
+
+	memcpy(dev_priv->mm.l3_remap_info + (offset/4),
+	       buf + (offset/4),
+	       count);
+
+	i915_gem_l3_remap(drm_dev);
+
+	mutex_unlock(&drm_dev->struct_mutex);
+
+	return count;
+}
+
+static struct bin_attribute dpf_attrs = {
+	.attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
+	.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.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/4] drm/i915: l3 parity sysfs interface
  2012-07-27  4:19   ` Zhang, Xiong Y
@ 2012-07-27 16:50     ` Ben Widawsky
  0 siblings, 0 replies; 11+ messages in thread
From: Ben Widawsky @ 2012-07-27 16:50 UTC (permalink / raw)
  To: Zhang, Xiong Y; +Cc: intel-gfx

On Fri, 27 Jul 2012 04:19:10 +0000
"Zhang, Xiong Y" <xiong.y.zhang@intel.com> wrote:

>    
>    Who will monitor this sysfs interface, 2D driver or 3D driver or other application ?
>    Now, I don't find any user of this sysfs interface in 2D driver or 3D driver.
> 
> thanks

The notification is meant to be received through a udev event. What user
space should do at that point has been somewhat up to discussion thus
far. In order to correct the issues, a neutral root third party should
receieve the event and program the sysfs entry with the remap
information (possibly also force a GPU reset through debugfs).

In the ideal case, I think we should have GPU clients somehow register
that they want to be notified by such an event, maybe a signal based
mechanism, so they can dump all of their buffers and start over. That
should allow us to not force the GPU reset.

So far, we've not had any GPU clients that care enough abuot a faulty
cacheline to use such an interface. It was really provided as a
gpgpu/compute shader type of feature.


> 
> -----Original Message-----
> From: intel-gfx-bounces+xiong.y.zhang=intel.com@lists.freedesktop.org [mailto:intel-gfx-bounces+xiong.y.zhang=intel.com@lists.freedesktop.org] On Behalf Of Ben Widawsky
> Sent: Saturday, May 26, 2012 7:56 AM
> To: intel-gfx@lists.freedesktop.org
> Cc: Ben Widawsky
> Subject: [Intel-gfx] [PATCH 4/4] drm/i915: l3 parity sysfs interface
> 
> Dumb binary interfaces which allow root-only updates of the cache remapping registers. As mentioned in a previous patch, software using this interface needs to know about HW limits, and other programming considerations as the kernel interface does no checking for these things on the root-only interface.
> 
> v1: Drop extra posting reads (Chris)
> Return negative values in the sysfs interfaces on errors (Chris)
> 
> v2: Return -EINVAL for offset % 4 (Jesse) Move schizo userspace check out (Jesse) Cleaner sysfs item initializers (Daniel)
> 
> Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> ---
>  drivers/gpu/drm/i915/i915_sysfs.c |  121 ++++++++++++++++++++++++++++++++++++-
>  1 file changed, 119 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
> index 79f8344..c201327 100644
> --- a/drivers/gpu/drm/i915/i915_sysfs.c
> +++ b/drivers/gpu/drm/i915/i915_sysfs.c
> @@ -29,6 +29,7 @@
>  #include <linux/module.h>
>  #include <linux/stat.h>
>  #include <linux/sysfs.h>
> +#include "intel_drv.h"
>  #include "i915_drv.h"
>  
>  static u32 calc_residency(struct drm_device *dev, const u32 reg) @@ -92,20 +93,136 @@ static struct attribute_group rc6_attr_group = {
>  	.attrs =  rc6_attrs
>  };
>  
> +static int l3_access_valid(struct drm_device *dev, loff_t offset) {
> +	if (!IS_IVYBRIDGE(dev))
> +		return -EPERM;
> +
> +	if (offset % 4 != 0)
> +		return -EINVAL;
> +
> +	if (offset >= GEN7_L3LOG_SIZE)
> +		return -ENXIO;
> +
> +	return 0;
> +}
> +
> +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;
> +	uint32_t misccpctl;
> +	int i, ret;
> +
> +	ret = l3_access_valid(drm_dev, offset);
> +	if (ret)
> +		return ret;
> +
> +	ret = i915_mutex_lock_interruptible(drm_dev);
> +	if (ret)
> +		return ret;
> +
> +	misccpctl = I915_READ(GEN7_MISCCPCTL);
> +	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
> +
> +	for (i = offset; count >= 4 && i < GEN7_L3LOG_SIZE; i += 4, count -= 4)
> +		*((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + i);
> +
> +	I915_WRITE(GEN7_MISCCPCTL, 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;
> +	u32 *temp = NULL; /* Just here to make handling failures easy */
> +	int ret;
> +
> +	ret = l3_access_valid(drm_dev, offset);
> +	if (ret)
> +		return ret;
> +
> +	ret = i915_mutex_lock_interruptible(drm_dev);
> +	if (ret)
> +		return ret;
> +
> +	if (!dev_priv->mm.l3_remap_info) {
> +		temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
> +		if (!temp) {
> +			mutex_unlock(&drm_dev->struct_mutex);
> +			return -ENOMEM;
> +		}
> +	}
> +
> +	ret = i915_gpu_idle(drm_dev);
> +	if (ret) {
> +		kfree(temp);
> +		mutex_unlock(&drm_dev->struct_mutex);
> +		return ret;
> +	}
> +
> +	/* TODO: Ideally we really want a GPU reset here to make sure errors
> +	 * aren't propagated. Since I cannot find a stable way to reset the GPU
> +	 * at this point it is left as a TODO.
> +	*/
> +	if (temp)
> +		dev_priv->mm.l3_remap_info = temp;
> +
> +	memcpy(dev_priv->mm.l3_remap_info + (offset/4),
> +	       buf + (offset/4),
> +	       count);
> +
> +	i915_gem_l3_remap(drm_dev);
> +
> +	mutex_unlock(&drm_dev->struct_mutex);
> +
> +	return count;
> +}
> +
> +static struct bin_attribute dpf_attrs = {
> +	.attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
> +	.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.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Ben Widawsky, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2012-07-27 16:50 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-25 23:56 [PATCH 1/4 v2] drm/i915: Dynamic Parity Detection handling Ben Widawsky
2012-05-25 23:56 ` [PATCH 2/4] drm/i915: enable parity error interrupts Ben Widawsky
2012-05-25 23:56 ` [PATCH 3/4 v2] drm/i915: remap l3 on hw init Ben Widawsky
2012-05-25 23:56 ` [PATCH 4/4] drm/i915: l3 parity sysfs interface Ben Widawsky
2012-05-31 10:45   ` Daniel Vetter
2012-05-31 15:55     ` Ben Widawsky
2012-07-27  4:19   ` Zhang, Xiong Y
2012-07-27 16:50     ` Ben Widawsky
2012-05-25 23:56 ` [PATCH 5/6] tools/dpf: Tool to read and write l3 remap registers Ben Widawsky
2012-05-28 20:16   ` Paul Menzel
2012-05-25 23:56 ` [PATCH 6/6] tests/dpf: simple dpf test Ben Widawsky

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.