blob: 5c82ec7f8bbda7fea7ec8a1f81c14add4a25c6d8 [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 {
Tony Jones1beeffe2007-08-20 13:46:20 -070050 struct device *hwmon_dev;
Rudolf Marekbebe4672007-05-08 17:22:02 +020051 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
Rudolf Marekbebe4672007-05-08 17:22:02 +020061/*
62 * Sysfs stuff
63 */
64
65static ssize_t show_name(struct device *dev, struct device_attribute
66 *devattr, char *buf)
67{
68 int ret;
69 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
70 struct coretemp_data *data = dev_get_drvdata(dev);
71
72 if (attr->index == SHOW_NAME)
73 ret = sprintf(buf, "%s\n", data->name);
74 else /* show label */
75 ret = sprintf(buf, "Core %d\n", data->id);
76 return ret;
77}
78
79static ssize_t show_alarm(struct device *dev, struct device_attribute
80 *devattr, char *buf)
81{
82 struct coretemp_data *data = coretemp_update_device(dev);
83 /* read the Out-of-spec log, never clear */
84 return sprintf(buf, "%d\n", data->alarm);
85}
86
87static ssize_t show_temp(struct device *dev,
88 struct device_attribute *devattr, char *buf)
89{
90 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
91 struct coretemp_data *data = coretemp_update_device(dev);
92 int err;
93
94 if (attr->index == SHOW_TEMP)
95 err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
96 else
97 err = sprintf(buf, "%d\n", data->tjmax);
98
99 return err;
100}
101
102static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
103 SHOW_TEMP);
104static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
105 SHOW_TJMAX);
106static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
107static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
108static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
109
110static struct attribute *coretemp_attributes[] = {
111 &sensor_dev_attr_name.dev_attr.attr,
112 &sensor_dev_attr_temp1_label.dev_attr.attr,
113 &dev_attr_temp1_crit_alarm.attr,
114 &sensor_dev_attr_temp1_input.dev_attr.attr,
115 &sensor_dev_attr_temp1_crit.dev_attr.attr,
116 NULL
117};
118
119static const struct attribute_group coretemp_group = {
120 .attrs = coretemp_attributes,
121};
122
123static struct coretemp_data *coretemp_update_device(struct device *dev)
124{
125 struct coretemp_data *data = dev_get_drvdata(dev);
126
127 mutex_lock(&data->update_lock);
128
129 if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
130 u32 eax, edx;
131
132 data->valid = 0;
133 rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
134 data->alarm = (eax >> 5) & 1;
135 /* update only if data has been valid */
136 if (eax & 0x80000000) {
137 data->temp = data->tjmax - (((eax >> 16)
138 & 0x7f) * 1000);
139 data->valid = 1;
140 } else {
141 dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
142 }
143 data->last_updated = jiffies;
144 }
145
146 mutex_unlock(&data->update_lock);
147 return data;
148}
149
150static int __devinit coretemp_probe(struct platform_device *pdev)
151{
152 struct coretemp_data *data;
Mike Travis92cb7612007-10-19 20:35:04 +0200153 struct cpuinfo_x86 *c = &cpu_data(pdev->id);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200154 int err;
155 u32 eax, edx;
156
157 if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) {
158 err = -ENOMEM;
159 dev_err(&pdev->dev, "Out of memory\n");
160 goto exit;
161 }
162
163 data->id = pdev->id;
164 data->name = "coretemp";
165 mutex_init(&data->update_lock);
166 /* Tjmax default is 100 degrees C */
167 data->tjmax = 100000;
168
169 /* test if we can access the THERM_STATUS MSR */
170 err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
171 if (err) {
172 dev_err(&pdev->dev,
173 "Unable to access THERM_STATUS MSR, giving up\n");
174 goto exit_free;
175 }
176
Rudolf Marek67f363b2007-05-27 22:17:43 +0200177 /* Check if we have problem with errata AE18 of Core processors:
178 Readings might stop update when processor visited too deep sleep,
179 fixed for stepping D0 (6EC).
180 */
181
182 if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
183 /* check for microcode update */
184 rdmsr_on_cpu(data->id, MSR_IA32_UCODE_REV, &eax, &edx);
185 if (edx < 0x39) {
Jean Delvare6d79af72007-06-23 17:16:24 -0700186 err = -ENODEV;
Rudolf Marek67f363b2007-05-27 22:17:43 +0200187 dev_err(&pdev->dev,
188 "Errata AE18 not fixed, update BIOS or "
189 "microcode of the CPU!\n");
190 goto exit_free;
191 }
192 }
193
Rudolf Marekbebe4672007-05-08 17:22:02 +0200194 /* Some processors have Tjmax 85 following magic should detect it
195 Intel won't disclose the information without signed NDA, but
196 individuals cannot sign it. Catch(ed) 22.
197 */
198
199 if (((c->x86_model == 0xf) && (c->x86_mask > 3)) ||
200 (c->x86_model == 0xe)) {
201 err = rdmsr_safe_on_cpu(data->id, 0xee, &eax, &edx);
202 if (err) {
203 dev_warn(&pdev->dev,
204 "Unable to access MSR 0xEE, Tjmax left at %d "
205 "degrees C\n", data->tjmax/1000);
206 } else if (eax & 0x40000000) {
207 data->tjmax = 85000;
208 }
209 }
210
Rudolf Marek67f363b2007-05-27 22:17:43 +0200211 /* Intel says that above should not work for desktop Core2 processors,
212 but it seems to work. There is no other way how get the absolute
213 readings. Warn the user about this. First check if are desktop,
214 bit 50 of MSR_IA32_PLATFORM_ID should be 0.
215 */
216
217 rdmsr_safe_on_cpu(data->id, MSR_IA32_PLATFORM_ID, &eax, &edx);
218
219 if ((c->x86_model == 0xf) && (!(edx & 0x00040000))) {
220 dev_warn(&pdev->dev, "Using undocumented features, absolute "
221 "temperature might be wrong!\n");
222 }
223
Rudolf Marekbebe4672007-05-08 17:22:02 +0200224 platform_set_drvdata(pdev, data);
225
226 if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
227 goto exit_free;
228
Tony Jones1beeffe2007-08-20 13:46:20 -0700229 data->hwmon_dev = hwmon_device_register(&pdev->dev);
230 if (IS_ERR(data->hwmon_dev)) {
231 err = PTR_ERR(data->hwmon_dev);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200232 dev_err(&pdev->dev, "Class registration failed (%d)\n",
233 err);
234 goto exit_class;
235 }
236
237 return 0;
238
239exit_class:
240 sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
241exit_free:
242 kfree(data);
243exit:
244 return err;
245}
246
247static int __devexit coretemp_remove(struct platform_device *pdev)
248{
249 struct coretemp_data *data = platform_get_drvdata(pdev);
250
Tony Jones1beeffe2007-08-20 13:46:20 -0700251 hwmon_device_unregister(data->hwmon_dev);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200252 sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
253 platform_set_drvdata(pdev, NULL);
254 kfree(data);
255 return 0;
256}
257
258static struct platform_driver coretemp_driver = {
259 .driver = {
260 .owner = THIS_MODULE,
261 .name = DRVNAME,
262 },
263 .probe = coretemp_probe,
264 .remove = __devexit_p(coretemp_remove),
265};
266
267struct pdev_entry {
268 struct list_head list;
269 struct platform_device *pdev;
270 unsigned int cpu;
271};
272
273static LIST_HEAD(pdev_list);
274static DEFINE_MUTEX(pdev_list_mutex);
275
276static int __cpuinit coretemp_device_add(unsigned int cpu)
277{
278 int err;
279 struct platform_device *pdev;
280 struct pdev_entry *pdev_entry;
281
282 pdev = platform_device_alloc(DRVNAME, cpu);
283 if (!pdev) {
284 err = -ENOMEM;
285 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
286 goto exit;
287 }
288
289 pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
290 if (!pdev_entry) {
291 err = -ENOMEM;
292 goto exit_device_put;
293 }
294
295 err = platform_device_add(pdev);
296 if (err) {
297 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
298 err);
299 goto exit_device_free;
300 }
301
302 pdev_entry->pdev = pdev;
303 pdev_entry->cpu = cpu;
304 mutex_lock(&pdev_list_mutex);
305 list_add_tail(&pdev_entry->list, &pdev_list);
306 mutex_unlock(&pdev_list_mutex);
307
308 return 0;
309
310exit_device_free:
311 kfree(pdev_entry);
312exit_device_put:
313 platform_device_put(pdev);
314exit:
315 return err;
316}
317
318#ifdef CONFIG_HOTPLUG_CPU
Adrian Bunkd2bc7b12007-07-06 01:23:06 +0200319static void coretemp_device_remove(unsigned int cpu)
Rudolf Marekbebe4672007-05-08 17:22:02 +0200320{
321 struct pdev_entry *p, *n;
322 mutex_lock(&pdev_list_mutex);
323 list_for_each_entry_safe(p, n, &pdev_list, list) {
324 if (p->cpu == cpu) {
325 platform_device_unregister(p->pdev);
326 list_del(&p->list);
327 kfree(p);
328 }
329 }
330 mutex_unlock(&pdev_list_mutex);
331}
332
333static int coretemp_cpu_callback(struct notifier_block *nfb,
334 unsigned long action, void *hcpu)
335{
336 unsigned int cpu = (unsigned long) hcpu;
337
338 switch (action) {
339 case CPU_ONLINE:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700340 case CPU_ONLINE_FROZEN:
Rudolf Marekbebe4672007-05-08 17:22:02 +0200341 coretemp_device_add(cpu);
342 break;
343 case CPU_DEAD:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700344 case CPU_DEAD_FROZEN:
Rudolf Marekbebe4672007-05-08 17:22:02 +0200345 coretemp_device_remove(cpu);
346 break;
347 }
348 return NOTIFY_OK;
349}
350
Satyam Sharma59a35ba2007-08-23 09:14:25 +0530351static struct notifier_block coretemp_cpu_notifier = {
Rudolf Marekbebe4672007-05-08 17:22:02 +0200352 .notifier_call = coretemp_cpu_callback,
353};
354#endif /* !CONFIG_HOTPLUG_CPU */
355
356static int __init coretemp_init(void)
357{
358 int i, err = -ENODEV;
359 struct pdev_entry *p, *n;
360
Rudolf Marekbebe4672007-05-08 17:22:02 +0200361 /* quick check if we run Intel */
Mike Travis92cb7612007-10-19 20:35:04 +0200362 if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
Rudolf Marekbebe4672007-05-08 17:22:02 +0200363 goto exit;
364
365 err = platform_driver_register(&coretemp_driver);
366 if (err)
367 goto exit;
368
369 for_each_online_cpu(i) {
Mike Travis92cb7612007-10-19 20:35:04 +0200370 struct cpuinfo_x86 *c = &cpu_data(i);
Rudolf Marekbebe4672007-05-08 17:22:02 +0200371
Rudolf Marekc9403362007-10-07 13:42:09 +0200372 /* check if family 6, models e, f, 16 */
Rudolf Marekbebe4672007-05-08 17:22:02 +0200373 if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
Rudolf Marekc9403362007-10-07 13:42:09 +0200374 !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
375 (c->x86_model == 0x16))) {
Rudolf Marekbebe4672007-05-08 17:22:02 +0200376
377 /* supported CPU not found, but report the unknown
378 family 6 CPU */
379 if ((c->x86 == 0x6) && (c->x86_model > 0xf))
380 printk(KERN_WARNING DRVNAME ": Unknown CPU "
381 "model %x\n", c->x86_model);
382 continue;
383 }
384
385 err = coretemp_device_add(i);
386 if (err)
387 goto exit_devices_unreg;
388 }
389 if (list_empty(&pdev_list)) {
390 err = -ENODEV;
391 goto exit_driver_unreg;
392 }
393
394#ifdef CONFIG_HOTPLUG_CPU
395 register_hotcpu_notifier(&coretemp_cpu_notifier);
396#endif
397 return 0;
398
399exit_devices_unreg:
400 mutex_lock(&pdev_list_mutex);
401 list_for_each_entry_safe(p, n, &pdev_list, list) {
402 platform_device_unregister(p->pdev);
403 list_del(&p->list);
404 kfree(p);
405 }
406 mutex_unlock(&pdev_list_mutex);
407exit_driver_unreg:
408 platform_driver_unregister(&coretemp_driver);
409exit:
410 return err;
411}
412
413static void __exit coretemp_exit(void)
414{
415 struct pdev_entry *p, *n;
416#ifdef CONFIG_HOTPLUG_CPU
417 unregister_hotcpu_notifier(&coretemp_cpu_notifier);
418#endif
419 mutex_lock(&pdev_list_mutex);
420 list_for_each_entry_safe(p, n, &pdev_list, list) {
421 platform_device_unregister(p->pdev);
422 list_del(&p->list);
423 kfree(p);
424 }
425 mutex_unlock(&pdev_list_mutex);
426 platform_driver_unregister(&coretemp_driver);
427}
428
429MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
430MODULE_DESCRIPTION("Intel Core temperature monitor");
431MODULE_LICENSE("GPL");
432
433module_init(coretemp_init)
434module_exit(coretemp_exit)