diff mbox series

[2/7] drm/i915/hwmon: Add HWMON current voltage support

Message ID 20220825132118.784407-3-badal.nilawar@intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915: Add HWMON support | expand

Commit Message

Nilawar, Badal Aug. 25, 2022, 1:21 p.m. UTC
From: Riana Tauro <riana.tauro@intel.com>

Use i915 HWMON subsystem to display current input voltage.

v2:
  - Updated date and kernel version in feature description
  - Fixed review comments (Ashutosh)
v3: Use macro HWMON_CHANNEL_INFO to define hwmon channel (Guenter)
v4:
  - Fixed review comments (Ashutosh)
  - Use hwm_ prefix for static functions (Ashutosh)

Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Anshuman Gupta <anshuman.gupta@intel.com>
Signed-off-by: Riana Tauro <riana.tauro@intel.com>
Signed-off-by: Badal Nilawar <badal.nilawar@intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
---
 .../ABI/testing/sysfs-driver-intel-i915-hwmon |  7 +++
 drivers/gpu/drm/i915/gt/intel_gt_regs.h       |  3 ++
 drivers/gpu/drm/i915/i915_hwmon.c             | 47 +++++++++++++++++++
 3 files changed, 57 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon

Comments

Ashutosh Dixit Aug. 29, 2022, 5:30 p.m. UTC | #1
On Thu, 25 Aug 2022 06:21:13 -0700, Badal Nilawar wrote:
>
> From: Riana Tauro <riana.tauro@intel.com>
>
> Use i915 HWMON subsystem to display current input voltage.

A couple of suggestions to improve comments in this patch below and after
addressing those this patch is:

Reviewed-by: Ashutosh Dixit <ashutosh.dixit@intel.com>

> diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c
> index 103dd543a214..2192d0fd4c66 100644
> --- a/drivers/gpu/drm/i915/i915_hwmon.c
> +++ b/drivers/gpu/drm/i915/i915_hwmon.c
> @@ -11,8 +11,10 @@
>  #include "i915_hwmon.h"
>  #include "i915_reg.h"
>  #include "intel_mchbar_regs.h"
> +#include "gt/intel_gt_regs.h"

In later patches we have added units for different quantities here. So I
think we should add those units for voltage to this patch too. It's in
Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon but I think it's
better to add to this file too otherwise if anyone looks at it is seems to
be missing.

So I would add the following to this patch:

/*
 * SF_* - scale factors for particular quantities according to hwmon spec.
 * - voltage - millivolts
 */
#define SF_VOLTAGE	1000

> +static int
> +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
> +{
> +	struct i915_hwmon *hwmon = ddat->hwmon;
> +	intel_wakeref_t wakeref;
> +	u32 reg_value;
> +
> +	switch (attr) {
> +	case hwmon_in_input:
> +		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
> +			reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status);
> +		/* In units of 2.5 millivolt */
> +		*val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10);

Let's complete this comment to so that it is clear what's happening:

		/* HW register value is in units of 2.5 millivolt */
Gupta, Anshuman Sept. 12, 2022, 2:09 p.m. UTC | #2
> -----Original Message-----
> From: Nilawar, Badal <badal.nilawar@intel.com>
> Sent: Thursday, August 25, 2022 6:51 PM
> To: intel-gfx@lists.freedesktop.org
> Cc: Dixit, Ashutosh <ashutosh.dixit@intel.com>; Tauro, Riana
> <riana.tauro@intel.com>; Gupta, Anshuman <anshuman.gupta@intel.com>;
> Ewins, Jon <jon.ewins@intel.com>; linux-hwmon@vger.kernel.org
> Subject: [PATCH 2/7] drm/i915/hwmon: Add HWMON current voltage support
> 
> From: Riana Tauro <riana.tauro@intel.com>
> 
> Use i915 HWMON subsystem to display current input voltage.
> 
> v2:
>   - Updated date and kernel version in feature description
>   - Fixed review comments (Ashutosh)
> v3: Use macro HWMON_CHANNEL_INFO to define hwmon channel (Guenter)
> v4:
>   - Fixed review comments (Ashutosh)
>   - Use hwm_ prefix for static functions (Ashutosh)
> 
> Cc: Guenter Roeck <linux@roeck-us.net>
> Cc: Anshuman Gupta <anshuman.gupta@intel.com>
> Signed-off-by: Riana Tauro <riana.tauro@intel.com>
> Signed-off-by: Badal Nilawar <badal.nilawar@intel.com>
> Acked-by: Guenter Roeck <linux@roeck-us.net>
> ---
>  .../ABI/testing/sysfs-driver-intel-i915-hwmon |  7 +++
>  drivers/gpu/drm/i915/gt/intel_gt_regs.h       |  3 ++
>  drivers/gpu/drm/i915/i915_hwmon.c             | 47 +++++++++++++++++++
>  3 files changed, 57 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
> 
> diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
> b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
> new file mode 100644
> index 000000000000..24c4b7477d51
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
> @@ -0,0 +1,7 @@
> +What:		/sys/devices/.../hwmon/hwmon<i>/in0_input
> +Date:		June 2022
> +KernelVersion:	5.19
> +Contact:	dri-devel@lists.freedesktop.org
> +Description:	RO. Current Voltage in millivolt.
> +
> +		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 94f9ddcfb3a5..5d4fbda4d326 100644
> --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h
> +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
> @@ -1508,6 +1508,9 @@
>  #define VLV_RENDER_C0_COUNT			_MMIO(0x138118)
>  #define VLV_MEDIA_C0_COUNT			_MMIO(0x13811c)
> 
> +#define GEN12_RPSTAT1				_MMIO(0x1381b4)
> +#define   GEN12_VOLTAGE_MASK			REG_GENMASK(10, 0)
> +
>  #define GEN11_GT_INTR_DW(x)			_MMIO(0x190018 +
> ((x) * 4))
>  #define   GEN11_CSME				(31)
>  #define   GEN11_GUNIT				(28)
> diff --git a/drivers/gpu/drm/i915/i915_hwmon.c
> b/drivers/gpu/drm/i915/i915_hwmon.c
> index 103dd543a214..2192d0fd4c66 100644
> --- a/drivers/gpu/drm/i915/i915_hwmon.c
> +++ b/drivers/gpu/drm/i915/i915_hwmon.c
> @@ -11,8 +11,10 @@
>  #include "i915_hwmon.h"
>  #include "i915_reg.h"
>  #include "intel_mchbar_regs.h"
> +#include "gt/intel_gt_regs.h"
> 
>  struct hwm_reg {
> +	i915_reg_t gt_perf_status;
>  };
> 
>  struct hwm_drvdata {
> @@ -29,14 +31,49 @@ struct i915_hwmon {
>  };
> 
>  static const struct hwmon_channel_info *hwm_info[] = {
> +	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
>  	NULL
>  };
> 
> +static umode_t
> +hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr) {
> +	switch (attr) {
> +	case hwmon_in_input:
> +		return i915_mmio_reg_valid(ddat->hwmon->rg.gt_perf_status)
> ? 0444 : 0;
> +	default:
> +		return 0;
> +	}
> +}
> +
> +static int
> +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) {
> +	struct i915_hwmon *hwmon = ddat->hwmon;
> +	intel_wakeref_t wakeref;
> +	u32 reg_value;
> +
> +	switch (attr) {
> +	case hwmon_in_input:
Other attributes in this series take hwmon->lock before accessing i915 registers ,
So do we need lock here as well ?
Thanks,
Anshuman Gupta. 
> +		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
> +			reg_value = intel_uncore_read(ddat->uncore, hwmon-
> >rg.gt_perf_status);
> +		/* In units of 2.5 millivolt */
> +		*val =
> DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) *
> 25, 10);
> +		return 0;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
>  static umode_t
>  hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
>  	       u32 attr, int channel)
>  {
> +	struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
> +
>  	switch (type) {
> +	case hwmon_in:
> +		return hwm_in_is_visible(ddat, attr);
>  	default:
>  		return 0;
>  	}
> @@ -46,7 +83,11 @@ static int
>  hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
>  	 int channel, long *val)
>  {
> +	struct hwm_drvdata *ddat = dev_get_drvdata(dev);
> +
>  	switch (type) {
> +	case hwmon_in:
> +		return hwm_in_read(ddat, attr, val);
>  	default:
>  		return -EOPNOTSUPP;
>  	}
> @@ -76,6 +117,12 @@ static const struct hwmon_chip_info hwm_chip_info = {
> static void  hwm_get_preregistration_info(struct drm_i915_private *i915)  {
> +	struct i915_hwmon *hwmon = i915->hwmon;
> +
> +	if (IS_DG1(i915) || IS_DG2(i915))
> +		hwmon->rg.gt_perf_status = GEN12_RPSTAT1;
> +	else
> +		hwmon->rg.gt_perf_status = INVALID_MMIO_REG;
>  }
> 
>  void i915_hwmon_register(struct drm_i915_private *i915)
> --
> 2.25.1
Ashutosh Dixit Sept. 12, 2022, 4:37 p.m. UTC | #3
On Mon, 12 Sep 2022 07:09:28 -0700, Gupta, Anshuman wrote:
>
> > +static int
> > +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) {
> > +	struct i915_hwmon *hwmon = ddat->hwmon;
> > +	intel_wakeref_t wakeref;
> > +	u32 reg_value;
> > +
> > +	switch (attr) {
> > +	case hwmon_in_input:
>
> Other attributes in this series take hwmon->lock before accessing i915
> registers , So do we need lock here as well ?

The lock is being taken only for RMW and for making sure energy counter
updates happen atomically. We are not taking the lock for just reads so IMO
no lock is needed here.

> > +		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
> > +			reg_value = intel_uncore_read(ddat->uncore, hwmon-
> > >rg.gt_perf_status);
> > +		/* In units of 2.5 millivolt */
> > +		*val =
> > DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) *
> > 25, 10);
> > +		return 0;
> > +	default:
> > +		return -EOPNOTSUPP;
> > +	}
> > +}

Thanks.
--
Ashutosh
Gupta, Anshuman Sept. 13, 2022, 8:11 a.m. UTC | #4
> -----Original Message-----
> From: Dixit, Ashutosh <ashutosh.dixit@intel.com>
> Sent: Monday, September 12, 2022 10:08 PM
> To: Gupta, Anshuman <anshuman.gupta@intel.com>
> Cc: Nilawar, Badal <badal.nilawar@intel.com>; intel-gfx@lists.freedesktop.org;
> Tauro, Riana <riana.tauro@intel.com>; Ewins, Jon <jon.ewins@intel.com>;
> linux-hwmon@vger.kernel.org
> Subject: Re: [PATCH 2/7] drm/i915/hwmon: Add HWMON current voltage
> support
> 
> On Mon, 12 Sep 2022 07:09:28 -0700, Gupta, Anshuman wrote:
> >
> > > +static int
> > > +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) {
> > > +	struct i915_hwmon *hwmon = ddat->hwmon;
> > > +	intel_wakeref_t wakeref;
> > > +	u32 reg_value;
> > > +
> > > +	switch (attr) {
> > > +	case hwmon_in_input:
> >
> > Other attributes in this series take hwmon->lock before accessing i915
> > registers , So do we need lock here as well ?
> 
> The lock is being taken only for RMW and for making sure energy counter
> updates happen atomically. We are not taking the lock for just reads so IMO no
> lock is needed here.
If that is the case, then why it needs to grab a lock for rmw on different
Register ? Like in patch  3 of this series grabs hwmon->howmon_lock for rmw  on 
two different register pkg_power_sku_unit and pkg_rapl_limit. One register rmw 
should be independent of other register here ?
Thanks,
Anshuman Gupta

> 
> > > +		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
> > > +			reg_value = intel_uncore_read(ddat->uncore, hwmon-
> > > >rg.gt_perf_status);
> > > +		/* In units of 2.5 millivolt */
> > > +		*val =
> > > DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value)
> * 25,
> > > 10);
> > > +		return 0;
> > > +	default:
> > > +		return -EOPNOTSUPP;
> > > +	}
> > > +}
> 
> Thanks.
> --
> Ashutosh
Ashutosh Dixit Sept. 13, 2022, 3:19 p.m. UTC | #5
On Tue, 13 Sep 2022 01:11:57 -0700, Gupta, Anshuman wrote:
>

Hi Anshuman,

