drm/i915/hwmon: Display clamped PL1 limit
authorAshutosh Dixit <ashutosh.dixit@intel.com>
Thu, 15 Dec 2022 19:17:27 +0000 (11:17 -0800)
committerAnshuman Gupta <anshuman.gupta@intel.com>
Fri, 6 Jan 2023 10:23:59 +0000 (15:53 +0530)
HW allows arbitrary PL1 limits to be set but silently clamps these values
to "typical but not guaranteed" min/max values in pkg_power_sku
register. Follow the same pattern for sysfs, allow arbitrary PL1 limits to
be set but display clamped values when read, so that users see PL1 limits
HW is likely using. Otherwise users think HW is using arbitrarily high/low
PL1 limits they might have set. The previous write/read I1 power1_crit
limit also follows the same clamping pattern.

v2: Explain "why" in commit message and include bug link (Jani Nikula)

Bug: https://gitlab.freedesktop.org/drm/intel/-/issues/7704
Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Reviewed-by: Anshuman Gupta <anshuman.gupta@intel.com>
Signed-off-by: Anshuman Gupta <anshuman.gupta@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221215191727.2468770-1-ashutosh.dixit@intel.com
drivers/gpu/drm/i915/i915_hwmon.c
drivers/gpu/drm/i915/intel_mchbar_regs.h

index cca7a4350ec8fd0d042c9dd5ef1d8a222489ad6d..1225bc432f0d59ef79f185cf76f2725618295e46 100644 (file)
@@ -359,6 +359,38 @@ hwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan)
        }
 }
 
+/*
+ * HW allows arbitrary PL1 limits to be set but silently clamps these values to
+ * "typical but not guaranteed" min/max values in rg.pkg_power_sku. Follow the
+ * same pattern for sysfs, allow arbitrary PL1 limits to be set but display
+ * clamped values when read. Write/read I1 also follows the same pattern.
+ */
+static int
+hwm_power_max_read(struct hwm_drvdata *ddat, long *val)
+{
+       struct i915_hwmon *hwmon = ddat->hwmon;
+       intel_wakeref_t wakeref;
+       u64 r, min, max;
+
+       *val = hwm_field_read_and_scale(ddat,
+                                       hwmon->rg.pkg_rapl_limit,
+                                       PKG_PWR_LIM_1,
+                                       hwmon->scl_shift_power,
+                                       SF_POWER);
+
+       with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
+               r = intel_uncore_read64(ddat->uncore, hwmon->rg.pkg_power_sku);
+       min = REG_FIELD_GET(PKG_MIN_PWR, r);
+       min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
+       max = REG_FIELD_GET(PKG_MAX_PWR, r);
+       max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power);
+
+       if (min && max)
+               *val = clamp_t(u64, *val, min, max);
+
+       return 0;
+}
+
 static int
 hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
 {
@@ -368,12 +400,7 @@ hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
 
        switch (attr) {
        case hwmon_power_max:
-               *val = hwm_field_read_and_scale(ddat,
-                                               hwmon->rg.pkg_rapl_limit,
-                                               PKG_PWR_LIM_1,
-                                               hwmon->scl_shift_power,
-                                               SF_POWER);
-               return 0;
+               return hwm_power_max_read(ddat, val);
        case hwmon_power_rated_max:
                *val = hwm_field_read_and_scale(ddat,
                                                hwmon->rg.pkg_power_sku,
index f93e9af43ac357229c16be4d155d957fb28d552e..73900c098d591258b1206db056b0925596d73370 100644 (file)
  */
 #define PCU_PACKAGE_POWER_SKU                  _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5930)
 #define   PKG_PKG_TDP                          GENMASK_ULL(14, 0)
+#define   PKG_MIN_PWR                          GENMASK_ULL(30, 16)
+#define   PKG_MAX_PWR                          GENMASK_ULL(46, 32)
 #define   PKG_MAX_WIN                          GENMASK_ULL(54, 48)
 #define     PKG_MAX_WIN_X                      GENMASK_ULL(54, 53)
 #define     PKG_MAX_WIN_Y                      GENMASK_ULL(52, 48)