Commit c8939848 authored by Ashutosh Dixit's avatar Ashutosh Dixit Committed by Anshuman Gupta

drm/i915/hwmon: Expose card reactive critical power

Expose the card reactive critical (I1) power. I1 is exposed as
power1_crit in microwatts (typically for client products) or as
curr1_crit in milliamperes (typically for server).

v2: Add curr1_crit functionality (Ashutosh)
v3: Use HWMON_CHANNEL_INFO to define power1_crit, curr1_crit (Badal)
v4: Use hwm_ prefix for static functions (Ashutosh)
v5: KernelVersion: 6.2, Date: February 2023 in doc (Tvrtko)
v6: Change contact to intel-gfx (Rodrigo)

Cc: Sujaritha Sundaresan <sujaritha.sundaresan@intel.com>
Signed-off-by: default avatarAshutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: default avatarBadal Nilawar <badal.nilawar@intel.com>
Acked-by: default avatarGuenter Roeck <linux@roeck-us.net>
Reviewed-by: default avatarAnshuman Gupta <anshuman.gupta@intel.com>
Signed-off-by: default avatarAnshuman Gupta <anshuman.gupta@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-6-ashutosh.dixit@intel.com
parent c41b8bdc
......@@ -26,6 +26,32 @@ Description: RO. Card default power limit (default TDP setting).
Only supported for particular Intel i915 graphics platforms.
What: /sys/devices/.../hwmon/hwmon<i>/power1_crit
Date: February 2023
KernelVersion: 6.2
Contact: intel-gfx@lists.freedesktop.org
Description: RW. Card reactive critical (I1) power limit in microwatts.
Card reactive critical (I1) power limit in microwatts is exposed
for client products. The power controller will throttle the
operating frequency if the power averaged over a window exceeds
this limit.
Only supported for particular Intel i915 graphics platforms.
What: /sys/devices/.../hwmon/hwmon<i>/curr1_crit
Date: February 2023
KernelVersion: 6.2
Contact: intel-gfx@lists.freedesktop.org
Description: RW. Card reactive critical (I1) power limit in milliamperes.
Card reactive critical (I1) power limit in milliamperes is
exposed for server products. The power controller will throttle
the operating frequency if the power averaged over a window
exceeds this limit.
Only supported for particular Intel i915 graphics platforms.
What: /sys/devices/.../hwmon/hwmon<i>/energy1_input
Date: February 2023
KernelVersion: 6.2
......
......@@ -11,16 +11,19 @@
#include "i915_hwmon.h"
#include "i915_reg.h"
#include "intel_mchbar_regs.h"
#include "intel_pcode.h"
#include "gt/intel_gt_regs.h"
/*
* SF_* - scale factors for particular quantities according to hwmon spec.
* - voltage - millivolts
* - power - microwatts
* - curr - milliamperes
* - energy - microjoules
*/
#define SF_VOLTAGE 1000
#define SF_POWER 1000000
#define SF_CURR 1000
#define SF_ENERGY 1000000
struct hwm_reg {
......@@ -158,11 +161,25 @@ hwm_energy(struct hwm_drvdata *ddat, long *energy)
static const struct hwmon_channel_info *hwm_info[] = {
HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX),
HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT),
HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
HWMON_CHANNEL_INFO(curr, HWMON_C_CRIT),
NULL
};
/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */
static int hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval)
{
return snb_pcode_read_p(&i915->uncore, PCODE_POWER_SETUP,
POWER_SETUP_SUBCOMMAND_READ_I1, 0, uval);
}
static int hwm_pcode_write_i1(struct drm_i915_private *i915, u32 uval)
{
return snb_pcode_write_p(&i915->uncore, PCODE_POWER_SETUP,
POWER_SETUP_SUBCOMMAND_WRITE_I1, 0, uval);
}
static umode_t
hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr)
{
......@@ -198,13 +215,18 @@ hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
static umode_t
hwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan)
{
struct drm_i915_private *i915 = ddat->uncore->i915;
struct i915_hwmon *hwmon = ddat->hwmon;
u32 uval;
switch (attr) {
case hwmon_power_max:
return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? 0664 : 0;
case hwmon_power_rated_max:
return i915_mmio_reg_valid(hwmon->rg.pkg_power_sku) ? 0444 : 0;
case hwmon_power_crit:
return (hwm_pcode_read_i1(i915, &uval) ||
!(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
default:
return 0;
}
......@@ -214,6 +236,8 @@ static int
hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
{
struct i915_hwmon *hwmon = ddat->hwmon;
int ret;
u32 uval;
switch (attr) {
case hwmon_power_max:
......@@ -230,6 +254,15 @@ hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
hwmon->scl_shift_power,
SF_POWER);
return 0;
case hwmon_power_crit:
ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval);
if (ret)
return ret;
if (!(uval & POWER_SETUP_I1_WATTS))
return -ENODEV;
*val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
SF_POWER, POWER_SETUP_I1_SHIFT);
return 0;
default:
return -EOPNOTSUPP;
}
......@@ -239,6 +272,7 @@ static int
hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val)
{
struct i915_hwmon *hwmon = ddat->hwmon;
u32 uval;
switch (attr) {
case hwmon_power_max:
......@@ -248,6 +282,9 @@ hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val)
hwmon->scl_shift_power,
SF_POWER, val);
return 0;
case hwmon_power_crit:
uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_POWER);
return hwm_pcode_write_i1(ddat->uncore->i915, uval);
default:
return -EOPNOTSUPP;
}
......@@ -280,6 +317,56 @@ hwm_energy_read(struct hwm_drvdata *ddat, u32 attr, long *val)
}
}
static umode_t
hwm_curr_is_visible(const struct hwm_drvdata *ddat, u32 attr)
{
struct drm_i915_private *i915 = ddat->uncore->i915;
u32 uval;
switch (attr) {
case hwmon_curr_crit:
return (hwm_pcode_read_i1(i915, &uval) ||
(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
default:
return 0;
}
}
static int
hwm_curr_read(struct hwm_drvdata *ddat, u32 attr, long *val)
{
int ret;
u32 uval;
switch (attr) {
case hwmon_curr_crit:
ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval);
if (ret)
return ret;
if (uval & POWER_SETUP_I1_WATTS)
return -ENODEV;
*val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
SF_CURR, POWER_SETUP_I1_SHIFT);
return 0;
default:
return -EOPNOTSUPP;
}
}
static int
hwm_curr_write(struct hwm_drvdata *ddat, u32 attr, long val)
{
u32 uval;
switch (attr) {
case hwmon_curr_crit:
uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_CURR);
return hwm_pcode_write_i1(ddat->uncore->i915, uval);
default:
return -EOPNOTSUPP;
}
}
static umode_t
hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
u32 attr, int channel)
......@@ -293,6 +380,8 @@ hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
return hwm_power_is_visible(ddat, attr, channel);
case hwmon_energy:
return hwm_energy_is_visible(ddat, attr);
case hwmon_curr:
return hwm_curr_is_visible(ddat, attr);
default:
return 0;
}
......@@ -311,6 +400,8 @@ hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
return hwm_power_read(ddat, attr, channel, val);
case hwmon_energy:
return hwm_energy_read(ddat, attr, val);
case hwmon_curr:
return hwm_curr_read(ddat, attr, val);
default:
return -EOPNOTSUPP;
}
......@@ -325,6 +416,8 @@ hwm_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
switch (type) {
case hwmon_power:
return hwm_power_write(ddat, attr, channel, val);
case hwmon_curr:
return hwm_curr_write(ddat, attr, val);
default:
return -EOPNOTSUPP;
}
......
......@@ -6650,6 +6650,12 @@
#define DG1_PCODE_STATUS 0x7E
#define DG1_UNCORE_GET_INIT_STATUS 0x0
#define DG1_UNCORE_INIT_STATUS_COMPLETE 0x1
#define PCODE_POWER_SETUP 0x7C
#define POWER_SETUP_SUBCOMMAND_READ_I1 0x4
#define POWER_SETUP_SUBCOMMAND_WRITE_I1 0x5
#define POWER_SETUP_I1_WATTS REG_BIT(31)
#define POWER_SETUP_I1_SHIFT 6 /* 10.6 fixed point format */
#define POWER_SETUP_I1_DATA_MASK REG_GENMASK(15, 0)
#define GEN12_PCODE_READ_SAGV_BLOCK_TIME_US 0x23
#define XEHP_PCODE_FREQUENCY_CONFIG 0x6e /* xehpsdv, pvc */
/* XEHP_PCODE_FREQUENCY_CONFIG sub-commands (param1) */
......
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