aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Oruba <peter.oruba@amd.com>2008-07-28 12:44:17 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-28 13:57:55 -0400
commit3e135d887c973b525d43fbb67dfc5972694882f6 (patch)
treef24650c6d57c72f4fe77b96b19d891bee6865349
parent1abae31096007cc993f67ae2576fe8f812270ad6 (diff)
x86: code split to two parts
Split off existing code into two seperate files. One file holds general code, the other file vendor specific parts. No functional changes, only refactoring. Temporarily Introduced a new module name 'ucode' for result, due to already taken name 'microcode'. Signed-off-by: Peter Oruba <peter.oruba@amd.com> Cc: Tigran Aivazian <tigran@aivazian.fsnet.co.uk> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/Makefile3
-rw-r--r--arch/x86/kernel/microcode.c463
-rw-r--r--arch/x86/kernel/microcode_intel.c387
3 files changed, 488 insertions, 365 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index a9be2a0dde80..abb32aed7f4b 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -51,7 +51,8 @@ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
51obj-$(CONFIG_MCA) += mca_32.o 51obj-$(CONFIG_MCA) += mca_32.o
52obj-$(CONFIG_X86_MSR) += msr.o 52obj-$(CONFIG_X86_MSR) += msr.o
53obj-$(CONFIG_X86_CPUID) += cpuid.o 53obj-$(CONFIG_X86_CPUID) += cpuid.o
54obj-$(CONFIG_MICROCODE) += microcode_intel.o 54obj-$(CONFIG_MICROCODE) += ucode.o
55ucode-objs := microcode.o microcode_intel.o
55obj-$(CONFIG_PCI) += early-quirks.o 56obj-$(CONFIG_PCI) += early-quirks.o
56apm-y := apm_32.o 57apm-y := apm_32.o
57obj-$(CONFIG_APM) += apm.o 58obj-$(CONFIG_APM) += apm.o
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
new file mode 100644
index 000000000000..c1047d7f7ede
--- /dev/null
+++ b/arch/x86/kernel/microcode.c
@@ -0,0 +1,463 @@
1/*
2 * Intel CPU Microcode Update Driver for Linux
3 *
4 * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
5 * 2006 Shaohua Li <shaohua.li@intel.com>
6 *
7 * This driver allows to upgrade microcode on Intel processors
8 * belonging to IA-32 family - PentiumPro, Pentium II,
9 * Pentium III, Xeon, Pentium 4, etc.
10 *
11 * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
12 * Software Developer's Manual
13 * Order Number 253668 or free download from:
14 *
15 * http://developer.intel.com/design/pentium4/manuals/253668.htm
16 *
17 * For more information, go to http://www.urbanmyth.org/microcode
18 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version
22 * 2 of the License, or (at your option) any later version.
23 *
24 * 1.0 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
25 * Initial release.
26 * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
27 * Added read() support + cleanups.
28 * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
29 * Added 'device trimming' support. open(O_WRONLY) zeroes
30 * and frees the saved copy of applied microcode.
31 * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
32 * Made to use devfs (/dev/cpu/microcode) + cleanups.
33 * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
34 * Added misc device support (now uses both devfs and misc).
35 * Added MICROCODE_IOCFREE ioctl to clear memory.
36 * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
37 * Messages for error cases (non Intel & no suitable microcode).
38 * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
39 * Removed ->release(). Removed exclusive open and status bitmap.
40 * Added microcode_rwsem to serialize read()/write()/ioctl().
41 * Removed global kernel lock usage.
42 * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
43 * Write 0 to 0x8B msr and then cpuid before reading revision,
44 * so that it works even if there were no update done by the
45 * BIOS. Otherwise, reading from 0x8B gives junk (which happened
46 * to be 0 on my machine which is why it worked even when I
47 * disabled update by the BIOS)
48 * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
49 * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
50 * Tigran Aivazian <tigran@veritas.com>
51 * Intel Pentium 4 processor support and bugfixes.
52 * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
53 * Bugfix for HT (Hyper-Threading) enabled processors
54 * whereby processor resources are shared by all logical processors
55 * in a single CPU package.
56 * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
57 * Tigran Aivazian <tigran@veritas.com>,
58 * Serialize updates as required on HT processors due to speculative
59 * nature of implementation.
60 * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
61 * Fix the panic when writing zero-length microcode chunk.
62 * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
63 * Jun Nakajima <jun.nakajima@intel.com>
64 * Support for the microcode updates in the new format.
65 * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
66 * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
67 * because we no longer hold a copy of applied microcode
68 * in kernel memory.
69 * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
70 * Fix sigmatch() macro to handle old CPUs with pf == 0.
71 * Thanks to Stuart Swales for pointing out this bug.
72 */
73
74//#define DEBUG /* pr_debug */
75#include <linux/capability.h>
76#include <linux/kernel.h>
77#include <linux/init.h>
78#include <linux/sched.h>
79#include <linux/smp_lock.h>
80#include <linux/cpumask.h>
81#include <linux/module.h>
82#include <linux/slab.h>
83#include <linux/vmalloc.h>
84#include <linux/miscdevice.h>
85#include <linux/spinlock.h>
86#include <linux/mm.h>
87#include <linux/fs.h>
88#include <linux/mutex.h>
89#include <linux/cpu.h>
90#include <linux/firmware.h>
91#include <linux/platform_device.h>
92
93#include <asm/msr.h>
94#include <asm/uaccess.h>
95#include <asm/processor.h>
96#include <asm/microcode.h>
97
98MODULE_DESCRIPTION("Microcode Update Driver");
99MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
100MODULE_LICENSE("GPL");
101
102#define MICROCODE_VERSION "1.14a"
103
104/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
105DEFINE_MUTEX(microcode_mutex);
106
107struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
108
109extern long get_next_ucode(void **mc, long offset);
110extern int microcode_sanity_check(void *mc);
111extern int get_matching_microcode(void *mc, int cpu);
112extern void collect_cpu_info(int cpu_num);
113extern int cpu_request_microcode(int cpu);
114extern void microcode_fini_cpu(int cpu);
115extern void apply_microcode(int cpu);
116extern int apply_microcode_check_cpu(int cpu);
117
118#ifdef CONFIG_MICROCODE_OLD_INTERFACE
119void __user *user_buffer; /* user area microcode data buffer */
120unsigned int user_buffer_size; /* it's size */
121
122static int do_microcode_update (void)
123{
124 long cursor = 0;
125 int error = 0;
126 void *new_mc = NULL;
127 int cpu;
128 cpumask_t old;
129 cpumask_of_cpu_ptr_declare(newmask);
130
131 old = current->cpus_allowed;
132
133 while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
134 error = microcode_sanity_check(new_mc);
135 if (error)
136 goto out;
137 /*
138 * It's possible the data file has multiple matching ucode,
139 * lets keep searching till the latest version
140 */
141 for_each_online_cpu(cpu) {
142 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
143
144 if (!uci->valid)
145 continue;
146 cpumask_of_cpu_ptr_next(newmask, cpu);
147 set_cpus_allowed_ptr(current, newmask);
148 error = get_maching_microcode(new_mc, cpu);
149 if (error < 0)
150 goto out;
151 if (error == 1)
152 apply_microcode(cpu);
153 }
154 vfree(new_mc);
155 }
156out:
157 if (cursor > 0)
158 vfree(new_mc);
159 if (cursor < 0)
160 error = cursor;
161 set_cpus_allowed_ptr(current, &old);
162 return error;
163}
164
165static int microcode_open (struct inode *unused1, struct file *unused2)
166{
167 cycle_kernel_lock();
168 return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
169}
170
171static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
172{
173 ssize_t ret;
174
175 if ((len >> PAGE_SHIFT) > num_physpages) {
176 printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
177 return -EINVAL;
178 }
179
180 get_online_cpus();
181 mutex_lock(&microcode_mutex);
182
183 user_buffer = (void __user *) buf;
184 user_buffer_size = (int) len;
185
186 ret = do_microcode_update();
187 if (!ret)
188 ret = (ssize_t)len;
189
190 mutex_unlock(&microcode_mutex);
191 put_online_cpus();
192
193 return ret;
194}
195
196static const struct file_operations microcode_fops = {
197 .owner = THIS_MODULE,
198 .write = microcode_write,
199 .open = microcode_open,
200};
201
202static struct miscdevice microcode_dev = {
203 .minor = MICROCODE_MINOR,
204 .name = "microcode",
205 .fops = &microcode_fops,
206};
207
208static int __init microcode_dev_init (void)
209{
210 int error;
211
212 error = misc_register(&microcode_dev);
213 if (error) {
214 printk(KERN_ERR
215 "microcode: can't misc_register on minor=%d\n",
216 MICROCODE_MINOR);
217 return error;
218 }
219
220 return 0;
221}
222
223static void microcode_dev_exit (void)
224{
225 misc_deregister(&microcode_dev);
226}
227
228MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
229#else
230#define microcode_dev_init() 0
231#define microcode_dev_exit() do { } while(0)
232#endif
233
234/* fake device for request_firmware */
235struct platform_device *microcode_pdev;
236
237static void microcode_init_cpu(int cpu, int resume)
238{
239 cpumask_t old;
240 cpumask_of_cpu_ptr(newmask, cpu);
241 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
242
243 old = current->cpus_allowed;
244
245 set_cpus_allowed_ptr(current, newmask);
246 mutex_lock(&microcode_mutex);
247 collect_cpu_info(cpu);
248 if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
249 cpu_request_microcode(cpu);
250 mutex_unlock(&microcode_mutex);
251 set_cpus_allowed_ptr(current, &old);
252}
253
254static ssize_t reload_store(struct sys_device *dev,
255 struct sysdev_attribute *attr,
256 const char *buf, size_t sz)
257{
258 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
259 char *end;
260 unsigned long val = simple_strtoul(buf, &end, 0);
261 int err = 0;
262 int cpu = dev->id;
263
264 if (end == buf)
265 return -EINVAL;
266 if (val == 1) {
267 cpumask_t old;
268 cpumask_of_cpu_ptr(newmask, cpu);
269
270 old = current->cpus_allowed;
271
272 get_online_cpus();
273 set_cpus_allowed_ptr(current, newmask);
274
275 mutex_lock(&microcode_mutex);
276 if (uci->valid)
277 err = cpu_request_microcode(cpu);
278 mutex_unlock(&microcode_mutex);
279 put_online_cpus();
280 set_cpus_allowed_ptr(current, &old);
281 }
282 if (err)
283 return err;
284 return sz;
285}
286
287static ssize_t version_show(struct sys_device *dev,
288 struct sysdev_attribute *attr, char *buf)
289{
290 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
291
292 return sprintf(buf, "0x%x\n", uci->rev);
293}
294
295static ssize_t pf_show(struct sys_device *dev,
296 struct sysdev_attribute *attr, char *buf)
297{
298 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
299
300 return sprintf(buf, "0x%x\n", uci->pf);
301}
302
303static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
304static SYSDEV_ATTR(version, 0400, version_show, NULL);
305static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
306
307static struct attribute *mc_default_attrs[] = {
308 &attr_reload.attr,
309 &attr_version.attr,
310 &attr_processor_flags.attr,
311 NULL
312};
313
314static struct attribute_group mc_attr_group = {
315 .attrs = mc_default_attrs,
316 .name = "microcode",
317};
318
319static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
320{
321 int err, cpu = sys_dev->id;
322 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
323
324 if (!cpu_online(cpu))
325 return 0;
326
327 pr_debug("microcode: CPU%d added\n", cpu);
328 memset(uci, 0, sizeof(*uci));
329
330 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
331 if (err)
332 return err;
333
334 microcode_init_cpu(cpu, resume);
335
336 return 0;
337}
338
339static int mc_sysdev_add(struct sys_device *sys_dev)
340{
341 return __mc_sysdev_add(sys_dev, 0);
342}
343
344static int mc_sysdev_remove(struct sys_device *sys_dev)
345{
346 int cpu = sys_dev->id;
347
348 if (!cpu_online(cpu))
349 return 0;
350
351 pr_debug("microcode: CPU%d removed\n", cpu);
352 microcode_fini_cpu(cpu);
353 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
354 return 0;
355}
356
357static int mc_sysdev_resume(struct sys_device *dev)
358{
359 int cpu = dev->id;
360
361 if (!cpu_online(cpu))
362 return 0;
363 pr_debug("microcode: CPU%d resumed\n", cpu);
364 /* only CPU 0 will apply ucode here */
365 apply_microcode(0);
366 return 0;
367}
368
369static struct sysdev_driver mc_sysdev_driver = {
370 .add = mc_sysdev_add,
371 .remove = mc_sysdev_remove,
372 .resume = mc_sysdev_resume,
373};
374
375static __cpuinit int
376mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
377{
378 unsigned int cpu = (unsigned long)hcpu;
379 struct sys_device *sys_dev;
380
381 sys_dev = get_cpu_sysdev(cpu);
382 switch (action) {
383 case CPU_UP_CANCELED_FROZEN:
384 /* The CPU refused to come up during a system resume */
385 microcode_fini_cpu(cpu);
386 break;
387 case CPU_ONLINE:
388 case CPU_DOWN_FAILED:
389 mc_sysdev_add(sys_dev);
390 break;
391 case CPU_ONLINE_FROZEN:
392 /* System-wide resume is in progress, try to apply microcode */
393 if (apply_microcode_check_cpu(cpu)) {
394 /* The application of microcode failed */
395 microcode_fini_cpu(cpu);
396 __mc_sysdev_add(sys_dev, 1);
397 break;
398 }
399 case CPU_DOWN_FAILED_FROZEN:
400 if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
401 printk(KERN_ERR "microcode: Failed to create the sysfs "
402 "group for CPU%d\n", cpu);
403 break;
404 case CPU_DOWN_PREPARE:
405 mc_sysdev_remove(sys_dev);
406 break;
407 case CPU_DOWN_PREPARE_FROZEN:
408 /* Suspend is in progress, only remove the interface */
409 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
410 break;
411 }
412 return NOTIFY_OK;
413}
414
415static struct notifier_block __refdata mc_cpu_notifier = {
416 .notifier_call = mc_cpu_callback,
417};
418
419static int __init microcode_init (void)
420{
421 int error;
422
423 printk(KERN_INFO
424 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
425
426 error = microcode_dev_init();
427 if (error)
428 return error;
429 microcode_pdev = platform_device_register_simple("microcode", -1,
430 NULL, 0);
431 if (IS_ERR(microcode_pdev)) {
432 microcode_dev_exit();
433 return PTR_ERR(microcode_pdev);
434 }
435
436 get_online_cpus();
437 error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
438 put_online_cpus();
439 if (error) {
440 microcode_dev_exit();
441 platform_device_unregister(microcode_pdev);
442 return error;
443 }
444
445 register_hotcpu_notifier(&mc_cpu_notifier);
446 return 0;
447}
448
449static void __exit microcode_exit (void)
450{
451 microcode_dev_exit();
452
453 unregister_hotcpu_notifier(&mc_cpu_notifier);
454
455 get_online_cpus();
456 sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
457 put_online_cpus();
458
459 platform_device_unregister(microcode_pdev);
460}
461
462module_init(microcode_init)
463module_exit(microcode_exit)
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index 4e7b2f65fed6..eded0a154ea8 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -95,18 +95,16 @@
95#include <asm/processor.h> 95#include <asm/processor.h>
96#include <asm/microcode.h> 96#include <asm/microcode.h>
97 97
98MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); 98MODULE_DESCRIPTION("Microcode Update Driver");
99MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); 99MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
100MODULE_LICENSE("GPL"); 100MODULE_LICENSE("GPL");
101 101
102#define MICROCODE_VERSION "1.14a"
103
104#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ 102#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
105#define MC_HEADER_SIZE (sizeof (struct microcode_header)) /* 48 bytes */ 103#define MC_HEADER_SIZE (sizeof(struct microcode_header)) /* 48 bytes */
106#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */ 104#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
107#define EXT_HEADER_SIZE (sizeof (struct extended_sigtable)) /* 20 bytes */ 105#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable)) /* 20 bytes */
108#define EXT_SIGNATURE_SIZE (sizeof (struct extended_signature)) /* 12 bytes */ 106#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature)) /* 12 bytes */
109#define DWSIZE (sizeof (u32)) 107#define DWSIZE (sizeof(u32))
110#define get_totalsize(mc) \ 108#define get_totalsize(mc) \
111 (((struct microcode *)mc)->hdr.totalsize ? \ 109 (((struct microcode *)mc)->hdr.totalsize ? \
112 ((struct microcode *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE) 110 ((struct microcode *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
@@ -123,11 +121,11 @@ MODULE_LICENSE("GPL");
123static DEFINE_SPINLOCK(microcode_update_lock); 121static DEFINE_SPINLOCK(microcode_update_lock);
124 122
125/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ 123/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
126static DEFINE_MUTEX(microcode_mutex); 124extern struct mutex microcode_mutex;
127 125
128static struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; 126extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
129 127
130static void collect_cpu_info(int cpu_num) 128void collect_cpu_info(int cpu_num)
131{ 129{
132 struct cpuinfo_x86 *c = &cpu_data(cpu_num); 130 struct cpuinfo_x86 *c = &cpu_data(cpu_num);
133 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 131 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
@@ -140,7 +138,7 @@ static void collect_cpu_info(int cpu_num)
140 uci->valid = 1; 138 uci->valid = 1;
141 139
142 if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || 140 if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
143 cpu_has(c, X86_FEATURE_IA64)) { 141 cpu_has(c, X86_FEATURE_IA64)) {
144 printk(KERN_ERR "microcode: CPU%d not a capable Intel " 142 printk(KERN_ERR "microcode: CPU%d not a capable Intel "
145 "processor\n", cpu_num); 143 "processor\n", cpu_num);
146 uci->valid = 0; 144 uci->valid = 0;
@@ -175,7 +173,7 @@ static inline int microcode_update_match(int cpu_num,
175 return 1; 173 return 1;
176} 174}
177 175
178static int microcode_sanity_check(void *mc) 176int microcode_sanity_check(void *mc)
179{ 177{
180 struct microcode_header *mc_header = mc; 178 struct microcode_header *mc_header = mc;
181 struct extended_sigtable *ext_header = NULL; 179 struct extended_sigtable *ext_header = NULL;
@@ -259,7 +257,7 @@ static int microcode_sanity_check(void *mc)
259 * return 1 - found update 257 * return 1 - found update
260 * return < 0 - error 258 * return < 0 - error
261 */ 259 */
262static int get_maching_microcode(void *mc, int cpu) 260int get_matching_microcode(void *mc, int cpu)
263{ 261{
264 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 262 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
265 struct microcode_header *mc_header = mc; 263 struct microcode_header *mc_header = mc;
@@ -288,7 +286,7 @@ static int get_maching_microcode(void *mc, int cpu)
288 return 0; 286 return 0;
289find: 287find:
290 pr_debug("microcode: CPU%d found a matching microcode update with" 288 pr_debug("microcode: CPU%d found a matching microcode update with"
291 " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev); 289 " version 0x%x (current=0x%x)\n", cpu, mc_header->rev, uci->rev);
292 new_mc = vmalloc(total_size); 290 new_mc = vmalloc(total_size);
293 if (!new_mc) { 291 if (!new_mc) {
294 printk(KERN_ERR "microcode: error! Can not allocate memory\n"); 292 printk(KERN_ERR "microcode: error! Can not allocate memory\n");
@@ -303,7 +301,7 @@ find:
303 return 1; 301 return 1;
304} 302}
305 303
306static void apply_microcode(int cpu) 304void apply_microcode(int cpu)
307{ 305{
308 unsigned long flags; 306 unsigned long flags;
309 unsigned int val[2]; 307 unsigned int val[2];
@@ -344,10 +342,10 @@ static void apply_microcode(int cpu)
344} 342}
345 343
346#ifdef CONFIG_MICROCODE_OLD_INTERFACE 344#ifdef CONFIG_MICROCODE_OLD_INTERFACE
347static void __user *user_buffer; /* user area microcode data buffer */ 345extern void __user *user_buffer; /* user area microcode data buffer */
348static unsigned int user_buffer_size; /* it's size */ 346extern unsigned int user_buffer_size; /* it's size */
349 347
350static long get_next_ucode(void **mc, long offset) 348long get_next_ucode(void **mc, long offset)
351{ 349{
352 struct microcode_header mc_header; 350 struct microcode_header mc_header;
353 unsigned long total_size; 351 unsigned long total_size;
@@ -375,117 +373,6 @@ static long get_next_ucode(void **mc, long offset)
375 } 373 }
376 return offset + total_size; 374 return offset + total_size;
377} 375}
378
379static int do_microcode_update (void)
380{
381 long cursor = 0;
382 int error = 0;
383 void *new_mc = NULL;
384 int cpu;
385 cpumask_t old;
386 cpumask_of_cpu_ptr_declare(newmask);
387
388 old = current->cpus_allowed;
389
390 while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
391 error = microcode_sanity_check(new_mc);
392 if (error)
393 goto out;
394 /*
395 * It's possible the data file has multiple matching ucode,
396 * lets keep searching till the latest version
397 */
398 for_each_online_cpu(cpu) {
399 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
400
401 if (!uci->valid)
402 continue;
403 cpumask_of_cpu_ptr_next(newmask, cpu);
404 set_cpus_allowed_ptr(current, newmask);
405 error = get_maching_microcode(new_mc, cpu);
406 if (error < 0)
407 goto out;
408 if (error == 1)
409 apply_microcode(cpu);
410 }
411 vfree(new_mc);
412 }
413out:
414 if (cursor > 0)
415 vfree(new_mc);
416 if (cursor < 0)
417 error = cursor;
418 set_cpus_allowed_ptr(current, &old);
419 return error;
420}
421
422static int microcode_open (struct inode *unused1, struct file *unused2)
423{
424 cycle_kernel_lock();
425 return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
426}
427
428static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
429{
430 ssize_t ret;
431
432 if ((len >> PAGE_SHIFT) > num_physpages) {
433 printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
434 return -EINVAL;
435 }
436
437 get_online_cpus();
438 mutex_lock(&microcode_mutex);
439
440 user_buffer = (void __user *) buf;
441 user_buffer_size = (int) len;
442
443 ret = do_microcode_update();
444 if (!ret)
445 ret = (ssize_t)len;
446
447 mutex_unlock(&microcode_mutex);
448 put_online_cpus();
449
450 return ret;
451}
452
453static const struct file_operations microcode_fops = {
454 .owner = THIS_MODULE,
455 .write = microcode_write,
456 .open = microcode_open,
457};
458
459static struct miscdevice microcode_dev = {
460 .minor = MICROCODE_MINOR,
461 .name = "microcode",
462 .fops = &microcode_fops,
463};
464
465static int __init microcode_dev_init (void)
466{
467 int error;
468
469 error = misc_register(&microcode_dev);
470 if (error) {
471 printk(KERN_ERR
472 "microcode: can't misc_register on minor=%d\n",
473 MICROCODE_MINOR);
474 return error;
475 }
476
477 return 0;
478}
479
480static void microcode_dev_exit (void)
481{
482 misc_deregister(&microcode_dev);
483}
484
485MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
486#else
487#define microcode_dev_init() 0
488#define microcode_dev_exit() do { } while(0)
489#endif 376#endif
490 377
491static long get_next_ucode_from_buffer(void **mc, const u8 *buf, 378static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
@@ -515,9 +402,9 @@ static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
515} 402}
516 403
517/* fake device for request_firmware */ 404/* fake device for request_firmware */
518static struct platform_device *microcode_pdev; 405extern struct platform_device *microcode_pdev;
519 406
520static int cpu_request_microcode(int cpu) 407int cpu_request_microcode(int cpu)
521{ 408{
522 char name[30]; 409 char name[30];
523 struct cpuinfo_x86 *c = &cpu_data(cpu); 410 struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -530,7 +417,7 @@ static int cpu_request_microcode(int cpu)
530 417
531 /* We should bind the task to the CPU */ 418 /* We should bind the task to the CPU */
532 BUG_ON(cpu != raw_smp_processor_id()); 419 BUG_ON(cpu != raw_smp_processor_id());
533 sprintf(name,"intel-ucode/%02x-%02x-%02x", 420 sprintf(name, "intel-ucode/%02x-%02x-%02x",
534 c->x86, c->x86_model, c->x86_mask); 421 c->x86, c->x86_model, c->x86_mask);
535 error = request_firmware(&firmware, name, &microcode_pdev->dev); 422 error = request_firmware(&firmware, name, &microcode_pdev->dev);
536 if (error) { 423 if (error) {
@@ -544,7 +431,7 @@ static int cpu_request_microcode(int cpu)
544 error = microcode_sanity_check(mc); 431 error = microcode_sanity_check(mc);
545 if (error) 432 if (error)
546 break; 433 break;
547 error = get_maching_microcode(mc, cpu); 434 error = get_matching_microcode(mc, cpu);
548 if (error < 0) 435 if (error < 0)
549 break; 436 break;
550 /* 437 /*
@@ -566,7 +453,7 @@ static int cpu_request_microcode(int cpu)
566 return error; 453 return error;
567} 454}
568 455
569static int apply_microcode_check_cpu(int cpu) 456int apply_microcode_check_cpu(int cpu)
570{ 457{
571 struct cpuinfo_x86 *c = &cpu_data(cpu); 458 struct cpuinfo_x86 *c = &cpu_data(cpu);
572 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 459 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -615,241 +502,13 @@ static int apply_microcode_check_cpu(int cpu)
615 return err; 502 return err;
616} 503}
617 504
618static void microcode_init_cpu(int cpu, int resume) 505void microcode_fini_cpu(int cpu)
619{
620 cpumask_t old;
621 cpumask_of_cpu_ptr(newmask, cpu);
622 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
623
624 old = current->cpus_allowed;
625
626 set_cpus_allowed_ptr(current, newmask);
627 mutex_lock(&microcode_mutex);
628 collect_cpu_info(cpu);
629 if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
630 cpu_request_microcode(cpu);
631 mutex_unlock(&microcode_mutex);
632 set_cpus_allowed_ptr(current, &old);
633}
634
635static void microcode_fini_cpu(int cpu)
636{ 506{
637 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 507 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
638 508
639 mutex_lock(&microcode_mutex); 509 mutex_lock(&microcode_mutex);
640 uci->valid = 0; 510 uci->valid = 0;
641 vfree(uci->mc); 511 kfree(uci->mc);
642 uci->mc = NULL; 512 uci->mc = NULL;
643 mutex_unlock(&microcode_mutex); 513 mutex_unlock(&microcode_mutex);
644} 514}
645
646static ssize_t reload_store(struct sys_device *dev,
647 struct sysdev_attribute *attr,
648 const char *buf, size_t sz)
649{
650 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
651 char *end;
652 unsigned long val = simple_strtoul(buf, &end, 0);
653 int err = 0;
654 int cpu = dev->id;
655
656 if (end == buf)
657 return -EINVAL;
658 if (val == 1) {
659 cpumask_t old;
660 cpumask_of_cpu_ptr(newmask, cpu);
661
662 old = current->cpus_allowed;
663
664 get_online_cpus();
665 set_cpus_allowed_ptr(current, newmask);
666
667 mutex_lock(&microcode_mutex);
668 if (uci->valid)
669 err = cpu_request_microcode(cpu);
670 mutex_unlock(&microcode_mutex);
671 put_online_cpus();
672 set_cpus_allowed_ptr(current, &old);
673 }
674 if (err)
675 return err;
676 return sz;
677}
678
679static ssize_t version_show(struct sys_device *dev,
680 struct sysdev_attribute *attr, char *buf)
681{
682 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
683
684 return sprintf(buf, "0x%x\n", uci->rev);
685}
686
687static ssize_t pf_show(struct sys_device *dev,
688 struct sysdev_attribute *attr, char *buf)
689{
690 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
691
692 return sprintf(buf, "0x%x\n", uci->pf);
693}
694
695static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
696static SYSDEV_ATTR(version, 0400, version_show, NULL);
697static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
698
699static struct attribute *mc_default_attrs[] = {
700 &attr_reload.attr,
701 &attr_version.attr,
702 &attr_processor_flags.attr,
703 NULL
704};
705
706static struct attribute_group mc_attr_group = {
707 .attrs = mc_default_attrs,
708 .name = "microcode",
709};
710
711static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
712{
713 int err, cpu = sys_dev->id;
714 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
715
716 if (!cpu_online(cpu))
717 return 0;
718
719 pr_debug("microcode: CPU%d added\n", cpu);
720 memset(uci, 0, sizeof(*uci));
721
722 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
723 if (err)
724 return err;
725
726 microcode_init_cpu(cpu, resume);
727
728 return 0;
729}
730
731static int mc_sysdev_add(struct sys_device *sys_dev)
732{
733 return __mc_sysdev_add(sys_dev, 0);
734}
735
736static int mc_sysdev_remove(struct sys_device *sys_dev)
737{
738 int cpu = sys_dev->id;
739
740 if (!cpu_online(cpu))
741 return 0;
742
743 pr_debug("microcode: CPU%d removed\n", cpu);
744 microcode_fini_cpu(cpu);
745 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
746 return 0;
747}
748
749static int mc_sysdev_resume(struct sys_device *dev)
750{
751 int cpu = dev->id;
752
753 if (!cpu_online(cpu))
754 return 0;
755 pr_debug("microcode: CPU%d resumed\n", cpu);
756 /* only CPU 0 will apply ucode here */
757 apply_microcode(0);
758 return 0;
759}
760
761static struct sysdev_driver mc_sysdev_driver = {
762 .add = mc_sysdev_add,
763 .remove = mc_sysdev_remove,
764 .resume = mc_sysdev_resume,
765};
766
767static __cpuinit int
768mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
769{
770 unsigned int cpu = (unsigned long)hcpu;
771 struct sys_device *sys_dev;
772
773 sys_dev = get_cpu_sysdev(cpu);
774 switch (action) {
775 case CPU_UP_CANCELED_FROZEN:
776 /* The CPU refused to come up during a system resume */
777 microcode_fini_cpu(cpu);
778 break;
779 case CPU_ONLINE:
780 case CPU_DOWN_FAILED:
781 mc_sysdev_add(sys_dev);
782 break;
783 case CPU_ONLINE_FROZEN:
784 /* System-wide resume is in progress, try to apply microcode */
785 if (apply_microcode_check_cpu(cpu)) {
786 /* The application of microcode failed */
787 microcode_fini_cpu(cpu);
788 __mc_sysdev_add(sys_dev, 1);
789 break;
790 }
791 case CPU_DOWN_FAILED_FROZEN:
792 if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
793 printk(KERN_ERR "microcode: Failed to create the sysfs "
794 "group for CPU%d\n", cpu);
795 break;
796 case CPU_DOWN_PREPARE:
797 mc_sysdev_remove(sys_dev);
798 break;
799 case CPU_DOWN_PREPARE_FROZEN:
800 /* Suspend is in progress, only remove the interface */
801 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
802 break;
803 }
804 return NOTIFY_OK;
805}
806
807static struct notifier_block __refdata mc_cpu_notifier = {
808 .notifier_call = mc_cpu_callback,
809};
810
811static int __init microcode_init (void)
812{
813 int error;
814
815 printk(KERN_INFO
816 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
817
818 error = microcode_dev_init();
819 if (error)
820 return error;
821 microcode_pdev = platform_device_register_simple("microcode", -1,
822 NULL, 0);
823 if (IS_ERR(microcode_pdev)) {
824 microcode_dev_exit();
825 return PTR_ERR(microcode_pdev);
826 }
827
828 get_online_cpus();
829 error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
830 put_online_cpus();
831 if (error) {
832 microcode_dev_exit();
833 platform_device_unregister(microcode_pdev);
834 return error;
835 }
836
837 register_hotcpu_notifier(&mc_cpu_notifier);
838 return 0;
839}
840
841static void __exit microcode_exit (void)
842{
843 microcode_dev_exit();
844
845 unregister_hotcpu_notifier(&mc_cpu_notifier);
846
847 get_online_cpus();
848 sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
849 put_online_cpus();
850
851 platform_device_unregister(microcode_pdev);
852}
853
854module_init(microcode_init)
855module_exit(microcode_exit)