55
66#include <linux/hwmon.h>
77#include <linux/hwmon-sysfs.h>
8+ #include <linux/jiffies.h>
89#include <linux/types.h>
910
1011#include "i915_drv.h"
@@ -36,18 +37,25 @@ struct hwm_reg {
3637 i915_reg_t pkg_rapl_limit ;
3738 i915_reg_t energy_status_all ;
3839 i915_reg_t energy_status_tile ;
40+ i915_reg_t fan_speed ;
3941};
4042
4143struct hwm_energy_info {
4244 u32 reg_val_prev ;
4345 long accum_energy ; /* Accumulated energy for energy1_input */
4446};
4547
48+ struct hwm_fan_info {
49+ u32 reg_val_prev ;
50+ u64 time_prev ;
51+ };
52+
4653struct hwm_drvdata {
4754 struct i915_hwmon * hwmon ;
4855 struct intel_uncore * uncore ;
4956 struct device * hwmon_dev ;
5057 struct hwm_energy_info ei ; /* Energy info for energy1_input */
58+ struct hwm_fan_info fi ; /* Fan info for fan1_input */
5159 char name [12 ];
5260 int gt_n ;
5361 bool reset_in_progress ;
@@ -276,6 +284,7 @@ static const struct hwmon_channel_info * const hwm_info[] = {
276284 HWMON_CHANNEL_INFO (power , HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT ),
277285 HWMON_CHANNEL_INFO (energy , HWMON_E_INPUT ),
278286 HWMON_CHANNEL_INFO (curr , HWMON_C_CRIT ),
287+ HWMON_CHANNEL_INFO (fan , HWMON_F_INPUT ),
279288 NULL
280289};
281290
@@ -613,6 +622,69 @@ hwm_curr_write(struct hwm_drvdata *ddat, u32 attr, long val)
613622 }
614623}
615624
625+ static umode_t
626+ hwm_fan_is_visible (const struct hwm_drvdata * ddat , u32 attr )
627+ {
628+ struct i915_hwmon * hwmon = ddat -> hwmon ;
629+
630+ if (attr == hwmon_fan_input && i915_mmio_reg_valid (hwmon -> rg .fan_speed ))
631+ return 0444 ;
632+
633+ return 0 ;
634+ }
635+
636+ static int
637+ hwm_fan_input_read (struct hwm_drvdata * ddat , long * val )
638+ {
639+ struct i915_hwmon * hwmon = ddat -> hwmon ;
640+ struct hwm_fan_info * fi = & ddat -> fi ;
641+ u64 rotations , time_now , time ;
642+ intel_wakeref_t wakeref ;
643+ u32 reg_val ;
644+ int ret = 0 ;
645+
646+ wakeref = intel_runtime_pm_get (ddat -> uncore -> rpm );
647+ mutex_lock (& hwmon -> hwmon_lock );
648+
649+ reg_val = intel_uncore_read (ddat -> uncore , hwmon -> rg .fan_speed );
650+ time_now = get_jiffies_64 ();
651+
652+ /*
653+ * HW register value is accumulated count of pulses from
654+ * PWM fan with the scale of 2 pulses per rotation.
655+ */
656+ rotations = (reg_val - fi -> reg_val_prev ) / 2 ;
657+
658+ time = jiffies_delta_to_msecs (time_now - fi -> time_prev );
659+ if (unlikely (!time )) {
660+ ret = - EAGAIN ;
661+ goto exit ;
662+ }
663+
664+ /*
665+ * Calculate fan speed in RPM by time averaging two subsequent
666+ * readings in minutes.
667+ * RPM = number of rotations * msecs per minute / time in msecs
668+ */
669+ * val = DIV_ROUND_UP_ULL (rotations * (MSEC_PER_SEC * 60 ), time );
670+
671+ fi -> reg_val_prev = reg_val ;
672+ fi -> time_prev = time_now ;
673+ exit :
674+ mutex_unlock (& hwmon -> hwmon_lock );
675+ intel_runtime_pm_put (ddat -> uncore -> rpm , wakeref );
676+ return ret ;
677+ }
678+
679+ static int
680+ hwm_fan_read (struct hwm_drvdata * ddat , u32 attr , long * val )
681+ {
682+ if (attr == hwmon_fan_input )
683+ return hwm_fan_input_read (ddat , val );
684+
685+ return - EOPNOTSUPP ;
686+ }
687+
616688static umode_t
617689hwm_is_visible (const void * drvdata , enum hwmon_sensor_types type ,
618690 u32 attr , int channel )
@@ -628,6 +700,8 @@ hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
628700 return hwm_energy_is_visible (ddat , attr );
629701 case hwmon_curr :
630702 return hwm_curr_is_visible (ddat , attr );
703+ case hwmon_fan :
704+ return hwm_fan_is_visible (ddat , attr );
631705 default :
632706 return 0 ;
633707 }
@@ -648,6 +722,8 @@ hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
648722 return hwm_energy_read (ddat , attr , val );
649723 case hwmon_curr :
650724 return hwm_curr_read (ddat , attr , val );
725+ case hwmon_fan :
726+ return hwm_fan_read (ddat , attr , val );
651727 default :
652728 return - EOPNOTSUPP ;
653729 }
@@ -739,12 +815,14 @@ hwm_get_preregistration_info(struct drm_i915_private *i915)
739815 hwmon -> rg .pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT ;
740816 hwmon -> rg .energy_status_all = PCU_PACKAGE_ENERGY_STATUS ;
741817 hwmon -> rg .energy_status_tile = INVALID_MMIO_REG ;
818+ hwmon -> rg .fan_speed = PCU_PWM_FAN_SPEED ;
742819 } else {
743820 hwmon -> rg .pkg_power_sku_unit = INVALID_MMIO_REG ;
744821 hwmon -> rg .pkg_power_sku = INVALID_MMIO_REG ;
745822 hwmon -> rg .pkg_rapl_limit = INVALID_MMIO_REG ;
746823 hwmon -> rg .energy_status_all = INVALID_MMIO_REG ;
747824 hwmon -> rg .energy_status_tile = INVALID_MMIO_REG ;
825+ hwmon -> rg .fan_speed = INVALID_MMIO_REG ;
748826 }
749827
750828 with_intel_runtime_pm (uncore -> rpm , wakeref ) {
@@ -755,6 +833,16 @@ hwm_get_preregistration_info(struct drm_i915_private *i915)
755833 if (i915_mmio_reg_valid (hwmon -> rg .pkg_power_sku_unit ))
756834 val_sku_unit = intel_uncore_read (uncore ,
757835 hwmon -> rg .pkg_power_sku_unit );
836+
837+ /*
838+ * Store the initial fan register value, so that we can use it for
839+ * initial fan speed calculation.
840+ */
841+ if (i915_mmio_reg_valid (hwmon -> rg .fan_speed )) {
842+ ddat -> fi .reg_val_prev = intel_uncore_read (uncore ,
843+ hwmon -> rg .fan_speed );
844+ ddat -> fi .time_prev = get_jiffies_64 ();
845+ }
758846 }
759847
760848 hwmon -> scl_shift_power = REG_FIELD_GET (PKG_PWR_UNIT , val_sku_unit );
0 commit comments