OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [hwmon/] [coretemp.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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
 
41
typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
42
 
43
/*
44
 * Functions declaration
45
 */
46
 
47
static struct coretemp_data *coretemp_update_device(struct device *dev);
48
 
49
struct coretemp_data {
50
        struct device *hwmon_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
 
61
/*
62
 * Sysfs stuff
63
 */
64
 
65
static 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
 
79
static 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
 
87
static 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
 
102
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
103
                          SHOW_TEMP);
104
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
105
                          SHOW_TJMAX);
106
static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
107
static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
108
static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
109
 
110
static 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
 
119
static const struct attribute_group coretemp_group = {
120
        .attrs = coretemp_attributes,
121
};
122
 
123
static 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
 
150
static int __devinit coretemp_probe(struct platform_device *pdev)
151
{
152
        struct coretemp_data *data;
153
        struct cpuinfo_x86 *c = &cpu_data(pdev->id);
154
        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
 
177
        /* 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) {
186
                        err = -ENODEV;
187
                        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
 
194
        /* 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
 
211
        /* 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
 
224
        platform_set_drvdata(pdev, data);
225
 
226
        if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
227
                goto exit_free;
228
 
229
        data->hwmon_dev = hwmon_device_register(&pdev->dev);
230
        if (IS_ERR(data->hwmon_dev)) {
231
                err = PTR_ERR(data->hwmon_dev);
232
                dev_err(&pdev->dev, "Class registration failed (%d)\n",
233
                        err);
234
                goto exit_class;
235
        }
236
 
237
        return 0;
238
 
239
exit_class:
240
        sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
241
exit_free:
242
        kfree(data);
243
exit:
244
        return err;
245
}
246
 
247
static int __devexit coretemp_remove(struct platform_device *pdev)
248
{
249
        struct coretemp_data *data = platform_get_drvdata(pdev);
250
 
251
        hwmon_device_unregister(data->hwmon_dev);
252
        sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
253
        platform_set_drvdata(pdev, NULL);
254
        kfree(data);
255
        return 0;
256
}
257
 
258
static 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
 
267
struct pdev_entry {
268
        struct list_head list;
269
        struct platform_device *pdev;
270
        unsigned int cpu;
271
};
272
 
273
static LIST_HEAD(pdev_list);
274
static DEFINE_MUTEX(pdev_list_mutex);
275
 
276
static 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
 
310
exit_device_free:
311
        kfree(pdev_entry);
312
exit_device_put:
313
        platform_device_put(pdev);
314
exit:
315
        return err;
316
}
317
 
318
#ifdef CONFIG_HOTPLUG_CPU
319
static void coretemp_device_remove(unsigned int cpu)
320
{
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
 
333
static 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:
340
        case CPU_DOWN_FAILED:
341
                coretemp_device_add(cpu);
342
                break;
343
        case CPU_DOWN_PREPARE:
344
                coretemp_device_remove(cpu);
345
                break;
346
        }
347
        return NOTIFY_OK;
348
}
349
 
350
static struct notifier_block coretemp_cpu_notifier = {
351
        .notifier_call = coretemp_cpu_callback,
352
};
353
#endif                          /* !CONFIG_HOTPLUG_CPU */
354
 
355
static int __init coretemp_init(void)
356
{
357
        int i, err = -ENODEV;
358
        struct pdev_entry *p, *n;
359
 
360
        /* quick check if we run Intel */
361
        if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
362
                goto exit;
363
 
364
        err = platform_driver_register(&coretemp_driver);
365
        if (err)
366
                goto exit;
367
 
368
        for_each_online_cpu(i) {
369
                struct cpuinfo_x86 *c = &cpu_data(i);
370
 
371
                /* check if family 6, models e, f, 16 */
372
                if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
373
                    !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
374
                        (c->x86_model == 0x16))) {
375
 
376
                        /* supported CPU not found, but report the unknown
377
                           family 6 CPU */
378
                        if ((c->x86 == 0x6) && (c->x86_model > 0xf))
379
                                printk(KERN_WARNING DRVNAME ": Unknown CPU "
380
                                        "model %x\n", c->x86_model);
381
                        continue;
382
                }
383
 
384
                err = coretemp_device_add(i);
385
                if (err)
386
                        goto exit_devices_unreg;
387
        }
388
        if (list_empty(&pdev_list)) {
389
                err = -ENODEV;
390
                goto exit_driver_unreg;
391
        }
392
 
393
#ifdef CONFIG_HOTPLUG_CPU
394
        register_hotcpu_notifier(&coretemp_cpu_notifier);
395
#endif
396
        return 0;
397
 
398
exit_devices_unreg:
399
        mutex_lock(&pdev_list_mutex);
400
        list_for_each_entry_safe(p, n, &pdev_list, list) {
401
                platform_device_unregister(p->pdev);
402
                list_del(&p->list);
403
                kfree(p);
404
        }
405
        mutex_unlock(&pdev_list_mutex);
406
exit_driver_unreg:
407
        platform_driver_unregister(&coretemp_driver);
408
exit:
409
        return err;
410
}
411
 
412
static void __exit coretemp_exit(void)
413
{
414
        struct pdev_entry *p, *n;
415
#ifdef CONFIG_HOTPLUG_CPU
416
        unregister_hotcpu_notifier(&coretemp_cpu_notifier);
417
#endif
418
        mutex_lock(&pdev_list_mutex);
419
        list_for_each_entry_safe(p, n, &pdev_list, list) {
420
                platform_device_unregister(p->pdev);
421
                list_del(&p->list);
422
                kfree(p);
423
        }
424
        mutex_unlock(&pdev_list_mutex);
425
        platform_driver_unregister(&coretemp_driver);
426
}
427
 
428
MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
429
MODULE_DESCRIPTION("Intel Core temperature monitor");
430
MODULE_LICENSE("GPL");
431
 
432
module_init(coretemp_init)
433
module_exit(coretemp_exit)

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.