This patch adds the core and pkg support to coretemp. These thresholds can be configured via the sysfs interfaces tempX_max and tempX_max_hyst. An interrupt is generated when CPU temperature reaches or crosses above tempX_max OR drops below tempX_max_hyst. This patch is based on the documentation in sec:14.5 of IA Manual vol 3A, that can be downloaded from here: http://download.intel.com/design/processor/manuals/253668.pdf Signed-off-by: Durgadoss R <durgadoss.r@xxxxxxxxx> --- Documentation/hwmon/coretemp | 7 ++ drivers/hwmon/coretemp.c | 135 ++++++++++++++++++++++++++++++++---------- 2 files changed, 110 insertions(+), 32 deletions(-) diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp index f85e913..fa8776a 100644 --- a/Documentation/hwmon/coretemp +++ b/Documentation/hwmon/coretemp @@ -35,6 +35,13 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files: All Sysfs entries are named with their core_id (represented here by 'X'). tempX_input - Core temperature (in millidegrees Celsius). tempX_max - All cooling devices should be turned on (on Core2). + Initialized with IA32_THERM_INTERRUPT. When the CPU + temperature reaches this temperature, an interrupt is + generated and tempX_max_alarm is set. +tempX_max_hyst - If the CPU temperature falls below than temperature, + an interrupt is generated and tempX_max_alarm is reset. +tempX_max_alarm - Set if the temperature reaches or exceeds tempX_max. + Reset if the temperature drops to or below tempX_max_hyst. tempX_crit - Maximum junction temperature (in millidegrees Celsius). tempX_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 de3d246..c155ae2 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -44,7 +44,7 @@ #define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */ #define NUM_REAL_CORES 16 /* Number of Real cores per cpu */ #define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */ -#define MAX_ATTRS 5 /* Maximum no of per-core attrs */ +#define MAX_ATTRS 7 /* Maximum no of per-core attrs */ #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) #ifdef CONFIG_SMP @@ -74,11 +74,13 @@ struct temp_data { int temp; int ttarget; + int tmin; int tjmax; unsigned long last_updated; unsigned int cpu; u32 cpu_core_id; u32 status_reg; + u32 intrpt_reg; bool is_pkg_data; bool valid; struct sensor_device_attribute sd_attrs[MAX_ATTRS]; @@ -137,6 +139,22 @@ static ssize_t show_crit_alarm(struct device *dev, return sprintf(buf, "%d\n", (eax >> 5) & 1); } +static ssize_t show_max_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u32 eax, edx; + 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]; + + rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); + + if (eax & THERM_LOG_THRESHOLD1) + return sprintf(buf, "1\n"); + + return sprintf(buf, "0\n"); +} + static ssize_t show_tjmax(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -155,6 +173,69 @@ static ssize_t show_ttarget(struct device *dev, return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget); } +static ssize_t store_ttarget(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct platform_data *pdata = dev_get_drvdata(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct temp_data *tdata = pdata->core_data[attr->index]; + u32 eax, edx; + unsigned long val; + int diff; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + diff = (tdata->tjmax - val) / 1000; + + mutex_lock(&tdata->update_lock); + rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx); + eax = (eax & ~THERM_MASK_THRESHOLD1) | + (diff << THERM_SHIFT_THRESHOLD1); + wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx); + tdata->ttarget = val; + mutex_unlock(&tdata->update_lock); + + return count; +} + +static ssize_t show_tmin(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin); +} + +static ssize_t store_tmin(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct platform_data *pdata = dev_get_drvdata(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct temp_data *tdata = pdata->core_data[attr->index]; + u32 eax, edx; + unsigned long val; + int diff; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + diff = (tdata->tjmax - val) / 1000; + + mutex_lock(&tdata->update_lock); + rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx); + eax = (eax & ~THERM_MASK_THRESHOLD0) | + (diff << THERM_SHIFT_THRESHOLD0); + wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx); + tdata->tmin = val; + mutex_unlock(&tdata->update_lock); + + return count; +} + static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -364,11 +445,16 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, static ssize_t (*rd_ptr[MAX_ATTRS]) (struct device *dev, struct device_attribute *devattr, char *buf) = { show_label, show_crit_alarm, show_ttarget, - show_temp, show_tjmax }; + show_temp, show_tjmax, show_tmin, show_max_alarm }; + static ssize_t (*rw_ptr[MAX_ATTRS]) (struct device *dev, + struct device_attribute *devattr, const char *buf, + size_t count) = { NULL, NULL, store_ttarget, NULL, + NULL, store_tmin, NULL }; static const char *names[MAX_ATTRS] = { "temp%d_label", "temp%d_crit_alarm", "temp%d_max", "temp%d_input", - "temp%d_crit" }; + "temp%d_crit", "temp%d_max_hyst", + "temp%d_max_alarm" }; for (i = 0; i < MAX_ATTRS; i++) { snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i], @@ -376,8 +462,10 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr); tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i]; tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO; + if (rw_ptr[i]) + tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR; tdata->sd_attrs[i].dev_attr.show = rd_ptr[i]; - tdata->sd_attrs[i].dev_attr.store = NULL; + tdata->sd_attrs[i].dev_attr.store = rw_ptr[i]; tdata->sd_attrs[i].index = attr_no; err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr); if (err) @@ -391,37 +479,18 @@ exit_free: return err; } -static void update_ttarget(__u8 cpu_model, struct temp_data *tdata, - struct device *dev) +static void get_ttarget(struct temp_data *tdata, struct device *dev) { int err; u32 eax, edx; - /* - * Initialize ttarget value. Eventually this will be - * initialized with the value from MSR_IA32_THERM_INTERRUPT - * register. If IA32_TEMPERATURE_TARGET is supported, this - * value will be over written below. - * To Do: Patch to initialize ttarget from MSR_IA32_THERM_INTERRUPT - */ - tdata->ttarget = tdata->tjmax - 20000; - - /* - * Read the still undocumented IA32_TEMPERATURE_TARGET. It exists - * on older CPUs but not in this register, - * Atoms don't have it either. - */ - if (cpu_model > 0xe && cpu_model != 0x1c) { - err = rdmsr_safe_on_cpu(tdata->cpu, - MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); - if (err) { - dev_warn(dev, - "Unable to read IA32_TEMPERATURE_TARGET MSR\n"); - } else { - tdata->ttarget = tdata->tjmax - - ((eax >> 8) & 0xff) * 1000; - } - } + /* Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT */ + err = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_THERM_INTERRUPT, + &eax, &edx); + if (err) + dev_warn(dev, "unable to read MSR_IA32_THERM_INTERRUPT\n"); + else + tdata->ttarget = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; } static int __devinit chk_ucode_version(struct platform_device *pdev) @@ -481,6 +550,8 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS; + tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT : + MSR_IA32_THERM_INTERRUPT; tdata->is_pkg_data = pkg_flag; tdata->cpu = cpu; tdata->cpu_core_id = TO_CORE_ID(cpu); @@ -533,7 +604,7 @@ static int create_core_data(struct platform_data *pdata, else tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); - update_ttarget(c->x86_model, tdata, &pdev->dev); + get_ttarget(tdata, &pdev->dev); pdata->core_data[attr_no] = tdata; /* Create sysfs interfaces */ -- 1.6.1 _______________________________________________ lm-sensors mailing list lm-sensors@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors