drm/i915/hwmon: Extend power/energy for XEHPSDV

Extend hwmon power/energy for XEHPSDV especially per gt level energy
usage.

v2: Update to latest HWMON spec (Ashutosh)
v3: Fix review comments (Ashutosh)
v4: Fix review comments (Anshuman)
v5: s/hwmon_device_register_with_info/
    devm_hwmon_device_register_with_info/ (Ashutosh)
v6: Change contact to intel-gfx (Rodrigo)
    GEN12_RPSTAT1 is available for all Gen12+ (Andi)

Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: Dale B Stimson <dale.b.stimson@intel.com>
Signed-off-by: Badal Nilawar <badal.nilawar@intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Reviewed-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Reviewed-by: Anshuman Gupta <anshuman.gupta@intel.com>
Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
Signed-off-by: Anshuman Gupta <anshuman.gupta@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-8-ashutosh.dixit@intel.com
This commit is contained in:
Dale B Stimson 2022-10-13 08:45:26 -07:00 committed by Anshuman Gupta
parent 4c2572fe0a
commit a6a924abf8
3 changed files with 110 additions and 3 deletions

View File

@ -65,6 +65,11 @@ What: /sys/devices/.../hwmon/hwmon<i>/energy1_input
Date: February 2023
KernelVersion: 6.2
Contact: intel-gfx@lists.freedesktop.org
Description: RO. Energy input of device in microjoules.
Description: RO. Energy input of device or gt in microjoules.
For i915 device level hwmon devices (name "i915") this
reflects energy input for the entire device. For gt level
hwmon devices (name "i915_gtN") this reflects energy input
for the gt.
Only supported for particular Intel i915 graphics platforms.

View File

@ -1589,6 +1589,11 @@
#define GEN12_SFC_DONE(n) _MMIO(0x1cc000 + (n) * 0x1000)
#define GT0_PACKAGE_ENERGY_STATUS _MMIO(0x250004)
#define GT0_PACKAGE_RAPL_LIMIT _MMIO(0x250008)
#define GT0_PACKAGE_POWER_SKU_UNIT _MMIO(0x250068)
#define GT0_PLATFORM_ENERGY_STATUS _MMIO(0x25006c)
/*
* Standalone Media's non-engine GT registers are located at their regular GT
* offsets plus 0x380000. This extra offset is stored inside the intel_uncore

View File

@ -12,6 +12,7 @@
#include "i915_reg.h"
#include "intel_mchbar_regs.h"
#include "intel_pcode.h"
#include "gt/intel_gt.h"
#include "gt/intel_gt_regs.h"
/*
@ -34,6 +35,7 @@ struct hwm_reg {
i915_reg_t pkg_power_sku;
i915_reg_t pkg_rapl_limit;
i915_reg_t energy_status_all;
i915_reg_t energy_status_tile;
};
struct hwm_energy_info {
@ -47,10 +49,12 @@ struct hwm_drvdata {
struct device *hwmon_dev;
struct hwm_energy_info ei; /* Energy info for energy1_input */
char name[12];
int gt_n;
};
struct i915_hwmon {
struct hwm_drvdata ddat;
struct hwm_drvdata ddat_gt[I915_MAX_GT];
struct mutex hwmon_lock; /* counter overflow logic and rmw */
struct hwm_reg rg;
int scl_shift_power;
@ -144,7 +148,10 @@ hwm_energy(struct hwm_drvdata *ddat, long *energy)
i915_reg_t rgaddr;
u32 reg_val;
rgaddr = hwmon->rg.energy_status_all;
if (ddat->gt_n >= 0)
rgaddr = hwmon->rg.energy_status_tile;
else
rgaddr = hwmon->rg.energy_status_all;
mutex_lock(&hwmon->hwmon_lock);
@ -283,6 +290,11 @@ static const struct hwmon_channel_info *hwm_info[] = {
NULL
};
static const struct hwmon_channel_info *hwm_gt_info[] = {
HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
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)
{
@ -414,7 +426,10 @@ hwm_energy_is_visible(const struct hwm_drvdata *ddat, u32 attr)
switch (attr) {
case hwmon_energy_input:
rgaddr = hwmon->rg.energy_status_all;
if (ddat->gt_n >= 0)
rgaddr = hwmon->rg.energy_status_tile;
else
rgaddr = hwmon->rg.energy_status_all;
return i915_mmio_reg_valid(rgaddr) ? 0444 : 0;
default:
return 0;
@ -550,6 +565,44 @@ static const struct hwmon_chip_info hwm_chip_info = {
.info = hwm_info,
};
static umode_t
hwm_gt_is_visible(const void *drvdata, enum hwmon_sensor_types type,
u32 attr, int channel)
{
struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
switch (type) {
case hwmon_energy:
return hwm_energy_is_visible(ddat, attr);
default:
return 0;
}
}
static int
hwm_gt_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct hwm_drvdata *ddat = dev_get_drvdata(dev);
switch (type) {
case hwmon_energy:
return hwm_energy_read(ddat, attr, val);
default:
return -EOPNOTSUPP;
}
}
static const struct hwmon_ops hwm_gt_ops = {
.is_visible = hwm_gt_is_visible,
.read = hwm_gt_read,
};
static const struct hwmon_chip_info hwm_gt_chip_info = {
.ops = &hwm_gt_ops,
.info = hwm_gt_info,
};
static void
hwm_get_preregistration_info(struct drm_i915_private *i915)
{
@ -558,7 +611,9 @@ hwm_get_preregistration_info(struct drm_i915_private *i915)
struct hwm_drvdata *ddat = &hwmon->ddat;
intel_wakeref_t wakeref;
u32 val_sku_unit = 0;
struct intel_gt *gt;
long energy;
int i;
/* Available for all Gen12+/dGfx */
hwmon->rg.gt_perf_status = GEN12_RPSTAT1;
@ -568,11 +623,19 @@ hwm_get_preregistration_info(struct drm_i915_private *i915)
hwmon->rg.pkg_power_sku = PCU_PACKAGE_POWER_SKU;
hwmon->rg.pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT;
hwmon->rg.energy_status_all = PCU_PACKAGE_ENERGY_STATUS;
hwmon->rg.energy_status_tile = INVALID_MMIO_REG;
} else if (IS_XEHPSDV(i915)) {
hwmon->rg.pkg_power_sku_unit = GT0_PACKAGE_POWER_SKU_UNIT;
hwmon->rg.pkg_power_sku = INVALID_MMIO_REG;
hwmon->rg.pkg_rapl_limit = GT0_PACKAGE_RAPL_LIMIT;
hwmon->rg.energy_status_all = GT0_PLATFORM_ENERGY_STATUS;
hwmon->rg.energy_status_tile = GT0_PACKAGE_ENERGY_STATUS;
} else {
hwmon->rg.pkg_power_sku_unit = INVALID_MMIO_REG;
hwmon->rg.pkg_power_sku = INVALID_MMIO_REG;
hwmon->rg.pkg_rapl_limit = INVALID_MMIO_REG;
hwmon->rg.energy_status_all = INVALID_MMIO_REG;
hwmon->rg.energy_status_tile = INVALID_MMIO_REG;
}
with_intel_runtime_pm(uncore->rpm, wakeref) {
@ -595,6 +658,10 @@ hwm_get_preregistration_info(struct drm_i915_private *i915)
*/
if (i915_mmio_reg_valid(hwmon->rg.energy_status_all))
hwm_energy(ddat, &energy);
if (i915_mmio_reg_valid(hwmon->rg.energy_status_tile)) {
for_each_gt(gt, i915, i)
hwm_energy(&hwmon->ddat_gt[i], &energy);
}
}
void i915_hwmon_register(struct drm_i915_private *i915)
@ -603,6 +670,9 @@ void i915_hwmon_register(struct drm_i915_private *i915)
struct i915_hwmon *hwmon;
struct device *hwmon_dev;
struct hwm_drvdata *ddat;
struct hwm_drvdata *ddat_gt;
struct intel_gt *gt;
int i;
/* hwmon is available only for dGfx */
if (!IS_DGFX(i915))
@ -619,6 +689,16 @@ void i915_hwmon_register(struct drm_i915_private *i915)
ddat->hwmon = hwmon;
ddat->uncore = &i915->uncore;
snprintf(ddat->name, sizeof(ddat->name), "i915");
ddat->gt_n = -1;
for_each_gt(gt, i915, i) {
ddat_gt = hwmon->ddat_gt + i;
ddat_gt->hwmon = hwmon;
ddat_gt->uncore = gt->uncore;
snprintf(ddat_gt->name, sizeof(ddat_gt->name), "i915_gt%u", i);
ddat_gt->gt_n = i;
}
hwm_get_preregistration_info(i915);
@ -633,6 +713,23 @@ void i915_hwmon_register(struct drm_i915_private *i915)
}
ddat->hwmon_dev = hwmon_dev;
for_each_gt(gt, i915, i) {
ddat_gt = hwmon->ddat_gt + i;
/*
* Create per-gt directories only if a per-gt attribute is
* visible. Currently this is only energy
*/
if (!hwm_gt_is_visible(ddat_gt, hwmon_energy, hwmon_energy_input, 0))
continue;
hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat_gt->name,
ddat_gt,
&hwm_gt_chip_info,
NULL);
if (!IS_ERR(hwmon_dev))
ddat_gt->hwmon_dev = hwmon_dev;
}
}
void i915_hwmon_unregister(struct drm_i915_private *i915)