drm/i915/bdw: Check for slice, subslice and EU count for BDW
authorŁukasz Daniluk <lukasz.daniluk@intel.com>
Fri, 25 Sep 2015 09:54:58 +0000 (11:54 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 30 Sep 2015 12:13:03 +0000 (14:13 +0200)
Added checks for available slices, subslices and EUs for Broadwell. This
information is filled in intel_device_info and is available to user with
GET_PARAM.
Added checks for enabled slices, subslices and EU for Broadwell. This
information is based on available counts but takes power gated slices
into account. It can be read in debugfs.
Introduce new register defines that contain information on slices on
Broadwell.

v2:
- Introduce GT_SLICE_INFO register
- Change Broadwell sseu_device_status function to use GT_SLICE_INFO
  register instead of RPCS register
- Undo removal of dev_priv variables in Cherryview and Gen9
  sseu_device_satus functions

v3:
- Fix style issues

v4:
- Corrected comment
- Reverted reordering of defines

Cc: Jeff Mcgee <jeff.mcgee@intel.com>
Cc: Arun Siluvery <arun.siluvery@linux.intel.com>
Signed-off-by: Łukasz Daniluk <lukasz.daniluk@intel.com>
Reviewed-by: Jeff McGee <jeff.mcgee@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_reg.h

index 9839831dd6e58c0a418be2122c4a9187f0d6026a..2ac1ba8135934d811b5ea01d55ad42f2f6d0abea 100644 (file)
@@ -5048,13 +5048,38 @@ static void gen9_sseu_device_status(struct drm_device *dev,
        }
 }
 
+static void broadwell_sseu_device_status(struct drm_device *dev,
+                                        struct sseu_dev_status *stat)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int s;
+       u32 slice_info = I915_READ(GEN8_GT_SLICE_INFO);
+
+       stat->slice_total = hweight32(slice_info & GEN8_LSLICESTAT_MASK);
+
+       if (stat->slice_total) {
+               stat->subslice_per_slice = INTEL_INFO(dev)->subslice_per_slice;
+               stat->subslice_total = stat->slice_total *
+                                      stat->subslice_per_slice;
+               stat->eu_per_subslice = INTEL_INFO(dev)->eu_per_subslice;
+               stat->eu_total = stat->eu_per_subslice * stat->subslice_total;
+
+               /* subtract fused off EU(s) from enabled slice(s) */
+               for (s = 0; s < stat->slice_total; s++) {
+                       u8 subslice_7eu = INTEL_INFO(dev)->subslice_7eu[s];
+
+                       stat->eu_total -= hweight8(subslice_7eu);
+               }
+       }
+}
+
 static int i915_sseu_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        struct sseu_dev_status stat;
 
-       if ((INTEL_INFO(dev)->gen < 8) || IS_BROADWELL(dev))
+       if (INTEL_INFO(dev)->gen < 8)
                return -ENODEV;
 
        seq_puts(m, "SSEU Device Info\n");
@@ -5079,6 +5104,8 @@ static int i915_sseu_status(struct seq_file *m, void *unused)
        memset(&stat, 0, sizeof(stat));
        if (IS_CHERRYVIEW(dev)) {
                cherryview_sseu_device_status(dev, &stat);
+       } else if (IS_BROADWELL(dev)) {
+               broadwell_sseu_device_status(dev, &stat);
        } else if (INTEL_INFO(dev)->gen >= 9) {
                gen9_sseu_device_status(dev, &stat);
        }
index ae1ba47e4ef0b0a19aac03a104fee3ac661e22d5..20b4b7924f517c06f827b2ef0b074e38cd3997dd 100644 (file)
@@ -702,6 +702,82 @@ static void gen9_sseu_info_init(struct drm_device *dev)
        info->has_eu_pg = (info->eu_per_subslice > 2);
 }
 