> > -----Original Message-----
> > From: Dixit, Ashutosh <ashutosh.dixit@intel.com>
> > Sent: Monday, September 12, 2022 10:08 PM
> > To: Gupta, Anshuman <anshuman.gupta@intel.com>
> > Cc: Nilawar, Badal <badal.nilawar@intel.com>; intel-gfx@lists.freedesktop.org;
> > Tauro, Riana <riana.tauro@intel.com>; Ewins, Jon <jon.ewins@intel.com>;
> > linux-hwmon@vger.kernel.org
> > Subject: Re: [PATCH 2/7] drm/i915/hwmon: Add HWMON current voltage
> > support
> >
> > On Mon, 12 Sep 2022 07:09:28 -0700, Gupta, Anshuman wrote:
> > >
> > > > +static int
> > > > +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) {
> > > > +	struct i915_hwmon *hwmon = ddat->hwmon;
> > > > +	intel_wakeref_t wakeref;
> > > > +	u32 reg_value;
> > > > +
> > > > +	switch (attr) {
> > > > +	case hwmon_in_input:
> > >
> > > Other attributes in this series take hwmon->lock before accessing i915
> > > registers , So do we need lock here as well ?
> >
> > The lock is being taken only for RMW and for making sure energy counter
> > updates happen atomically. We are not taking the lock for just reads so IMO no
> > lock is needed here.
>
> If that is the case, then why it needs to grab a lock for rmw on
> different Register ? Like in patch 3 of this series grabs
> hwmon->howmon_lock for rmw on two different register pkg_power_sku_unit
> and pkg_rapl_limit.

I don't see this happening, where do you see it?

> One register rmw should be independent of other register here ?

Yes each register RMW is independent. In Patch 3 only hwm_power_write (not
hwm_power_read) is taking the lock for RMW on pkg_rapl_limit (lock is not
taken for pkg_power_sku_unit). So the assumption is that RMW of a single
register are not atomic and must be serialized with a lock. Reads are
considered to not need a lock.

Thanks.
--
Ashutosh


> >
> > > > +		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
> > > > +			reg_value = intel_uncore_read(ddat->uncore, hwmon-
> > > > >rg.gt_perf_status);
> > > > +		/* In units of 2.5 millivolt */
> > > > +		*val =
> > > > DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value)
> > * 25,
> > > > 10);
> > > > +		return 0;
> > > > +	default:
> > > > +		return -EOPNOTSUPP;
> > > > +	}
> > > > +}
> >
> > Thanks.
> > --
> > Ashutosh
Gupta, Anshuman Sept. 15, 2022, 6:29 a.m. UTC | #6
> -----Original Message-----
> From: Dixit, Ashutosh <ashutosh.dixit@intel.com>
> Sent: Tuesday, September 13, 2022 8:49 PM
> To: Gupta, Anshuman <anshuman.gupta@intel.com>
> Cc: Nilawar, Badal <badal.nilawar@intel.com>; intel-gfx@lists.freedesktop.org;
> Tauro, Riana <riana.tauro@intel.com>; Ewins, Jon <jon.ewins@intel.com>;
> linux-hwmon@vger.kernel.org
> Subject: Re: [PATCH 2/7] drm/i915/hwmon: Add HWMON current voltage
> support
> 
> On Tue, 13 Sep 2022 01:11:57 -0700, Gupta, Anshuman wrote:
> >
> 
> Hi Anshuman,
> 
> > > -----Original Message-----
> > > From: Dixit, Ashutosh <ashutosh.dixit@intel.com>
> > > Sent: Monday, September 12, 2022 10:08 PM
> > > To: Gupta, Anshuman <anshuman.gupta@intel.com>
> > > Cc: Nilawar, Badal <badal.nilawar@intel.com>;
> > > intel-gfx@lists.freedesktop.org; Tauro, Riana
> > > <riana.tauro@intel.com>; Ewins, Jon <jon.ewins@intel.com>;
> > > linux-hwmon@vger.kernel.org
> > > Subject: Re: [PATCH 2/7] drm/i915/hwmon: Add HWMON current voltage
> > > support
> > >
> > > On Mon, 12 Sep 2022 07:09:28 -0700, Gupta, Anshuman wrote:
> > > >
> > > > > +static int
> > > > > +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) {
> > > > > +	struct i915_hwmon *hwmon = ddat->hwmon;
> > > > > +	intel_wakeref_t wakeref;
> > > > > +	u32 reg_value;
> > > > > +
> > > > > +	switch (attr) {
> > > > > +	case hwmon_in_input:
> > > >
> > > > Other attributes in this series take hwmon->lock before accessing
> > > > i915 registers , So do we need lock here as well ?
> > >
> > > The lock is being taken only for RMW and for making sure energy
> > > counter updates happen atomically. We are not taking the lock for
> > > just reads so IMO no lock is needed here.
> >
> > If that is the case, then why it needs to grab a lock for rmw on
> > different Register ? Like in patch 3 of this series grabs
> > hwmon->howmon_lock for rmw on two different register
> > hwmon->pkg_power_sku_unit
> > and pkg_rapl_limit.
> 
> I don't see this happening, where do you see it?
> 
> > One register rmw should be independent of other register here ?
> 
> Yes each register RMW is independent. In Patch 3 only hwm_power_write (not
> hwm_power_read) is taking the lock for RMW on pkg_rapl_limit (lock is not
> taken for pkg_power_sku_unit). So the assumption is that RMW of a single
> register are not atomic and must be serialized with a lock. Reads are considered
> to not need a lock.
Thanks for explanation , and my apologies for the noise.
Br,
Anshuman Gupta.
> 
> Thanks.
> --
> Ashutosh
> 
> 
> > >
> > > > > +		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
> > > > > +			reg_value = intel_uncore_read(ddat->uncore,
> hwmon-
> > > > > >rg.gt_perf_status);
> > > > > +		/* In units of 2.5 millivolt */
> > > > > +		*val =
> > > > > DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK,
> reg_value)
> > > * 25,
> > > > > 10);
> > > > > +		return 0;
> > > > > +	default:
> > > > > +		return -EOPNOTSUPP;
> > > > > +	}
> > > > > +}
> > >
> > > Thanks.
> > > --
> > > Ashutosh
Nilawar, Badal Sept. 15, 2022, 2:40 p.m. UTC | #7
On 29-08-2022 23:00, Dixit, Ashutosh wrote:
> On Thu, 25 Aug 2022 06:21:13 -0700, Badal Nilawar wrote:
>>
>> From: Riana Tauro <riana.tauro@intel.com>
>>
>> Use i915 HWMON subsystem to display current input voltage.
> 
> A couple of suggestions to improve comments in this patch below and after
> addressing those this patch is:
> 
> Reviewed-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
> 
>> diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c
>> index 103dd543a214..2192d0fd4c66 100644
>> --- a/drivers/gpu/drm/i915/i915_hwmon.c
>> +++ b/drivers/gpu/drm/i915/i915_hwmon.c
>> @@ -11,8 +11,10 @@
>>   #include "i915_hwmon.h"
>>   #include "i915_reg.h"
>>   #include "intel_mchbar_regs.h"
>> +#include "gt/intel_gt_regs.h"
> 
> In later patches we have added units for different quantities here. So I
> think we should add those units for voltage to this patch too. It's in
> Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon but I think it's
> better to add to this file too otherwise if anyone looks at it is seems to
> be missing.
> 
> So I would add the following to this patch:
> 
> /*
>   * SF_* - scale factors for particular quantities according to hwmon spec.
>   * - voltage - millivolts
>   */
Sure I will add above comment.
> #define SF_VOLTAGE	1000
we are not using above scale factor for voltage. As our scale factor is 
2.5 millivolts shall I add like.
#define SF_VOLTAGE_MUL 25
#define SF_VOLTAGE_DIV 10
> 
>> +static int
>> +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
>> +{
>> +	struct i915_hwmon *hwmon = ddat->hwmon;
>> +	intel_wakeref_t wakeref;
>> +	u32 reg_value;
>> +
>> +	switch (attr) {
>> +	case hwmon_in_input:
>> +		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
>> +			reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status);
>> +		/* In units of 2.5 millivolt */
>> +		*val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10);
		
