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_min. The expectation is that _min is lesser than the current temperature and _max is higher than the current temperature. Whenever the current temperature crosses these limits, an interrupt is generated. This patch is generated against stable Linux-2.6 kernel. As per Guenter's earlier comments the ABI names are changed to _max and _min. Kindly review and merge. ------------------------------------------------------------------ From: Durgadoss R <durgadoss.r@xxxxxxxxx> Date: Thu, 16 Dec 2010 23:09:54 +0530 Subject: [PATCH] Adding_threshold_support_to_coretemp This patch adds the core thermal threshold support to coretemp.c. These thresholds can be read/written using the sysfs interface temp1_max and temp1_min. These can be used to generate interrupts, to do dynamic power management. Signed-off-by: Durgadoss R <durgadoss.r@xxxxxxxxx> --- Documentation/hwmon/coretemp | 6 ++ arch/x86/include/asm/msr-index.h | 12 ++++ drivers/hwmon/coretemp.c | 118 +++++++++++++++++++++++++++++++++++--- 3 files changed, 127 insertions(+), 9 deletions(-) diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp index 25568f8..096cd8b 100644 --- a/Documentation/hwmon/coretemp +++ b/Documentation/hwmon/coretemp @@ -29,6 +29,12 @@ 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). + If the IA32_TEMPERATURE_TARGET is not supported, this + value indicates the higher core threshold. When the CPU + temperature crosses this temperature, an interrupt is + generated. +temp1_min - Indicates the lower threshold of the core. An interrupt is + generated when CPU temperature crosses this threshold. 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/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 3ea3dc4..31cefad 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -253,6 +253,18 @@ #define PACKAGE_THERM_INT_LOW_ENABLE (1 << 1) #define PACKAGE_THERM_INT_PLN_ENABLE (1 << 24) +/* Thermal Thresholds Support */ +#define THERM_INT_THRESHOLD0_ENABLE (1 << 15) +#define THERM_OFFSET_THRESHOLD0 8 +#define THERM_MASK_THRESHOLD0 (0x7f << THERM_OFFSET_THRESHOLD0) +#define THERM_INT_THRESHOLD1_ENABLE (1 << 23) +#define THERM_OFFSET_THRESHOLD1 16 +#define THERM_MASK_THRESHOLD1 (0x7f << THERM_OFFSET_THRESHOLD1) +#define THERM_STATUS_THRESHOLD0 (1 << 6) +#define THERM_LOG_THRESHOLD0 (1 << 7) +#define THERM_STATUS_THRESHOLD1 (1 << 8) +#define THERM_LOG_THRESHOLD1 (1 << 9) + /* MISC_ENABLE bits: architectural */ #define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0) #define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 42de98d..30d873e 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -39,7 +39,7 @@ #define DRVNAME "coretemp" -typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL, +typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_TMIN, SHOW_LABEL, SHOW_NAME } SHOW; /* @@ -59,9 +59,11 @@ struct coretemp_data { int temp; int tjmax; int ttarget; + int tmin; u8 alarm; }; +static int set_core_threshold(struct coretemp_data *data, int val, int indx); /* * Sysfs stuff */ @@ -99,17 +101,37 @@ static ssize_t show_temp(struct device *dev, err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN; else if (attr->index == SHOW_TJMAX) err = sprintf(buf, "%d\n", data->tjmax); - else + else if (attr->index == SHOW_TTARGET) err = sprintf(buf, "%d\n", data->ttarget); + else + err = sprintf(buf, "%d\n", data->tmin); 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 = coretemp_update_device(dev); + unsigned long val; + int err; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + err = set_core_threshold(data, val, attr->index); + + return (err) ? -EINVAL : 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 SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, + store_temp, SHOW_TTARGET); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, + store_temp, SHOW_TMIN); static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL); 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); @@ -120,6 +142,8 @@ static struct attribute *coretemp_attributes[] = { &dev_attr_temp1_crit_alarm.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_min.dev_attr.attr, NULL }; @@ -298,6 +322,76 @@ static void __devinit get_ucode_rev_on_cpu(void *edx) rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx); } +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 == SHOW_TMIN) { + eax = (eax & ~THERM_MASK_THRESHOLD0) | + (diff << THERM_OFFSET_THRESHOLD0); + data->tmin = temp; + } else { + eax = (eax & ~THERM_MASK_THRESHOLD1) | + (diff << THERM_OFFSET_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 enable_thresh_support(struct coretemp_data *data) +{ + 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); + + 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); + + return 0; +} + static int __devinit coretemp_probe(struct platform_device *pdev) { struct coretemp_data *data; @@ -353,10 +447,21 @@ static int __devinit coretemp_probe(struct platform_device *pdev) data->tjmax = get_tjmax(c, data->id, &pdev->dev); platform_set_drvdata(pdev, data); + /* Enable threshold support */ + enable_thresh_support(data); + + /* Set Initial Core thresholds. + * The lower and upper threshold values here are assumed + */ + set_core_threshold(data, 0, SHOW_TMIN); + set_core_threshold(data, 90000, SHOW_TTARGET); + /* * read the still undocumented IA32_TEMPERATURE_TARGET. It exists * on older CPUs but not in this register, * Atoms don't have it either. + * If this register is not supported, then ttarget has the value + * of upper core threshold, set by set_core_threshold; */ if ((c->x86_model > 0xe) && (c->x86_model != 0x1c)) { @@ -368,10 +473,6 @@ 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; } } @@ -404,7 +505,6 @@ 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); platform_set_drvdata(pdev, NULL); kfree(data); return 0; -- 1.6.5.2
Attachment:
0001-Adding_threshold_support_to_coretemp.patch
Description: 0001-Adding_threshold_support_to_coretemp.patch
_______________________________________________ lm-sensors mailing list lm-sensors@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors