/* * This function's return type of u64 allows for the case where the scaling * of the field taken from the 32-bit register value might cause a result to * exceed 32 bits.
*/ static u64
hwm_field_read_and_scale(struct hwm_drvdata *ddat, i915_reg_t rgadr,
u32 field_msk, int nshift, u32 scale_factor)
{ struct intel_uncore *uncore = ddat->uncore;
intel_wakeref_t wakeref;
u32 reg_value;
/* * hwm_energy - 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 * energy1_input overflows. This at 1000 W is an overflow duration of 278 years.
*/ staticvoid
hwm_energy(struct hwm_drvdata *ddat, long *energy)
{ struct intel_uncore *uncore = ddat->uncore; struct i915_hwmon *hwmon = ddat->hwmon; struct hwm_energy_info *ei = &ddat->ei;
intel_wakeref_t wakeref;
i915_reg_t rgaddr;
u32 reg_val;
with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r);
y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r); /* * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17) * = (4 | x) << (y - 2) * where (y - 2) ensures a 1.x fixed point representation of 1.x * However because y can be < 2, we compute * tau4 = (4 | x) << y * but 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 * power(2,y)' format, x = 0, y = 0x12 * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds
*/ #define PKG_MAX_WIN_DEFAULT 0x12ull
/* * val must be < max in hwmon interface units. The steps below are * explained in i915_power1_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); /* Convert to 1.x * power(2,y) */ if (!val) { /* Avoid ilog2(0) */
y = 0;
x = 0;
} else {
y = ilog2(val); /* x = (val - (1 << y)) >> (y - 2); */
x = (val - (1ul << y)) << x_w >> y;
}
/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */ staticint hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval)
{ /* Avoid ILLEGAL_SUBCOMMAND "mailbox access failed" warning in snb_pcode_read */ if (IS_DG1(i915) || IS_DG2(i915)) return -ENXIO;
/* * 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.
*/ staticint
hwm_power_max_read(struct hwm_drvdata *ddat, long *val)
{ struct i915_hwmon *hwmon = ddat->hwmon;
intel_wakeref_t wakeref;
u64 r, min, max;
/* Check if PL1 limit is disabled */
with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit); if (!(r & PKG_PWR_LIM_1_EN)) {
*val = PL1_DISABLE; return 0;
}
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;
}
staticint
hwm_power_max_write(struct hwm_drvdata *ddat, long val)
{ struct i915_hwmon *hwmon = ddat->hwmon;
intel_wakeref_t wakeref;
DEFINE_WAIT(wait); int ret = 0;
u32 nval;
/* Block waiting for GuC reset to complete when needed */ for (;;) {
wakeref = intel_runtime_pm_get(ddat->uncore->rpm);
mutex_lock(&hwmon->hwmon_lock);
schedule();
}
finish_wait(&ddat->waitq, &wait); if (ret) gotoexit;
/* Disable PL1 limit and verify, because the limit cannot be disabled on all platforms */ if (val == PL1_DISABLE) {
intel_uncore_rmw(ddat->uncore, hwmon->rg.pkg_rapl_limit,
PKG_PWR_LIM_1_EN, 0);
nval = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
if (nval & PKG_PWR_LIM_1_EN)
ret = -ENODEV; gotoexit;
}
/* Computation in 64-bits to avoid overflow. Round to nearest. */
nval = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_power, SF_POWER);
nval = PKG_PWR_LIM_1_EN | REG_FIELD_PREP(PKG_PWR_LIM_1, nval);
/* * 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; gotoexit;
}
/* * 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);
with_intel_runtime_pm(uncore->rpm, wakeref) { /* * The contents of register hwmon->rg.pkg_power_sku_unit do not change, * so read it once and store the shift values.
*/ if (i915_mmio_reg_valid(hwmon->rg.pkg_power_sku_unit))
val_sku_unit = intel_uncore_read(uncore,
hwmon->rg.pkg_power_sku_unit);
/* * Store the initial fan register value, so that we can use it for * initial fan speed calculation.
*/ if (i915_mmio_reg_valid(hwmon->rg.fan_speed)) {
ddat->fi.reg_val_prev = intel_uncore_read(uncore,
hwmon->rg.fan_speed);
ddat->fi.time_prev = get_jiffies_64();
}
}
/* * Initialize 'struct hwm_energy_info', i.e. set fields to the * first value of the energy register read
*/ 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);
}
}
/* hwmon_dev points to device hwmon<i> */
hwmon_dev = hwmon_device_register_with_info(dev, ddat->name,
ddat,
&hwm_chip_info,
hwm_groups); if (IS_ERR(hwmon_dev)) goto err;
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;
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.