blob: 7c1795225b06587def9fae2bd370641ff29a5731 [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
41typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
42
43/*
44 * Functions declaration
45 */
46
47static struct coretemp_data *coretemp_update_device(struct device *dev);
48
49struct coretemp_data {
50 struct class_device *class_dev;
51 struct mutex update_lock;
52 const char *name;
53 u32 id;
54 char valid; /* zero until following fields are valid */
55 unsigned long last_updated; /* in jiffies */
56 int temp;
57 int tjmax;
58 u8 alarm;
59};
60
61static struct coretemp_data *coretemp_update_device(struct device *dev);
62
63/*
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;
98 else
99 err = sprintf(buf, "%d\n", data->tjmax);
100
101 return err;
102}
103
104static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
105 SHOW_TEMP);
106static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
107 SHOW_TJMAX);
108static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
109static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
110static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
111
112static struct attribute *coretemp_attributes[] = {
113 &sensor_dev_attr_name.dev_attr.attr,
114 &sensor_dev_attr_temp1_label.dev_attr.attr,
115 &dev_attr_temp1_crit_alarm.attr,
116 &sensor_dev_attr_temp1_input.dev_attr.attr,
117 &sensor_dev_attr_temp1_crit.dev_attr.attr,
118 NULL
119};
120
121static const struct attribute_group coretemp_group = {
122 .attrs = coretemp_attributes,
123};
124
125static struct coretemp_data *coretemp_update_device(struct device *dev)
126{
127 struct coretemp_data *data = dev_get_drvdata(dev);
128
129 mutex_lock(&data->update_lock);
130
131 if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
132 u32 eax, edx;
133
134 data->valid = 0;
135 rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
136 data->alarm = (eax >> 5) & 1;
137 /* update only if data has been valid */
138 if (eax & 0x80000000) {
139 data->temp = data->tjmax - (((eax >> 16)
140 & 0x7f) * 1000);
141 data->valid = 1;
142 } else {
143 dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
144 }
145 data->last_updated = jiffies;
146 }
147
148 mutex_unlock(&data->update_lock);
149 return data;
150}
151
152static int __devinit coretemp_probe(struct platform_device *pdev)
153{
154 struct coretemp_data *data;
155 struct cpuinfo_x86 *c = &(cpu_data)[pdev->id];
156 int err;
157 u32 eax, edx;
158
159 if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) {
160 err = -ENOMEM;
161 dev_err(&pdev->dev, "Out of memory\n");
162 goto exit;
163 }
164
165 data->id = pdev->id;
166 data->name = "coretemp";
167 mutex_init(&data->update_lock);
168 /* Tjmax default is 100 degrees C */
169 data->tjmax = 100000;
170
171 /* test if we can access the THERM_STATUS MSR */
172 err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
173 if (err) {
174 dev_err(&pdev->dev,
175 "Unable to access THERM_STATUS MSR, giving up\n");
176 goto exit_free;
177 }
178
Rudolf Marek67f363b2007-05-27 22:17:43 +0200179 /* Check if we have problem with errata AE18 of Core processors:
180 Readings might stop update when processor visited too deep sleep,
181 fixed for stepping D0 (6EC).
182 */
183
184 if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
185 /* check for microcode update */
186 rdmsr_on_cpu(data->id, MSR_IA32_UCODE_REV, &eax, &edx);
187 if (edx < 0x39) {
Jean Delvare6d79af72007-06-23 17:16:24 -0700188 err = -ENODEV;
Rudolf Marek67f363b2007-05-27 22:17:43 +0200189 dev_err(&pdev->dev,
190 "Errata AE18 not fixed, update BIOS or "
191 "microcode of the CPU!\n");
192 goto exit_free;
193 }
194 }
195
Rudolf Marekbebe4672007-05-08 17:22:02 +0200196 /* Some processors have Tjmax 85 following magic should detect it
197 Intel won't disclose the information without signed NDA, but
198 individuals cannot sign it. Catch(ed) 22.
199 */
200
201 if (((c->x86_model == 0xf) && (c->x86_mask > 3)) ||
202 (c->x86_model == 0xe)) {
203 err = rdmsr_safe_on_cpu(data->id, 0xee, &eax, &edx);
204 if (err) {
205 dev_warn(&pdev->dev,
206 "Unable to access MSR 0xEE, Tjmax left at %d "
207 "degrees C\n", data->tjmax/1000);
208 } else if (eax & 0x40000000) {
209 data->tjmax = 85000;
210 }
211 }
212
Rudolf Marek67f363b2007-05-27 22:17:43 +0200213 /* Intel says that above should not work for desktop Core2 processors,
214 but it seems to work. There is no other way how get the absolute
215 readings. Warn the user about this. First check if are desktop,
216 bit 50 of MSR_IA32_PLATFORM_ID should be 0.
217 */
218
219 rdmsr_safe_on_cpu(data->id, MSR_IA32_PLATFORM_ID, &eax, &edx);
220
221 if ((c->x86_model == 0xf) && (!(edx & 0x00040000))) {
222 dev_warn(&pdev->dev, "Using undocumented features, absolute "
223 "temperature might be wrong!\n");
224 }
225
Rudolf Marekbebe4672007-05-08 17:22:02 +0200226 platform_set_drvdata(pdev, data);
227
228 if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
229 goto exit_free;
230
231 data->class_dev = hwmon_device_register(&pdev->dev);
232 if (IS_ERR(data->class_dev)) {
233 err = PTR_ERR(data->class_dev);
234 dev_err(&pdev->dev, "Class registration failed (%d)\n",
235 err);
236 goto exit_class;
237 }
238
239 return 0;
240
241exit_class:
242 sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
243exit_free:
244 kfree(data);
245exit:
246 return err;
247}
248
249static int __devexit coretemp_remove(struct platform_device *pdev)
250{
251 struct coretemp_data *data = platform_get_drvdata(pdev);
252
253 hwmon_device_unregister(data->class_dev);
254 sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
255 platform_set_drvdata(pdev, NULL);
256 kfree(data);
257 return 0;
258}
259
260static struct platform_driver coretemp_driver = {
261 .driver = {
262 .owner = THIS_MODULE,
263 .name = DRVNAME,
264 },
265 .probe = coretemp_probe,
266 .remove = __devexit_p(coretemp_remove),
267};
268
269struct pdev_entry {
270 struct list_head list;
271 struct platform_device *pdev;
272 unsigned int cpu;
273};
274
275static LIST_HEAD(pdev_list);
276static DEFINE_MUTEX(pdev_list_mutex);
277
278static int __cpuinit coretemp_device_add(unsigned int cpu)
279{
280 int err;
281 struct platform_device *pdev;
282 struct pdev_entry *pdev_entry;
283
284 pdev = platform_device_alloc(DRVNAME, cpu);
285 if (!pdev) {
286 err = -ENOMEM;
287 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
288 goto exit;
289 }
290
291 pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
292 if (!pdev_entry) {
293 err = -ENOMEM;
294 goto exit_device_put;
295 }
296
297 err = platform_device_add(pdev);
298 if (err) {
299 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
300 err);
301 goto exit_device_free;
302 }
303
304 pdev_entry->pdev = pdev;
305 pdev_entry->cpu = cpu;
306 mutex_lock(&pdev_list_mutex);
307 list_add_tail(&pdev_entry->list, &pdev_list);
308 mutex_unlock(&pdev_list_mutex);
309
310 return 0;
311
312exit_device_free:
313 kfree(pdev_entry);
314exit_device_put:
315 platform_device_put(pdev);
316exit:
317 return err;
318}
319
320#ifdef CONFIG_HOTPLUG_CPU
Adrian Bunkd2bc7b12007-07-06 01:23:06 +0200321static void coretemp_device_remove(unsigned int cpu)
Rudolf Marekbebe4672007-05-08 17:22:02 +0200322{
323 struct pdev_entry *p, *n;
324 mutex_lock(&pdev_list_mutex);
325 list_for_each_entry_safe(p, n, &pdev_list, list) {
326 if (p->cpu == cpu) {
327 platform_device_unregister(p->pdev);
328 list_del(&p->list);
329 kfree(p);
330 }
331 }
332 mutex_unlock(&pdev_list_mutex);
333}
334
335static int coretemp_cpu_callback(struct notifier_block *nfb,
336 unsigned long action, void *hcpu)
337{
338 unsigned int cpu = (unsigned long) hcpu;
339
340 switch (action) {
341 case CPU_ONLINE:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700342 case CPU_ONLINE_FROZEN:
Rudolf Marekbebe4672007-05-08 17:22:02 +0200343 coretemp_device_add(cpu);
344 break;
345 case CPU_DEAD:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700346 case CPU_DEAD_FROZEN:
Rudolf Marekbebe4672007-05-08 17:22:02 +0200347 coretemp_device_remove(cpu);
348 break;
349 }
350 return NOTIFY_OK;
351}
352
353static struct notifier_block __cpuinitdata coretemp_cpu_notifier = {
354 .notifier_call = coretemp_cpu_callback,
355};
356#endif /* !CONFIG_HOTPLUG_CPU */
357
358static int __init coretemp_init(void)
359{
360 int i, err = -ENODEV;
361 struct pdev_entry *p, *n;
362
Rudolf Marekbebe4672007-05-08 17:22:02 +0200363 /* quick check if we run Intel */
364 if (cpu_data[0].x86_vendor != X86_VENDOR_INTEL)
365 goto exit;
366
367 err = platform_driver_register(&coretemp_driver);
368 if (err)
369 goto exit;
370
371 for_each_online_cpu(i) {
372 struct cpuinfo_x86 *c = &(cpu_data)[i];
373
374 /* check if family 6, models e, f */
375 if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
376 !((c->x86_model == 0xe) || (c->x86_model == 0xf))) {
377
378 /* supported CPU not found, but report the unknown
379 family 6 CPU */
380 if ((c->x86 == 0x6) && (c->x86_model > 0xf))
381 printk(KERN_WARNING DRVNAME ": Unknown CPU "
382 "model %x\n", c->x86_model);
383 continue;
384 }
385
386 err = coretemp_device_add(i);
387 if (err)
388 goto exit_devices_unreg;
389 }
390 if (list_empty(&pdev_list)) {
391 err = -ENODEV;
392 goto exit_driver_unreg;
393 }
394
395#ifdef CONFIG_HOTPLUG_CPU
396 register_hotcpu_notifier(&coretemp_cpu_notifier);
397#endif
398 return 0;
399
400exit_devices_unreg:
401 mutex_lock(&pdev_list_mutex);
402 list_for_each_entry_safe(p, n, &pdev_list, list) {
403 platform_device_unregister(p->pdev);
404 list_del(&p->list);
405 kfree(p);
406 }
407 mutex_unlock(&pdev_list_mutex);
408exit_driver_unreg:
409 platform_driver_unregister(&coretemp_driver);
410exit:
411 return err;
412}
413
414static void __exit coretemp_exit(void)
415{
416 struct pdev_entry *p, *n;
417#ifdef CONFIG_HOTPLUG_CPU
418 unregister_hotcpu_notifier(&coretemp_cpu_notifier);
419#endif
420 mutex_lock(&pdev_list_mutex);
421 list_for_each_entry_safe(p, n, &pdev_list, list) {
422 platform_device_unregister(p->pdev);
423 list_del(&p->list);
424 kfree(p);
425 }
426 mutex_unlock(&pdev_list_mutex);
427 platform_driver_unregister(&coretemp_driver);
428}
429
430MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
431MODULE_DESCRIPTION("Intel Core temperature monitor");
432MODULE_LICENSE("GPL");
433
434module_init(coretemp_init)
435module_exit(coretemp_exit)