And use above scale factors here.
*val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 
SF_VOLTAGE_MUL, SF_VOLTAGE_DIV);
Regards,
Badal
> 
> Let's complete this comment to so that it is clear what's happening:
> 
> 		/* HW register value is in units of 2.5 millivolt */
Ashutosh Dixit Sept. 21, 2022, 12:02 a.m. UTC | #8
On Thu, 15 Sep 2022 07:40:37 -0700, Nilawar, Badal wrote:
>
> On 29-08-2022 23:00, Dixit, Ashutosh wrote:
> > On Thu, 25 Aug 2022 06:21:13 -0700, Badal Nilawar wrote:
> >>
> >> +static int
> >> +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
> >> +{
> >> +	struct i915_hwmon *hwmon = ddat->hwmon;
> >> +	intel_wakeref_t wakeref;
> >> +	u32 reg_value;
> >> +
> >> +	switch (attr) {
> >> +	case hwmon_in_input:
> >> +		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
> >> +			reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status);
> >> +		/* In units of 2.5 millivolt */
> >> +		*val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10);
>
> And use above scale factors here.
> *val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) *
> SF_VOLTAGE_MUL, SF_VOLTAGE_DIV);
> Regards,
> Badal
> >
> > Let's complete this comment to so that it is clear what's happening:
> >
> >		/* HW register value is in units of 2.5 millivolt */

This was missed in the latest rev so if we could remember to add this that would be great.
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
new file mode 100644
index 000000000000..24c4b7477d51
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
@@ -0,0 +1,7 @@ 
+What:		/sys/devices/.../hwmon/hwmon<i>/in0_input
+Date:		June 2022
+KernelVersion:	5.19
+Contact:	dri-devel@lists.freedesktop.org
+Description:	RO. Current Voltage in millivolt.
+
+		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 94f9ddcfb3a5..5d4fbda4d326 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
@@ -1508,6 +1508,9 @@ 
 #define VLV_RENDER_C0_COUNT			_MMIO(0x138118)
 #define VLV_MEDIA_C0_COUNT			_MMIO(0x13811c)
 
+#define GEN12_RPSTAT1				_MMIO(0x1381b4)
+#define   GEN12_VOLTAGE_MASK			REG_GENMASK(10, 0)
+
 #define GEN11_GT_INTR_DW(x)			_MMIO(0x190018 + ((x) * 4))
 #define   GEN11_CSME				(31)
 #define   GEN11_GUNIT				(28)
diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c
index 103dd543a214..2192d0fd4c66 100644
--- a/drivers/gpu/drm/i915/i915_hwmon.c
+++ b/drivers/gpu/drm/i915/i915_hwmon.c
@@ -11,8 +11,10 @@ 
 #include "i915_hwmon.h"
 #include "i915_reg.h"
 #include "intel_mchbar_regs.h"
+#include "gt/intel_gt_regs.h"
 
 struct hwm_reg {
+	i915_reg_t gt_perf_status;
 };
 
 struct hwm_drvdata {
@@ -29,14 +31,49 @@  struct i915_hwmon {
 };
 
 static const struct hwmon_channel_info *hwm_info[] = {
+	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
 	NULL
 };
 
+static umode_t
+hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr)
+{
+	switch (attr) {
+	case hwmon_in_input:
+		return i915_mmio_reg_valid(ddat->hwmon->rg.gt_perf_status) ? 0444 : 0;
+	default:
+		return 0;
+	}
+}
+
+static int
+hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
+{
+	struct i915_hwmon *hwmon = ddat->hwmon;
+	intel_wakeref_t wakeref;
+	u32 reg_value;
+
+	switch (attr) {
+	case hwmon_in_input:
+		with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
+			reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status);
+		/* In units of 2.5 millivolt */
+		*val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static umode_t
 hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
 	       u32 attr, int channel)
 {
+	struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
+
 	switch (type) {
+	case hwmon_in:
+		return hwm_in_is_visible(ddat, attr);
 	default:
 		return 0;
 	}
@@ -46,7 +83,11 @@  static int
 hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 	 int channel, long *val)
 {
+	struct hwm_drvdata *ddat = dev_get_drvdata(dev);
+
 	switch (type) {
+	case hwmon_in:
+		return hwm_in_read(ddat, attr, val);
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -76,6 +117,12 @@  static const struct hwmon_chip_info hwm_chip_info = {
 static void
 hwm_get_preregistration_info(struct drm_i915_private *i915)
 {
+	struct i915_hwmon *hwmon = i915->hwmon;
+
+	if (IS_DG1(i915) || IS_DG2(i915))
+		hwmon->rg.gt_perf_status = GEN12_RPSTAT1;
+	else
+		hwmon->rg.gt_perf_status = INVALID_MMIO_REG;
 }
 
 void i915_hwmon_register(struct drm_i915_private *i915)