blob: 52914e95e9dcbce27a8689be6fd1322e50e55ce8 [file] [log] [blame]
Rudolf Marekbebe4672007-05-08 17:22:02 +02001/*
2 * coretemp.c - Linux kernel module for hardware monitoring
3 *
4 * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
5 *
6 * Inspired from many hwmon drivers
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23#include <linux/module.h>
24#include <linux/delay.h>
25#include <linux/init.h>
26#include <linux/slab.h>
27#include <linux/jiffies.h>
28#include <linux/hwmon.h>
29#include <linux/sysfs.h>
30#include <linux/hwmon-sysfs.h>
31#include <linux/err.h>
32#include <linux/mutex.h>
33#include <linux/list.h>
34#include <linux/platform_device.h>
35#include <linux/cpu.h>
36#include <asm/msr.h>
37#include <asm/processor.h>
38
39#define DRVNAME "coretemp"
40
Rudolf Marek6369a2882008-01-18 00:42:54 +010041typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
42 SHOW_NAME } SHOW;
Rudolf Marekbebe4672007-05-08 17:22:02 +020043
44/*
45 * Functions declaration
46 */
47
48static struct coretemp_data *coretemp_update_device(struct device *dev);
49
50struct coretemp_data {
Tony Jones1beeffe2007-08-20 13:46:20 -070051 struct device *hwmon_dev;
Rudolf Marekbebe4672007-05-08 17:22:02 +020052 struct mutex update_lock;
53 const char *name;
54 u32 id;
55 char valid; /* zero until following fields are valid */
56 unsigned long last_updated; /* in jiffies */
57 int temp;
58 int tjmax;
Rudolf Marek6369a2882008-01-18 00:42:54 +010059 int ttarget;
Rudolf Marekbebe4672007-05-08 17:22:02 +020060 u8 alarm;
61};
62
Rudolf Marekbebe4672007-05-08 17:22:02 +020063/*
64 * Sysfs stuff
65 */
66
67static ssize_t show_name(struct device *dev, struct device_attribute
68 *devattr, char *buf)
69{
70 int ret;
71 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
72 struct coretemp_data *data = dev_get_drvdata(dev);
73
74 if (attr->index == SHOW_NAME)
75 ret = sprintf(buf, "%s\n", data->name);
76 else /* show label */
77 ret = sprintf(buf, "Core %d\n", data->id);
78 return ret;
79}
80
81static ssize_t show_alarm(struct device *dev, struct device_attribute
82 *devattr, char *buf)
83{
84 struct coretemp_data *data = coretemp_update_device(dev);
85 /* read the Out-of-spec log, never clear */
86 return sprintf(buf, "%d\n", data->alarm);
87}
88
89static ssize_t show_temp(struct device *dev,
90 struct device_attribute *devattr, char *buf)
91{
92 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
93 struct coretemp_data *data = coretemp_update_device(dev);
94 int err;
95
96 if (attr->index == SHOW_TEMP)
97 err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
Rudolf Marek6369a2882008-01-18 00:42:54 +010098 else if (attr->index == SHOW_TJMAX)
Rudolf Marekbebe4672007-05-08 17:22:02 +020099 err = sprintf(buf, "%d\n", data->tjmax);
Rudolf Marek6369a2882008-01-18 00:42:54 +0100100 else
101 err = sprintf(buf, "%d\n", data->ttarget);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200102 return err;
103}
104
105static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
106 SHOW_TEMP);
107static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
108 SHOW_TJMAX);
Rudolf Marek6369a2882008-01-18 00:42:54 +0100109static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
110 SHOW_TTARGET);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200111static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
112static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
113static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
114
115static struct attribute *coretemp_attributes[] = {
116 &sensor_dev_attr_name.dev_attr.attr,
117 &sensor_dev_attr_temp1_label.dev_attr.attr,
118 &dev_attr_temp1_crit_alarm.attr,
119 &sensor_dev_attr_temp1_input.dev_attr.attr,
120 &sensor_dev_attr_temp1_crit.dev_attr.attr,
121 NULL
122};
123
124static const struct attribute_group coretemp_group = {
125 .attrs = coretemp_attributes,
126};
127
128static struct coretemp_data *coretemp_update_device(struct device *dev)
129{
130 struct coretemp_data *data = dev_get_drvdata(dev);
131
132 mutex_lock(&data->update_lock);
133
134 if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
135 u32 eax, edx;
136
137 data->valid = 0;
138 rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
139 data->alarm = (eax >> 5) & 1;
140 /* update only if data has been valid */
141 if (eax & 0x80000000) {
142 data->temp = data->tjmax - (((eax >> 16)
143 & 0x7f) * 1000);
144 data->valid = 1;
145 } else {
146 dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
147 }
148 data->last_updated = jiffies;
149 }
150
151 mutex_unlock(&data->update_lock);
152 return data;
153}
154
155static int __devinit coretemp_probe(struct platform_device *pdev)
156{
157 struct coretemp_data *data;
Mike Travis92cb7612007-10-19 20:35:04 +0200158 struct cpuinfo_x86 *c = &cpu_data(pdev->id);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200159 int err;
160 u32 eax, edx;
161
162 if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) {
163 err = -ENOMEM;
164 dev_err(&pdev->dev, "Out of memory\n");
165 goto exit;
166 }
167
168 data->id = pdev->id;
169 data->name = "coretemp";
170 mutex_init(&data->update_lock);
171 /* Tjmax default is 100 degrees C */
172 data->tjmax = 100000;
173
174 /* test if we can access the THERM_STATUS MSR */
175 err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
176 if (err) {
177 dev_err(&pdev->dev,
178 "Unable to access THERM_STATUS MSR, giving up\n");
179 goto exit_free;
180 }
181
Rudolf Marek67f363b2007-05-27 22:17:43 +0200182 /* Check if we have problem with errata AE18 of Core processors:
183 Readings might stop update when processor visited too deep sleep,
184 fixed for stepping D0 (6EC).
185 */
186
187 if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
188 /* check for microcode update */
189 rdmsr_on_cpu(data->id, MSR_IA32_UCODE_REV, &eax, &edx);
190 if (edx < 0x39) {
Jean Delvare6d79af72007-06-23 17:16:24 -0700191 err = -ENODEV;
Rudolf Marek67f363b2007-05-27 22:17:43 +0200192 dev_err(&pdev->dev,
193 "Errata AE18 not fixed, update BIOS or "
194 "microcode of the CPU!\n");
195 goto exit_free;
196 }
197 }
198
Rudolf Marekbebe4672007-05-08 17:22:02 +0200199 /* Some processors have Tjmax 85 following magic should detect it
200 Intel won't disclose the information without signed NDA, but
201 individuals cannot sign it. Catch(ed) 22.
202 */
203
204 if (((c->x86_model == 0xf) && (c->x86_mask > 3)) ||
205 (c->x86_model == 0xe)) {
206 err = rdmsr_safe_on_cpu(data->id, 0xee, &eax, &edx);
207 if (err) {
208 dev_warn(&pdev->dev,
209 "Unable to access MSR 0xEE, Tjmax left at %d "
210 "degrees C\n", data->tjmax/1000);
211 } else if (eax & 0x40000000) {
212 data->tjmax = 85000;
213 }
214 }
215
Rudolf Marek67f363b2007-05-27 22:17:43 +0200216 /* Intel says that above should not work for desktop Core2 processors,
217 but it seems to work. There is no other way how get the absolute
218 readings. Warn the user about this. First check if are desktop,
219 bit 50 of MSR_IA32_PLATFORM_ID should be 0.
220 */
221
222 rdmsr_safe_on_cpu(data->id, MSR_IA32_PLATFORM_ID, &eax, &edx);
223
224 if ((c->x86_model == 0xf) && (!(edx & 0x00040000))) {
225 dev_warn(&pdev->dev, "Using undocumented features, absolute "
226 "temperature might be wrong!\n");
227 }
228
Rudolf Marekbebe4672007-05-08 17:22:02 +0200229 platform_set_drvdata(pdev, data);
230
Rudolf Marek6369a2882008-01-18 00:42:54 +0100231 /* read the still undocumented IA32_TEMPERATURE_TARGET it exists
232 on older CPUs but not in this register */
233
234 if (c->x86_model > 0xe) {
235 err = rdmsr_safe_on_cpu(data->id, 0x1a2, &eax, &edx);
236 if (err) {
237 dev_warn(&pdev->dev, "Unable to read"
238 " IA32_TEMPERATURE_TARGET MSR\n");
239 } else {
240 data->ttarget = data->tjmax -
241 (((eax >> 8) & 0xff) * 1000);
242 err = device_create_file(&pdev->dev,
243 &sensor_dev_attr_temp1_max.dev_attr);
244 if (err)
245 goto exit_free;
246 }
247 }
248
Rudolf Marekbebe4672007-05-08 17:22:02 +0200249 if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
Rudolf Marek6369a2882008-01-18 00:42:54 +0100250 goto exit_dev;
Rudolf Marekbebe4672007-05-08 17:22:02 +0200251
Tony Jones1beeffe2007-08-20 13:46:20 -0700252 data->hwmon_dev = hwmon_device_register(&pdev->dev);
253 if (IS_ERR(data->hwmon_dev)) {
254 err = PTR_ERR(data->hwmon_dev);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200255 dev_err(&pdev->dev, "Class registration failed (%d)\n",
256 err);
257 goto exit_class;
258 }
259
260 return 0;
261
262exit_class:
263 sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
Rudolf Marek6369a2882008-01-18 00:42:54 +0100264exit_dev:
265 device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200266exit_free:
267 kfree(data);
268exit:
269 return err;
270}
271
272static int __devexit coretemp_remove(struct platform_device *pdev)
273{
274 struct coretemp_data *data = platform_get_drvdata(pdev);
275
Tony Jones1beeffe2007-08-20 13:46:20 -0700276 hwmon_device_unregister(data->hwmon_dev);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200277 sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
Rudolf Marek6369a2882008-01-18 00:42:54 +0100278 device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200279 platform_set_drvdata(pdev, NULL);
280 kfree(data);
281 return 0;
282}
283
284static struct platform_driver coretemp_driver = {
285 .driver = {
286 .owner = THIS_MODULE,
287 .name = DRVNAME,
288 },
289 .probe = coretemp_probe,
290 .remove = __devexit_p(coretemp_remove),
291};
292
293struct pdev_entry {
294 struct list_head list;
295 struct platform_device *pdev;
296 unsigned int cpu;
297};
298
299static LIST_HEAD(pdev_list);
300static DEFINE_MUTEX(pdev_list_mutex);
301
302static int __cpuinit coretemp_device_add(unsigned int cpu)
303{
304 int err;
305 struct platform_device *pdev;
306 struct pdev_entry *pdev_entry;
307
308 pdev = platform_device_alloc(DRVNAME, cpu);
309 if (!pdev) {
310 err = -ENOMEM;
311 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
312 goto exit;
313 }
314
315 pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
316 if (!pdev_entry) {
317 err = -ENOMEM;
318 goto exit_device_put;
319 }
320
321 err = platform_device_add(pdev);
322 if (err) {
323 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
324 err);
325 goto exit_device_free;
326 }
327
328 pdev_entry->pdev = pdev;
329 pdev_entry->cpu = cpu;
330 mutex_lock(&pdev_list_mutex);
331 list_add_tail(&pdev_entry->list, &pdev_list);
332 mutex_unlock(&pdev_list_mutex);
333
334 return 0;
335
336exit_device_free:
337 kfree(pdev_entry);
338exit_device_put:
339 platform_device_put(pdev);
340exit:
341 return err;
342}
343
344#ifdef CONFIG_HOTPLUG_CPU
Adrian Bunkd2bc7b12007-07-06 01:23:06 +0200345static void coretemp_device_remove(unsigned int cpu)
Rudolf Marekbebe4672007-05-08 17:22:02 +0200346{
347 struct pdev_entry *p, *n;
348 mutex_lock(&pdev_list_mutex);
349 list_for_each_entry_safe(p, n, &pdev_list, list) {
350 if (p->cpu == cpu) {
351 platform_device_unregister(p->pdev);
352 list_del(&p->list);
353 kfree(p);
354 }
355 }
356 mutex_unlock(&pdev_list_mutex);
357}
358
359static int coretemp_cpu_callback(struct notifier_block *nfb,
360 unsigned long action, void *hcpu)
361{
362 unsigned int cpu = (unsigned long) hcpu;
363
364 switch (action) {
365 case CPU_ONLINE:
Rafael J. Wysocki561d9a92007-12-03 18:01:50 +0100366 case CPU_DOWN_FAILED:
Rudolf Marekbebe4672007-05-08 17:22:02 +0200367 coretemp_device_add(cpu);
368 break;
Rafael J. Wysocki561d9a92007-12-03 18:01:50 +0100369 case CPU_DOWN_PREPARE:
Rudolf Marekbebe4672007-05-08 17:22:02 +0200370 coretemp_device_remove(cpu);
371 break;
372 }
373 return NOTIFY_OK;
374}
375
Satyam Sharma59a35ba2007-08-23 09:14:25 +0530376static struct notifier_block coretemp_cpu_notifier = {
Rudolf Marekbebe4672007-05-08 17:22:02 +0200377 .notifier_call = coretemp_cpu_callback,
378};
379#endif /* !CONFIG_HOTPLUG_CPU */
380
381static int __init coretemp_init(void)
382{
383 int i, err = -ENODEV;
384 struct pdev_entry *p, *n;
385
Rudolf Marekbebe4672007-05-08 17:22:02 +0200386 /* quick check if we run Intel */
Mike Travis92cb7612007-10-19 20:35:04 +0200387 if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
Rudolf Marekbebe4672007-05-08 17:22:02 +0200388 goto exit;
389
390 err = platform_driver_register(&coretemp_driver);
391 if (err)
392 goto exit;
393
394 for_each_online_cpu(i) {
Mike Travis92cb7612007-10-19 20:35:04 +0200395 struct cpuinfo_x86 *c = &cpu_data(i);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200396
Rudolf Marekc9403362007-10-07 13:42:09 +0200397 /* check if family 6, models e, f, 16 */
Rudolf Marekbebe4672007-05-08 17:22:02 +0200398 if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
Rudolf Marekc9403362007-10-07 13:42:09 +0200399 !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
400 (c->x86_model == 0x16))) {
Rudolf Marekbebe4672007-05-08 17:22:02 +0200401
402 /* supported CPU not found, but report the unknown
403 family 6 CPU */
404 if ((c->x86 == 0x6) && (c->x86_model > 0xf))
405 printk(KERN_WARNING DRVNAME ": Unknown CPU "
406 "model %x\n", c->x86_model);
407 continue;
408 }
409
410 err = coretemp_device_add(i);
411 if (err)
412 goto exit_devices_unreg;
413 }
414 if (list_empty(&pdev_list)) {
415 err = -ENODEV;
416 goto exit_driver_unreg;
417 }
418
419#ifdef CONFIG_HOTPLUG_CPU
420 register_hotcpu_notifier(&coretemp_cpu_notifier);
421#endif
422 return 0;
423
424exit_devices_unreg:
425 mutex_lock(&pdev_list_mutex);
426 list_for_each_entry_safe(p, n, &pdev_list, list) {
427 platform_device_unregister(p->pdev);
428 list_del(&p->list);
429 kfree(p);
430 }
431 mutex_unlock(&pdev_list_mutex);
432exit_driver_unreg:
433 platform_driver_unregister(&coretemp_driver);
434exit:
435 return err;
436}
437
438static void __exit coretemp_exit(void)
439{
440 struct pdev_entry *p, *n;
441#ifdef CONFIG_HOTPLUG_CPU
442 unregister_hotcpu_notifier(&coretemp_cpu_notifier);
443#endif
444 mutex_lock(&pdev_list_mutex);
445 list_for_each_entry_safe(p, n, &pdev_list, list) {
446 platform_device_unregister(p->pdev);
447 list_del(&p->list);
448 kfree(p);
449 }
450 mutex_unlock(&pdev_list_mutex);
451 platform_driver_unregister(&coretemp_driver);
452}
453
454MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
455MODULE_DESCRIPTION("Intel Core temperature monitor");
456MODULE_LICENSE("GPL");
457
458module_init(coretemp_init)
459module_exit(coretemp_exit)