This patch, the first one in the series, enables the support for core temperature thresholds in coretemp.c These thresholds can be read/written using the sysfs interface temp1_core_thresh[0/1].
Interrupts are generated when the current temperature crosses any of the configured thresholds. These interrupts can be used to do power management. This set of patches were submitted upstream(to lm-sensors), and getting reviewed. ----------------------------------------------------------- From: Durgadoss R <[email protected]> Date: Tue, 14 Dec 2010 06:01:39 +0530 Subject: [PATCH 1/2] 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_core_thresh[0/1]. These can be used to generate interrupts, to do dynamic power management. Signed-off-by: Durgadoss R <[email protected]> --- arch/x86/include/asm/msr-index.h | 12 ++++ drivers/hwmon/coretemp.c | 132 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 8c7ae43..45ada61 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -239,6 +239,18 @@ #define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 +/* 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 05344af..d97ef59 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -42,6 +42,9 @@ typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL, SHOW_NAME } SHOW; +/* C indicates core thermal thresholds */ +enum thresholds { C_TTHRESH0, C_TTHRESH1} THRESH; + /* * Functions declaration */ @@ -59,9 +62,13 @@ struct coretemp_data { int temp; int tjmax; int ttarget; + int c_tthresh0; + int c_tthresh1; u8 alarm; }; +static int set_core_threshold(struct coretemp_data *data, int val, + enum thresholds thresh); /* * Sysfs stuff */ @@ -104,6 +111,41 @@ static ssize_t show_temp(struct device *dev, return err; } +static ssize_t show_threshold(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct coretemp_data *data = coretemp_update_device(dev); + + if (!data->valid) + return -EINVAL; + + switch (attr->index) { + case C_TTHRESH0: + return sprintf(buf, "%d\n", data->c_tthresh0); + case C_TTHRESH1: + return sprintf(buf, "%d\n", data->c_tthresh1); + default: + return -EINVAL; + } +} + +static ssize_t set_threshold(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, @@ -113,6 +155,10 @@ static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 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); +static SENSOR_DEVICE_ATTR(temp1_core_thresh0, S_IWUSR | S_IRUGO, + show_threshold, set_threshold, C_TTHRESH0); +static SENSOR_DEVICE_ATTR(temp1_core_thresh1, S_IWUSR | S_IRUGO, + show_threshold, set_threshold, C_TTHRESH1); static struct attribute *coretemp_attributes[] = { &sensor_dev_attr_name.dev_attr.attr, @@ -120,6 +166,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_core_thresh0.dev_attr.attr, + &sensor_dev_attr_temp1_core_thresh1.dev_attr.attr, NULL }; @@ -291,6 +339,77 @@ static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id, } } +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, + enum thresholds thresh) +{ + 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 (thresh == C_TTHRESH0) { + eax = (eax & ~THERM_MASK_THRESHOLD0) | + (diff << THERM_OFFSET_THRESHOLD0); + data->c_tthresh0 = temp; + } else { + eax = (eax & ~THERM_MASK_THRESHOLD1) | + (diff << THERM_OFFSET_THRESHOLD1); + data->c_tthresh1 = 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; @@ -339,6 +458,15 @@ 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, C_TTHRESH0); + set_core_threshold(data, 90000, C_TTHRESH1); + /* * read the still undocumented IA32_TEMPERATURE_TARGET. It exists * on older CPUs but not in this register, @@ -391,6 +519,10 @@ 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); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp1_core_thresh0.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp1_core_thresh1.dev_attr); platform_set_drvdata(pdev, NULL); kfree(data); return 0; -- 1.6.5.2
0001-Adding_threshold_support_to_coretemp.patch
Description: 0001-Adding_threshold_support_to_coretemp.patch
_______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
