diff mbox series

[3/3] hwmon (coretemp): Add support for dynamic ttarget

Message ID 20221108075051.5139-4-rui.zhang@intel.com (mailing list archive)
State Changes Requested
Headers show
Series hwmon (coretemp): Add support for dynamic tjmax/ttarget | expand

Commit Message

Zhang, Rui Nov. 8, 2022, 7:50 a.m. UTC
Tjmax value retrieved from MSR_IA32_TEMPERATURE_TARGET can be changed at
runtime when the Intel SST-PP (Intel Speed Select Technology -
Performance Profile) level is changed. As a result, the ttarget value
also becomes dyamic.

Improve the code to always get updated ttarget value.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/hwmon/coretemp.c | 69 ++++++++++++++++++++++++++++------------
 1 file changed, 48 insertions(+), 21 deletions(-)

Comments

Guenter Roeck Nov. 11, 2022, 9:34 p.m. UTC | #1
On Tue, Nov 08, 2022 at 03:50:51PM +0800, Zhang Rui wrote:
> Tjmax value retrieved from MSR_IA32_TEMPERATURE_TARGET can be changed at
> runtime when the Intel SST-PP (Intel Speed Select Technology -
> Performance Profile) level is changed. As a result, the ttarget value
> also becomes dyamic.
> 
> Improve the code to always get updated ttarget value.
> 
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> ---
>  drivers/hwmon/coretemp.c | 69 ++++++++++++++++++++++++++++------------
>  1 file changed, 48 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
> index 5292f7844860..d6084600862f 100644
> --- a/drivers/hwmon/coretemp.c
> +++ b/drivers/hwmon/coretemp.c
> @@ -69,7 +69,6 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
>   */
>  struct temp_data {
>  	int temp;
> -	int ttarget;
>  	int tjmax;
>  	unsigned long last_updated;
>  	unsigned int cpu;
> @@ -96,6 +95,7 @@ struct platform_data {
>  };
>  
>  static int get_tjmax(struct temp_data *tdata, struct device *dev);
> +static int get_ttarget(struct temp_data *tdata, struct device *dev);

Please rearrange to code to avoid forward declarations.

>  
>  /* Keep track of how many zone pointers we allocated in init() */
>  static int max_zones __read_mostly;
> @@ -150,8 +150,17 @@ static ssize_t show_ttarget(struct device *dev,
>  {
>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
>  	struct platform_data *pdata = dev_get_drvdata(dev);
> +	struct temp_data *tdata = pdata->core_data[attr->index];
> +	int ttarget;
> +
> +	mutex_lock(&tdata->update_lock);

Is that mutex really necessary ? I don't immediately see the need
for it.

> +	ttarget = get_ttarget(tdata, dev);
> +	mutex_unlock(&tdata->update_lock);
>  
> -	return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
> +	if (ttarget >= 0)
> +		return sprintf(buf, "%d\n", ttarget);
> +	else
> +		return ttarget;

else after return is unnecessary. Much better would be

	if (ttarget < 0)
		return ttarget;
	return sprintf(buf, "%d\n", ttarget);

>  }
>  
>  static ssize_t show_temp(struct device *dev,
> @@ -393,6 +402,38 @@ static int get_tjmax(struct temp_data *tdata, struct device *dev)
>  	return tdata->tjmax;
>  }
>  
> +static int get_ttarget(struct temp_data *tdata, struct device *dev)
> +{
> +	u32 eax, edx;
> +	struct cpuinfo_x86 *c = &cpu_data(tdata->cpu);
> +	int tj_max, ttarget_offset, ret;

Please use tjmax for consistency.

> +
> +	/*
> +	 * ttarget is valid only if tjmax can be retrieved from
> +	 * MSR_IA32_TEMPERATURE_TARGET
> +	 */
> +	if (tdata->tjmax)
> +		return -ENODEV;
> +
> +	if (c->x86_model <= 0xe || c->x86_model == 0x1c)
> +		return -ENODEV;
> +

Does it really make sense to re-check this each time the target temperature
is read ?

> +	/*
> +	 * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
> +	 * The target temperature is available on older CPUs but not in this
> +	 * register. Atoms don't have the register at all.
> +	 */
> +	ret = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET,
> +					&eax, &edx);

Please watch multi-line alignment.

> +	if (ret)
> +		return ret;
> +
> +	tj_max = (eax >> 16) & 0xff;
> +	ttarget_offset = (eax >> 8) & 0xff;
> +
> +	return (tj_max - ttarget_offset) * 1000;
> +}
> +
>  static int create_core_attrs(struct temp_data *tdata, struct device *dev,
>  			     int attr_no)
>  {
> @@ -468,9 +509,8 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
>  {
>  	struct temp_data *tdata;
>  	struct platform_data *pdata = platform_get_drvdata(pdev);
> -	struct cpuinfo_x86 *c = &cpu_data(cpu);
>  	u32 eax, edx;
> -	int err, index, attr_no, tjmax;
> +	int err, index, attr_no;
>  
>  	/*
>  	 * Find attr number for sysfs:
> @@ -504,23 +544,10 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
>  	if (err)
>  		goto exit_free;
>  
> -	/* We can access status register. Get Critical Temperature */
> -	tjmax = get_tjmax(tdata, &pdev->dev);
> -
> -	/*
> -	 * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
> -	 * The target temperature is available on older CPUs but not in this
> -	 * register. Atoms don't have the register at all.
> -	 */
> -	if (c->x86_model > 0xe && c->x86_model != 0x1c) {
> -		err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET,
> -					&eax, &edx);
> -		if (!err) {
> -			tdata->ttarget
> -			  = tjmax - ((eax >> 8) & 0xff) * 1000;
> -			tdata->attr_size++;
> -		}
> -	}
> +	/* Make sure tdata->tjmax is a valid indicator for dynamic/static tjmax */
> +	get_tjmax(tdata, &pdev->dev);
> +	if (get_ttarget(tdata, &pdev->dev) >= 0)
> +		tdata->attr_size++;
>  
>  	pdata->core_data[attr_no] = tdata;
>
Zhang, Rui Nov. 12, 2022, 8:37 a.m. UTC | #2
Hi, Guenter,

Thanks for reviewing the patches.
I will address the comments in next version. And also some comments
below.

On Fri, 2022-11-11 at 13:34 -0800, Guenter Roeck wrote:
> >  
> >  /* Keep track of how many zone pointers we allocated in init() */
> >  static int max_zones __read_mostly;
> > @@ -150,8 +150,17 @@ static ssize_t show_ttarget(struct device
> > *dev,
> >  {
> >  	struct sensor_device_attribute *attr =
> > to_sensor_dev_attr(devattr);
> >  	struct platform_data *pdata = dev_get_drvdata(dev);
> > +	struct temp_data *tdata = pdata->core_data[attr->index];
> > +	int ttarget;
> > +
> > +	mutex_lock(&tdata->update_lock);
> 
> Is that mutex really necessary ? I don't immediately see the need
> for it.

I just followed the same pattern as show_crit_alarm().
I checked the history and it was introduced by commit 723f573433b2
("hwmon: (coretemp) Fixup target cpu for package when cpu is
offlined"), to make sure the msr is not running on an offlined cpu.

> > +
> > +	/*
> > +	 * ttarget is valid only if tjmax can be retrieved from
> > +	 * MSR_IA32_TEMPERATURE_TARGET
> > +	 */
> > +	if (tdata->tjmax)
> > +		return -ENODEV;
> > +
> > +	if (c->x86_model <= 0xe || c->x86_model == 0x1c)
> > +		return -ENODEV;
> > +
> 
> Does it really make sense to re-check this each time the target
> temperature
> is read ?

You're right. We can keep this as it was, when deciding whether to
create this sysfs attr or not. Then the check in get_ttarget() can be
removed.

thanks,
rui
Guenter Roeck Nov. 12, 2022, 3:10 p.m. UTC | #3
On Sat, Nov 12, 2022 at 04:37:50PM +0800, Zhang Rui wrote:
> Hi, Guenter,
> 
> Thanks for reviewing the patches.
> I will address the comments in next version. And also some comments
> below.
> 
> On Fri, 2022-11-11 at 13:34 -0800, Guenter Roeck wrote:
> > >  
> > >  /* Keep track of how many zone pointers we allocated in init() */
> > >  static int max_zones __read_mostly;
> > > @@ -150,8 +150,17 @@ static ssize_t show_ttarget(struct device
> > > *dev,
> > >  {
> > >  	struct sensor_device_attribute *attr =
> > > to_sensor_dev_attr(devattr);
> > >  	struct platform_data *pdata = dev_get_drvdata(dev);
> > > +	struct temp_data *tdata = pdata->core_data[attr->index];
> > > +	int ttarget;
> > > +
> > > +	mutex_lock(&tdata->update_lock);
> > 
> > Is that mutex really necessary ? I don't immediately see the need
> > for it.
> 
> I just followed the same pattern as show_crit_alarm().
> I checked the history and it was introduced by commit 723f573433b2
> ("hwmon: (coretemp) Fixup target cpu for package when cpu is
> offlined"), to make sure the msr is not running on an offlined cpu.
> 
Good point. I am not sure if it matters at that point if the code
uses the old or the new CPU, but I guess it is safer.

Thanks for the clarification,

Guenter

> > > +
> > > +	/*
> > > +	 * ttarget is valid only if tjmax can be retrieved from
> > > +	 * MSR_IA32_TEMPERATURE_TARGET
> > > +	 */
> > > +	if (tdata->tjmax)
> > > +		return -ENODEV;
> > > +
> > > +	if (c->x86_model <= 0xe || c->x86_model == 0x1c)
> > > +		return -ENODEV;
> > > +
> > 
> > Does it really make sense to re-check this each time the target
> > temperature
> > is read ?
> 
> You're right. We can keep this as it was, when deciding whether to
> create this sysfs attr or not. Then the check in get_ttarget() can be
> removed.
> 
> thanks,
> rui
>
diff mbox series

Patch

diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 5292f7844860..d6084600862f 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -69,7 +69,6 @@  MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
  */
 struct temp_data {
 	int temp;
-	int ttarget;
 	int tjmax;
 	unsigned long last_updated;
 	unsigned int cpu;
@@ -96,6 +95,7 @@  struct platform_data {
 };
 
 static int get_tjmax(struct temp_data *tdata, struct device *dev);
+static int get_ttarget(struct temp_data *tdata, struct device *dev);
 
 /* Keep track of how many zone pointers we allocated in init() */
 static int max_zones __read_mostly;
@@ -150,8 +150,17 @@  static ssize_t show_ttarget(struct device *dev,
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct platform_data *pdata = dev_get_drvdata(dev);
+	struct temp_data *tdata = pdata->core_data[attr->index];
+	int ttarget;
+
+	mutex_lock(&tdata->update_lock);
+	ttarget = get_ttarget(tdata, dev);
+	mutex_unlock(&tdata->update_lock);
 
-	return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
+	if (ttarget >= 0)
+		return sprintf(buf, "%d\n", ttarget);
+	else
+		return ttarget;
 }
 
 static ssize_t show_temp(struct device *dev,
@@ -393,6 +402,38 @@  static int get_tjmax(struct temp_data *tdata, struct device *dev)
 	return tdata->tjmax;
 }
 
+static int get_ttarget(struct temp_data *tdata, struct device *dev)
+{
+	u32 eax, edx;
+	struct cpuinfo_x86 *c = &cpu_data(tdata->cpu);
+	int tj_max, ttarget_offset, ret;
+
+	/*
+	 * ttarget is valid only if tjmax can be retrieved from
+	 * MSR_IA32_TEMPERATURE_TARGET
+	 */
+	if (tdata->tjmax)
+		return -ENODEV;
+
+	if (c->x86_model <= 0xe || c->x86_model == 0x1c)
+		return -ENODEV;
+
+	/*
+	 * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
+	 * The target temperature is available on older CPUs but not in this
+	 * register. Atoms don't have the register at all.
+	 */
+	ret = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET,
+					&eax, &edx);
+	if (ret)
+		return ret;
+
+	tj_max = (eax >> 16) & 0xff;
+	ttarget_offset = (eax >> 8) & 0xff;
+
+	return (tj_max - ttarget_offset) * 1000;
+}
+
 static int create_core_attrs(struct temp_data *tdata, struct device *dev,
 			     int attr_no)
 {
@@ -468,9 +509,8 @@  static int create_core_data(struct platform_device *pdev, unsigned int cpu,
 {
 	struct temp_data *tdata;
 	struct platform_data *pdata = platform_get_drvdata(pdev);
-	struct cpuinfo_x86 *c = &cpu_data(cpu);
 	u32 eax, edx;
-	int err, index, attr_no, tjmax;
+	int err, index, attr_no;
 
 	/*
 	 * Find attr number for sysfs:
@@ -504,23 +544,10 @@  static int create_core_data(struct platform_device *pdev, unsigned int cpu,
 	if (err)
 		goto exit_free;
 
-	/* We can access status register. Get Critical Temperature */
-	tjmax = get_tjmax(tdata, &pdev->dev);
-
-	/*
-	 * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
-	 * The target temperature is available on older CPUs but not in this
-	 * register. Atoms don't have the register at all.
-	 */
-	if (c->x86_model > 0xe && c->x86_model != 0x1c) {
-		err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET,
-					&eax, &edx);
-		if (!err) {
-			tdata->ttarget
-			  = tjmax - ((eax >> 8) & 0xff) * 1000;
-			tdata->attr_size++;
-		}
-	}
+	/* Make sure tdata->tjmax is a valid indicator for dynamic/static tjmax */
+	get_tjmax(tdata, &pdev->dev);
+	if (get_ttarget(tdata, &pdev->dev) >= 0)
+		tdata->attr_size++;
 
 	pdata->core_data[attr_no] = tdata;