aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDurgadoss R <durgadoss.r@intel.com>2011-07-12 07:07:16 -0400
committerGuenter Roeck <guenter.roeck@ericsson.com>2011-07-28 03:17:36 -0400
commitc814a4c7c4aad795835583344353963a0a673eb0 (patch)
treedbf51076911e529ce082049d26323b560cb7b1f2
parent8c1d04192e2ef1e6d38e9d5e9c500e5330d20339 (diff)
hwmon: (coretemp) Add core/pkg threshold support to Coretemp
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 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@intel.com> Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
-rw-r--r--Documentation/hwmon/coretemp7
-rw-r--r--drivers/hwmon/coretemp.c177
2 files changed, 139 insertions, 45 deletions
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
index f85e913a3401..fa8776ab9b18 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:
35All Sysfs entries are named with their core_id (represented here by 'X'). 35All Sysfs entries are named with their core_id (represented here by 'X').
36tempX_input - Core temperature (in millidegrees Celsius). 36tempX_input - Core temperature (in millidegrees Celsius).
37tempX_max - All cooling devices should be turned on (on Core2). 37tempX_max - All cooling devices should be turned on (on Core2).
38 Initialized with IA32_THERM_INTERRUPT. When the CPU
39 temperature reaches this temperature, an interrupt is
40 generated and tempX_max_alarm is set.
41tempX_max_hyst - If the CPU temperature falls below than temperature,
42 an interrupt is generated and tempX_max_alarm is reset.
43tempX_max_alarm - Set if the temperature reaches or exceeds tempX_max.
44 Reset if the temperature drops to or below tempX_max_hyst.
38tempX_crit - Maximum junction temperature (in millidegrees Celsius). 45tempX_crit - Maximum junction temperature (in millidegrees Celsius).
39tempX_crit_alarm - Set when Out-of-spec bit is set, never clears. 46tempX_crit_alarm - Set when Out-of-spec bit is set, never clears.
40 Correct CPU operation is no longer guaranteed. 47 Correct CPU operation is no longer guaranteed.
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 0070d5476dd0..59d83e83da7f 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -44,7 +44,9 @@
44#define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */ 44#define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */
45#define NUM_REAL_CORES 16 /* Number of Real cores per cpu */ 45#define NUM_REAL_CORES 16 /* Number of Real cores per cpu */
46#define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */ 46#define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */
47#define MAX_ATTRS 5 /* Maximum no of per-core attrs */ 47#define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */
48#define MAX_THRESH_ATTRS 3 /* Maximum no of Threshold attrs */
49#define TOTAL_ATTRS (MAX_CORE_ATTRS + MAX_THRESH_ATTRS)
48#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) 50#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
49 51
50#ifdef CONFIG_SMP 52#ifdef CONFIG_SMP
@@ -67,6 +69,9 @@
67 * This value is passed as "id" field to rdmsr/wrmsr functions. 69 * This value is passed as "id" field to rdmsr/wrmsr functions.
68 * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS, 70 * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
69 * from where the temperature values should be read. 71 * from where the temperature values should be read.
72 * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT,
73 * from where the thresholds are read.
74 * @attr_size: Total number of pre-core attrs displayed in the sysfs.
70 * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data. 75 * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
71 * Otherwise, temp_data holds coretemp data. 76 * Otherwise, temp_data holds coretemp data.
72 * @valid: If this is 1, the current temperature is valid. 77 * @valid: If this is 1, the current temperature is valid.
@@ -74,15 +79,18 @@
74struct temp_data { 79struct temp_data {
75 int temp; 80 int temp;
76 int ttarget; 81 int ttarget;
82 int tmin;
77 int tjmax; 83 int tjmax;
78 unsigned long last_updated; 84 unsigned long last_updated;
79 unsigned int cpu; 85 unsigned int cpu;
80 u32 cpu_core_id; 86 u32 cpu_core_id;
81 u32 status_reg; 87 u32 status_reg;
88 u32 intrpt_reg;
89 int attr_size;
82 bool is_pkg_data; 90 bool is_pkg_data;
83 bool valid; 91 bool valid;
84 struct sensor_device_attribute sd_attrs[MAX_ATTRS]; 92 struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
85 char attr_name[MAX_ATTRS][CORETEMP_NAME_LENGTH]; 93 char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
86 struct mutex update_lock; 94 struct mutex update_lock;
87}; 95};
88 96
@@ -135,6 +143,19 @@ static ssize_t show_crit_alarm(struct device *dev,
135 return sprintf(buf, "%d\n", (eax >> 5) & 1); 143 return sprintf(buf, "%d\n", (eax >> 5) & 1);
136} 144}
137 145
146static ssize_t show_max_alarm(struct device *dev,
147 struct device_attribute *devattr, char *buf)
148{
149 u32 eax, edx;
150 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
151 struct platform_data *pdata = dev_get_drvdata(dev);
152 struct temp_data *tdata = pdata->core_data[attr->index];
153
154 rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
155
156 return sprintf(buf, "%d\n", !!(eax & THERM_STATUS_THRESHOLD1));
157}
158
138static ssize_t show_tjmax(struct device *dev, 159static ssize_t show_tjmax(struct device *dev,
139 struct device_attribute *devattr, char *buf) 160 struct device_attribute *devattr, char *buf)
140{ 161{
@@ -153,6 +174,83 @@ static ssize_t show_ttarget(struct device *dev,
153 return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget); 174 return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
154} 175}
155 176
177static ssize_t store_ttarget(struct device *dev,
178 struct device_attribute *devattr,
179 const char *buf, size_t count)
180{
181 struct platform_data *pdata = dev_get_drvdata(dev);
182 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
183 struct temp_data *tdata = pdata->core_data[attr->index];
184 u32 eax, edx;
185 unsigned long val;
186 int diff;
187
188 if (strict_strtoul(buf, 10, &val))
189 return -EINVAL;
190
191 /*
192 * THERM_MASK_THRESHOLD1 is 7 bits wide. Values are entered in terms
193 * of milli degree celsius. Hence don't accept val > (127 * 1000)
194 */
195 if (val > tdata->tjmax || val > 127000)
196 return -EINVAL;
197
198 diff = (tdata->tjmax - val) / 1000;
199
200 mutex_lock(&tdata->update_lock);
201 rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
202 eax = (eax & ~THERM_MASK_THRESHOLD1) |
203 (diff << THERM_SHIFT_THRESHOLD1);
204 wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
205 tdata->ttarget = val;
206 mutex_unlock(&tdata->update_lock);
207
208 return count;
209}
210
211static ssize_t show_tmin(struct device *dev,
212 struct device_attribute *devattr, char *buf)
213{
214 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
215 struct platform_data *pdata = dev_get_drvdata(dev);
216
217 return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin);
218}
219
220static ssize_t store_tmin(struct device *dev,
221 struct device_attribute *devattr,
222 const char *buf, size_t count)
223{
224 struct platform_data *pdata = dev_get_drvdata(dev);
225 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
226 struct temp_data *tdata = pdata->core_data[attr->index];
227 u32 eax, edx;
228 unsigned long val;
229 int diff;
230
231 if (strict_strtoul(buf, 10, &val))
232 return -EINVAL;
233
234 /*
235 * THERM_MASK_THRESHOLD0 is 7 bits wide. Values are entered in terms
236 * of milli degree celsius. Hence don't accept val > (127 * 1000)
237 */
238 if (val > tdata->tjmax || val > 127000)
239 return -EINVAL;
240
241 diff = (tdata->tjmax - val) / 1000;
242
243 mutex_lock(&tdata->update_lock);
244 rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
245 eax = (eax & ~THERM_MASK_THRESHOLD0) |
246 (diff << THERM_SHIFT_THRESHOLD0);
247 wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
248 tdata->tmin = val;
249 mutex_unlock(&tdata->update_lock);
250
251 return count;
252}
253
156static ssize_t show_temp(struct device *dev, 254static ssize_t show_temp(struct device *dev,
157 struct device_attribute *devattr, char *buf) 255 struct device_attribute *devattr, char *buf)
158{ 256{
@@ -344,23 +442,31 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
344 int attr_no) 442 int attr_no)
345{ 443{
346 int err, i; 444 int err, i;
347 static ssize_t (*rd_ptr[MAX_ATTRS]) (struct device *dev, 445 static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev,
348 struct device_attribute *devattr, char *buf) = { 446 struct device_attribute *devattr, char *buf) = {
349 show_label, show_crit_alarm, show_ttarget, 447 show_label, show_crit_alarm, show_temp, show_tjmax,
350 show_temp, show_tjmax }; 448 show_max_alarm, show_ttarget, show_tmin };
351 static const char *names[MAX_ATTRS] = { 449 static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev,
450 struct device_attribute *devattr, const char *buf,
451 size_t count) = { NULL, NULL, NULL, NULL, NULL,
452 store_ttarget, store_tmin };
453 static const char *names[TOTAL_ATTRS] = {
352 "temp%d_label", "temp%d_crit_alarm", 454 "temp%d_label", "temp%d_crit_alarm",
353 "temp%d_max", "temp%d_input", 455 "temp%d_input", "temp%d_crit",
354 "temp%d_crit" }; 456 "temp%d_max_alarm", "temp%d_max",
457 "temp%d_max_hyst" };
355 458
356 for (i = 0; i < MAX_ATTRS; i++) { 459 for (i = 0; i < tdata->attr_size; i++) {
357 snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i], 460 snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
358 attr_no); 461 attr_no);
359 sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr); 462 sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
360 tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i]; 463 tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
361 tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO; 464 tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
465 if (rw_ptr[i]) {
466 tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR;
467 tdata->sd_attrs[i].dev_attr.store = rw_ptr[i];
468 }
362 tdata->sd_attrs[i].dev_attr.show = rd_ptr[i]; 469 tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
363 tdata->sd_attrs[i].dev_attr.store = NULL;
364 tdata->sd_attrs[i].index = attr_no; 470 tdata->sd_attrs[i].index = attr_no;
365 err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr); 471 err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
366 if (err) 472 if (err)
@@ -374,38 +480,6 @@ exit_free:
374 return err; 480 return err;
375} 481}
376 482
377static void update_ttarget(__u8 cpu_model, struct temp_data *tdata,
378 struct device *dev)
379{
380 int err;
381 u32 eax, edx;
382
383 /*
384 * Initialize ttarget value. Eventually this will be
385 * initialized with the value from MSR_IA32_THERM_INTERRUPT
386 * register. If IA32_TEMPERATURE_TARGET is supported, this
387 * value will be over written below.
388 * To Do: Patch to initialize ttarget from MSR_IA32_THERM_INTERRUPT
389 */
390 tdata->ttarget = tdata->tjmax - 20000;
391
392 /*
393 * Read the still undocumented IA32_TEMPERATURE_TARGET. It exists
394 * on older CPUs but not in this register,
395 * Atoms don't have it either.
396 */
397 if (cpu_model > 0xe && cpu_model != 0x1c) {
398 err = rdmsr_safe_on_cpu(tdata->cpu,
399 MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
400 if (err) {
401 dev_warn(dev,
402 "Unable to read IA32_TEMPERATURE_TARGET MSR\n");
403 } else {
404 tdata->ttarget = tdata->tjmax -
405 ((eax >> 8) & 0xff) * 1000;
406 }
407 }
408}
409 483
410static int __devinit chk_ucode_version(struct platform_device *pdev) 484static int __devinit chk_ucode_version(struct platform_device *pdev)
411{ 485{
@@ -464,9 +538,12 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
464 538
465 tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS : 539 tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
466 MSR_IA32_THERM_STATUS; 540 MSR_IA32_THERM_STATUS;
541 tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT :
542 MSR_IA32_THERM_INTERRUPT;
467 tdata->is_pkg_data = pkg_flag; 543 tdata->is_pkg_data = pkg_flag;
468 tdata->cpu = cpu; 544 tdata->cpu = cpu;
469 tdata->cpu_core_id = TO_CORE_ID(cpu); 545 tdata->cpu_core_id = TO_CORE_ID(cpu);
546 tdata->attr_size = MAX_CORE_ATTRS;
470 mutex_init(&tdata->update_lock); 547 mutex_init(&tdata->update_lock);
471 return tdata; 548 return tdata;
472} 549}
@@ -516,7 +593,17 @@ static int create_core_data(struct platform_data *pdata,
516 else 593 else
517 tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); 594 tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
518 595
519 update_ttarget(c->x86_model, tdata, &pdev->dev); 596 /*
597 * Test if we can access the intrpt register. If so, increase the
598 * 'size' enough to have ttarget/tmin/max_alarm interfaces.
599 * Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT
600 */
601 err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx);
602 if (!err) {
603 tdata->attr_size += MAX_THRESH_ATTRS;
604 tdata->ttarget = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
605 }
606
520 pdata->core_data[attr_no] = tdata; 607 pdata->core_data[attr_no] = tdata;
521 608
522 /* Create sysfs interfaces */ 609 /* Create sysfs interfaces */
@@ -553,7 +640,7 @@ static void coretemp_remove_core(struct platform_data *pdata,
553 struct temp_data *tdata = pdata->core_data[indx]; 640 struct temp_data *tdata = pdata->core_data[indx];
554 641
555 /* Remove the sysfs attributes */ 642 /* Remove the sysfs attributes */
556 for (i = 0; i < MAX_ATTRS; i++) 643 for (i = 0; i < tdata->attr_size; i++)
557 device_remove_file(dev, &tdata->sd_attrs[i].dev_attr); 644 device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
558 645
559 kfree(pdata->core_data[indx]); 646 kfree(pdata->core_data[indx]);