Re: [PATCH v2] drm/xe/hwmon: handle CRI+ power interval encoding
"Nilawar, Badal" <[email protected]>
| Newsgroups | org.freedesktop.lists.intel-xe |
|---|---|
| Message-ID | <[email protected]> |
On 03-07-2026 21:03, Karthik Poosa wrote: > On CRI and newer platforms, the power-limit interval encoding is changed > from the legacy 1.x * 2^y format to a U5.2 value in milliseconds. > Update the interval calculation accordingly for CRI and future platforms. > > v2: Round the fractional bit to 1 for values greater than 0.5 ms in the > show path, as the minimum supported time is 1 ms. > No special handling is needed in the store path since sysfs inputs are > only in milliseconds. (Badal) > > Signed-off-by: Karthik Poosa <[email protected]> Reviewed-by: Badal Nilawar <[email protected]> > --- > drivers/gpu/drm/xe/xe_hwmon.c | 86 ++++++++++++++++++++++------------- > 1 file changed, 55 insertions(+), 31 deletions(-) > > diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c > index de3f2aeffc3f..49f7e0edcc4b 100644 > --- a/drivers/gpu/drm/xe/xe_hwmon.c > +++ b/drivers/gpu/drm/xe/xe_hwmon.c > @@ -575,23 +575,36 @@ xe_hwmon_power_max_interval_show(struct device *dev, struct device_attribute *at > > mutex_unlock(&hwmon->hwmon_lock); > > - x = REG_FIELD_GET(PWR_LIM_TIME_X, reg_val); > - y = REG_FIELD_GET(PWR_LIM_TIME_Y, reg_val); > + if (hwmon->xe->info.platform >= XE_CRESCENTISLAND) { > + /** > + * On CRI and newer platforms, the interval encoding changed. > + * The value is now stored directly in milliseconds as U5.2, > + * replacing the older 1.x * 2^y representation. > + * Bits [6:2] hold the integer part and bits [1:0] the fraction, > + * so convert to milliseconds by extracting integer/fractional parts. > + * Round fraction value to 1 when it is >= 0.5. > + */ > + reg_val = REG_FIELD_GET(PWR_LIM_TIME, reg_val); > + out = (u64)((reg_val >> 2) + ((reg_val & 0x3) >= 2)); > + } else { > + 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; > + /* > + * 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); > + /* val in hwmon interface units (millisec) */ > + out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); > + } > > return sysfs_emit(buf, "%llu\n", out); > } > @@ -637,24 +650,35 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a > 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; > + if (hwmon->xe->info.platform >= XE_CRESCENTISLAND) { > + /** > + * On CRI and newer platforms, the interval encoding changed. > + * The value is now stored directly in milliseconds as U5.2, > + * replacing the older 1.x * 2^y representation. > + * Bits [6:2] hold the integer part and bits [1:0] the fraction,so > + * convert from milliseconds by shifting the value left by 2 to fit into the field. > + */ > + rxy = REG_FIELD_PREP(PWR_LIM_TIME, (val << 2)); > } else { > - y = ilog2(val); > - x = (val - (1ul << y)) << x_w >> y; > - } > + /* 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; > + } > > - rxy = REG_FIELD_PREP(PWR_LIM_TIME_X, x) | > - REG_FIELD_PREP(PWR_LIM_TIME_Y, y); > + rxy = REG_FIELD_PREP(PWR_LIM_TIME_X, x) | > + REG_FIELD_PREP(PWR_LIM_TIME_Y, y); > + } > > guard(xe_pm_runtime)(hwmon->xe); >