All of lore.kernel.org
 help / color / mirror / Atom feed
From: Fenghua Yu <fenghua.yu@intel.com>
To: "R, Durgadoss" <durgadoss.r@intel.com>
Cc: "Yu, Fenghua" <fenghua.yu@intel.com>,
	Guenter Roeck <guenter.roeck@ericsson.com>,
	"khali@linux-fr.org" <khali@linux-fr.org>,
	"lm-sensors@lm-sensors.org" <lm-sensors@lm-sensors.org>,
	linux-kernel <linux-kernel@vger.kernel.org>,
	H Peter Anvin <hpa@zytor.com>
Subject: Re: [lm-sensors]
Date: Thu, 20 Jan 2011 22:17:05 +0000	[thread overview]
Message-ID: <20110120221704.GA26954@linux-os.sc.intel.com> (raw)
In-Reply-To: <D6D887BA8C9DFF48B5233887EF046541094482ED6A@bgsmsx502.gar.corp.intel.com>

On Wed, Jan 19, 2011 at 11:45:44PM -0800, R, Durgadoss wrote:
> Hi,
> 
> This patch adds the core temperature threshold support to
> coretemp.c. 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.
> 
> This patch needs the x86 patch, that can be downloaded
> from here:
> http://git.kernel.org/tip/9e76a97efd31a08cb19d0ba12013b8fb4ad3e474
> 
> ---------------------------------------------
> From: Durgadoss R <durgadoss.r@intel.com>
> 
> Date: Wed, 19 Jan 2011 03:52:19 +0530
> Subject: PATCH[1/1] hwmon:Adding_Threshold_support_to_coretemp
> 
> This patch adds the core temperature threshold support to
> coretemp.c. 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>
> 
> ---
>  Documentation/hwmon/coretemp |    8 ++
>  drivers/hwmon/coretemp.c     |  222 ++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 210 insertions(+), 20 deletions(-)
> 
> diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
> index 25568f8..2b89ae1 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 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..0d09255 100644
> --- a/drivers/hwmon/coretemp.c
> +++ b/drivers/hwmon/coretemp.c
> @@ -36,17 +36,21 @@
>  #include <asm/msr.h>
>  #include <asm/processor.h>
>  #include <asm/smp.h>
> +#include <asm/mce.h>
> +#include <asm/apic.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 };
>  
>  /*
>   * Functions declaration
>   */
>  
>  static struct coretemp_data *coretemp_update_device(struct device *dev);
> +static void update_alarm(struct coretemp_data *data);
> +static int set_core_threshold(struct coretemp_data *data, int temp, int thres);
>  
>  struct coretemp_data {
>  	struct device *hwmon_dev;
> @@ -59,7 +63,9 @@ struct coretemp_data {
>  	int temp;
>  	int tjmax;
>  	int ttarget;
> -	u8 alarm;
> +	int tmin;
> +	u8 max_alarm;
> +	u8 crit_alarm;
>  };
>  
>  /*
> @@ -83,9 +89,16 @@ 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);
> +	}
> +
> +	return sprintf(buf, "%d\n", data->max_alarm);
>  }
>  
>  static ssize_t show_temp(struct device *dev,
> @@ -93,33 +106,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 +174,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 +205,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 +364,110 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
>  	rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
>  }
>  
> +#ifdef CONFIG_X86_MCE
> +/* Platform thermal Interrupt Handler */
> +static int coretemp_interrupt(__u64 msr_val)
> +{
> +	if (msr_val & THERM_LOG_THRESHOLD0) {
> +		if (!(msr_val & THERM_STATUS_THRESHOLD0))
> +			pr_info(":Lower Threshold Reached\n");
> +		/* 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(":Upper Threshold Reached\n");
> +		/* Reset the Threshold1 interrupt */
> +		wrmsrl(MSR_IA32_THERM_STATUS, msr_val & ~THERM_LOG_THRESHOLD1);
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +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);
> +}
> +
> +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 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);
> +	} else {
> +		eax &= (~(THERM_INT_THRESHOLD0_ENABLE |
> +						THERM_INT_THRESHOLD1_ENABLE));
> +	}
> +
> +	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);
> +
> +#ifdef CONFIG_X86_MCE
> +	if (enable)
> +		platform_thermal_notify = coretemp_interrupt;
> +	else
> +		platform_thermal_notify = NULL;
> +#endif
> +	return 0;
> +}
> +
>  static int __devinit coretemp_probe(struct platform_device *pdev)
>  {
>  	struct coretemp_data *data;
> @@ -351,6 +521,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 overwritten below
> +	 */
> +	data->ttarget = data->tjmax - 20000;
>  	platform_set_drvdata(pdev, data);
>  
>  	/*
> @@ -368,13 +542,21 @@ 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;
>  		}
>  	}
>  
> +	/* Threshold support is available if the ACPI flag (bit 22) is set */
> +	if (cpu_has(c, X86_FEATURE_ACPI)) {
> +		/* 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);
> +	}
> +
>  	if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
>  		goto exit_dev;
>  
> @@ -404,7 +586,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;

This patch has compilation error:
ERROR: "platform_thermal_notify" [drivers/hwmon/coretemp.ko] undefined!

The reason is commit 9e76a97efd31a08cb19d0ba12013b8fb4ad3e474 patch for 
therm_throt.c in upstream doesn't export the symbol platform_thermal_notify.

The following patch should fix the issue. Apply it before compiling your patch.

Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---

 arch/x86/kernel/cpu/mcheck/therm_throt.c |    1 +
 1 files changed, 1 insertion(+)

diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index e12246f..6f8c5e9 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -59,6 +59,7 @@ struct thermal_state {
 
 /* Callback to handle core threshold interrupts */
 int (*platform_thermal_notify)(__u64 msr_val);
+EXPORT_SYMBOL(platform_thermal_notify);
 
 static DEFINE_PER_CPU(struct thermal_state, thermal_state);
 

_______________________________________________
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: Fenghua Yu <fenghua.yu@intel.com>
To: "R, Durgadoss" <durgadoss.r@intel.com>
Cc: "Yu, Fenghua" <fenghua.yu@intel.com>,
	Guenter Roeck <guenter.roeck@ericsson.com>,
	"khali@linux-fr.org" <khali@linux-fr.org>,
	"lm-sensors@lm-sensors.org" <lm-sensors@lm-sensors.org>,
	linux-kernel <linux-kernel@vger.kernel.org>,
	H Peter Anvin <hpa@zytor.com>
Subject: Re: patch[1/1]:hwmon:Adding_Threshold_support_to_coretemp
Date: Thu, 20 Jan 2011 14:17:05 -0800	[thread overview]
Message-ID: <20110120221704.GA26954@linux-os.sc.intel.com> (raw)
In-Reply-To: <D6D887BA8C9DFF48B5233887EF046541094482ED6A@bgsmsx502.gar.corp.intel.com>

On Wed, Jan 19, 2011 at 11:45:44PM -0800, R, Durgadoss wrote:
> Hi,
> 
> This patch adds the core temperature threshold support to
> coretemp.c. 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.
> 
> This patch needs the x86 patch, that can be downloaded
> from here:
> http://git.kernel.org/tip/9e76a97efd31a08cb19d0ba12013b8fb4ad3e474
> 
> ---------------------------------------------
> From: Durgadoss R <durgadoss.r@intel.com>
> 
> Date: Wed, 19 Jan 2011 03:52:19 +0530
> Subject: PATCH[1/1] hwmon:Adding_Threshold_support_to_coretemp
> 
> This patch adds the core temperature threshold support to
> coretemp.c. 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>
> 
> ---
>  Documentation/hwmon/coretemp |    8 ++
>  drivers/hwmon/coretemp.c     |  222 ++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 210 insertions(+), 20 deletions(-)
> 
> diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
> index 25568f8..2b89ae1 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 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..0d09255 100644
> --- a/drivers/hwmon/coretemp.c
> +++ b/drivers/hwmon/coretemp.c
> @@ -36,17 +36,21 @@
>  #include <asm/msr.h>
>  #include <asm/processor.h>
>  #include <asm/smp.h>
> +#include <asm/mce.h>
> +#include <asm/apic.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 };
>  
>  /*
>   * Functions declaration
>   */
>  
>  static struct coretemp_data *coretemp_update_device(struct device *dev);
> +static void update_alarm(struct coretemp_data *data);
> +static int set_core_threshold(struct coretemp_data *data, int temp, int thres);
>  
>  struct coretemp_data {
>  	struct device *hwmon_dev;
> @@ -59,7 +63,9 @@ struct coretemp_data {
>  	int temp;
>  	int tjmax;
>  	int ttarget;
> -	u8 alarm;
> +	int tmin;
> +	u8 max_alarm;
> +	u8 crit_alarm;
>  };
>  
>  /*
> @@ -83,9 +89,16 @@ 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);
> +	}
> +
> +	return sprintf(buf, "%d\n", data->max_alarm);
>  }
>  
>  static ssize_t show_temp(struct device *dev,
> @@ -93,33 +106,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 +174,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 +205,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 +364,110 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
>  	rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
>  }
>  
> +#ifdef CONFIG_X86_MCE
> +/* Platform thermal Interrupt Handler */
> +static int coretemp_interrupt(__u64 msr_val)
> +{
> +	if (msr_val & THERM_LOG_THRESHOLD0) {
> +		if (!(msr_val & THERM_STATUS_THRESHOLD0))
> +			pr_info(":Lower Threshold Reached\n");
> +		/* 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(":Upper Threshold Reached\n");
> +		/* Reset the Threshold1 interrupt */
> +		wrmsrl(MSR_IA32_THERM_STATUS, msr_val & ~THERM_LOG_THRESHOLD1);
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +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);
> +}
> +
> +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 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);
> +	} else {
> +		eax &= (~(THERM_INT_THRESHOLD0_ENABLE |
> +						THERM_INT_THRESHOLD1_ENABLE));
> +	}
> +
> +	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);
> +
> +#ifdef CONFIG_X86_MCE
> +	if (enable)
> +		platform_thermal_notify = coretemp_interrupt;
> +	else
> +		platform_thermal_notify = NULL;
> +#endif
> +	return 0;
> +}
> +
>  static int __devinit coretemp_probe(struct platform_device *pdev)
>  {
>  	struct coretemp_data *data;
> @@ -351,6 +521,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 overwritten below
> +	 */
> +	data->ttarget = data->tjmax - 20000;
>  	platform_set_drvdata(pdev, data);
>  
>  	/*
> @@ -368,13 +542,21 @@ 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;
>  		}
>  	}
>  
> +	/* Threshold support is available if the ACPI flag (bit 22) is set */
> +	if (cpu_has(c, X86_FEATURE_ACPI)) {
> +		/* 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);
> +	}
> +
>  	if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
>  		goto exit_dev;
>  
> @@ -404,7 +586,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;

This patch has compilation error:
ERROR: "platform_thermal_notify" [drivers/hwmon/coretemp.ko] undefined!

The reason is commit 9e76a97efd31a08cb19d0ba12013b8fb4ad3e474 patch for 
therm_throt.c in upstream doesn't export the symbol platform_thermal_notify.

The following patch should fix the issue. Apply it before compiling your patch.

Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---

 arch/x86/kernel/cpu/mcheck/therm_throt.c |    1 +
 1 files changed, 1 insertion(+)

diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index e12246f..6f8c5e9 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -59,6 +59,7 @@ struct thermal_state {
 
 /* Callback to handle core threshold interrupts */
 int (*platform_thermal_notify)(__u64 msr_val);
+EXPORT_SYMBOL(platform_thermal_notify);
 
 static DEFINE_PER_CPU(struct thermal_state, thermal_state);
 

  reply	other threads:[~2011-01-20 22:17 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-20  7:57 [lm-sensors] patch[1/1]:hwmon:Adding_Threshold_support_to_coretemp R, Durgadoss
2011-01-20 22:17 ` Fenghua Yu [this message]
2011-01-20 22:17   ` patch[1/1]:hwmon:Adding_Threshold_support_to_coretemp Fenghua Yu
2011-01-21  2:26   ` [lm-sensors] Guenter Roeck
2011-01-21  2:26     ` patch[1/1]:hwmon:Adding_Threshold_support_to_coretemp Guenter Roeck
2011-01-21  4:12     ` [lm-sensors] [PATCH] x86, mcheck, Fenghua Yu
2011-01-21  4:12       ` [PATCH] x86,mcheck,therm_throt.c: Export symbol platform_thermal_notify to allow coretemp to handler intr Fenghua Yu
2011-01-21 15:37       ` [lm-sensors] [tip:x86/urgent] x86, mcheck, tip-bot for Fenghua Yu
2011-01-21 15:37         ` [tip:x86/urgent] x86, mcheck, therm_throt.c: Export symbol platform_thermal_notify to allow coretemp to handler intr tip-bot for Fenghua Yu
  -- strict thread matches above, loose matches on Subject: below --
2010-12-28 10:38 [lm-sensors] Patch[2/2]:hwmon:Adding_Threshold_Support_to_Coretemp.c R, Durgadoss
2011-01-04 19:40 ` [lm-sensors] Guenter Roeck
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=20110120221704.GA26954@linux-os.sc.intel.com \
    --to=fenghua.yu@intel.com \
    --cc=durgadoss.r@intel.com \
    --cc=guenter.roeck@ericsson.com \
    --cc=hpa@zytor.com \
    --cc=khali@linux-fr.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lm-sensors@lm-sensors.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.