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.vers...@linux.intel.com>
CC: Bryan Bell <bryan.j.b...@intel.com>
Signed-off-by: Ben Widawsky <b...@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

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

Reply via email to