Commit 3873218f authored by Jeff McGee's avatar Jeff McGee Committed by Daniel Vetter

drm/i915/skl: Determine SKL slice/subslice/EU info

Read fuse registers to determine the available slice total,
subslice total, subslice per slice, EU total, and EU per subslice
counts of the SKL device. The EU per subslice attribute is more
precisely defined as the maximum EU available on any one subslice,
since available EU counts may vary across subslices due to fusing.
Set flags indicating the SKL device's slice/subslice/EU (SSEU)
power gating capability. Make all values available via debugfs
entry 'i915_sseu_status'.

v2: Several small clean-ups suggested by Damien. Most notably,
    used smaller types for the new device info fields to reduce
    memory usage and improved the clarity/readability of the
    method used to extract attribute values from the fuse
    registers.
Signed-off-by: default avatarJeff McGee <jeff.mcgee@intel.com>
Reviewed-by: default avatarDamien Lespiau <damien.lespiau@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent d0bbbc4f
...@@ -4358,6 +4358,35 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops, ...@@ -4358,6 +4358,35 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops,
i915_cache_sharing_get, i915_cache_sharing_set, i915_cache_sharing_get, i915_cache_sharing_set,
"%llu\n"); "%llu\n");
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;
if (INTEL_INFO(dev)->gen < 9)
return -ENODEV;
seq_puts(m, "SSEU Device Info\n");
seq_printf(m, " Available Slice Total: %u\n",
INTEL_INFO(dev)->slice_total);
seq_printf(m, " Available Subslice Total: %u\n",
INTEL_INFO(dev)->subslice_total);
seq_printf(m, " Available Subslice Per Slice: %u\n",
INTEL_INFO(dev)->subslice_per_slice);
seq_printf(m, " Available EU Total: %u\n",
INTEL_INFO(dev)->eu_total);
seq_printf(m, " Available EU Per Subslice: %u\n",
INTEL_INFO(dev)->eu_per_subslice);
seq_printf(m, " Has Slice Power Gating: %s\n",
yesno(INTEL_INFO(dev)->has_slice_pg));
seq_printf(m, " Has Subslice Power Gating: %s\n",
yesno(INTEL_INFO(dev)->has_subslice_pg));
seq_printf(m, " Has EU Power Gating: %s\n",
yesno(INTEL_INFO(dev)->has_eu_pg));
return 0;
}
static int i915_forcewake_open(struct inode *inode, struct file *file) static int i915_forcewake_open(struct inode *inode, struct file *file)
{ {
struct drm_device *dev = inode->i_private; struct drm_device *dev = inode->i_private;
...@@ -4471,6 +4500,7 @@ static const struct drm_info_list i915_debugfs_list[] = { ...@@ -4471,6 +4500,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_dp_mst_info", i915_dp_mst_info, 0}, {"i915_dp_mst_info", i915_dp_mst_info, 0},
{"i915_wa_registers", i915_wa_registers, 0}, {"i915_wa_registers", i915_wa_registers, 0},
{"i915_ddb_info", i915_ddb_info, 0}, {"i915_ddb_info", i915_ddb_info, 0},
{"i915_sseu_status", i915_sseu_status, 0},
}; };
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
......
...@@ -606,6 +606,7 @@ static void intel_device_info_runtime_init(struct drm_device *dev) ...@@ -606,6 +606,7 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
} }
} }
/* Initialize slice/subslice/EU info */
if (IS_CHERRYVIEW(dev)) { if (IS_CHERRYVIEW(dev)) {
u32 fuse, mask_eu; u32 fuse, mask_eu;
...@@ -615,7 +616,79 @@ static void intel_device_info_runtime_init(struct drm_device *dev) ...@@ -615,7 +616,79 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
CHV_FGT_EU_DIS_SS1_R0_MASK | CHV_FGT_EU_DIS_SS1_R0_MASK |
CHV_FGT_EU_DIS_SS1_R1_MASK); CHV_FGT_EU_DIS_SS1_R1_MASK);
info->eu_total = 16 - hweight32(mask_eu); info->eu_total = 16 - hweight32(mask_eu);
} else if (IS_SKYLAKE(dev)) {
const int s_max = 3, ss_max = 4, 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 & GEN9_F2_SS_DIS_MASK) >>
GEN9_F2_SS_DIS_SHIFT;
eu_disable[0] = I915_READ(GEN8_EU_DISABLE0);
eu_disable[1] = I915_READ(GEN8_EU_DISABLE1);
eu_disable[2] = I915_READ(GEN8_EU_DISABLE2);
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++) {
if (ss_disable & (0x1 << ss))
/* skip disabled subslice */
continue;
info->eu_total += eu_max -
hweight8(eu_disable[s] >>
(ss * eu_max));
}
}
/*
* SKL 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;
/*
* SKL supports slice power gating on devices with more than
* one slice, and supports EU power gating on devices with
* more than one EU pair per subslice.
*/
info->has_slice_pg = (info->slice_total > 1) ? 1 : 0;
info->has_subslice_pg = 0;
info->has_eu_pg = (info->eu_per_subslice > 2) ? 1 : 0;
} }
DRM_DEBUG_DRIVER("slice total: %u\n", info->slice_total);
DRM_DEBUG_DRIVER("subslice total: %u\n", info->subslice_total);
DRM_DEBUG_DRIVER("subslice per slice: %u\n", info->subslice_per_slice);
DRM_DEBUG_DRIVER("EU total: %u\n", info->eu_total);
DRM_DEBUG_DRIVER("EU per subslice: %u\n", info->eu_per_subslice);
DRM_DEBUG_DRIVER("has slice power gating: %s\n",
info->has_slice_pg ? "y" : "n");
DRM_DEBUG_DRIVER("has subslice power gating: %s\n",
info->has_subslice_pg ? "y" : "n");
DRM_DEBUG_DRIVER("has EU power gating: %s\n",
info->has_eu_pg ? "y" : "n");
} }
/** /**
......
...@@ -693,7 +693,16 @@ struct intel_device_info { ...@@ -693,7 +693,16 @@ struct intel_device_info {
int trans_offsets[I915_MAX_TRANSCODERS]; int trans_offsets[I915_MAX_TRANSCODERS];
int palette_offsets[I915_MAX_PIPES]; int palette_offsets[I915_MAX_PIPES];
int cursor_offsets[I915_MAX_PIPES]; int cursor_offsets[I915_MAX_PIPES];
unsigned int eu_total;
/* Slice/subslice/EU info */
u8 slice_total;
u8 subslice_total;
u8 subslice_per_slice;
u8 eu_total;
u8 eu_per_subslice;
u8 has_slice_pg:1;
u8 has_subslice_pg:1;
u8 has_eu_pg:1;
}; };
#undef DEFINE_FLAG #undef DEFINE_FLAG
......
...@@ -1516,6 +1516,17 @@ enum skl_disp_power_wells { ...@@ -1516,6 +1516,17 @@ enum skl_disp_power_wells {
#define CHV_FGT_EU_DIS_SS1_R1_SHIFT 28 #define CHV_FGT_EU_DIS_SS1_R1_SHIFT 28
#define CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT) #define CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
#define GEN8_FUSE2 0x9120
#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_DISABLE1 0x9138
#define GEN8_EU_DISABLE2 0x913c
#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 #define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050
#define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0) #define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0)
#define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2) #define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment