Commit 92d44a42 authored by Badal Nilawar's avatar Badal Nilawar Committed by Rodrigo Vivi

drm/xe/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: Move PCODE_MBOX macro to pcode file (Riana)
v3: s/IS_DG2/(gt_to_xe(gt)->info.platform == XE_DG2)
v4: Fix review comments (Andi)
Acked-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: default avatarRiana Tauro <riana.tauro@intel.com>
Signed-off-by: default avatarBadal Nilawar <badal.nilawar@intel.com>
Reviewed-by: default avatarAndi Shyti <andi.shyti@linux.intel.com>
Link: https://lore.kernel.org/r/20230925081842.3566834-3-badal.nilawar@intel.comSigned-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent fb1b7060
...@@ -20,3 +20,29 @@ Description: RO. Card default power limit (default TDP setting). ...@@ -20,3 +20,29 @@ Description: RO. Card default power limit (default TDP setting).
Only supported for particular Intel xe graphics platforms. Only supported for particular Intel xe graphics platforms.
What: /sys/devices/.../hwmon/hwmon<i>/power1_crit
Date: September 2023
KernelVersion: 6.5
Contact: intel-xe@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 xe graphics platforms.
What: /sys/devices/.../hwmon/hwmon<i>/curr1_crit
Date: September 2023
KernelVersion: 6.5
Contact: intel-xe@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 xe graphics platforms.
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "xe_gt.h" #include "xe_gt.h"
#include "xe_hwmon.h" #include "xe_hwmon.h"
#include "xe_mmio.h" #include "xe_mmio.h"
#include "xe_pcode.h"
#include "xe_pcode_api.h"
enum xe_hwmon_reg { enum xe_hwmon_reg {
REG_PKG_RAPL_LIMIT, REG_PKG_RAPL_LIMIT,
...@@ -29,6 +31,7 @@ enum xe_hwmon_reg_operation { ...@@ -29,6 +31,7 @@ enum xe_hwmon_reg_operation {
* SF_* - scale factors for particular quantities according to hwmon spec. * SF_* - scale factors for particular quantities according to hwmon spec.
*/ */
#define SF_POWER 1000000 /* microwatts */ #define SF_POWER 1000000 /* microwatts */
#define SF_CURR 1000 /* milliamperes */
struct xe_hwmon { struct xe_hwmon {
struct device *hwmon_dev; struct device *hwmon_dev;
...@@ -184,18 +187,43 @@ static int xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, long *value) ...@@ -184,18 +187,43 @@ static int xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, long *value)
} }
static const struct hwmon_channel_info *hwmon_info[] = { static const struct hwmon_channel_info *hwmon_info[] = {
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(curr, HWMON_C_CRIT),
NULL NULL
}; };
/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */
static int xe_hwmon_pcode_read_i1(struct xe_gt *gt, u32 *uval)
{
/* Avoid Illegal Subcommand error */
if (gt_to_xe(gt)->info.platform == XE_DG2)
return -ENXIO;
return xe_pcode_read(gt, PCODE_MBOX(PCODE_POWER_SETUP,
POWER_SETUP_SUBCOMMAND_READ_I1, 0),
uval, 0);
}
static int xe_hwmon_pcode_write_i1(struct xe_gt *gt, u32 uval)
{
return xe_pcode_write(gt, PCODE_MBOX(PCODE_POWER_SETUP,
POWER_SETUP_SUBCOMMAND_WRITE_I1, 0),
uval);
}
static umode_t static umode_t
xe_hwmon_power_is_visible(struct xe_hwmon *hwmon, u32 attr, int chan) xe_hwmon_power_is_visible(struct xe_hwmon *hwmon, u32 attr, int chan)
{ {
u32 uval;
switch (attr) { switch (attr) {
case hwmon_power_max: case hwmon_power_max:
return xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT) ? 0664 : 0; return xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT) ? 0664 : 0;
case hwmon_power_rated_max: case hwmon_power_rated_max:
return xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU) ? 0444 : 0; return xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU) ? 0444 : 0;
case hwmon_power_crit:
return (xe_hwmon_pcode_read_i1(hwmon->gt, &uval) ||
!(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
default: default:
return 0; return 0;
} }
...@@ -204,11 +232,23 @@ xe_hwmon_power_is_visible(struct xe_hwmon *hwmon, u32 attr, int chan) ...@@ -204,11 +232,23 @@ xe_hwmon_power_is_visible(struct xe_hwmon *hwmon, u32 attr, int chan)
static int static int
xe_hwmon_power_read(struct xe_hwmon *hwmon, u32 attr, int chan, long *val) xe_hwmon_power_read(struct xe_hwmon *hwmon, u32 attr, int chan, long *val)
{ {
int ret;
u32 uval;
switch (attr) { switch (attr) {
case hwmon_power_max: case hwmon_power_max:
return xe_hwmon_power_max_read(hwmon, val); return xe_hwmon_power_max_read(hwmon, val);
case hwmon_power_rated_max: case hwmon_power_rated_max:
return xe_hwmon_power_rated_max_read(hwmon, val); return xe_hwmon_power_rated_max_read(hwmon, val);
case hwmon_power_crit:
ret = xe_hwmon_pcode_read_i1(hwmon->gt, &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: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -217,9 +257,63 @@ xe_hwmon_power_read(struct xe_hwmon *hwmon, u32 attr, int chan, long *val) ...@@ -217,9 +257,63 @@ xe_hwmon_power_read(struct xe_hwmon *hwmon, u32 attr, int chan, long *val)
static int static int
xe_hwmon_power_write(struct xe_hwmon *hwmon, u32 attr, int chan, long val) xe_hwmon_power_write(struct xe_hwmon *hwmon, u32 attr, int chan, long val)
{ {
u32 uval;
switch (attr) { switch (attr) {
case hwmon_power_max: case hwmon_power_max:
return xe_hwmon_power_max_write(hwmon, val); return xe_hwmon_power_max_write(hwmon, val);
case hwmon_power_crit:
uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_POWER);
return xe_hwmon_pcode_write_i1(hwmon->gt, uval);
default:
return -EOPNOTSUPP;
}
}
static umode_t
xe_hwmon_curr_is_visible(const struct xe_hwmon *hwmon, u32 attr)
{
u32 uval;
switch (attr) {
case hwmon_curr_crit:
return (xe_hwmon_pcode_read_i1(hwmon->gt, &uval) ||
(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
default:
return 0;
}
}
static int
xe_hwmon_curr_read(struct xe_hwmon *hwmon, u32 attr, long *val)
{
int ret;
u32 uval;
switch (attr) {
case hwmon_curr_crit:
ret = xe_hwmon_pcode_read_i1(hwmon->gt, &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
xe_hwmon_curr_write(struct xe_hwmon *hwmon, 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 xe_hwmon_pcode_write_i1(hwmon->gt, uval);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -238,6 +332,9 @@ xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, ...@@ -238,6 +332,9 @@ xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
case hwmon_power: case hwmon_power:
ret = xe_hwmon_power_is_visible(hwmon, attr, channel); ret = xe_hwmon_power_is_visible(hwmon, attr, channel);
break; break;
case hwmon_curr:
ret = xe_hwmon_curr_is_visible(hwmon, attr);
break;
default: default:
ret = 0; ret = 0;
break; break;
...@@ -261,6 +358,9 @@ xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, ...@@ -261,6 +358,9 @@ xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
case hwmon_power: case hwmon_power:
ret = xe_hwmon_power_read(hwmon, attr, channel, val); ret = xe_hwmon_power_read(hwmon, attr, channel, val);
break; break;
case hwmon_curr:
ret = xe_hwmon_curr_read(hwmon, attr, val);
break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; break;
...@@ -284,6 +384,9 @@ xe_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, ...@@ -284,6 +384,9 @@ xe_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
case hwmon_power: case hwmon_power:
ret = xe_hwmon_power_write(hwmon, attr, channel, val); ret = xe_hwmon_power_write(hwmon, attr, channel, val);
break; break;
case hwmon_curr:
ret = xe_hwmon_curr_write(hwmon, attr, val);
break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; break;
......
...@@ -22,4 +22,9 @@ int xe_pcode_write_timeout(struct xe_gt *gt, u32 mbox, u32 val, ...@@ -22,4 +22,9 @@ int xe_pcode_write_timeout(struct xe_gt *gt, u32 mbox, u32 val,
int xe_pcode_request(struct xe_gt *gt, u32 mbox, u32 request, int xe_pcode_request(struct xe_gt *gt, u32 mbox, u32 request,
u32 reply_mask, u32 reply, int timeout_ms); u32 reply_mask, u32 reply, int timeout_ms);
#define PCODE_MBOX(mbcmd, param1, param2)\
(FIELD_PREP(PCODE_MB_COMMAND, mbcmd)\
| FIELD_PREP(PCODE_MB_PARAM1, param1)\
| FIELD_PREP(PCODE_MB_PARAM2, param2))
#endif #endif
...@@ -35,6 +35,13 @@ ...@@ -35,6 +35,13 @@
#define DGFX_GET_INIT_STATUS 0x0 #define DGFX_GET_INIT_STATUS 0x0
#define DGFX_INIT_STATUS_COMPLETE 0x1 #define DGFX_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)
struct pcode_err_decode { struct pcode_err_decode {
int errno; int errno;
const char *str; const char *str;
......
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