This patch adds support to decode system memory bandwidth
which will be used for arbitrated display memory percentage
calculation in GEN9 based system.

Changes from v1:
 - Address comments from Paulo
 - implement decode function for SKL/KBL also
Changes from v2:
 - Rewrite the code as per HW team inputs
 - Addresses review comments

Signed-off-by: Mahesh Kumar <mahesh1.ku...@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.c | 173 ++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_drv.h |  12 +++
 drivers/gpu/drm/i915/i915_reg.h |  37 +++++++++
 3 files changed, 222 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 4074601..f79bf92 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -976,6 +976,173 @@ static void intel_sanitize_options(struct 
drm_i915_private *dev_priv)
        DRM_DEBUG_DRIVER("use GPU sempahores? %s\n", yesno(i915.semaphores));
 }
 
+static inline void skl_memdev_get_channel_rank(uint32_t val, enum rank *rank)
+{
+       uint8_t l_rank, s_rank;
+       uint8_t l_size, s_size;
+       enum rank ch_rank = DRAM_RANK_SINGLE;
+
+       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_rank = (val >> SKL_DRAM_RANK_L_SHIFT) & SKL_DRAM_RANK_MASK;
+       s_rank = (val >> SKL_DRAM_RANK_S_SHIFT) & SKL_DRAM_RANK_MASK;
+
+       /*
+        * If any of the slot has dual rank memory consider
+        * dual rank memory channel
+        */
+       if (l_rank == SKL_DRAM_RANK_DUAL || s_rank == SKL_DRAM_RANK_DUAL)
+               ch_rank = DRAM_RANK_DUAL;
+
+       /*
+        * If both the slot has single rank memory then configuration
+        * is dual rank memory
+        */
+       if ((l_size && l_rank == SKL_DRAM_RANK_SINGLE) &&
+               (s_size && s_rank == SKL_DRAM_RANK_SINGLE))
+               ch_rank = DRAM_RANK_DUAL;
+       *rank = ch_rank;
+}
+
+static int
+skl_get_memdev_info(struct drm_i915_private *dev_priv)
+{
+       struct memdev_info *memdev_info = &dev_priv->memdev_info;
+       uint32_t mem_freq_khz;
+       uint32_t val;
+       enum rank ch0_rank, ch1_rank;
+
+       val = I915_READ(SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU);
+       mem_freq_khz = (val & SKL_REQ_DATA_MASK) *
+                               SKL_MEMORY_FREQ_MULTIPLIER_KHZ;
+
+       val = I915_READ(SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN);
+       if (val != 0x0) {
+               memdev_info->num_channels++;
+               skl_memdev_get_channel_rank(val, &ch0_rank);
+       }
+
+       val = I915_READ(SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN);
+       if (val != 0x0) {
+               memdev_info->num_channels++;
+               skl_memdev_get_channel_rank(val, &ch1_rank);
+       }
+
+       if (memdev_info->num_channels == 0) {
+               DRM_ERROR("Number of mem channels are zero\n");
+               return -EINVAL;
+       }
+
+       memdev_info->bandwidth_kbps = (memdev_info->num_channels *
+                                                       mem_freq_khz * 8);
+
+       if (memdev_info->bandwidth_kbps == 0) {
+               DRM_ERROR("Couldn't get system memory bandwidth\n");
+               return -EINVAL;
+       }
+       memdev_info->valid = true;
+
+       /*
+        * If any of channel is single rank channel,
+        * consider single rank memory
+        */
+       if (ch0_rank == DRAM_RANK_SINGLE || ch1_rank == DRAM_RANK_SINGLE)
+               memdev_info->rank = DRAM_RANK_SINGLE;
+       else
+               memdev_info->rank = max(ch0_rank, ch1_rank);
+
+       return 0;
+}
+
+static int
+bxt_get_memdev_info(struct drm_i915_private *dev_priv)
+{
+       struct memdev_info *memdev_info = &dev_priv->memdev_info;
+       uint32_t dram_channels;
+       uint32_t mem_freq_khz, val;
+       uint8_t num_active_channels;
+       int i;
+
+       val = I915_READ(BXT_P_CR_MC_BIOS_REQ_0_0_0);
+       mem_freq_khz = ((val & BXT_REQ_DATA_MASK) *
+                               BXT_MEMORY_FREQ_MULTIPLIER_KHZ);
+
+       dram_channels = (val >> BXT_DRAM_CHANNEL_ACTIVE_SHIFT) &
+                                       BXT_DRAM_CHANNEL_ACTIVE_MASK;
+       num_active_channels = hweight32(dram_channels);
+
+       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;
+       }
+       memdev_info->valid = true;
+
+       /*
+        * Now read each DUNIT8/9/10/11 to check the rank of each dimms.
+        */
+       for (i = 0; i < BXT_D_CR_DRP0_DUNIT_MAX; i++) {
+               val = I915_READ(BXT_D_CR_DRP0_DUNIT(i));
+               if (val != 0xFFFFFFFF) {
+                       uint8_t rank;
+                       enum rank ch_rank;
+
+                       memdev_info->num_channels++;
+                       rank = val & BXT_DRAM_RANK_MASK;
+                       if (rank == BXT_DRAM_RANK_SINGLE)
+                               ch_rank = DRAM_RANK_SINGLE;
+                       else if (rank == BXT_DRAM_RANK_DUAL)
+                               ch_rank = DRAM_RANK_DUAL;
+                       else
+                               ch_rank = DRAM_RANK_INVALID;
+
+                       /*
+                        * If any of channel is having single rank memory
+                        * consider memory as single rank
+                        */
+                       if (memdev_info->rank == DRAM_RANK_INVALID)
+                               memdev_info->rank = ch_rank;
+                       else if (ch_rank == DRAM_RANK_SINGLE)
+                               memdev_info->rank = DRAM_RANK_SINGLE;
+               }
+       }
+       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->rank = DRAM_RANK_INVALID;
+       memdev_info->num_channels = 0;
+
+       if (!IS_GEN9(dev_priv))
+               return;
+
+       if (IS_BROXTON(dev_priv))
+               ret = bxt_get_memdev_info(dev_priv);
+       else
+               ret = skl_get_memdev_info(dev_priv);
+       if (ret)
+               return;
+
+       DRM_DEBUG_DRIVER("DRAM bandwidth: %d KBps total-channels: %d\n",
+                               memdev_info->bandwidth_kbps,
+                               memdev_info->num_channels);
+       if (memdev_info->rank == DRAM_RANK_INVALID)
+               DRM_INFO("Counld not get memory rank info\n");
+       else {
+               DRM_DEBUG_DRIVER("DRAM rank: %s\n",
+                               (memdev_info->rank == DRAM_RANK_DUAL) ?
+                                               "dual" : "single");
+       }
+}
+
+
 /**
  * i915_driver_init_hw - setup state requiring device access
  * @dev_priv: device private
@@ -1078,6 +1245,12 @@ static int i915_driver_init_hw(struct drm_i915_private 
*dev_priv)
                        DRM_DEBUG_DRIVER("can't enable MSI");
        }
 
+       /*
+        * 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;
 
 out_ggtt:
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 20691e9..171163c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2168,6 +2168,18 @@ struct drm_i915_private {
                bool distrust_bios_wm;
        } wm;
 
+       struct memdev_info {
+               bool valid;
+               uint32_t bandwidth_kbps;
+               uint8_t num_channels;
+               enum rank {
+                       DRAM_RANK_INVALID = 0,
+                       DRAM_RANK_SINGLE,
+                       DRAM_RANK_DUAL
+               } rank;
+       } memdev_info;
+
+
        struct i915_runtime_pm pm;
 
        /* Abstract the submission mechanism (legacy ringbuffer or execlists) 
away */
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 300418a..9a06810 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7672,6 +7672,43 @@ enum {
 #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_ACTIVE_CHANNEL_SHIFT          12
+#define BXT_DRAM_ACTIVE_CHANNEL_MASK           0xF
+/*
+ * BIOS programs this field of REQ_DATA [5:0] in integer
+ * multiple of 133333 KHz (133.33MHz)
+ */
+#define        BXT_MEMORY_FREQ_MULTIPLIER_KHZ          133333
+#define BXT_D_CR_DRP0_DUNIT8                   0x1000
+#define BXT_D_CR_DRP0_DUNIT9                   0x1200
+#define BXT_D_CR_DRP0_DUNIT_MAX                        4
+#define _MMIO_MCHBAR_DUNIT(x, a, b) _MMIO(MCHBAR_MIRROR_BASE_SNB + (a) + 
(x)*((b)-(a)))
+#define BXT_D_CR_DRP0_DUNIT(x) _MMIO_MCHBAR_DUNIT(x, BXT_D_CR_DRP0_DUNIT8, 
BXT_D_CR_DRP0_DUNIT9)
+#define BXT_DRAM_CHANNEL_ACTIVE_SHIFT          12
+#define BXT_DRAM_CHANNEL_ACTIVE_MASK           0xF
+#define BXT_DRAM_RANK_MASK                     0x3
+#define BXT_DRAM_RANK_SINGLE                   0x1
+#define BXT_DRAM_RANK_DUAL                     0x3
+
+/*
+ * SKL memory frequeny multiplier is 266667 KHz (266.67 MHz)
+ */
+#define        SKL_MEMORY_FREQ_MULTIPLIER_KHZ          266667
+#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                     0x1F
+#define SKL_DRAM_SIZE_L_SHIFT                  0
+#define SKL_DRAM_SIZE_S_SHIFT                  16
+#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)
-- 
2.10.1

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

Reply via email to