[PATCH] [v2] drm/i915: Expose LLC size to user space

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The algorithm/information was originally written by Chad, though I
changed the control flow, and I think his original code had a couple of
bugs, though I didn't look very hard before rewriting. That could have
also been different interpretations of the spec.

I've tested this on two platforms, and it seems to perform how I want.

With this patch is a small tool for igt to query the size. This can be
used as a reference for DRI clients wishing to query the information.

v2: Update name of the SDM location (Bryan)
Dissent: Use a new param instead of reusing HAS_LLC param (Chris, Chad)
Fix unicode multiply symbol (Ben)

CC: Chad Versace <chad.versace at linux.intel.com>
CC: Bryan Bell <bryan.j.bell at intel.com>
Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_dma.c |  3 +++
 drivers/gpu/drm/i915/i915_drv.h |  2 ++
 drivers/gpu/drm/i915/i915_gem.c | 55 +++++++++++++++++++++++++++++++++++++++++
 include/uapi/drm/i915_drm.h     |  1 +
 4 files changed, 61 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 0e22142..1224586 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1000,6 +1000,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
 	case I915_PARAM_HAS_EXEC_HANDLE_LUT:
 		value = 1;
 		break;
+	case I915_PARAM_LLC_SIZE:
+		value = dev_priv->llc_size;
+		break;
 	default:
 		DRM_DEBUG("Unknown parameter %d\n", param->param);
 		return -EINVAL;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c8d6104..43a549d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1187,6 +1187,8 @@ typedef struct drm_i915_private {
 	/* Old dri1 support infrastructure, beware the dragons ya fools entering
 	 * here! */
 	struct i915_dri1_state dri1;
+
+	size_t llc_size;
 } drm_i915_private_t;
 
 /* Iterate over initialised rings */
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index af61be8..629837d 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4282,6 +4282,59 @@ i915_gem_lastclose(struct drm_device *dev)
 		DRM_ERROR("failed to idle hardware: %d\n", ret);
 }
 
+/**
+ * Return the size, in bytes, of the CPU L3 cache size. If the CPU has no L3
+ * cache, or if an error occurs in obtaining the cache size, then return 0.
+ * From Intel 64 and IA32 Architectures Developer's Manual: Vol. 2A -> section
+ * 3.2 -> CPUID
+ *
+ * Deterministic Cache Parmaeters (Function 04h)":
+ *    When EAX is initialized to a value of 4, the CPUID instruction returns
+ *    deterministic cache information in the EAX, EBX, ECX and EDX registers.
+ *    This function requires ECX be initialized with an index which indicates
+ *    which cache to return information about. The OS is expected to call this
+ *    function (CPUID.4) with ECX = 0, 1, 2, until EAX[4:0] == 0, indicating no
+ *    more caches. The order in which the caches are returned is not specified
+ *    and may change at Intel's discretion.
+ *
+ * Calculating the Cache Size in bytes:
+ *          = (Ways +1) * (Partitions +1) * (Line Size +1) * (Sets +1)
+ *          = (EBX[31:22] +1) * (EBX[21:12] +1) * (EBX[11:0] +1 * (ECX + 1)
+ */
+static size_t get_llc_size(struct drm_device *dev)
+{
+	u8 cnt = 0;
+	unsigned int eax, ebx, ecx, edx;
+
+	if (!HAS_LLC(dev))
+		return 0;
+
+	do {
+		uint32_t cache_level;
+		uint32_t associativity, line_partitions, line_size, sets;
+
+		eax = 4;
+		ecx = cnt;
+		__cpuid(&eax, &ebx, &ecx, &edx);
+
+		cache_level = (eax >> 5) & 0x7;
+		if (cache_level != 3)
+			continue;
+
+		associativity = ((ebx >> 22) & 0x3ff) + 1;
+		line_partitions = ((ebx >> 12) & 0x3ff) + 1;
+		line_size = (ebx & 0xfff) + 1;
+		sets = ecx + 1;
+
+		return associativity * line_partitions * line_size * sets;
+	} while (eax & 0x1f && ++cnt);
+
+	/* Let user space know we have non-zero LLC, we can't figure it out */
+	DRM_DEBUG_DRIVER("Couldn't find LLC size. Bug?\n");
+	return 1;
+}
+
+
 static void
 init_ring_lists(struct intel_ring_buffer *ring)
 {
@@ -4333,6 +4386,8 @@ i915_gem_load(struct drm_device *dev)
 	else
 		dev_priv->num_fence_regs = 8;
 
+	dev_priv->llc_size = get_llc_size(dev);
+
 	/* Initialize fence registers to zero */
 	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
 	i915_gem_restore_fences(dev);
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 923ed7f..c54559e 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -310,6 +310,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_PINNED_BATCHES	 24
 #define I915_PARAM_HAS_EXEC_NO_RELOC	 25
 #define I915_PARAM_HAS_EXEC_HANDLE_LUT   26
+#define I915_PARAM_LLC_SIZE		 27
 
 typedef struct drm_i915_getparam {
 	int param;
-- 
1.8.3.2



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux