Message ID | 20240812081538.1457396-1-raag.jadav@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v5] drm/i915/hwmon: expose fan speed | expand |
On Mon, Aug 12, 2024 at 01:45:38PM +0530, Raag Jadav wrote: > Add hwmon support for fan1_input attribute, which will expose fan speed > in RPM. With this in place we can monitor fan speed using lm-sensors tool. > > $ sensors > i915-pci-0300 > Adapter: PCI adapter > in0: 653.00 mV > fan1: 3833 RPM > power1: N/A (max = 43.00 W) > energy1: 32.02 kJ ... > +static int > +hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val) > +{ > + struct i915_hwmon *hwmon = ddat->hwmon; > + struct hwm_fan_info *fi = &ddat->fi; > + u64 rotations, time_now, time; > + intel_wakeref_t wakeref; > + u32 reg_val, pulses; > + int ret = 0; > + > + if (attr != hwmon_fan_input) > + return -EOPNOTSUPP; > + > + wakeref = intel_runtime_pm_get(ddat->uncore->rpm); > + mutex_lock(&hwmon->hwmon_lock); > + > + reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed); > + time_now = get_jiffies_64(); > + /* Handle HW register overflow */ > + if (reg_val >= fi->reg_val_prev) > + pulses = reg_val - fi->reg_val_prev; > + else > + pulses = UINT_MAX - fi->reg_val_prev + reg_val; Isn't it the abs_diff() reimplementation? > + /* > + * HW register value is accumulated count of pulses from > + * PWM fan with the scale of 2 pulses per rotation. > + */ > + rotations = pulses / 2; > + > + time = jiffies_delta_to_msecs(time_now - fi->time_prev); > + if (unlikely(!time)) { > + ret = -EAGAIN; > + goto exit; > + } > + > + /* > + * Convert to minutes for calculating RPM. > + * RPM = number of rotations * msecs per minute / time in msecs > + */ > + *val = DIV_ROUND_UP(rotations * (MSEC_PER_SEC * 60), time); > + > + fi->reg_val_prev = reg_val; > + fi->time_prev = time_now; > +exit: > + mutex_unlock(&hwmon->hwmon_lock); > + intel_runtime_pm_put(ddat->uncore->rpm, wakeref); > + return ret; > +}
Hi Raag, > +static int > +hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val) > +{ > + struct i915_hwmon *hwmon = ddat->hwmon; > + struct hwm_fan_info *fi = &ddat->fi; > + u64 rotations, time_now, time; > + intel_wakeref_t wakeref; > + u32 reg_val, pulses; > + int ret = 0; > + > + if (attr != hwmon_fan_input) > + return -EOPNOTSUPP; > + > + wakeref = intel_runtime_pm_get(ddat->uncore->rpm); > + mutex_lock(&hwmon->hwmon_lock); > + > + reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed); > + time_now = get_jiffies_64(); > + > + /* Handle HW register overflow */ > + if (reg_val >= fi->reg_val_prev) > + pulses = reg_val - fi->reg_val_prev; > + else > + pulses = UINT_MAX - fi->reg_val_prev + reg_val; > + > + /* > + * HW register value is accumulated count of pulses from > + * PWM fan with the scale of 2 pulses per rotation. > + */ > + rotations = pulses / 2; > + > + time = jiffies_delta_to_msecs(time_now - fi->time_prev); > + if (unlikely(!time)) { > + ret = -EAGAIN; > + goto exit; > + } Can you please add a comment describing how you obtain the speed calculation? Basically at every read you store the values. Is it possible that we don't have reads for a long time and the register resets more than once? Thanks, Andi > + /* > + * Convert to minutes for calculating RPM. > + * RPM = number of rotations * msecs per minute / time in msecs > + */ > + *val = DIV_ROUND_UP(rotations * (MSEC_PER_SEC * 60), time); > + > + fi->reg_val_prev = reg_val; > + fi->time_prev = time_now; > +exit: > + mutex_unlock(&hwmon->hwmon_lock); > + intel_runtime_pm_put(ddat->uncore->rpm, wakeref); > + return ret; > +}
Hi Raag, kernel test robot noticed the following build errors: [auto build test ERROR on groeck-staging/hwmon-next] [also build test ERROR on linus/master v6.11-rc3 next-20240812] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Raag-Jadav/drm-i915-hwmon-expose-fan-speed/20240812-161645 base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next patch link: https://lore.kernel.org/r/20240812081538.1457396-1-raag.jadav%40intel.com patch subject: [PATCH v5] drm/i915/hwmon: expose fan speed config: i386-randconfig-012-20240813 (https://download.01.org/0day-ci/archive/20240813/202408130500.SgCVoR2D-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240813/202408130500.SgCVoR2D-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202408130500.SgCVoR2D-lkp@intel.com/ All errors (new ones prefixed by >>): ld: drivers/gpu/drm/i915/i915_hwmon.o: in function `hwm_fan_read': >> drivers/gpu/drm/i915/i915_hwmon.c:675: undefined reference to `__udivdi3' vim +675 drivers/gpu/drm/i915/i915_hwmon.c 633 634 static int 635 hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val) 636 { 637 struct i915_hwmon *hwmon = ddat->hwmon; 638 struct hwm_fan_info *fi = &ddat->fi; 639 u64 rotations, time_now, time; 640 intel_wakeref_t wakeref; 641 u32 reg_val, pulses; 642 int ret = 0; 643 644 if (attr != hwmon_fan_input) 645 return -EOPNOTSUPP; 646 647 wakeref = intel_runtime_pm_get(ddat->uncore->rpm); 648 mutex_lock(&hwmon->hwmon_lock); 649 650 reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed); 651 time_now = get_jiffies_64(); 652 653 /* Handle HW register overflow */ 654 if (reg_val >= fi->reg_val_prev) 655 pulses = reg_val - fi->reg_val_prev; 656 else 657 pulses = UINT_MAX - fi->reg_val_prev + reg_val; 658 659 /* 660 * HW register value is accumulated count of pulses from 661 * PWM fan with the scale of 2 pulses per rotation. 662 */ 663 rotations = pulses / 2; 664 665 time = jiffies_delta_to_msecs(time_now - fi->time_prev); 666 if (unlikely(!time)) { 667 ret = -EAGAIN; 668 goto exit; 669 } 670 671 /* 672 * Convert to minutes for calculating RPM. 673 * RPM = number of rotations * msecs per minute / time in msecs 674 */ > 675 *val = DIV_ROUND_UP(rotations * (MSEC_PER_SEC * 60), time); 676 677 fi->reg_val_prev = reg_val; 678 fi->time_prev = time_now; 679 exit: 680 mutex_unlock(&hwmon->hwmon_lock); 681 intel_runtime_pm_put(ddat->uncore->rpm, wakeref); 682 return ret; 683 } 684
Hi Raag,
kernel test robot noticed the following build errors:
[auto build test ERROR on groeck-staging/hwmon-next]
[also build test ERROR on linus/master v6.11-rc3 next-20240812]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Raag-Jadav/drm-i915-hwmon-expose-fan-speed/20240812-161645
base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next
patch link: https://lore.kernel.org/r/20240812081538.1457396-1-raag.jadav%40intel.com
patch subject: [PATCH v5] drm/i915/hwmon: expose fan speed
config: i386-allyesconfig (https://download.01.org/0day-ci/archive/20240813/202408130800.XtY6XxQ5-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240813/202408130800.XtY6XxQ5-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408130800.XtY6XxQ5-lkp@intel.com/
All errors (new ones prefixed by >>):
ld: drivers/gpu/drm/i915/i915_hwmon.o: in function `hwm_read':
>> i915_hwmon.c:(.text+0xe60): undefined reference to `__udivdi3'
On Mon, Aug 12, 2024 at 04:15:14PM +0300, Andy Shevchenko wrote: > On Mon, Aug 12, 2024 at 01:45:38PM +0530, Raag Jadav wrote: > > Add hwmon support for fan1_input attribute, which will expose fan speed > > in RPM. With this in place we can monitor fan speed using lm-sensors tool. > > > > $ sensors > > i915-pci-0300 > > Adapter: PCI adapter > > in0: 653.00 mV > > fan1: 3833 RPM > > power1: N/A (max = 43.00 W) > > energy1: 32.02 kJ > > ... > > > +static int > > +hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val) > > +{ > > + struct i915_hwmon *hwmon = ddat->hwmon; > > + struct hwm_fan_info *fi = &ddat->fi; > > + u64 rotations, time_now, time; > > + intel_wakeref_t wakeref; > > + u32 reg_val, pulses; > > + int ret = 0; > > + > > + if (attr != hwmon_fan_input) > > + return -EOPNOTSUPP; > > + > > + wakeref = intel_runtime_pm_get(ddat->uncore->rpm); > > + mutex_lock(&hwmon->hwmon_lock); > > + > > + reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed); > > + time_now = get_jiffies_64(); > > > + /* Handle HW register overflow */ > > + if (reg_val >= fi->reg_val_prev) > > + pulses = reg_val - fi->reg_val_prev; > > + else > > + pulses = UINT_MAX - fi->reg_val_prev + reg_val; > > Isn't it the abs_diff() reimplementation? Not exactly. This is specific to 32 bit register overflow, so we count from max value. Raag
On Mon, Aug 12, 2024 at 03:50:47PM +0200, Andi Shyti wrote: > Hi Raag, > > > +static int > > +hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val) > > +{ > > + struct i915_hwmon *hwmon = ddat->hwmon; > > + struct hwm_fan_info *fi = &ddat->fi; > > + u64 rotations, time_now, time; > > + intel_wakeref_t wakeref; > > + u32 reg_val, pulses; > > + int ret = 0; > > + > > + if (attr != hwmon_fan_input) > > + return -EOPNOTSUPP; > > + > > + wakeref = intel_runtime_pm_get(ddat->uncore->rpm); > > + mutex_lock(&hwmon->hwmon_lock); > > + > > + reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed); > > + time_now = get_jiffies_64(); > > + > > + /* Handle HW register overflow */ > > + if (reg_val >= fi->reg_val_prev) > > + pulses = reg_val - fi->reg_val_prev; > > + else > > + pulses = UINT_MAX - fi->reg_val_prev + reg_val; > > + > > + /* > > + * HW register value is accumulated count of pulses from > > + * PWM fan with the scale of 2 pulses per rotation. > > + */ > > + rotations = pulses / 2; > > + > > + time = jiffies_delta_to_msecs(time_now - fi->time_prev); > > + if (unlikely(!time)) { > > + ret = -EAGAIN; > > + goto exit; > > + } > > Can you please add a comment describing how you obtain the speed > calculation? That's what I initially tried but ended up dropping it in favour of RPM formula below, which I found to be doing a better job of explaining than a few lines of description. > Basically at every read you store the values. Is it possible that > we don't have reads for a long time and the register resets more > than once? Considering a fan continuously running at higher speeds (for example 4000 RPM which is quite optimistic), with the scale of 2 pulses per rotation, a 32 bit register will take around a year to overflow, which is more than most usecases I could think of. Raag > > + /* > > + * Convert to minutes for calculating RPM. > > + * RPM = number of rotations * msecs per minute / time in msecs > > + */ > > + *val = DIV_ROUND_UP(rotations * (MSEC_PER_SEC * 60), time); > > + > > + fi->reg_val_prev = reg_val; > > + fi->time_prev = time_now; > > +exit: > > + mutex_unlock(&hwmon->hwmon_lock); > > + intel_runtime_pm_put(ddat->uncore->rpm, wakeref); > > + return ret; > > +}
On Tue, Aug 13, 2024 at 08:45:19AM +0300, Raag Jadav wrote: > On Mon, Aug 12, 2024 at 04:15:14PM +0300, Andy Shevchenko wrote: > > On Mon, Aug 12, 2024 at 01:45:38PM +0530, Raag Jadav wrote: ... > > > +static int > > > +hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val) > > > +{ > > > + struct i915_hwmon *hwmon = ddat->hwmon; > > > + struct hwm_fan_info *fi = &ddat->fi; > > > + u64 rotations, time_now, time; > > > + intel_wakeref_t wakeref; > > > + u32 reg_val, pulses; > > > + int ret = 0; > > > + > > > + if (attr != hwmon_fan_input) > > > + return -EOPNOTSUPP; > > > + > > > + wakeref = intel_runtime_pm_get(ddat->uncore->rpm); > > > + mutex_lock(&hwmon->hwmon_lock); > > > + > > > + reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed); > > > + time_now = get_jiffies_64(); > > > > > + /* Handle HW register overflow */ > > > + if (reg_val >= fi->reg_val_prev) > > > + pulses = reg_val - fi->reg_val_prev; > > > + else > > > + pulses = UINT_MAX - fi->reg_val_prev + reg_val; > > > > Isn't it the abs_diff() reimplementation? > > Not exactly. This is specific to 32 bit register overflow, so we count > from max value. I see. But since you have the both variables of u32, why: 1) UINT_MAX? 2) Not simply using pulses = reg_val - fi->reg_val_prev; which will wrap over correctly? Note, in your case (in comparison to the wrap over variant) the off-by-one is present. Is it on purpose?
On Tue, Aug 13, 2024 at 11:27:22AM +0300, Andy Shevchenko wrote: > On Tue, Aug 13, 2024 at 08:45:19AM +0300, Raag Jadav wrote: > > On Mon, Aug 12, 2024 at 04:15:14PM +0300, Andy Shevchenko wrote: > > > On Mon, Aug 12, 2024 at 01:45:38PM +0530, Raag Jadav wrote: > > ... > > > > > +static int > > > > +hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val) > > > > +{ > > > > + struct i915_hwmon *hwmon = ddat->hwmon; > > > > + struct hwm_fan_info *fi = &ddat->fi; > > > > + u64 rotations, time_now, time; > > > > + intel_wakeref_t wakeref; > > > > + u32 reg_val, pulses; > > > > + int ret = 0; > > > > + > > > > + if (attr != hwmon_fan_input) > > > > + return -EOPNOTSUPP; > > > > + > > > > + wakeref = intel_runtime_pm_get(ddat->uncore->rpm); > > > > + mutex_lock(&hwmon->hwmon_lock); > > > > + > > > > + reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed); > > > > + time_now = get_jiffies_64(); > > > > > > > + /* Handle HW register overflow */ > > > > + if (reg_val >= fi->reg_val_prev) > > > > + pulses = reg_val - fi->reg_val_prev; > > > > + else > > > > + pulses = UINT_MAX - fi->reg_val_prev + reg_val; > > > > > > Isn't it the abs_diff() reimplementation? > > > > Not exactly. This is specific to 32 bit register overflow, so we count > > from max value. > > I see. But since you have the both variables of u32, why: > 1) UINT_MAX? > 2) Not simply using > > pulses = reg_val - fi->reg_val_prev; > > which will wrap over correctly? Agree. Will update. Raag
> > > + /* > > > + * HW register value is accumulated count of pulses from > > > + * PWM fan with the scale of 2 pulses per rotation. > > > + */ > > > + rotations = pulses / 2; > > > + > > > + time = jiffies_delta_to_msecs(time_now - fi->time_prev); > > > + if (unlikely(!time)) { > > > + ret = -EAGAIN; > > > + goto exit; > > > + } > > > > Can you please add a comment describing how you obtain the speed > > calculation? > > That's what I initially tried but ended up dropping it in favour of RPM > formula below, which I found to be doing a better job of explaining than > a few lines of description. > > > Basically at every read you store the values. Is it possible that > > we don't have reads for a long time and the register resets more > > than once? > > Considering a fan continuously running at higher speeds (for example 4000 RPM > which is quite optimistic), with the scale of 2 pulses per rotation, a 32 bit > register will take around a year to overflow, which is more than most usecases > I could think of. Which can be considered as a worse case scenario. I would have preferred here a runtime calculation, which means read now, wait a bit, read again and calculate. The read might be slow, but efficient. Anyway, your argument makes sense, so that I'm not going to push on this, I already r-b'ed it. Thanks, Andi
diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon index 92fe7c5c5ac1..be4141a7522f 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -75,3 +75,11 @@ Description: RO. Energy input of device or gt in microjoules. for the gt. Only supported for particular Intel i915 graphics platforms. + +What: /sys/bus/pci/drivers/i915/.../hwmon/hwmon<i>/fan1_input +Date: November 2024 +KernelVersion: 6.12 +Contact: intel-gfx@lists.freedesktop.org +Description: RO. Fan speed of device in RPM. + + Only supported for particular Intel i915 graphics platforms. diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index e42b3a5d4e63..57a3c83d3655 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -1553,6 +1553,8 @@ #define VLV_RENDER_C0_COUNT _MMIO(0x138118) #define VLV_MEDIA_C0_COUNT _MMIO(0x13811c) +#define PCU_PWM_FAN_SPEED _MMIO(0x138140) + #define GEN12_RPSTAT1 _MMIO(0x1381b4) #define GEN12_VOLTAGE_MASK REG_GENMASK(10, 0) #define GEN12_CAGF_MASK REG_GENMASK(19, 11) diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index 49db3e09826c..a867b81a0900 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -5,6 +5,7 @@ #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> +#include <linux/jiffies.h> #include <linux/types.h> #include "i915_drv.h" @@ -36,6 +37,7 @@ struct hwm_reg { i915_reg_t pkg_rapl_limit; i915_reg_t energy_status_all; i915_reg_t energy_status_tile; + i915_reg_t fan_speed; }; struct hwm_energy_info { @@ -43,11 +45,17 @@ struct hwm_energy_info { long accum_energy; /* Accumulated energy for energy1_input */ }; +struct hwm_fan_info { + u32 reg_val_prev; + u64 time_prev; +}; + struct hwm_drvdata { struct i915_hwmon *hwmon; struct intel_uncore *uncore; struct device *hwmon_dev; struct hwm_energy_info ei; /* Energy info for energy1_input */ + struct hwm_fan_info fi; /* Fan info for fan1_input */ char name[12]; int gt_n; bool reset_in_progress; @@ -276,6 +284,7 @@ static const struct hwmon_channel_info * const hwm_info[] = { HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT), HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT), HWMON_CHANNEL_INFO(curr, HWMON_C_CRIT), + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), NULL }; @@ -613,6 +622,66 @@ hwm_curr_write(struct hwm_drvdata *ddat, u32 attr, long val) } } +static umode_t +hwm_fan_is_visible(const struct hwm_drvdata *ddat, u32 attr) +{ + struct i915_hwmon *hwmon = ddat->hwmon; + + return attr == hwmon_fan_input && + i915_mmio_reg_valid(hwmon->rg.fan_speed) ? 0444 : 0; +} + +static int +hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val) +{ + struct i915_hwmon *hwmon = ddat->hwmon; + struct hwm_fan_info *fi = &ddat->fi; + u64 rotations, time_now, time; + intel_wakeref_t wakeref; + u32 reg_val, pulses; + int ret = 0; + + if (attr != hwmon_fan_input) + return -EOPNOTSUPP; + + wakeref = intel_runtime_pm_get(ddat->uncore->rpm); + mutex_lock(&hwmon->hwmon_lock); + + reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed); + time_now = get_jiffies_64(); + + /* Handle HW register overflow */ + if (reg_val >= fi->reg_val_prev) + pulses = reg_val - fi->reg_val_prev; + else + pulses = UINT_MAX - fi->reg_val_prev + reg_val; + + /* + * HW register value is accumulated count of pulses from + * PWM fan with the scale of 2 pulses per rotation. + */ + rotations = pulses / 2; + + time = jiffies_delta_to_msecs(time_now - fi->time_prev); + if (unlikely(!time)) { + ret = -EAGAIN; + goto exit; + } + + /* + * Convert to minutes for calculating RPM. + * RPM = number of rotations * msecs per minute / time in msecs + */ + *val = DIV_ROUND_UP(rotations * (MSEC_PER_SEC * 60), time); + + fi->reg_val_prev = reg_val; + fi->time_prev = time_now; +exit: + mutex_unlock(&hwmon->hwmon_lock); + intel_runtime_pm_put(ddat->uncore->rpm, wakeref); + return ret; +} + static umode_t hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) @@ -628,6 +697,8 @@ hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, return hwm_energy_is_visible(ddat, attr); case hwmon_curr: return hwm_curr_is_visible(ddat, attr); + case hwmon_fan: + return hwm_fan_is_visible(ddat, attr); default: return 0; } @@ -648,6 +719,8 @@ hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, return hwm_energy_read(ddat, attr, val); case hwmon_curr: return hwm_curr_read(ddat, attr, val); + case hwmon_fan: + return hwm_fan_read(ddat, attr, val); default: return -EOPNOTSUPP; } @@ -739,12 +812,14 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) 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; + hwmon->rg.fan_speed = PCU_PWM_FAN_SPEED; } 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; + hwmon->rg.fan_speed = INVALID_MMIO_REG; } with_intel_runtime_pm(uncore->rpm, wakeref) { @@ -755,6 +830,16 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) 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(); + } } hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit);