[PATCH v2] drm/i915: Decode system memory bandwidth
Mahesh Kumar
mahesh1.kumar at intel.com
Mon Jul 9 13:59:00 UTC 2018
This patch adds support to decode system memory bandwidth and other
parameters, which will be used for arbitrated display memory
percentage calculation in GEN9 based systems and WM latency level-0
Work-around decision on GEN9+ platforms.
Signed-off-by: Mahesh Kumar <mahesh1.kumar at intel.com>
---
drivers/gpu/drm/i915/i915_drv.c | 233 ++++++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/i915_drv.h | 13 +++
drivers/gpu/drm/i915/i915_reg.h | 38 +++++++
drivers/gpu/drm/i915/intel_pm.c | 12 +++
4 files changed, 296 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 0db3c83cce29..c817ed62d130 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -1063,6 +1063,233 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv)
intel_gvt_sanitize_options(dev_priv);
}
+static enum memdev_rank
+skl_memdev_get_channel_rank(struct memdev_info *memdev_info, u32 val)
+{
+ u8 l_rank, s_rank;
+ u8 l_size, s_size;
+ u8 l_width, s_width;
+ enum memdev_rank rank;
+ bool found_16gb = false;
+
+ if (!val)
+ return I915_DRAM_RANK_INVALID;
+
+ l_size = (val >> SKL_DRAM_SIZE_L_SHIFT) & SKL_DRAM_SIZE_MASK;
+ s_size = (val >> SKL_DRAM_SIZE_S_SHIFT) & SKL_DRAM_SIZE_MASK;
+ l_width = (val >> SKL_DRAM_WIDTH_L_SHIFT) & SKL_DRAM_WIDTH_MASK;
+ s_width = (val >> SKL_DRAM_WIDTH_S_SHIFT) & SKL_DRAM_WIDTH_MASK;
+ l_rank = (val >> SKL_DRAM_RANK_L_SHIFT) & SKL_DRAM_RANK_MASK;
+ s_rank = (val >> SKL_DRAM_RANK_S_SHIFT) & SKL_DRAM_RANK_MASK;
+
+ if (l_size == 0 && s_size == 0)
+ return I915_DRAM_RANK_INVALID;
+
+ memdev_info->valid_dimm = true;
+
+ if (l_rank == SKL_DRAM_RANK_DUAL || s_rank == SKL_DRAM_RANK_DUAL)
+ rank = I915_DRAM_RANK_DUAL;
+ else if ((l_size && l_rank == SKL_DRAM_RANK_SINGLE) &&
+ (s_size && s_rank == SKL_DRAM_RANK_SINGLE))
+ rank = I915_DRAM_RANK_DUAL;
+ else
+ rank = I915_DRAM_RANK_SINGLE;
+
+ if ((l_size == 16 && l_width == SKL_DRAM_WIDTH_X8 &&
+ l_rank == SKL_DRAM_RANK_SINGLE) ||
+ (s_size == 16 && s_width == SKL_DRAM_WIDTH_X8 &&
+ s_rank == SKL_DRAM_RANK_SINGLE))
+ found_16gb = true;
+ else if ((l_size == 32 && l_width == SKL_DRAM_WIDTH_X8 &&
+ l_rank == SKL_DRAM_RANK_DUAL) ||
+ (s_size == 32 && s_width == SKL_DRAM_WIDTH_X8 &&
+ s_rank == SKL_DRAM_RANK_DUAL))
+ found_16gb = true;
+ else if ((l_size == 8 && l_width == SKL_DRAM_WIDTH_X16 &&
+ l_rank == SKL_DRAM_RANK_SINGLE) ||
+ (s_size == 8 && s_width == SKL_DRAM_WIDTH_X16 &&
+ s_rank == SKL_DRAM_RANK_SINGLE))
+ found_16gb = true;
+ else if ((l_size == 16 && l_width == SKL_DRAM_WIDTH_X16 &&
+ l_rank == SKL_DRAM_RANK_DUAL) ||
+ (s_size == 16 && s_width == SKL_DRAM_WIDTH_X16 &&
+ s_rank == SKL_DRAM_RANK_DUAL))
+ found_16gb = true;
+
+ if (memdev_info->is_16gb_dimm == false)
+ memdev_info->is_16gb_dimm = found_16gb;
+
+ return rank;
+}
+
+static int
+skl_get_dimm_info(struct drm_i915_private *dev_priv)
+{
+ struct memdev_info *memdev_info = &dev_priv->memdev_info;
+ enum memdev_rank ch0_rank, ch1_rank;
+ u32 val;
+
+ val = I915_READ(SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN);
+ DRM_INFO("Ch0 info : 0x%x\n", val);
+ ch0_rank = skl_memdev_get_channel_rank(memdev_info, val);
+ if (ch0_rank != I915_DRAM_RANK_INVALID)
+ memdev_info->num_channels++;
+
+ val = I915_READ(SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN);
+ DRM_INFO("Ch1 info : 0x%x\n", val);
+ ch1_rank = skl_memdev_get_channel_rank(memdev_info, val);
+ if (ch1_rank != I915_DRAM_RANK_INVALID)
+ memdev_info->num_channels++;
+
+ if (memdev_info->num_channels == 0) {
+ DRM_INFO("Number of memory channels is zero\n");
+ return -EINVAL;
+ }
+
+ /*
+ * If any of the channel is single rank channel, worst case output
+ * will be same as if single rank memory, so consider single rank
+ * memory.
+ */
+ if (ch0_rank == I915_DRAM_RANK_SINGLE ||
+ ch1_rank == I915_DRAM_RANK_SINGLE)
+ memdev_info->rank = I915_DRAM_RANK_SINGLE;
+ else
+ memdev_info->rank = max(ch0_rank, ch1_rank);
+
+ if (memdev_info->rank == I915_DRAM_RANK_INVALID) {
+ DRM_INFO("couldn't get memory rank information\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+skl_get_memdev_info(struct drm_i915_private *dev_priv)
+{
+ struct memdev_info *memdev_info = &dev_priv->memdev_info;
+ u32 mem_freq_khz, val;
+ int ret;
+
+ ret = skl_get_dimm_info(dev_priv);
+ if (ret)
+ return ret;
+
+ val = I915_READ(SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU);
+ mem_freq_khz = DIV_ROUND_UP((val & SKL_REQ_DATA_MASK) *
+ SKL_MEMORY_FREQ_MULTIPLIER_HZ, 1000);
+
+ memdev_info->bandwidth_kbps = memdev_info->num_channels *
+ mem_freq_khz * 8;
+
+ if (memdev_info->bandwidth_kbps == 0) {
+ DRM_INFO("Couldn't get system memory bandwidth\n");
+ return -EINVAL;
+ }
+
+ memdev_info->valid = true;
+ return 0;
+}
+
+static int
+bxt_get_memdev_info(struct drm_i915_private *dev_priv)
+{
+ struct memdev_info *memdev_info = &dev_priv->memdev_info;
+ u32 dram_channels;
+ u32 mem_freq_khz, val;
+ u8 num_active_channels;
+ int i;
+
+ val = I915_READ(BXT_P_CR_MC_BIOS_REQ_0_0_0);
+ mem_freq_khz = DIV_ROUND_UP((val & BXT_REQ_DATA_MASK) *
+ BXT_MEMORY_FREQ_MULTIPLIER_HZ, 1000);
+
+ dram_channels = (val >> BXT_DRAM_CHANNEL_ACTIVE_SHIFT) &
+ BXT_DRAM_CHANNEL_ACTIVE_MASK;
+ num_active_channels = hweight32(dram_channels);
+
+ /* Each active bit represents 4-byte channel */
+ memdev_info->bandwidth_kbps = (mem_freq_khz * num_active_channels * 4);
+
+ if (memdev_info->bandwidth_kbps == 0) {
+ DRM_ERROR("Couldn't get system memory bandwidth\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Now read each DUNIT8/9/10/11 to check the rank of each dimms.
+ */
+ for (i = BXT_D_CR_DRP0_DUNIT_START; i <= BXT_D_CR_DRP0_DUNIT_END; i++) {
+ val = I915_READ(BXT_D_CR_DRP0_DUNIT(i));
+ if (val != 0xFFFFFFFF) {
+ u8 rank;
+ enum memdev_rank ch_rank;
+
+ memdev_info->num_channels++;
+ rank = val & BXT_DRAM_RANK_MASK;
+ if (rank == BXT_DRAM_RANK_SINGLE)
+ ch_rank = I915_DRAM_RANK_SINGLE;
+ else if (rank == BXT_DRAM_RANK_DUAL)
+ ch_rank = I915_DRAM_RANK_DUAL;
+ else
+ ch_rank = I915_DRAM_RANK_INVALID;
+
+ /*
+ * If any of the channel is single rank channel,
+ * worst case output will be same as if single rank
+ * memory, so consider single rank memory.
+ */
+ if (memdev_info->rank == I915_DRAM_RANK_INVALID)
+ memdev_info->rank = ch_rank;
+ else if (ch_rank == I915_DRAM_RANK_SINGLE)
+ memdev_info->rank = I915_DRAM_RANK_SINGLE;
+ }
+ }
+
+ if (memdev_info->rank == I915_DRAM_RANK_INVALID) {
+ DRM_INFO("couldn't get memory rank information\n");
+ return -EINVAL;
+ }
+
+ memdev_info->valid = true;
+ memdev_info->valid_dimm = true;
+ return 0;
+}
+
+static void
+intel_get_memdev_info(struct drm_i915_private *dev_priv)
+{
+ struct memdev_info *memdev_info = &dev_priv->memdev_info;
+ int ret;
+
+ memdev_info->valid = false;
+ memdev_info->valid_dimm = false;
+ memdev_info->is_16gb_dimm = false;
+ memdev_info->rank = I915_DRAM_RANK_INVALID;
+ memdev_info->bandwidth_kbps = 0;
+ memdev_info->num_channels = 0;
+
+ if (INTEL_GEN(dev_priv) < 9)
+ return;
+
+ if (IS_BROXTON(dev_priv) || IS_GEMINILAKE(dev_priv))
+ ret = bxt_get_memdev_info(dev_priv);
+ else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+ ret = skl_get_memdev_info(dev_priv);
+ else
+ ret = skl_get_dimm_info(dev_priv);
+
+ if (ret)
+ return;
+
+ DRM_DEBUG_DRIVER("DRAM bandwidth: %u KBps, total-channels: %u\n",
+ memdev_info->bandwidth_kbps,
+ memdev_info->num_channels);
+ DRM_DEBUG_DRIVER("DRAM rank: %s rank 16GB-dimm=%s\n",
+ (memdev_info->rank == I915_DRAM_RANK_DUAL) ?
+ "dual" : "single", yesno(memdev_info->is_16gb_dimm));
+}
+
/**
* i915_driver_init_hw - setup state requiring device access
* @dev_priv: device private
@@ -1181,6 +1408,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
if (ret)
goto err_ggtt;
+ /*
+ * Fill the memdev structure to get the system raw bandwidth
+ * This will be used by WM algorithm, to implement GEN9 based WA
+ */
+ intel_get_memdev_info(dev_priv);
+
return 0;
err_ggtt:
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 09ab12458244..244adf8a30f1 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1912,6 +1912,19 @@ struct drm_i915_private {
bool distrust_bios_wm;
} wm;
+ struct memdev_info {
+ bool valid;
+ bool valid_dimm;
+ bool is_16gb_dimm;
+ u8 num_channels;
+ enum memdev_rank {
+ I915_DRAM_RANK_INVALID = 0,
+ I915_DRAM_RANK_SINGLE,
+ I915_DRAM_RANK_DUAL
+ } rank;
+ u32 bandwidth_kbps;
+ } memdev_info;
+
struct i915_runtime_pm runtime_pm;
struct {
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 0424e45f88db..fc8f387141f5 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -9421,6 +9421,44 @@ enum skl_power_gate {
#define DC_STATE_DEBUG_MASK_CORES (1 << 0)
#define DC_STATE_DEBUG_MASK_MEMORY_UP (1 << 1)
+#define BXT_P_CR_MC_BIOS_REQ_0_0_0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7114)
+#define BXT_REQ_DATA_MASK 0x3F
+#define BXT_DRAM_CHANNEL_ACTIVE_SHIFT 12
+#define BXT_DRAM_CHANNEL_ACTIVE_MASK 0xF
+#define BXT_MEMORY_FREQ_MULTIPLIER_HZ 133333333
+
+#define BXT_D_CR_DRP0_DUNIT8 0x1000
+#define BXT_D_CR_DRP0_DUNIT9 0x1200
+#define BXT_D_CR_DRP0_DUNIT_START 8
+#define BXT_D_CR_DRP0_DUNIT_END 11
+#define BXT_D_CR_DRP0_DUNIT(x) _MMIO(MCHBAR_MIRROR_BASE_SNB + \
+ _PICK_EVEN((x) - 8, BXT_D_CR_DRP0_DUNIT8,\
+ BXT_D_CR_DRP0_DUNIT9))
+#define BXT_DRAM_RANK_MASK 0x3
+#define BXT_DRAM_RANK_SINGLE 0x1
+#define BXT_DRAM_RANK_DUAL 0x3
+
+#define SKL_MEMORY_FREQ_MULTIPLIER_HZ 266666666
+#define SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5E04)
+#define SKL_REQ_DATA_MASK (0xF << 0)
+
+#define SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C)
+#define SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5010)
+#define SKL_DRAM_SIZE_MASK 0x3F
+#define SKL_DRAM_SIZE_L_SHIFT 0
+#define SKL_DRAM_SIZE_S_SHIFT 16
+#define SKL_DRAM_WIDTH_MASK 0x3
+#define SKL_DRAM_WIDTH_L_SHIFT 8
+#define SKL_DRAM_WIDTH_S_SHIFT 24
+#define SKL_DRAM_WIDTH_X8 0x0
+#define SKL_DRAM_WIDTH_X16 0x1
+#define SKL_DRAM_WIDTH_X32 0x2
+#define SKL_DRAM_RANK_MASK 0x1
+#define SKL_DRAM_RANK_L_SHIFT 10
+#define SKL_DRAM_RANK_S_SHIFT 26
+#define SKL_DRAM_RANK_SINGLE 0x0
+#define SKL_DRAM_RANK_DUAL 0x1
+
/* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register,
* since on HSW we can't write to it using I915_WRITE. */
#define D_COMP_HSW _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5F0C)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 53aaaa3e6886..34a688d9b780 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2874,6 +2874,18 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
}
}
+ /*
+ * WA Level-0 adjustment for 16GB DIMMs: SKL+
+ * If we could not get dimm info enable this WA to prevent from
+ * any underrun.
+ */
+ if (dev_priv->memdev_info.valid_dimm) {
+ if (dev_priv->memdev_info.is_16gb_dimm)
+ wm[0] += 1;
+ } else {
+ wm[0] += 1;
+ }
+
} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
uint64_t sskpd = I915_READ64(MCH_SSKPD);
--
2.16.2
More information about the Intel-gfx-trybot
mailing list