drm/i915: allow cache sharing policy control
Jesse Barnes [Wed, 3 Aug 2011 18:28:44 +0000 (11:28 -0700)]
Expose the SNB+ cache sharing policy register in debugfs.  The new file,
i915_cache_sharing, has 4 values, 0-3, with 0 being "max uncore
resources" and 3 being the minimum.  Exposing this control should make
benchmarking easier and help us choose a good default.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Keith Packard <keithp@keithp.com>

drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_reg.h

index 5bf7bf5..a8ab626 100644 (file)
@@ -1408,6 +1408,85 @@ static const struct file_operations i915_max_freq_fops = {
        .llseek = default_llseek,
 };
 
+static int
+i915_cache_sharing_open(struct inode *inode,
+                  struct file *filp)
+{
+       filp->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t
+i915_cache_sharing_read(struct file *filp,
+                  char __user *ubuf,
+                  size_t max,
+                  loff_t *ppos)
+{
+       struct drm_device *dev = filp->private_data;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       char buf[80];
+       u32 snpcr;
+       int len;
+
+       mutex_lock(&dev_priv->dev->struct_mutex);
+       snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
+       mutex_unlock(&dev_priv->dev->struct_mutex);
+
+       len = snprintf(buf, sizeof (buf),
+                      "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >>
+                      GEN6_MBC_SNPCR_SHIFT);
+
+       if (len > sizeof (buf))
+               len = sizeof (buf);
+
+       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+}
+
+static ssize_t
+i915_cache_sharing_write(struct file *filp,
+                 const char __user *ubuf,
+                 size_t cnt,
+                 loff_t *ppos)
+{
+       struct drm_device *dev = filp->private_data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       char buf[20];
+       u32 snpcr;
+       int val = 1;
+
+       if (cnt > 0) {
+               if (cnt > sizeof (buf) - 1)
+                       return -EINVAL;
+
+               if (copy_from_user(buf, ubuf, cnt))
+                       return -EFAULT;
+               buf[cnt] = 0;
+
+               val = simple_strtoul(buf, NULL, 0);
+       }
+
+       if (val < 0 || val > 3)
+               return -EINVAL;
+
+       DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val);
+
+       /* Update the cache sharing policy here as well */
+       snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
+       snpcr &= ~GEN6_MBC_SNPCR_MASK;
+       snpcr |= (val << GEN6_MBC_SNPCR_SHIFT);
+       I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
+
+       return cnt;
+}
+
+static const struct file_operations i915_cache_sharing_fops = {
+       .owner = THIS_MODULE,
+       .open = i915_cache_sharing_open,
+       .read = i915_cache_sharing_read,
+       .write = i915_cache_sharing_write,
+       .llseek = default_llseek,
+};
+
 /* As the drm_debugfs_init() routines are called before dev->dev_private is
  * allocated we need to hook into the minor for release. */
 static int
@@ -1522,6 +1601,21 @@ static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor)
        return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops);
 }
 
+static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor)
+{
+       struct drm_device *dev = minor->dev;
+       struct dentry *ent;
+
+       ent = debugfs_create_file("i915_cache_sharing",
+                                 S_IRUGO | S_IWUSR,
+                                 root, dev,
+                                 &i915_cache_sharing_fops);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+
+       return drm_add_fake_info_node(minor, ent, &i915_cache_sharing_fops);
+}
+
 static struct drm_info_list i915_debugfs_list[] = {
        {"i915_capabilities", i915_capabilities, 0},
        {"i915_gem_objects", i915_gem_object_info, 0},
@@ -1578,6 +1672,9 @@ int i915_debugfs_init(struct drm_minor *minor)
        ret = i915_max_freq_create(minor->debugfs_root, minor);
        if (ret)
                return ret;
+       ret = i915_cache_sharing_create(minor->debugfs_root, minor);
+       if (ret)
+               return ret;
 
        return drm_debugfs_create_files(i915_debugfs_list,
                                        I915_DEBUGFS_ENTRIES,
@@ -1594,6 +1691,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
                                 1, minor);
        drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops,
                                 1, minor);
+       drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops,
+                                1, minor);
 }
 
 #endif /* CONFIG_DEBUG_FS */
index 56cae72..d1331f7 100644 (file)
 #define  GRDOM_RENDER  (1<<2)
 #define  GRDOM_MEDIA   (3<<2)
 
+#define GEN6_MBCUNIT_SNPCR     0x900c /* for LLC config */
+#define   GEN6_MBC_SNPCR_SHIFT 21
+#define   GEN6_MBC_SNPCR_MASK  (3<<21)
+#define   GEN6_MBC_SNPCR_MAX   (0<<21)
+#define   GEN6_MBC_SNPCR_MED   (1<<21)
+#define   GEN6_MBC_SNPCR_LOW   (2<<21)
+#define   GEN6_MBC_SNPCR_MIN   (3<<21) /* only 1/16th of the cache is shared */
+
 #define GEN6_GDRST     0x941c
 #define  GEN6_GRDOM_FULL               (1 << 0)
 #define  GEN6_GRDOM_RENDER             (1 << 1)