All of lore.kernel.org
 help / color / mirror / Atom feed
From: Guenter Roeck <guenter.roeck@ericsson.com>
To: "R, Durgadoss" <durgadoss.r@intel.com>
Cc: "x86@kernel.org" <x86@kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"lm-sensors@lm-sensors.org" <lm-sensors@lm-sensors.org>,
	Fenghua Yu <fenghua.yu@intel.com>
Subject: Re: [lm-sensors]
Date: Tue, 04 Jan 2011 19:40:54 +0000	[thread overview]
Message-ID: <20110104194054.GA635@ericsson.com> (raw)
In-Reply-To: <D6D887BA8C9DFF48B5233887EF04654105C11DB93B@bgsmsx502.gar.corp.intel.com>

On Tue, Dec 28, 2010 at 03:56:57PM +0530, R, Durgadoss wrote:
> Hi,
> 
> I am submitting a patch to enable core thermal threshold
> Support to coretemp.c. There are two core thermal thresholds
> available through sysfs interfaces temp1_max and temp1_max_hyst.
> The temp1_max_alarm is set when temperature reaches or crosses
> above temp1_max or drops below temp1_max_hyst.
> 
> This patch is generated against stable Linux-2.6 kernel.
> 
> Kindly review and merge.
> ----------------------------------------------------------------
> From: Durgadoss R <durgadoss.r@intel.com>
> 
> Date: Sun, 19 Dec 2010 22:44:54 +0530
> Subject: [PATCH 2/2] hwmon:Adding_Threshold_Support_to_Coretemp
> 
> This patch adds core thermal thresholds support to coretemp.
> These thresholds can be configured via the sysfs interfaces temp1_max
> and temp1_max_hyst. An interrupt is generated when CPU temperature
> goes above temp1_max or drops below temp1_max_hyst.
> 
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>

Fenghua Yu <fenghua.yu@intel.com> as driver maintainer will have to Ack this patch.

Driver fails to build if MCE is not configured.

drivers/built-in.o: In function `config_thresh_intrpt':
coretemp.c:(.devinit.text+0xd909): undefined reference to `platform_thermal_notify'
coretemp.c:(.devinit.text+0xd91b): undefined reference to `platform_thermal_notify'
make: *** [.tmp_vmlinux1] Error 1

It also fails to build if APIC is not defined. See below. After that I gave up
trying more combinations. _Please_ do your homework.

> ---
>  Documentation/hwmon/coretemp |    8 ++
>  drivers/hwmon/coretemp.c     |  214 ++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 202 insertions(+), 20 deletions(-)
> 
> diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
> index 25568f8..615fdbe 100644
> --- a/Documentation/hwmon/coretemp
> +++ b/Documentation/hwmon/coretemp
> @@ -29,6 +29,14 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
>  
>  temp1_input	 - Core temperature (in millidegrees Celsius).
>  temp1_max	 - All cooling devices should be turned on (on Core2).
> +		   Initialized with IA32_TEMPERATURE_TARGET if supported,
> +		   otherwise initialized with (tjmax - 20). When the CPU
> +		   temperature reaches this temperature, an interrupt is
> +		   generated and temp1_max_alarm is set.
> +temp1_max_hyst	 - If the CPU temperature falls below than temperature,

	... falls below _this_ temperature ...

> +		   an interrupt is generated and temp1_max_alarm is reset.
> +temp1_max_alarm - Set if the temperature reaches or exceeds temp1_max.
> +		   Reset if the temperature drops to or below temp1_max_hyst.
>  temp1_crit	 - Maximum junction temperature (in millidegrees Celsius).
>  temp1_crit_alarm - Set when Out-of-spec bit is set, never clears.
>  		   Correct CPU operation is no longer guaranteed.
> diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
> index 42de98d..025902f 100644
> --- a/drivers/hwmon/coretemp.c
> +++ b/drivers/hwmon/coretemp.c
> @@ -36,11 +36,12 @@
>  #include <asm/msr.h>
>  #include <asm/processor.h>
>  #include <asm/smp.h>
> +#include <asm/mce.h>
>  
>  #define DRVNAME	"coretemp"
>  
> -typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
> -		SHOW_NAME } SHOW;
> +enum attributes { SHOW_TEMP, SHOW_TJMAX, CORE_TTARGET, CORE_TMIN, SHOW_LABEL,
> +		SHOW_NAME, SHOW_CRIT_ALARM, SHOW_MAX_ALARM } attrs;
>  
This defines a global variable named attrs. Not a good idea. You do not have to specify "attrs" here.

>  /*
>   * Functions declaration
> @@ -59,9 +60,14 @@ struct coretemp_data {
>  	int temp;
>  	int tjmax;
>  	int ttarget;
> -	u8 alarm;
> +	int tmin;
> +	u8 max_alarm;
> +	u8 crit_alarm;
>  };
>  
> +static void update_alarm(struct coretemp_data *data);
> +static int set_core_threshold(struct coretemp_data *data, int temp, int thres);
> +
Please keep with other function forward references. Yes, I know you need the struct,
but that doesn't have to be defined when you declare the forward references.
Or define the struct first and then all the forward declarations. 

>  /*
>   * Sysfs stuff
>   */
> @@ -83,9 +89,15 @@ static ssize_t show_name(struct device *dev, struct device_attribute
>  static ssize_t show_alarm(struct device *dev, struct device_attribute
>  			  *devattr, char *buf)
>  {
> -	struct coretemp_data *data = coretemp_update_device(dev);
> -	/* read the Out-of-spec log, never clear */
> -	return sprintf(buf, "%d\n", data->alarm);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +	struct coretemp_data *data = dev_get_drvdata(dev);
> +
> +	update_alarm(data);
> +	if (attr->index = SHOW_CRIT_ALARM)
> +		/* read the Out-of-spec log, never clear */
> +		return sprintf(buf, "%d\n", data->crit_alarm);
> +
Since the if () statement includes a comment, it is better to add { } to improve 
readability.

> +	return sprintf(buf, "%d\n", data->max_alarm);
>  }
>  
>  static ssize_t show_temp(struct device *dev,
> @@ -93,33 +105,67 @@ static ssize_t show_temp(struct device *dev,
>  {
>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
>  	struct coretemp_data *data = coretemp_update_device(dev);
> -	int err;
> +	int err = -EINVAL;
>  
> -	if (attr->index = SHOW_TEMP)
> +	switch (attr->index) {
> +	case SHOW_TEMP:
>  		err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
> -	else if (attr->index = SHOW_TJMAX)
> +		break;
> +	case SHOW_TJMAX:
>  		err = sprintf(buf, "%d\n", data->tjmax);
> -	else
> +		break;
> +	case CORE_TTARGET:
>  		err = sprintf(buf, "%d\n", data->ttarget);
> +		break;
> +	case CORE_TMIN:
> +		err = sprintf(buf, "%d\n", data->tmin);
> +		break;
> +	}
> +
>  	return err;
>  }
>  
> +
> +static ssize_t store_temp(struct device *dev,
> +		struct device_attribute *devattr, const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +	struct coretemp_data *data = dev_get_drvdata(dev);
> +	unsigned long val;
> +	int err;
> +
> +	if (strict_strtoul(buf, 10, &val))
> +		return -EINVAL;
> +
> +	err = set_core_threshold(data, val, attr->index);
> +
> +	return err ? err : count;
> +}
> +
>  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
>  			  SHOW_TEMP);
>  static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
>  			  SHOW_TJMAX);
> -static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
> -			  SHOW_TTARGET);
> -static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp,
> +						store_temp, CORE_TTARGET);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp,
> +						store_temp, CORE_TMIN);
> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
> +							SHOW_CRIT_ALARM);
> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
> +							SHOW_MAX_ALARM);
>  static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
>  static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
>  
>  static struct attribute *coretemp_attributes[] = {
>  	&sensor_dev_attr_name.dev_attr.attr,
>  	&sensor_dev_attr_temp1_label.dev_attr.attr,
> -	&dev_attr_temp1_crit_alarm.attr,
> +	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
>  	&sensor_dev_attr_temp1_input.dev_attr.attr,
>  	&sensor_dev_attr_temp1_crit.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
>  	NULL
>  };
>  
> @@ -127,6 +173,26 @@ static const struct attribute_group coretemp_group = {
>  	.attrs = coretemp_attributes,
>  };
>  
> +static void update_alarm(struct coretemp_data *data)
> +{
> +	u32 eax, edx;
> +
> +	rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
> +
> +	/* Update the critical temperature alarm */
> +	data->crit_alarm = (eax >> 5) & 1;
> +
> +	/* Temperature reached threshold1 */
> +	if (eax & THERM_LOG_THRESHOLD1)
> +		data->max_alarm = 1;
> +	/* Temperature reached threshold0 */
> +	else if (eax & THERM_LOG_THRESHOLD0)
> +		data->max_alarm = 0;
> +	/* If none of these cases, don't update max_alarm */
> +
> +	return;
> +}
> +
>  static struct coretemp_data *coretemp_update_device(struct device *dev)
>  {
>  	struct coretemp_data *data = dev_get_drvdata(dev);
> @@ -138,7 +204,6 @@ static struct coretemp_data *coretemp_update_device(struct device *dev)
>  
>  		data->valid = 0;
>  		rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
> -		data->alarm = (eax >> 5) & 1;
>  		/* update only if data has been valid */
>  		if (eax & 0x80000000) {
>  			data->temp = data->tjmax - (((eax >> 16)
> @@ -298,6 +363,106 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
>  	rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
>  }
>  
> +/* Platform thermal Interrupt Handler */
> +static int coretemp_interrupt(__u64 msr_val)
> +{
> +

That blank line isn't really needed.

> +	if (msr_val & THERM_LOG_THRESHOLD0) {
> +		if (!(msr_val & THERM_STATUS_THRESHOLD0))
> +			pr_info("%s:Lower Threshold Reached\n", __func__);

Info with each interrupt seems to be excessive. I would suggest to make it a debug message
if you really think it is needed. And __func__ should not be needed at all.

> +		/* Reset the Threshold0 interrupt */
> +		wrmsrl(MSR_IA32_THERM_STATUS, msr_val & ~THERM_LOG_THRESHOLD0);
> +	}
> +
> +	if (msr_val & THERM_LOG_THRESHOLD1) {
> +		if (msr_val & THERM_STATUS_THRESHOLD1)
> +			pr_info("%s:Upper Threshold Reached\n", __func__);

Same here.

> +		/* Reset the Threshold1 interrupt */
> +		wrmsrl(MSR_IA32_THERM_STATUS, msr_val & ~THERM_LOG_THRESHOLD1);
> +	}
> +
> +	return 0;
> +}
> +
> +static void configure_apic(void *info)
> +{
> +	u32 l;
> +	int *flag = (int *)info;
> +
> +	l = apic_read(APIC_LVTTHMR);
> +
> +	if (*flag)	/* Non-Zero flag Masks the APIC */
> +		apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
> +	else		/* Zero flag UnMasks the APIC */
> +		apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
> +}
> +
Fails to build if one manages to have APIC undefined (eg on a 32 bit kernel
with coretemp enabled and local APIC disabled).

drivers/hwmon/coretemp.c: In function ‘configure_apic’:
drivers/hwmon/coretemp.c:393: error: implicit declaration of function ‘apic_read’
drivers/hwmon/coretemp.c:396: error: implicit declaration of function ‘apic_write’

> +static int set_core_threshold(struct coretemp_data *data, int temp, int thres)
> +{
> +	u32 eax, edx;
> +	int diff;
> +	int flag = 1;
> +
> +	if (temp > data->tjmax)
> +		return -EINVAL;
> +
> +	mutex_lock(&data->update_lock);
> +
> +	diff = (data->tjmax - temp)/1000;
> +
> +	/* Mask the APIC */
> +	smp_call_function_single(data->id, &configure_apic, &flag, 1);
> +
> +	rdmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
> +
> +	if (thres = CORE_TMIN) {
> +		eax = (eax & ~THERM_MASK_THRESHOLD0) |
> +					(diff << THERM_SHIFT_THRESHOLD0);
> +		data->tmin = temp;
> +	} else {
> +		eax = (eax & ~THERM_MASK_THRESHOLD1) |
> +					(diff << THERM_SHIFT_THRESHOLD1);
> +		data->ttarget = temp;
> +	}
> +
> +	wrmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, eax, edx);
> +
> +	/* Unmask the APIC */
> +	flag = 0;
> +	smp_call_function_single(data->id, &configure_apic, &flag, 1);
> +
> +	mutex_unlock(&data->update_lock);
> +	return 0;
> +}
> +
> +static int __devinit config_thresh_intrpt(struct coretemp_data *data,
> +								int enable)
> +{
> +	u32 eax, edx;
> +	int flag = 1; /* Non-Zero Flag masks the apic */
> +
> +	smp_call_function_single(data->id, &configure_apic, &flag, 1);
> +
> +	rdmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
> +
> +	if (enable) {
> +		eax |= (THERM_INT_THRESHOLD0_ENABLE |
> +						THERM_INT_THRESHOLD1_ENABLE);
> +		platform_thermal_notify = coretemp_interrupt;
> +	} else {
> +		eax &= (~(THERM_INT_THRESHOLD0_ENABLE |
> +						THERM_INT_THRESHOLD1_ENABLE));
> +		platform_thermal_notify = NULL;
> +	}
> +
> +	wrmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, eax, edx);
> +
> +	flag = 0; /*Flag should be zero to unmask the apic */
> +	smp_call_function_single(data->id, &configure_apic, &flag, 1);
> +
> +	return 0;
> +}
> +
>  static int __devinit coretemp_probe(struct platform_device *pdev)
>  {
>  	struct coretemp_data *data;
> @@ -351,6 +516,10 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
>  	}
>  
>  	data->tjmax = get_tjmax(c, data->id, &pdev->dev);
> +	/* Initialize ttarget value. If IA32_TEMPERATURE_TARGET is
> +	 * supported, this value will be over written below

overwritten 

> +	 */
> +	data->ttarget = data->tjmax - 20000;
>  	platform_set_drvdata(pdev, data);
>  
>  	/*
> @@ -368,13 +537,18 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
>  		} else {
>  			data->ttarget = data->tjmax -
>  					(((eax >> 8) & 0xff) * 1000);
> -			err = device_create_file(&pdev->dev,
> -					&sensor_dev_attr_temp1_max.dev_attr);
> -			if (err)
> -				goto exit_free;
>  		}
>  	}
>  
> +	/* Enable threshold interrupt support */
> +	config_thresh_intrpt(data, 1);
> +
> +	/* Set Initial Core thresholds.
> +	 * The lower and upper threshold values here are assumed
> +	 */
> +	set_core_threshold(data, 0, CORE_TMIN);
> +	set_core_threshold(data, data->ttarget, CORE_TTARGET);
> +

I think I asked before ... are the threshold registers known to be supported on all intel CPUs
with coretemp support, or is some detection needed ?

>  	if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
>  		goto exit_dev;
>  
> @@ -404,7 +578,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev)
>  
>  	hwmon_device_unregister(data->hwmon_dev);
>  	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
> -	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
> +	config_thresh_intrpt(data, 0);
>  	platform_set_drvdata(pdev, NULL);
>  	kfree(data);
>  	return 0;
> -- 
> 1.6.5.2
> 


> _______________________________________________
> lm-sensors mailing list
> lm-sensors@lm-sensors.org
> http://lists.lm-sensors.org/mailman/listinfo/lm-sensors


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

WARNING: multiple messages have this Message-ID (diff)
From: Guenter Roeck <guenter.roeck@ericsson.com>
To: "R, Durgadoss" <durgadoss.r@intel.com>
Cc: "x86@kernel.org" <x86@kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"lm-sensors@lm-sensors.org" <lm-sensors@lm-sensors.org>,
	Fenghua Yu <fenghua.yu@intel.com>
Subject: Re: Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c
Date: Tue, 4 Jan 2011 11:40:54 -0800	[thread overview]
Message-ID: <20110104194054.GA635@ericsson.com> (raw)
In-Reply-To: <D6D887BA8C9DFF48B5233887EF04654105C11DB93B@bgsmsx502.gar.corp.intel.com>

On Tue, Dec 28, 2010 at 03:56:57PM +0530, R, Durgadoss wrote:
> Hi,
> 
> I am submitting a patch to enable core thermal threshold
> Support to coretemp.c. There are two core thermal thresholds
> available through sysfs interfaces temp1_max and temp1_max_hyst.
> The temp1_max_alarm is set when temperature reaches or crosses
> above temp1_max or drops below temp1_max_hyst.
> 
> This patch is generated against stable Linux-2.6 kernel.
> 
> Kindly review and merge.
> ----------------------------------------------------------------
> From: Durgadoss R <durgadoss.r@intel.com>
> 
> Date: Sun, 19 Dec 2010 22:44:54 +0530
> Subject: [PATCH 2/2] hwmon:Adding_Threshold_Support_to_Coretemp
> 
> This patch adds core thermal thresholds support to coretemp.
> These thresholds can be configured via the sysfs interfaces temp1_max
> and temp1_max_hyst. An interrupt is generated when CPU temperature
> goes above temp1_max or drops below temp1_max_hyst.
> 
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>

Fenghua Yu <fenghua.yu@intel.com> as driver maintainer will have to Ack this patch.

Driver fails to build if MCE is not configured.

drivers/built-in.o: In function `config_thresh_intrpt':
coretemp.c:(.devinit.text+0xd909): undefined reference to `platform_thermal_notify'
coretemp.c:(.devinit.text+0xd91b): undefined reference to `platform_thermal_notify'
make: *** [.tmp_vmlinux1] Error 1

It also fails to build if APIC is not defined. See below. After that I gave up
trying more combinations. _Please_ do your homework.

> ---
>  Documentation/hwmon/coretemp |    8 ++
>  drivers/hwmon/coretemp.c     |  214 ++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 202 insertions(+), 20 deletions(-)
> 
> diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
> index 25568f8..615fdbe 100644
> --- a/Documentation/hwmon/coretemp
> +++ b/Documentation/hwmon/coretemp
> @@ -29,6 +29,14 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
>  
>  temp1_input	 - Core temperature (in millidegrees Celsius).
>  temp1_max	 - All cooling devices should be turned on (on Core2).
> +		   Initialized with IA32_TEMPERATURE_TARGET if supported,
> +		   otherwise initialized with (tjmax - 20). When the CPU
> +		   temperature reaches this temperature, an interrupt is
> +		   generated and temp1_max_alarm is set.
> +temp1_max_hyst	 - If the CPU temperature falls below than temperature,

	... falls below _this_ temperature ...

> +		   an interrupt is generated and temp1_max_alarm is reset.
> +temp1_max_alarm - Set if the temperature reaches or exceeds temp1_max.
> +		   Reset if the temperature drops to or below temp1_max_hyst.
>  temp1_crit	 - Maximum junction temperature (in millidegrees Celsius).
>  temp1_crit_alarm - Set when Out-of-spec bit is set, never clears.
>  		   Correct CPU operation is no longer guaranteed.
> diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
> index 42de98d..025902f 100644
> --- a/drivers/hwmon/coretemp.c
> +++ b/drivers/hwmon/coretemp.c
> @@ -36,11 +36,12 @@
>  #include <asm/msr.h>
>  #include <asm/processor.h>
>  #include <asm/smp.h>
> +#include <asm/mce.h>
>  
>  #define DRVNAME	"coretemp"
>  
> -typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
> -		SHOW_NAME } SHOW;
> +enum attributes { SHOW_TEMP, SHOW_TJMAX, CORE_TTARGET, CORE_TMIN, SHOW_LABEL,
> +		SHOW_NAME, SHOW_CRIT_ALARM, SHOW_MAX_ALARM } attrs;
>  
This defines a global variable named attrs. Not a good idea. You do not have to specify "attrs" here.

>  /*
>   * Functions declaration
> @@ -59,9 +60,14 @@ struct coretemp_data {
>  	int temp;
>  	int tjmax;
>  	int ttarget;
> -	u8 alarm;
> +	int tmin;
> +	u8 max_alarm;
> +	u8 crit_alarm;
>  };
>  
> +static void update_alarm(struct coretemp_data *data);
> +static int set_core_threshold(struct coretemp_data *data, int temp, int thres);
> +
Please keep with other function forward references. Yes, I know you need the struct,
but that doesn't have to be defined when you declare the forward references.
Or define the struct first and then all the forward declarations. 

>  /*
>   * Sysfs stuff
>   */
> @@ -83,9 +89,15 @@ static ssize_t show_name(struct device *dev, struct device_attribute
>  static ssize_t show_alarm(struct device *dev, struct device_attribute
>  			  *devattr, char *buf)
>  {
> -	struct coretemp_data *data = coretemp_update_device(dev);
> -	/* read the Out-of-spec log, never clear */
> -	return sprintf(buf, "%d\n", data->alarm);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +	struct coretemp_data *data = dev_get_drvdata(dev);
> +
> +	update_alarm(data);
> +	if (attr->index == SHOW_CRIT_ALARM)
> +		/* read the Out-of-spec log, never clear */
> +		return sprintf(buf, "%d\n", data->crit_alarm);
> +
Since the if () statement includes a comment, it is better to add { } to improve 
readability.

> +	return sprintf(buf, "%d\n", data->max_alarm);
>  }
>  
>  static ssize_t show_temp(struct device *dev,
> @@ -93,33 +105,67 @@ static ssize_t show_temp(struct device *dev,
>  {
>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
>  	struct coretemp_data *data = coretemp_update_device(dev);
> -	int err;
> +	int err = -EINVAL;
>  
> -	if (attr->index == SHOW_TEMP)
> +	switch (attr->index) {
> +	case SHOW_TEMP:
>  		err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
> -	else if (attr->index == SHOW_TJMAX)
> +		break;
> +	case SHOW_TJMAX:
>  		err = sprintf(buf, "%d\n", data->tjmax);
> -	else
> +		break;
> +	case CORE_TTARGET:
>  		err = sprintf(buf, "%d\n", data->ttarget);
> +		break;
> +	case CORE_TMIN:
> +		err = sprintf(buf, "%d\n", data->tmin);
> +		break;
> +	}
> +
>  	return err;
>  }
>  
> +
> +static ssize_t store_temp(struct device *dev,
> +		struct device_attribute *devattr, const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +	struct coretemp_data *data = dev_get_drvdata(dev);
> +	unsigned long val;
> +	int err;
> +
> +	if (strict_strtoul(buf, 10, &val))
> +		return -EINVAL;
> +
> +	err = set_core_threshold(data, val, attr->index);
> +
> +	return err ? err : count;
> +}
> +
>  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
>  			  SHOW_TEMP);
>  static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
>  			  SHOW_TJMAX);
> -static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
> -			  SHOW_TTARGET);
> -static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp,
> +						store_temp, CORE_TTARGET);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp,
> +						store_temp, CORE_TMIN);
> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
> +							SHOW_CRIT_ALARM);
> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
> +							SHOW_MAX_ALARM);
>  static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
>  static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
>  
>  static struct attribute *coretemp_attributes[] = {
>  	&sensor_dev_attr_name.dev_attr.attr,
>  	&sensor_dev_attr_temp1_label.dev_attr.attr,
> -	&dev_attr_temp1_crit_alarm.attr,
> +	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
>  	&sensor_dev_attr_temp1_input.dev_attr.attr,
>  	&sensor_dev_attr_temp1_crit.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
>  	NULL
>  };
>  
> @@ -127,6 +173,26 @@ static const struct attribute_group coretemp_group = {
>  	.attrs = coretemp_attributes,
>  };
>  
> +static void update_alarm(struct coretemp_data *data)
> +{
> +	u32 eax, edx;
> +
> +	rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
> +
> +	/* Update the critical temperature alarm */
> +	data->crit_alarm = (eax >> 5) & 1;
> +
> +	/* Temperature reached threshold1 */
> +	if (eax & THERM_LOG_THRESHOLD1)
> +		data->max_alarm = 1;
> +	/* Temperature reached threshold0 */
> +	else if (eax & THERM_LOG_THRESHOLD0)
> +		data->max_alarm = 0;
> +	/* If none of these cases, don't update max_alarm */
> +
> +	return;
> +}
> +
>  static struct coretemp_data *coretemp_update_device(struct device *dev)
>  {
>  	struct coretemp_data *data = dev_get_drvdata(dev);
> @@ -138,7 +204,6 @@ static struct coretemp_data *coretemp_update_device(struct device *dev)
>  
>  		data->valid = 0;
>  		rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
> -		data->alarm = (eax >> 5) & 1;
>  		/* update only if data has been valid */
>  		if (eax & 0x80000000) {
>  			data->temp = data->tjmax - (((eax >> 16)
> @@ -298,6 +363,106 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
>  	rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
>  }
>  
> +/* Platform thermal Interrupt Handler */
> +static int coretemp_interrupt(__u64 msr_val)
> +{
> +

That blank line isn't really needed.

> +	if (msr_val & THERM_LOG_THRESHOLD0) {
> +		if (!(msr_val & THERM_STATUS_THRESHOLD0))
> +			pr_info("%s:Lower Threshold Reached\n", __func__);

Info with each interrupt seems to be excessive. I would suggest to make it a debug message
if you really think it is needed. And __func__ should not be needed at all.

> +		/* Reset the Threshold0 interrupt */
> +		wrmsrl(MSR_IA32_THERM_STATUS, msr_val & ~THERM_LOG_THRESHOLD0);
> +	}
> +
> +	if (msr_val & THERM_LOG_THRESHOLD1) {
> +		if (msr_val & THERM_STATUS_THRESHOLD1)
> +			pr_info("%s:Upper Threshold Reached\n", __func__);

Same here.

> +		/* Reset the Threshold1 interrupt */
> +		wrmsrl(MSR_IA32_THERM_STATUS, msr_val & ~THERM_LOG_THRESHOLD1);
> +	}
> +
> +	return 0;
> +}
> +
> +static void configure_apic(void *info)
> +{
> +	u32 l;
> +	int *flag = (int *)info;
> +
> +	l = apic_read(APIC_LVTTHMR);
> +
> +	if (*flag)	/* Non-Zero flag Masks the APIC */
> +		apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
> +	else		/* Zero flag UnMasks the APIC */
> +		apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
> +}
> +
Fails to build if one manages to have APIC undefined (eg on a 32 bit kernel
with coretemp enabled and local APIC disabled).

drivers/hwmon/coretemp.c: In function ‘configure_apic’:
drivers/hwmon/coretemp.c:393: error: implicit declaration of function ‘apic_read’
drivers/hwmon/coretemp.c:396: error: implicit declaration of function ‘apic_write’

> +static int set_core_threshold(struct coretemp_data *data, int temp, int thres)
> +{
> +	u32 eax, edx;
> +	int diff;
> +	int flag = 1;
> +
> +	if (temp > data->tjmax)
> +		return -EINVAL;
> +
> +	mutex_lock(&data->update_lock);
> +
> +	diff = (data->tjmax - temp)/1000;
> +
> +	/* Mask the APIC */
> +	smp_call_function_single(data->id, &configure_apic, &flag, 1);
> +
> +	rdmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
> +
> +	if (thres == CORE_TMIN) {
> +		eax = (eax & ~THERM_MASK_THRESHOLD0) |
> +					(diff << THERM_SHIFT_THRESHOLD0);
> +		data->tmin = temp;
> +	} else {
> +		eax = (eax & ~THERM_MASK_THRESHOLD1) |
> +					(diff << THERM_SHIFT_THRESHOLD1);
> +		data->ttarget = temp;
> +	}
> +
> +	wrmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, eax, edx);
> +
> +	/* Unmask the APIC */
> +	flag = 0;
> +	smp_call_function_single(data->id, &configure_apic, &flag, 1);
> +
> +	mutex_unlock(&data->update_lock);
> +	return 0;
> +}
> +
> +static int __devinit config_thresh_intrpt(struct coretemp_data *data,
> +								int enable)
> +{
> +	u32 eax, edx;
> +	int flag = 1; /* Non-Zero Flag masks the apic */
> +
> +	smp_call_function_single(data->id, &configure_apic, &flag, 1);
> +
> +	rdmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
> +
> +	if (enable) {
> +		eax |= (THERM_INT_THRESHOLD0_ENABLE |
> +						THERM_INT_THRESHOLD1_ENABLE);
> +		platform_thermal_notify = coretemp_interrupt;
> +	} else {
> +		eax &= (~(THERM_INT_THRESHOLD0_ENABLE |
> +						THERM_INT_THRESHOLD1_ENABLE));
> +		platform_thermal_notify = NULL;
> +	}
> +
> +	wrmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, eax, edx);
> +
> +	flag = 0; /*Flag should be zero to unmask the apic */
> +	smp_call_function_single(data->id, &configure_apic, &flag, 1);
> +
> +	return 0;
> +}
> +
>  static int __devinit coretemp_probe(struct platform_device *pdev)
>  {
>  	struct coretemp_data *data;
> @@ -351,6 +516,10 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
>  	}
>  
>  	data->tjmax = get_tjmax(c, data->id, &pdev->dev);
> +	/* Initialize ttarget value. If IA32_TEMPERATURE_TARGET is
> +	 * supported, this value will be over written below

overwritten 

> +	 */
> +	data->ttarget = data->tjmax - 20000;
>  	platform_set_drvdata(pdev, data);
>  
>  	/*
> @@ -368,13 +537,18 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
>  		} else {
>  			data->ttarget = data->tjmax -
>  					(((eax >> 8) & 0xff) * 1000);
> -			err = device_create_file(&pdev->dev,
> -					&sensor_dev_attr_temp1_max.dev_attr);
> -			if (err)
> -				goto exit_free;
>  		}
>  	}
>  
> +	/* Enable threshold interrupt support */
> +	config_thresh_intrpt(data, 1);
> +
> +	/* Set Initial Core thresholds.
> +	 * The lower and upper threshold values here are assumed
> +	 */
> +	set_core_threshold(data, 0, CORE_TMIN);
> +	set_core_threshold(data, data->ttarget, CORE_TTARGET);
> +

I think I asked before ... are the threshold registers known to be supported on all intel CPUs
with coretemp support, or is some detection needed ?

>  	if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
>  		goto exit_dev;
>  
> @@ -404,7 +578,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev)
>  
>  	hwmon_device_unregister(data->hwmon_dev);
>  	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
> -	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
> +	config_thresh_intrpt(data, 0);
>  	platform_set_drvdata(pdev, NULL);
>  	kfree(data);
>  	return 0;
> -- 
> 1.6.5.2
> 


> _______________________________________________
> lm-sensors mailing list
> lm-sensors@lm-sensors.org
> http://lists.lm-sensors.org/mailman/listinfo/lm-sensors


  reply	other threads:[~2011-01-04 19:40 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-12-28 10:26 Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c R, Durgadoss
2010-12-28 10:38 ` [lm-sensors] Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c R, Durgadoss
2011-01-04 19:40 ` Guenter Roeck [this message]
2011-01-04 19:40   ` Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c Guenter Roeck
  -- strict thread matches above, loose matches on Subject: below --
2011-01-20  7:57 [lm-sensors] patch[1/1]:hwmon:Adding_Threshold_support_to_coretemp R, Durgadoss
2011-01-20 22:17 ` [lm-sensors] Fenghua Yu
2011-01-21  2:26   ` [lm-sensors] Guenter Roeck
2011-01-03 11:53 Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c R, Durgadoss
2011-01-03 11:55 ` [lm-sensors] Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c R, Durgadoss
2010-12-20  6:09 Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c R, Durgadoss
2010-12-20  6:21 ` [lm-sensors] Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c R, Durgadoss
2009-11-14  9:09 [lm-sensors] + Jean Delvare
2009-06-12 18:16 [lm-sensors] =?UTF-8?Q?Re: [PATCH] hwmon: Add driver for VIA CPU tomaz.mertelj
2009-06-12 18:20 ` [lm-sensors] Michael S. Zick
2009-06-12 15:25 [lm-sensors] =?UTF-8?Q?Re: [PATCH] hwmon: Add driver for VIA CPU tomaz.mertelj
2009-06-12 15:31 ` [lm-sensors] " Michael S. Zick
2009-06-12 16:04   ` Michael S. Zick
2009-06-12 17:38     ` [lm-sensors] Michael S. Zick
2008-09-18  8:12 [lm-sensors] + Sebastian Siewior
2008-09-18  8:15 ` Sebastian Siewior
2008-09-18  8:25 ` Andrew Morton
2008-09-18  9:08 ` Sebastian Siewior
2008-09-18 20:02 ` Jean Delvare
2008-09-18 21:13 ` Andrew Morton
2008-09-19 13:13 ` Jean Delvare
2007-04-10 13:02 [lm-sensors] Hardware monitoring subsystem maintainer position is Jean Delvare
2007-04-12  5:57 ` [lm-sensors] Hardware monitoring subsystem maintainer Krzysztof Helt
2007-04-12  7:27   ` [lm-sensors] Hardware monitoring subsystem Hans de Goede
2007-04-15  2:07     ` [lm-sensors] Dmitry Torokhov
2005-06-11 10:20 [lm-sensors] wore
2005-10-26 22:17 ` [lm-sensors] Mauro Carvalho Chehab
2005-10-26 22:40 ` [lm-sensors] Greg KH
2005-10-26 22:46 ` [lm-sensors] Jean Delvare
2005-10-27 14:03 ` [lm-sensors] Mauro Carvalho Chehab
2005-10-27 16:53 ` [lm-sensors] Mauro Carvalho Chehab
2005-10-27 23:07 ` [lm-sensors] Jean Delvare
2005-10-27 23:43 ` [lm-sensors] Jean Delvare
2006-05-05 19:34 ` [lm-sensors] Dieter Jurzitza
2006-05-05 20:53 ` [lm-sensors] Dieter Jurzitza
2006-05-30  8:53 ` [lm-sensors] Laurent Pinchart
2006-12-03  8:22 ` [lm-sensors] Udo van den Heuvel
2006-12-03  8:38 ` [lm-sensors] Thomas Dohl
2006-12-03  8:49 ` [lm-sensors] Udo van den Heuvel
2006-12-03 20:20 ` [lm-sensors] Thomas Dohl
2007-01-08  7:39 ` [lm-sensors] Christophe de Rivière
2007-04-15  7:48 ` [lm-sensors] jk
2007-05-10 17:36 ` [lm-sensors] Dieter Rogiest
2007-05-10 18:02 ` [lm-sensors] Hans-Jürgen Koch
2007-05-10 18:46 ` [lm-sensors] Stephen Cormier
2007-05-10 19:31 ` [lm-sensors] Rudolf Marek
2007-05-10 20:34 ` [lm-sensors] Dieter Rogiest
2007-05-10 22:28 ` [lm-sensors] Rudolf Marek
2007-05-10 22:40 ` [lm-sensors] Dieter Rogiest
2007-07-24 12:06 ` [lm-sensors] Jean Delvare
2007-07-24 12:57 ` [lm-sensors] Christian Hohnstaedt
2007-07-24 13:09 ` [lm-sensors] Jean Delvare
2007-07-24 13:43 ` [lm-sensors] Christian Hohnstaedt
2007-08-12 11:13 ` [lm-sensors] Jean Delvare
2007-08-13  8:39 ` [lm-sensors] Christian Hohnstaedt
2007-08-13 12:29 ` [lm-sensors] Jean Delvare
2007-08-15 15:32 ` [lm-sensors] Christian Hohnstaedt
2007-08-15 19:28 ` [lm-sensors] Jean Delvare
2007-08-16  8:08 ` [lm-sensors] Christian Hohnstaedt
2007-10-07 18:38 ` [lm-sensors] Hans de Goede
2007-10-07 19:33 ` [lm-sensors] Mark M. Hoffman
2007-10-31 15:29 ` [lm-sensors] Hans de Goede
2008-06-01 10:15 ` [lm-sensors] Dominik Geyer
2008-09-17 13:50 ` [lm-sensors] Frank Myhr
2010-03-09 22:50 ` [lm-sensors] Phillip Pi
2010-10-31  7:42 ` [lm-sensors] Zamzit
2010-12-20  6:18 ` [lm-sensors] R, Durgadoss
2010-12-28 10:37 ` [lm-sensors] R, Durgadoss
2011-01-03 11:54 ` [lm-sensors] R, Durgadoss
2011-01-03 15:03   ` [lm-sensors] Guenter Roeck
2011-01-03 15:23     ` [lm-sensors] R, Durgadoss
2011-01-03 15:38       ` [lm-sensors] Guenter Roeck
2011-01-04  9:08         ` [lm-sensors] R, Durgadoss
2011-01-20 20:04 ` [lm-sensors] Guenter Roeck
2011-01-24 21:20 ` [lm-sensors] Yu, Fenghua
2011-03-28 18:11 ` [lm-sensors] R, Durgadoss
2011-04-05 17:47 ` [lm-sensors] Guenter Roeck
2011-04-06  6:54 ` [lm-sensors] R, Durgadoss
2011-04-06  7:18 ` [lm-sensors] Guenter Roeck
2011-06-21  9:44 ` [lm-sensors] Jay Alexander Fleming
2011-06-23 21:30 ` [lm-sensors] Valentijn Scholten
2011-06-24 22:01 ` [lm-sensors] Valentijn Scholten
2011-06-25 18:44 ` [lm-sensors] Valentijn Scholten
2011-10-01 13:38 ` [lm-sensors] Maryvonne JUDIT
2011-10-23 14:53 ` [lm-sensors] Malika et Christophe CHARBONNIER
2011-12-22  9:33 ` [lm-sensors] serge chartrain

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110104194054.GA635@ericsson.com \
    --to=guenter.roeck@ericsson.com \
    --cc=durgadoss.r@intel.com \
    --cc=fenghua.yu@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lm-sensors@lm-sensors.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.