diff options
Diffstat (limited to 'arch/x86/kernel/cpuid.c')
-rw-r--r-- | arch/x86/kernel/cpuid.c | 52 |
1 files changed, 23 insertions, 29 deletions
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index a63432d800f9..288e7a6598ac 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* ----------------------------------------------------------------------- * | 1 | /* ----------------------------------------------------------------------- * |
2 | * | 2 | * |
3 | * Copyright 2000 H. Peter Anvin - All Rights Reserved | 3 | * Copyright 2000-2008 H. Peter Anvin - All Rights Reserved |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 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 | 6 | * it under the terms of the GNU General Public License as published by |
@@ -17,6 +17,10 @@ | |||
17 | * and then read in chunks of 16 bytes. A larger size means multiple | 17 | * and then read in chunks of 16 bytes. A larger size means multiple |
18 | * reads of consecutive levels. | 18 | * reads of consecutive levels. |
19 | * | 19 | * |
20 | * The lower 32 bits of the file position is used as the incoming %eax, | ||
21 | * and the upper 32 bits of the file position as the incoming %ecx, | ||
22 | * the latter intended for "counting" eax levels like eax=4. | ||
23 | * | ||
20 | * This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on | 24 | * This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on |
21 | * an SMP box will direct the access to CPU %d. | 25 | * an SMP box will direct the access to CPU %d. |
22 | */ | 26 | */ |
@@ -43,35 +47,24 @@ | |||
43 | 47 | ||
44 | static struct class *cpuid_class; | 48 | static struct class *cpuid_class; |
45 | 49 | ||
46 | struct cpuid_command { | 50 | struct cpuid_regs { |
47 | u32 reg; | 51 | u32 eax, ebx, ecx, edx; |
48 | u32 *data; | ||
49 | }; | 52 | }; |
50 | 53 | ||
51 | static void cpuid_smp_cpuid(void *cmd_block) | 54 | static void cpuid_smp_cpuid(void *cmd_block) |
52 | { | 55 | { |
53 | struct cpuid_command *cmd = cmd_block; | 56 | struct cpuid_regs *cmd = (struct cpuid_regs *)cmd_block; |
54 | |||
55 | cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], | ||
56 | &cmd->data[3]); | ||
57 | } | ||
58 | |||
59 | static inline void do_cpuid(int cpu, u32 reg, u32 * data) | ||
60 | { | ||
61 | struct cpuid_command cmd; | ||
62 | |||
63 | cmd.reg = reg; | ||
64 | cmd.data = data; | ||
65 | 57 | ||
66 | smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1); | 58 | cpuid_count(cmd->eax, cmd->ecx, |
59 | &cmd->eax, &cmd->ebx, &cmd->ecx, &cmd->edx); | ||
67 | } | 60 | } |
68 | 61 | ||
69 | static loff_t cpuid_seek(struct file *file, loff_t offset, int orig) | 62 | static loff_t cpuid_seek(struct file *file, loff_t offset, int orig) |
70 | { | 63 | { |
71 | loff_t ret; | 64 | loff_t ret; |
65 | struct inode *inode = file->f_mapping->host; | ||
72 | 66 | ||
73 | lock_kernel(); | 67 | mutex_lock(&inode->i_mutex); |
74 | |||
75 | switch (orig) { | 68 | switch (orig) { |
76 | case 0: | 69 | case 0: |
77 | file->f_pos = offset; | 70 | file->f_pos = offset; |
@@ -84,8 +77,7 @@ static loff_t cpuid_seek(struct file *file, loff_t offset, int orig) | |||
84 | default: | 77 | default: |
85 | ret = -EINVAL; | 78 | ret = -EINVAL; |
86 | } | 79 | } |
87 | 80 | mutex_unlock(&inode->i_mutex); | |
88 | unlock_kernel(); | ||
89 | return ret; | 81 | return ret; |
90 | } | 82 | } |
91 | 83 | ||
@@ -93,19 +85,21 @@ static ssize_t cpuid_read(struct file *file, char __user *buf, | |||
93 | size_t count, loff_t * ppos) | 85 | size_t count, loff_t * ppos) |
94 | { | 86 | { |
95 | char __user *tmp = buf; | 87 | char __user *tmp = buf; |
96 | u32 data[4]; | 88 | struct cpuid_regs cmd; |
97 | u32 reg = *ppos; | ||
98 | int cpu = iminor(file->f_path.dentry->d_inode); | 89 | int cpu = iminor(file->f_path.dentry->d_inode); |
90 | u64 pos = *ppos; | ||
99 | 91 | ||
100 | if (count % 16) | 92 | if (count % 16) |
101 | return -EINVAL; /* Invalid chunk size */ | 93 | return -EINVAL; /* Invalid chunk size */ |
102 | 94 | ||
103 | for (; count; count -= 16) { | 95 | for (; count; count -= 16) { |
104 | do_cpuid(cpu, reg, data); | 96 | cmd.eax = pos; |
105 | if (copy_to_user(tmp, &data, 16)) | 97 | cmd.ecx = pos >> 32; |
98 | smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1); | ||
99 | if (copy_to_user(tmp, &cmd, 16)) | ||
106 | return -EFAULT; | 100 | return -EFAULT; |
107 | tmp += 16; | 101 | tmp += 16; |
108 | *ppos = reg++; | 102 | *ppos = ++pos; |
109 | } | 103 | } |
110 | 104 | ||
111 | return tmp - buf; | 105 | return tmp - buf; |
@@ -193,7 +187,7 @@ static int __init cpuid_init(void) | |||
193 | } | 187 | } |
194 | for_each_online_cpu(i) { | 188 | for_each_online_cpu(i) { |
195 | err = cpuid_device_create(i); | 189 | err = cpuid_device_create(i); |
196 | if (err != 0) | 190 | if (err != 0) |
197 | goto out_class; | 191 | goto out_class; |
198 | } | 192 | } |
199 | register_hotcpu_notifier(&cpuid_class_cpu_notifier); | 193 | register_hotcpu_notifier(&cpuid_class_cpu_notifier); |
@@ -208,7 +202,7 @@ out_class: | |||
208 | } | 202 | } |
209 | class_destroy(cpuid_class); | 203 | class_destroy(cpuid_class); |
210 | out_chrdev: | 204 | out_chrdev: |
211 | unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); | 205 | unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); |
212 | out: | 206 | out: |
213 | return err; | 207 | return err; |
214 | } | 208 | } |