+static void broadwell_sseu_info_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_device_info *info;
+       const int s_max = 3, ss_max = 3, eu_max = 8;
+       int s, ss;
+       u32 fuse2, eu_disable[s_max], s_enable, ss_disable;
+
+       fuse2 = I915_READ(GEN8_FUSE2);
+       s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
+       ss_disable = (fuse2 & GEN8_F2_SS_DIS_MASK) >> GEN8_F2_SS_DIS_SHIFT;
+
+       eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK;
+       eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) |
+                       ((I915_READ(GEN8_EU_DISABLE1) & GEN8_EU_DIS1_S1_MASK) <<
+                        (32 - GEN8_EU_DIS0_S1_SHIFT));
+       eu_disable[2] = (I915_READ(GEN8_EU_DISABLE1) >> GEN8_EU_DIS1_S2_SHIFT) |
+                       ((I915_READ(GEN8_EU_DISABLE2) & GEN8_EU_DIS2_S2_MASK) <<
+                        (32 - GEN8_EU_DIS1_S2_SHIFT));
+
+
+       info = (struct intel_device_info *)&dev_priv->info;
+       info->slice_total = hweight32(s_enable);
+
+       /*
+        * The subslice disable field is global, i.e. it applies
+        * to each of the enabled slices.
+        */
+       info->subslice_per_slice = ss_max - hweight32(ss_disable);
+       info->subslice_total = info->slice_total * info->subslice_per_slice;
+
+       /*
+        * Iterate through enabled slices and subslices to
+        * count the total enabled EU.
+        */
+       for (s = 0; s < s_max; s++) {
+               if (!(s_enable & (0x1 << s)))
+                       /* skip disabled slice */
+                       continue;
+
+               for (ss = 0; ss < ss_max; ss++) {
+                       u32 n_disabled;
+
+                       if (ss_disable & (0x1 << ss))
+                               /* skip disabled subslice */
+                               continue;
+
+                       n_disabled = hweight8(eu_disable[s] >> (ss * eu_max));
+
+                       /*
+                        * Record which subslices have 7 EUs.
+                        */
+                       if (eu_max - n_disabled == 7)
+                               info->subslice_7eu[s] |= 1 << ss;
+
+                       info->eu_total += eu_max - n_disabled;
+               }
+       }
+
+       /*
+        * BDW is expected to always have a uniform distribution of EU across
+        * subslices with the exception that any one EU in any one subslice may
+        * be fused off for die recovery.
+        */
+       info->eu_per_subslice = info->subslice_total ?
+               DIV_ROUND_UP(info->eu_total, info->subslice_total) : 0;
+
+       /*
+        * BDW supports slice power gating on devices with more than
+        * one slice.
+        */
+       info->has_slice_pg = (info->slice_total > 1);
+       info->has_subslice_pg = 0;
+       info->has_eu_pg = 0;
+}
+
 /*
  * Determine various intel_device_info fields at runtime.
  *
@@ -772,6 +848,8 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
        /* Initialize slice/subslice/EU info */
        if (IS_CHERRYVIEW(dev))
                cherryview_sseu_info_init(dev);
+       else if (IS_BROADWELL(dev))
+               broadwell_sseu_info_init(dev);
        else if (INTEL_INFO(dev)->gen >= 9)
                gen9_sseu_info_init(dev);
 
index 3709d6b2559f411ec3f605440bafebb05f6d753a..0b2e3148a5bf39960917119d6784cdba38c00c9f 100644 (file)
@@ -1887,12 +1887,27 @@ enum skl_disp_power_wells {
 #define   CHV_FGT_EU_DIS_SS1_R1_MASK   (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
 
 #define GEN8_FUSE2                     0x9120
+#define   GEN8_F2_SS_DIS_SHIFT         21
+#define   GEN8_F2_SS_DIS_MASK          (0x7 << GEN8_F2_SS_DIS_SHIFT)
 #define   GEN8_F2_S_ENA_SHIFT          25
 #define   GEN8_F2_S_ENA_MASK           (0x7 << GEN8_F2_S_ENA_SHIFT)
 
 #define   GEN9_F2_SS_DIS_SHIFT         20
 #define   GEN9_F2_SS_DIS_MASK          (0xf << GEN9_F2_SS_DIS_SHIFT)
 
+#define GEN8_EU_DISABLE0               0x9134
+#define   GEN8_EU_DIS0_S0_MASK         0xffffff
+#define   GEN8_EU_DIS0_S1_SHIFT                24
+#define   GEN8_EU_DIS0_S1_MASK         (0xff << GEN8_EU_DIS0_S1_SHIFT)
+
+#define GEN8_EU_DISABLE1               0x9138
+#define   GEN8_EU_DIS1_S1_MASK         0xffff
+#define   GEN8_EU_DIS1_S2_SHIFT                16
+#define   GEN8_EU_DIS1_S2_MASK         (0xffff << GEN8_EU_DIS1_S2_SHIFT)
+
+#define GEN8_EU_DISABLE2               0x913c
+#define   GEN8_EU_DIS2_S2_MASK         0xff
+
 #define GEN9_EU_DISABLE(slice)         (0x9134 + (slice)*0x4)
 
 #define GEN6_BSD_SLEEP_PSMI_CONTROL    0x12050
@@ -6885,6 +6900,9 @@ enum skl_disp_power_wells {
 #define   GEN6_RC6                     3
 #define   GEN6_RC7                     4
 
+#define GEN8_GT_SLICE_INFO             0x138064
+#define   GEN8_LSLICESTAT_MASK         0x7
+
 #define CHV_POWER_SS0_SIG1             0xa720
 #define CHV_POWER_SS1_SIG1             0xa728
 #define   CHV_SS_PG_ENABLE             (1<<1)