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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [x86/] [kernel/] [msr.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/* ----------------------------------------------------------------------- *
2
 *
3
 *   Copyright 2000 H. Peter Anvin - All Rights Reserved
4
 *
5
 *   This program is free software; you can redistribute it and/or modify
6
 *   it under the terms of the GNU General Public License as published by
7
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
8
 *   USA; either version 2 of the License, or (at your option) any later
9
 *   version; incorporated herein by reference.
10
 *
11
 * ----------------------------------------------------------------------- */
12
 
13
/*
14
 * x86 MSR access device
15
 *
16
 * This device is accessed by lseek() to the appropriate register number
17
 * and then read/write in chunks of 8 bytes.  A larger size means multiple
18
 * reads or writes of the same register.
19
 *
20
 * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
21
 * an SMP box will direct the access to CPU %d.
22
 */
23
 
24
#include <linux/module.h>
25
 
26
#include <linux/types.h>
27
#include <linux/errno.h>
28
#include <linux/fcntl.h>
29
#include <linux/init.h>
30
#include <linux/poll.h>
31
#include <linux/smp.h>
32
#include <linux/smp_lock.h>
33
#include <linux/major.h>
34
#include <linux/fs.h>
35
#include <linux/device.h>
36
#include <linux/cpu.h>
37
#include <linux/notifier.h>
38
 
39
#include <asm/processor.h>
40
#include <asm/msr.h>
41
#include <asm/uaccess.h>
42
#include <asm/system.h>
43
 
44
static struct class *msr_class;
45
 
46
static loff_t msr_seek(struct file *file, loff_t offset, int orig)
47
{
48
        loff_t ret = -EINVAL;
49
 
50
        lock_kernel();
51
        switch (orig) {
52
        case 0:
53
                file->f_pos = offset;
54
                ret = file->f_pos;
55
                break;
56
        case 1:
57
                file->f_pos += offset;
58
                ret = file->f_pos;
59
        }
60
        unlock_kernel();
61
        return ret;
62
}
63
 
64
static ssize_t msr_read(struct file *file, char __user * buf,
65
                        size_t count, loff_t * ppos)
66
{
67
        u32 __user *tmp = (u32 __user *) buf;
68
        u32 data[2];
69
        u32 reg = *ppos;
70
        int cpu = iminor(file->f_path.dentry->d_inode);
71
        int err;
72
 
73
        if (count % 8)
74
                return -EINVAL; /* Invalid chunk size */
75
 
76
        for (; count; count -= 8) {
77
                err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]);
78
                if (err)
79
                        return -EIO;
80
                if (copy_to_user(tmp, &data, 8))
81
                        return -EFAULT;
82
                tmp += 2;
83
        }
84
 
85
        return ((char __user *)tmp) - buf;
86
}
87
 
88
static ssize_t msr_write(struct file *file, const char __user *buf,
89
                         size_t count, loff_t *ppos)
90
{
91
        const u32 __user *tmp = (const u32 __user *)buf;
92
        u32 data[2];
93
        u32 reg = *ppos;
94
        int cpu = iminor(file->f_path.dentry->d_inode);
95
        int err;
96
 
97
        if (count % 8)
98
                return -EINVAL; /* Invalid chunk size */
99
 
100
        for (; count; count -= 8) {
101
                if (copy_from_user(&data, tmp, 8))
102
                        return -EFAULT;
103
                err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]);
104
                if (err)
105
                        return -EIO;
106
                tmp += 2;
107
        }
108
 
109
        return ((char __user *)tmp) - buf;
110
}
111
 
112
static int msr_open(struct inode *inode, struct file *file)
113
{
114
        unsigned int cpu = iminor(file->f_path.dentry->d_inode);
115
        struct cpuinfo_x86 *c = &cpu_data(cpu);
116
 
117
        if (cpu >= NR_CPUS || !cpu_online(cpu))
118
                return -ENXIO;  /* No such CPU */
119
        if (!cpu_has(c, X86_FEATURE_MSR))
120
                return -EIO;    /* MSR not supported */
121
 
122
        return 0;
123
}
124
 
125
/*
126
 * File operations we support
127
 */
128
static const struct file_operations msr_fops = {
129
        .owner = THIS_MODULE,
130
        .llseek = msr_seek,
131
        .read = msr_read,
132
        .write = msr_write,
133
        .open = msr_open,
134
};
135
 
136
static int __cpuinit msr_device_create(int cpu)
137
{
138
        struct device *dev;
139
 
140
        dev = device_create(msr_class, NULL, MKDEV(MSR_MAJOR, cpu),
141
                            "msr%d", cpu);
142
        return IS_ERR(dev) ? PTR_ERR(dev) : 0;
143
}
144
 
145
static void msr_device_destroy(int cpu)
146
{
147
        device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
148
}
149
 
150
static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
151
                                unsigned long action, void *hcpu)
152
{
153
        unsigned int cpu = (unsigned long)hcpu;
154
        int err = 0;
155
 
156
        switch (action) {
157
        case CPU_UP_PREPARE:
158
        case CPU_UP_PREPARE_FROZEN:
159
                err = msr_device_create(cpu);
160
                break;
161
        case CPU_UP_CANCELED:
162
        case CPU_UP_CANCELED_FROZEN:
163
        case CPU_DEAD:
164
        case CPU_DEAD_FROZEN:
165
                msr_device_destroy(cpu);
166
                break;
167
        }
168
        return err ? NOTIFY_BAD : NOTIFY_OK;
169
}
170
 
171
static struct notifier_block __cpuinitdata msr_class_cpu_notifier = {
172
        .notifier_call = msr_class_cpu_callback,
173
};
174
 
175
static int __init msr_init(void)
176
{
177
        int i, err = 0;
178
        i = 0;
179
 
180
        if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) {
181
                printk(KERN_ERR "msr: unable to get major %d for msr\n",
182
                       MSR_MAJOR);
183
                err = -EBUSY;
184
                goto out;
185
        }
186
        msr_class = class_create(THIS_MODULE, "msr");
187
        if (IS_ERR(msr_class)) {
188
                err = PTR_ERR(msr_class);
189
                goto out_chrdev;
190
        }
191
        for_each_online_cpu(i) {
192
                err = msr_device_create(i);
193
                if (err != 0)
194
                        goto out_class;
195
        }
196
        register_hotcpu_notifier(&msr_class_cpu_notifier);
197
 
198
        err = 0;
199
        goto out;
200
 
201
out_class:
202
        i = 0;
203
        for_each_online_cpu(i)
204
                msr_device_destroy(i);
205
        class_destroy(msr_class);
206
out_chrdev:
207
        unregister_chrdev(MSR_MAJOR, "cpu/msr");
208
out:
209
        return err;
210
}
211
 
212
static void __exit msr_exit(void)
213
{
214
        int cpu = 0;
215
        for_each_online_cpu(cpu)
216
                msr_device_destroy(cpu);
217
        class_destroy(msr_class);
218
        unregister_chrdev(MSR_MAJOR, "cpu/msr");
219
        unregister_hotcpu_notifier(&msr_class_cpu_notifier);
220
}
221
 
222
module_init(msr_init);
223
module_exit(msr_exit)
224
 
225
MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
226
MODULE_DESCRIPTION("x86 generic MSR driver");
227
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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