/* Attribute index for powerX_xxx_interval sysfs entries */ enum sensor_attr_power {
SENSOR_INDEX_PSYS_PL1,
SENSOR_INDEX_PKG_PL1,
SENSOR_INDEX_PSYS_PL2,
SENSOR_INDEX_PKG_PL2,
};
/* * For platforms that support mailbox commands for power limits, REG_PKG_POWER_SKU_UNIT is * not supported and below are SKU units to be used.
*/ #define PWR_UNIT 0x3 #define ENERGY_UNIT 0xe #define TIME_UNIT 0xa
/* * Timeout for power limit write mailbox command.
*/ #define PL_WRITE_MBX_TIMEOUT_MS (1)
/** * struct xe_hwmon_energy_info - to accumulate energy
*/ struct xe_hwmon_energy_info { /** @reg_val_prev: previous energy reg val */
u32 reg_val_prev; /** @accum_energy: accumulated energy */ long accum_energy;
};
/** * struct xe_hwmon_fan_info - to cache previous fan reading
*/ struct xe_hwmon_fan_info { /** @reg_val_prev: previous fan reg val */
u32 reg_val_prev; /** @time_prev: previous timestamp */
u64 time_prev;
};
/** * struct xe_hwmon - xe hwmon data structure
*/ struct xe_hwmon { /** @hwmon_dev: hwmon device for xe */ struct device *hwmon_dev; /** @xe: Xe device */ struct xe_device *xe; /** @hwmon_lock: lock for rw attributes*/ struct mutex hwmon_lock; /** @scl_shift_power: pkg power unit */ int scl_shift_power; /** @scl_shift_energy: pkg energy unit */ int scl_shift_energy; /** @scl_shift_time: pkg time unit */ int scl_shift_time; /** @ei: Energy info for energyN_input */ struct xe_hwmon_energy_info ei[CHANNEL_MAX]; /** @fi: Fan info for fanN_input */ struct xe_hwmon_fan_info fi[FAN_MAX]; /** @boot_power_limit_read: is boot power limits read */ bool boot_power_limit_read; /** @pl1_on_boot: power limit PL1 on boot */
u32 pl1_on_boot[CHANNEL_MAX]; /** @pl2_on_boot: power limit PL2 on boot */
u32 pl2_on_boot[CHANNEL_MAX];
};
staticint xe_hwmon_pcode_read_power_limit(conststruct xe_hwmon *hwmon, u32 attr, int channel,
u32 *uval)
{ struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
u32 val0 = 0, val1 = 0; int ret = 0;
/* * HW allows arbitrary PL1 limits to be set but silently clamps these values to * "typical but not guaranteed" min/max values in REG_PKG_POWER_SKU. Follow the * same pattern for sysfs, allow arbitrary PL1 limits to be set but display * clamped values when read.
*/ staticvoid xe_hwmon_power_max_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *value)
{
u32 reg_val = 0; struct xe_device *xe = hwmon->xe; struct xe_reg rapl_limit, pkg_power_sku; struct xe_mmio *mmio = xe_root_tile_mmio(xe);
/* For platforms with mailbox power limit support clamping would be done by pcode. */ if (!hwmon->xe->info.has_mbx_power_limits) {
u64 pkg_pwr, min, max;
pkg_pwr = xe_mmio_read64_2x32(mmio, pkg_power_sku);
min = REG_FIELD_GET(PKG_MIN_PWR, pkg_pwr);
max = REG_FIELD_GET(PKG_MAX_PWR, pkg_pwr);
min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power); if (min && max)
*value = clamp_t(u64, *value, min, max);
}
unlock:
mutex_unlock(&hwmon->hwmon_lock);
}
staticint xe_hwmon_power_max_write(struct xe_hwmon *hwmon, u32 attr, int channel, long value)
{ struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); int ret = 0;
u32 reg_val, max; struct xe_reg rapl_limit;
u64 max_supp_power_limit = 0;
/* Disable Power Limit and verify, as limit cannot be disabled on all platforms. */ if (value == PL_DISABLE) { if (hwmon->xe->info.has_mbx_power_limits) {
drm_dbg(&hwmon->xe->drm, "disabling %s on channel %d\n",
PWR_ATTR_TO_STR(attr), channel);
xe_hwmon_pcode_rmw_power_limit(hwmon, attr, channel, PWR_LIM_EN, 0);
xe_hwmon_pcode_read_power_limit(hwmon, attr, channel, ®_val);
} else {
reg_val = xe_mmio_rmw32(mmio, rapl_limit, PWR_LIM_EN, 0);
reg_val = xe_mmio_read32(mmio, rapl_limit);
}
if (reg_val & PWR_LIM_EN) {
drm_warn(&hwmon->xe->drm, "Power limit disable is not supported!\n");
ret = -EOPNOTSUPP;
} goto unlock;
}
/* * If the sysfs value exceeds the maximum pcode supported power limit value, clamp it to * the supported maximum (U12.3 format). * This is to avoid truncation during reg_val calculation below and ensure the valid * power limit is sent for pcode which would clamp it to card-supported value.
*/
max_supp_power_limit = ((PWR_LIM_VAL) >> hwmon->scl_shift_power) * SF_POWER; if (value > max_supp_power_limit) {
value = max_supp_power_limit;
drm_info(&hwmon->xe->drm, "Power limit clamped as selected %s exceeds channel %d limit\n",
PWR_ATTR_TO_STR(attr), channel);
}
/* Computation in 64-bits to avoid overflow. Round to nearest. */
reg_val = DIV_ROUND_CLOSEST_ULL((u64)value << hwmon->scl_shift_power, SF_POWER);
/* * Clamp power limit to GPU firmware default as maximum, as an additional protection to * pcode clamp.
*/ if (hwmon->xe->info.has_mbx_power_limits) {
max = (attr == PL1_HWMON_ATTR) ?
hwmon->pl1_on_boot[channel] : hwmon->pl2_on_boot[channel];
max = REG_FIELD_PREP(PWR_LIM_VAL, max); if (reg_val > max) {
reg_val = max;
drm_dbg(&hwmon->xe->drm, "Clamping power limit to GPU firmware default 0x%x\n",
reg_val);
}
}
staticvoid xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *value)
{ struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
u32 reg_val;
if (hwmon->xe->info.has_mbx_power_limits) { /* PL1 is rated max if supported. */
xe_hwmon_pcode_read_power_limit(hwmon, PL1_HWMON_ATTR, channel, ®_val);
} else { /* * This sysfs file won't be visible if REG_PKG_POWER_SKU is invalid, so valid check * for this register can be skipped. * See xe_hwmon_power_is_visible.
*/ struct xe_reg reg = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel);
/* * xe_hwmon_energy_get - Obtain energy value * * The underlying energy hardware register is 32-bits and is subject to * overflow. How long before overflow? For example, with an example * scaling bit shift of 14 bits (see register *PACKAGE_POWER_SKU_UNIT) and * a power draw of 1000 watts, the 32-bit counter will overflow in * approximately 4.36 minutes. * * Examples: * 1 watt: (2^32 >> 14) / 1 W / (60 * 60 * 24) secs/day -> 3 days * 1000 watts: (2^32 >> 14) / 1000 W / 60 secs/min -> 4.36 minutes * * The function significantly increases overflow duration (from 4.36 * minutes) by accumulating the energy register into a 'long' as allowed by * the hwmon API. Using x86_64 128 bit arithmetic (see mul_u64_u32_shr()), * a 'long' of 63 bits, SF_ENERGY of 1e6 (~20 bits) and * hwmon->scl_shift_energy of 14 bits we have 57 (63 - 20 + 14) bits before * energyN_input overflows. This at 1000 W is an overflow duration of 278 years.
*/ staticvoid
xe_hwmon_energy_get(struct xe_hwmon *hwmon, int channel, long *energy)
{ struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); struct xe_hwmon_energy_info *ei = &hwmon->ei[channel];
u32 reg_val; int ret = 0;
/* Energy is supported only for card and pkg */ if (channel > CHANNEL_PKG) {
*energy = 0; return;
}
if (hwmon->xe->info.platform == XE_BATTLEMAGE) {
u64 pmt_val;
ret = xe_pmt_telem_read(to_pci_dev(hwmon->xe->drm.dev),
xe_mmio_read32(mmio, PUNIT_TELEMETRY_GUID),
&pmt_val, BMG_ENERGY_STATUS_PMT_OFFSET, sizeof(pmt_val)); if (ret != sizeof(pmt_val)) {
drm_warn(&hwmon->xe->drm, "energy read from pmt failed, ret %d\n", ret);
*energy = 0; return;
}
if (hwmon->xe->info.has_mbx_power_limits) {
ret = xe_hwmon_pcode_read_power_limit(hwmon, power_attr, channel, ®_val); if (ret) {
drm_err(&hwmon->xe->drm, "power interval read fail, ch %d, attr %d, val 0x%08x, ret %d\n",
channel, power_attr, reg_val, ret);
reg_val = 0;
}
} else {
reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT,
channel));
}
mutex_unlock(&hwmon->hwmon_lock);
xe_pm_runtime_put(hwmon->xe);
x = REG_FIELD_GET(PWR_LIM_TIME_X, reg_val);
y = REG_FIELD_GET(PWR_LIM_TIME_Y, reg_val);
/* * tau = (1 + (x / 4)) * power(2,y), x = bits(23:22), y = bits(21:17) * = (4 | x) << (y - 2) * * Here (y - 2) ensures a 1.x fixed point representation of 1.x * As x is 2 bits so 1.x can be 1.0, 1.25, 1.50, 1.75 * * As y can be < 2, we compute tau4 = (4 | x) << y * and then add 2 when doing the final right shift to account for units
*/
tau4 = (u64)((1 << x_w) | x) << y;
/* val in hwmon interface units (millisec) */
out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
ret = kstrtoul(buf, 0, &val); if (ret) return ret;
/* * Max HW supported tau in '(1 + (x / 4)) * power(2,y)' format, x = 0, y = 0x12. * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds. * * The ideal scenario is for PKG_MAX_WIN to be read from the PKG_PWR_SKU register. * However, it is observed that existing discrete GPUs does not provide correct * PKG_MAX_WIN value, therefore a using default constant value. For future discrete GPUs * this may get resolved, in which case PKG_MAX_WIN should be obtained from PKG_PWR_SKU.
*/ #define PKG_MAX_WIN_DEFAULT 0x12ull
/* * val must be < max in hwmon interface units. The steps below are * explained in xe_hwmon_power_max_interval_show()
*/
r = FIELD_PREP(PKG_MAX_WIN, PKG_MAX_WIN_DEFAULT);
x = REG_FIELD_GET(PKG_MAX_WIN_X, r);
y = REG_FIELD_GET(PKG_MAX_WIN_Y, r);
tau4 = (u64)((1 << x_w) | x) << y;
max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
if (val > max_win) return -EINVAL;
/* val in hw units */
val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME) + 1;
/* * Convert val to 1.x * power(2,y) * y = ilog2(val) * x = (val - (1 << y)) >> (y - 2)
*/ if (!val) {
y = 0;
x = 0;
} else {
y = ilog2(val);
x = (val - (1ul << y)) << x_w >> y;
}
/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */ staticint xe_hwmon_pcode_read_i1(conststruct xe_hwmon *hwmon, u32 *uval)
{ struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
staticint xe_hwmon_power_curr_crit_write(struct xe_hwmon *hwmon, int channel, long value, u32 scale_factor)
{ int ret;
u32 uval;
u64 max_crit_power_curr = 0;
mutex_lock(&hwmon->hwmon_lock);
/* * If the sysfs value exceeds the pcode mailbox cmd POWER_SETUP_SUBCOMMAND_WRITE_I1 * max supported value, clamp it to the command's max (U10.6 format). * This is to avoid truncation during uval calculation below and ensure the valid power * limit is sent for pcode which would clamp it to card-supported value.
*/
max_crit_power_curr = (POWER_SETUP_I1_DATA_MASK >> POWER_SETUP_I1_SHIFT) * scale_factor; if (value > max_crit_power_curr) {
value = max_crit_power_curr;
drm_info(&hwmon->xe->drm, "Power limit clamped as selected exceeds channel %d limit\n",
channel);
}
uval = DIV_ROUND_CLOSEST_ULL(value << POWER_SETUP_I1_SHIFT, scale_factor);
ret = xe_hwmon_pcode_write_i1(hwmon, uval);
mutex_unlock(&hwmon->hwmon_lock); return ret;
}
staticvoid xe_hwmon_get_voltage(struct xe_hwmon *hwmon, int channel, long *value)
{ struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
u64 reg_val;
reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_GT_PERF_STATUS, channel)); /* HW register value in units of 2.5 millivolt */
*value = DIV_ROUND_CLOSEST(REG_FIELD_GET(VOLTAGE_MASK, reg_val) * 2500, SF_VOLTAGE);
}
static umode_t
xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
{ switch (attr) { case hwmon_temp_input: case hwmon_temp_label: return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_TEMP, channel)) ? 0444 : 0; default: return 0;
}
}
staticint
xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
{ struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
u64 reg_val;
/* * HW register value is accumulated count of pulses from PWM fan with the scale * of 2 pulses per rotation.
*/
rotations = (reg_val - fi->reg_val_prev) / 2;
time = jiffies_delta_to_msecs(time_now - fi->time_prev); if (unlikely(!time)) {
ret = -EAGAIN; goto unlock;
}
/* * Calculate fan speed in RPM by time averaging two subsequent readings in minutes. * RPM = number of rotations * msecs per minute / time in msecs
*/
*val = DIV_ROUND_UP_ULL(rotations * (MSEC_PER_SEC * 60), time);
switch (type) { case hwmon_temp:
ret = xe_hwmon_temp_is_visible(hwmon, attr, channel); break; case hwmon_power:
ret = xe_hwmon_power_is_visible(hwmon, attr, channel); break; case hwmon_curr:
ret = xe_hwmon_curr_is_visible(hwmon, attr, channel); break; case hwmon_in:
ret = xe_hwmon_in_is_visible(hwmon, attr, channel); break; case hwmon_energy:
ret = xe_hwmon_energy_is_visible(hwmon, attr, channel); break; case hwmon_fan:
ret = xe_hwmon_fan_is_visible(hwmon, attr, channel); break; default:
ret = 0; break;
}
xe_pm_runtime_put(hwmon->xe);
return ret;
}
staticint
xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val)
{ struct xe_hwmon *hwmon = dev_get_drvdata(dev); int ret;
xe_pm_runtime_get(hwmon->xe);
switch (type) { case hwmon_temp:
ret = xe_hwmon_temp_read(hwmon, attr, channel, val); break; case hwmon_power:
ret = xe_hwmon_power_read(hwmon, attr, channel, val); break; case hwmon_curr:
ret = xe_hwmon_curr_read(hwmon, attr, channel, val); break; case hwmon_in:
ret = xe_hwmon_in_read(hwmon, attr, channel, val); break; case hwmon_energy:
ret = xe_hwmon_energy_read(hwmon, attr, channel, val); break; case hwmon_fan:
ret = xe_hwmon_fan_read(hwmon, attr, channel, val); break; default:
ret = -EOPNOTSUPP; break;
}
xe_pm_runtime_put(hwmon->xe);
return ret;
}
staticint
xe_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val)
{ struct xe_hwmon *hwmon = dev_get_drvdata(dev); int ret;
xe_pm_runtime_get(hwmon->xe);
switch (type) { case hwmon_power:
ret = xe_hwmon_power_write(hwmon, attr, channel, val); break; case hwmon_curr:
ret = xe_hwmon_curr_write(hwmon, attr, channel, val); break; default:
ret = -EOPNOTSUPP; break;
}
xe_pm_runtime_put(hwmon->xe);
return ret;
}
staticint xe_hwmon_read_label(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, constchar **str)
{ switch (type) { case hwmon_temp: if (channel == CHANNEL_PKG)
*str = "pkg"; elseif (channel == CHANNEL_VRAM)
*str = "vram"; return 0; case hwmon_power: case hwmon_energy: case hwmon_curr: case hwmon_in: if (channel == CHANNEL_CARD)
*str = "card"; elseif (channel == CHANNEL_PKG)
*str = "pkg"; return 0; default: return -EOPNOTSUPP;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.