Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe/hwmon: Expose power1_max_interval

Expose power1_max_interval, that is the tau corresponding to PL1, as a
custom hwmon attribute. Some bit manipulation is needed because of the
format of PKG_PWR_LIM_1_TIME in
PACKAGE_RAPL_LIMIT register (1.x * power(2,y))

v2: Get rpm wake ref while accessing power1_max_interval
v3: %s/hwmon/xe_hwmon/
v4:
- As power1_max_interval is rw attr take lock in read function as well
- Refine comment about val to fix point conversion (Andi)
- Update kernel version and date in doc
v5: Fix review comments (Anshuman)

Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Reviewed-by: Anshuman Gupta <anshuman.gupta@intel.com>
Signed-off-by: Badal Nilawar <badal.nilawar@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231030115618.1382200-4-badal.nilawar@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

authored by

Badal Nilawar and committed by
Rodrigo Vivi
4446fcf2 fef6dd12

+169 -1
+9
Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
··· 59 59 Description: RO. Energy input of device in microjoules. 60 60 61 61 Only supported for particular Intel xe graphics platforms. 62 + 63 + What: /sys/devices/.../hwmon/hwmon<i>/power1_max_interval 64 + Date: October 2023 65 + KernelVersion: 6.6 66 + Contact: intel-xe@lists.freedesktop.org 67 + Description: RW. Sustained power limit interval (Tau in PL1/Tau) in 68 + milliseconds over which sustained power is averaged. 69 + 70 + Only supported for particular Intel xe graphics platforms.
+8
drivers/gpu/drm/xe/regs/xe_mchbar_regs.h
··· 22 22 #define PKG_TDP GENMASK_ULL(14, 0) 23 23 #define PKG_MIN_PWR GENMASK_ULL(30, 16) 24 24 #define PKG_MAX_PWR GENMASK_ULL(46, 32) 25 + #define PKG_MAX_WIN GENMASK_ULL(54, 48) 26 + #define PKG_MAX_WIN_X GENMASK_ULL(54, 53) 27 + #define PKG_MAX_WIN_Y GENMASK_ULL(52, 48) 28 + 25 29 26 30 #define PCU_CR_PACKAGE_POWER_SKU_UNIT XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x5938) 27 31 #define PKG_PWR_UNIT REG_GENMASK(3, 0) 28 32 #define PKG_ENERGY_UNIT REG_GENMASK(12, 8) 33 + #define PKG_TIME_UNIT REG_GENMASK(19, 16) 29 34 30 35 #define PCU_CR_PACKAGE_ENERGY_STATUS XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x593c) 31 36 32 37 #define PCU_CR_PACKAGE_RAPL_LIMIT XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x59a0) 33 38 #define PKG_PWR_LIM_1 REG_GENMASK(14, 0) 34 39 #define PKG_PWR_LIM_1_EN REG_BIT(15) 40 + #define PKG_PWR_LIM_1_TIME REG_GENMASK(23, 17) 41 + #define PKG_PWR_LIM_1_TIME_X REG_GENMASK(23, 22) 42 + #define PKG_PWR_LIM_1_TIME_Y REG_GENMASK(21, 17) 35 43 36 44 #endif /* _XE_MCHBAR_REGS_H_ */
+152 -1
drivers/gpu/drm/xe/xe_hwmon.c
··· 38 38 #define SF_CURR 1000 /* milliamperes */ 39 39 #define SF_VOLTAGE 1000 /* millivolts */ 40 40 #define SF_ENERGY 1000000 /* microjoules */ 41 + #define SF_TIME 1000 /* milliseconds */ 41 42 42 43 /** 43 44 * struct xe_hwmon_energy_info - to accumulate energy ··· 64 63 int scl_shift_power; 65 64 /** @scl_shift_energy: pkg energy unit */ 66 65 int scl_shift_energy; 66 + /** @scl_shift_time: pkg time unit */ 67 + int scl_shift_time; 67 68 /** @ei: Energy info for energy1_input */ 68 69 struct xe_hwmon_energy_info ei; 69 70 }; ··· 255 252 *energy = mul_u64_u32_shr(ei->accum_energy, SF_ENERGY, 256 253 hwmon->scl_shift_energy); 257 254 } 255 + 256 + static ssize_t 257 + xe_hwmon_power1_max_interval_show(struct device *dev, struct device_attribute *attr, 258 + char *buf) 259 + { 260 + struct xe_hwmon *hwmon = dev_get_drvdata(dev); 261 + u32 x, y, x_w = 2; /* 2 bits */ 262 + u64 r, tau4, out; 263 + 264 + xe_device_mem_access_get(gt_to_xe(hwmon->gt)); 265 + 266 + mutex_lock(&hwmon->hwmon_lock); 267 + 268 + xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, 269 + REG_READ32, &r, 0, 0); 270 + 271 + mutex_unlock(&hwmon->hwmon_lock); 272 + 273 + xe_device_mem_access_put(gt_to_xe(hwmon->gt)); 274 + 275 + x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r); 276 + y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r); 277 + 278 + /* 279 + * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17) 280 + * = (4 | x) << (y - 2) 281 + * 282 + * Here (y - 2) ensures a 1.x fixed point representation of 1.x 283 + * As x is 2 bits so 1.x can be 1.0, 1.25, 1.50, 1.75 284 + * 285 + * As y can be < 2, we compute tau4 = (4 | x) << y 286 + * and then add 2 when doing the final right shift to account for units 287 + */ 288 + tau4 = ((1 << x_w) | x) << y; 289 + 290 + /* val in hwmon interface units (millisec) */ 291 + out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); 292 + 293 + return sysfs_emit(buf, "%llu\n", out); 294 + } 295 + 296 + static ssize_t 297 + xe_hwmon_power1_max_interval_store(struct device *dev, struct device_attribute *attr, 298 + const char *buf, size_t count) 299 + { 300 + struct xe_hwmon *hwmon = dev_get_drvdata(dev); 301 + u32 x, y, rxy, x_w = 2; /* 2 bits */ 302 + u64 tau4, r, max_win; 303 + unsigned long val; 304 + int ret; 305 + 306 + ret = kstrtoul(buf, 0, &val); 307 + if (ret) 308 + return ret; 309 + 310 + /* 311 + * Max HW supported tau in '1.x * power(2,y)' format, x = 0, y = 0x12. 312 + * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds. 313 + * 314 + * The ideal scenario is for PKG_MAX_WIN to be read from the PKG_PWR_SKU register. 315 + * However, it is observed that existing discrete GPUs does not provide correct 316 + * PKG_MAX_WIN value, therefore a using default constant value. For future discrete GPUs 317 + * this may get resolved, in which case PKG_MAX_WIN should be obtained from PKG_PWR_SKU. 318 + */ 319 + #define PKG_MAX_WIN_DEFAULT 0x12ull 320 + 321 + /* 322 + * val must be < max in hwmon interface units. The steps below are 323 + * explained in xe_hwmon_power1_max_interval_show() 324 + */ 325 + r = FIELD_PREP(PKG_MAX_WIN, PKG_MAX_WIN_DEFAULT); 326 + x = REG_FIELD_GET(PKG_MAX_WIN_X, r); 327 + y = REG_FIELD_GET(PKG_MAX_WIN_Y, r); 328 + tau4 = ((1 << x_w) | x) << y; 329 + max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); 330 + 331 + if (val > max_win) 332 + return -EINVAL; 333 + 334 + /* val in hw units */ 335 + val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME); 336 + 337 + /* 338 + * Convert val to 1.x * power(2,y) 339 + * y = ilog2(val) 340 + * x = (val - (1 << y)) >> (y - 2) 341 + */ 342 + if (!val) { 343 + y = 0; 344 + x = 0; 345 + } else { 346 + y = ilog2(val); 347 + x = (val - (1ul << y)) << x_w >> y; 348 + } 349 + 350 + rxy = REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_X, x) | REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_Y, y); 351 + 352 + xe_device_mem_access_get(gt_to_xe(hwmon->gt)); 353 + 354 + mutex_lock(&hwmon->hwmon_lock); 355 + 356 + xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_RMW32, (u64 *)&r, 357 + PKG_PWR_LIM_1_TIME, rxy); 358 + 359 + mutex_unlock(&hwmon->hwmon_lock); 360 + 361 + xe_device_mem_access_put(gt_to_xe(hwmon->gt)); 362 + 363 + return count; 364 + } 365 + 366 + static SENSOR_DEVICE_ATTR(power1_max_interval, 0664, 367 + xe_hwmon_power1_max_interval_show, 368 + xe_hwmon_power1_max_interval_store, 0); 369 + 370 + static struct attribute *hwmon_attributes[] = { 371 + &sensor_dev_attr_power1_max_interval.dev_attr.attr, 372 + NULL 373 + }; 374 + 375 + static umode_t xe_hwmon_attributes_visible(struct kobject *kobj, 376 + struct attribute *attr, int index) 377 + { 378 + struct device *dev = kobj_to_dev(kobj); 379 + struct xe_hwmon *hwmon = dev_get_drvdata(dev); 380 + int ret = 0; 381 + 382 + xe_device_mem_access_get(gt_to_xe(hwmon->gt)); 383 + 384 + if (attr == &sensor_dev_attr_power1_max_interval.dev_attr.attr) 385 + ret = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT) ? attr->mode : 0; 386 + 387 + xe_device_mem_access_put(gt_to_xe(hwmon->gt)); 388 + 389 + return ret; 390 + } 391 + 392 + static const struct attribute_group hwmon_attrgroup = { 393 + .attrs = hwmon_attributes, 394 + .is_visible = xe_hwmon_attributes_visible, 395 + }; 396 + 397 + static const struct attribute_group *hwmon_groups[] = { 398 + &hwmon_attrgroup, 399 + NULL 400 + }; 258 401 259 402 static const struct hwmon_channel_info *hwmon_info[] = { 260 403 HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT), ··· 718 569 REG_READ32, &val_sku_unit, 0, 0); 719 570 hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit); 720 571 hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit); 572 + hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit); 721 573 } 722 574 723 575 /* ··· 765 615 /* hwmon_dev points to device hwmon<i> */ 766 616 hwmon->hwmon_dev = devm_hwmon_device_register_with_info(dev, "xe", hwmon, 767 617 &hwmon_chip_info, 768 - NULL); 618 + hwmon_groups); 619 + 769 620 if (IS_ERR(hwmon->hwmon_dev)) { 770 621 drm_warn(&xe->drm, "Failed to register xe hwmon (%pe)\n", hwmon->hwmon_dev); 771 622 xe->hwmon = NULL;