Commit 18dbc9160507dc7df998e00cd1dcd7889557307b
Committed by
Ingo Molnar
1 parent
a1c75cc501
Exists in
master
and in
7 other branches
x86: moved microcode.c to microcode_intel.c
Combine both generic and arch-specific parts of microcode into a single module (arch-specific parts are config-dependent). Also while we are at it, move arch-specific parts from microcode.h into their respective arch-specific .c files. Signed-off-by: Dmitry Adamushko <dmitry.adamushko@gmail.com> Cc: "Peter Oruba" <peter.oruba@amd.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Showing 7 changed files with 632 additions and 650 deletions Side-by-side Diff
arch/x86/Kconfig
... | ... | @@ -801,7 +801,7 @@ |
801 | 801 | module will be called microcode. |
802 | 802 | |
803 | 803 | config MICROCODE_INTEL |
804 | - tristate "Intel microcode patch loading support" | |
804 | + bool "Intel microcode patch loading support" | |
805 | 805 | depends on MICROCODE |
806 | 806 | default MICROCODE |
807 | 807 | select FW_LOADER |
808 | 808 | |
809 | 809 | |
... | ... | @@ -813,19 +813,13 @@ |
813 | 813 | Intel ingredients for this driver, check: |
814 | 814 | <http://www.urbanmyth.org/microcode/>. |
815 | 815 | |
816 | - This driver is only available as a module: the module | |
817 | - will be called microcode_intel. | |
818 | - | |
819 | 816 | config MICROCODE_AMD |
820 | - tristate "AMD microcode patch loading support" | |
817 | + bool "AMD microcode patch loading support" | |
821 | 818 | depends on MICROCODE |
822 | 819 | select FW_LOADER |
823 | 820 | --help--- |
824 | 821 | If you select this option, microcode patch loading support for AMD |
825 | 822 | processors will be enabled. |
826 | - | |
827 | - This driver is only available as a module: the module | |
828 | - will be called microcode_amd. | |
829 | 823 | |
830 | 824 | config MICROCODE_OLD_INTERFACE |
831 | 825 | def_bool y |
arch/x86/kernel/Makefile
... | ... | @@ -51,9 +51,6 @@ |
51 | 51 | obj-$(CONFIG_MCA) += mca_32.o |
52 | 52 | obj-$(CONFIG_X86_MSR) += msr.o |
53 | 53 | obj-$(CONFIG_X86_CPUID) += cpuid.o |
54 | -obj-$(CONFIG_MICROCODE) += microcode.o | |
55 | -obj-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o | |
56 | -obj-$(CONFIG_MICROCODE_AMD) += microcode_amd.o | |
57 | 54 | obj-$(CONFIG_PCI) += early-quirks.o |
58 | 55 | apm-y := apm_32.o |
59 | 56 | obj-$(CONFIG_APM) += apm.o |
... | ... | @@ -100,6 +97,11 @@ |
100 | 97 | scx200-y += scx200_32.o |
101 | 98 | |
102 | 99 | obj-$(CONFIG_OLPC) += olpc.o |
100 | + | |
101 | +microcode-y := microcode_core.o | |
102 | +microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o | |
103 | +microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o | |
104 | +obj-$(CONFIG_MICROCODE) += microcode.o | |
103 | 105 | |
104 | 106 | ### |
105 | 107 | # 64 bit specific files |
arch/x86/kernel/microcode.c
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 | |
59 | - * speculative 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 | -#include <linux/capability.h> | |
74 | -#include <linux/kernel.h> | |
75 | -#include <linux/init.h> | |
76 | -#include <linux/sched.h> | |
77 | -#include <linux/smp_lock.h> | |
78 | -#include <linux/cpumask.h> | |
79 | -#include <linux/module.h> | |
80 | -#include <linux/slab.h> | |
81 | -#include <linux/vmalloc.h> | |
82 | -#include <linux/miscdevice.h> | |
83 | -#include <linux/spinlock.h> | |
84 | -#include <linux/mm.h> | |
85 | -#include <linux/fs.h> | |
86 | -#include <linux/mutex.h> | |
87 | -#include <linux/cpu.h> | |
88 | -#include <linux/firmware.h> | |
89 | -#include <linux/platform_device.h> | |
90 | - | |
91 | -#include <asm/msr.h> | |
92 | -#include <asm/uaccess.h> | |
93 | -#include <asm/processor.h> | |
94 | -#include <asm/microcode.h> | |
95 | - | |
96 | -MODULE_DESCRIPTION("Microcode Update Driver"); | |
97 | -MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); | |
98 | -MODULE_LICENSE("GPL"); | |
99 | - | |
100 | -#define MICROCODE_VERSION "2.00" | |
101 | - | |
102 | -struct microcode_ops *microcode_ops; | |
103 | - | |
104 | -/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ | |
105 | -static DEFINE_MUTEX(microcode_mutex); | |
106 | - | |
107 | -struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | |
108 | -EXPORT_SYMBOL_GPL(ucode_cpu_info); | |
109 | - | |
110 | -#ifdef CONFIG_MICROCODE_OLD_INTERFACE | |
111 | -static int do_microcode_update(const void __user *buf, size_t size) | |
112 | -{ | |
113 | - cpumask_t old; | |
114 | - int error = 0; | |
115 | - int cpu; | |
116 | - | |
117 | - old = current->cpus_allowed; | |
118 | - | |
119 | - for_each_online_cpu(cpu) { | |
120 | - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
121 | - | |
122 | - if (!uci->valid) | |
123 | - continue; | |
124 | - | |
125 | - set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | |
126 | - error = microcode_ops->request_microcode_user(cpu, buf, size); | |
127 | - if (error < 0) | |
128 | - goto out; | |
129 | - if (!error) | |
130 | - microcode_ops->apply_microcode(cpu); | |
131 | - } | |
132 | -out: | |
133 | - set_cpus_allowed_ptr(current, &old); | |
134 | - return error; | |
135 | -} | |
136 | - | |
137 | -static int microcode_open(struct inode *unused1, struct file *unused2) | |
138 | -{ | |
139 | - cycle_kernel_lock(); | |
140 | - return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; | |
141 | -} | |
142 | - | |
143 | -static ssize_t microcode_write(struct file *file, const char __user *buf, | |
144 | - size_t len, loff_t *ppos) | |
145 | -{ | |
146 | - ssize_t ret; | |
147 | - | |
148 | - if ((len >> PAGE_SHIFT) > num_physpages) { | |
149 | - printk(KERN_ERR "microcode: too much data (max %ld pages)\n", | |
150 | - num_physpages); | |
151 | - return -EINVAL; | |
152 | - } | |
153 | - | |
154 | - get_online_cpus(); | |
155 | - mutex_lock(µcode_mutex); | |
156 | - | |
157 | - ret = do_microcode_update(buf, len); | |
158 | - if (!ret) | |
159 | - ret = (ssize_t)len; | |
160 | - | |
161 | - mutex_unlock(µcode_mutex); | |
162 | - put_online_cpus(); | |
163 | - | |
164 | - return ret; | |
165 | -} | |
166 | - | |
167 | -static const struct file_operations microcode_fops = { | |
168 | - .owner = THIS_MODULE, | |
169 | - .write = microcode_write, | |
170 | - .open = microcode_open, | |
171 | -}; | |
172 | - | |
173 | -static struct miscdevice microcode_dev = { | |
174 | - .minor = MICROCODE_MINOR, | |
175 | - .name = "microcode", | |
176 | - .fops = µcode_fops, | |
177 | -}; | |
178 | - | |
179 | -static int __init microcode_dev_init(void) | |
180 | -{ | |
181 | - int error; | |
182 | - | |
183 | - error = misc_register(µcode_dev); | |
184 | - if (error) { | |
185 | - printk(KERN_ERR | |
186 | - "microcode: can't misc_register on minor=%d\n", | |
187 | - MICROCODE_MINOR); | |
188 | - return error; | |
189 | - } | |
190 | - | |
191 | - return 0; | |
192 | -} | |
193 | - | |
194 | -static void microcode_dev_exit(void) | |
195 | -{ | |
196 | - misc_deregister(µcode_dev); | |
197 | -} | |
198 | - | |
199 | -MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); | |
200 | -#else | |
201 | -#define microcode_dev_init() 0 | |
202 | -#define microcode_dev_exit() do { } while (0) | |
203 | -#endif | |
204 | - | |
205 | -/* fake device for request_firmware */ | |
206 | -struct platform_device *microcode_pdev; | |
207 | - | |
208 | -static ssize_t reload_store(struct sys_device *dev, | |
209 | - struct sysdev_attribute *attr, | |
210 | - const char *buf, size_t sz) | |
211 | -{ | |
212 | - struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | |
213 | - char *end; | |
214 | - unsigned long val = simple_strtoul(buf, &end, 0); | |
215 | - int err = 0; | |
216 | - int cpu = dev->id; | |
217 | - | |
218 | - if (end == buf) | |
219 | - return -EINVAL; | |
220 | - if (val == 1) { | |
221 | - cpumask_t old = current->cpus_allowed; | |
222 | - | |
223 | - get_online_cpus(); | |
224 | - if (cpu_online(cpu)) { | |
225 | - set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | |
226 | - mutex_lock(µcode_mutex); | |
227 | - if (uci->valid) { | |
228 | - err = microcode_ops->request_microcode_fw(cpu, | |
229 | - µcode_pdev->dev); | |
230 | - if (!err) | |
231 | - microcode_ops->apply_microcode(cpu); | |
232 | - } | |
233 | - mutex_unlock(µcode_mutex); | |
234 | - set_cpus_allowed_ptr(current, &old); | |
235 | - } | |
236 | - put_online_cpus(); | |
237 | - } | |
238 | - if (err) | |
239 | - return err; | |
240 | - return sz; | |
241 | -} | |
242 | - | |
243 | -static ssize_t version_show(struct sys_device *dev, | |
244 | - struct sysdev_attribute *attr, char *buf) | |
245 | -{ | |
246 | - struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | |
247 | - | |
248 | - return sprintf(buf, "0x%x\n", uci->cpu_sig.rev); | |
249 | -} | |
250 | - | |
251 | -static ssize_t pf_show(struct sys_device *dev, | |
252 | - struct sysdev_attribute *attr, char *buf) | |
253 | -{ | |
254 | - struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | |
255 | - | |
256 | - return sprintf(buf, "0x%x\n", uci->cpu_sig.pf); | |
257 | -} | |
258 | - | |
259 | -static SYSDEV_ATTR(reload, 0200, NULL, reload_store); | |
260 | -static SYSDEV_ATTR(version, 0400, version_show, NULL); | |
261 | -static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL); | |
262 | - | |
263 | -static struct attribute *mc_default_attrs[] = { | |
264 | - &attr_reload.attr, | |
265 | - &attr_version.attr, | |
266 | - &attr_processor_flags.attr, | |
267 | - NULL | |
268 | -}; | |
269 | - | |
270 | -static struct attribute_group mc_attr_group = { | |
271 | - .attrs = mc_default_attrs, | |
272 | - .name = "microcode", | |
273 | -}; | |
274 | - | |
275 | -static void microcode_fini_cpu(int cpu) | |
276 | -{ | |
277 | - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
278 | - | |
279 | - mutex_lock(µcode_mutex); | |
280 | - microcode_ops->microcode_fini_cpu(cpu); | |
281 | - uci->valid = 0; | |
282 | - mutex_unlock(µcode_mutex); | |
283 | -} | |
284 | - | |
285 | -static void collect_cpu_info(int cpu) | |
286 | -{ | |
287 | - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
288 | - | |
289 | - memset(uci, 0, sizeof(*uci)); | |
290 | - if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig)) | |
291 | - uci->valid = 1; | |
292 | -} | |
293 | - | |
294 | -static int microcode_resume_cpu(int cpu) | |
295 | -{ | |
296 | - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
297 | - struct cpu_signature nsig; | |
298 | - | |
299 | - pr_debug("microcode: CPU%d resumed\n", cpu); | |
300 | - | |
301 | - if (!uci->mc.valid_mc) | |
302 | - return 1; | |
303 | - | |
304 | - /* | |
305 | - * Let's verify that the 'cached' ucode does belong | |
306 | - * to this cpu (a bit of paranoia): | |
307 | - */ | |
308 | - if (microcode_ops->collect_cpu_info(cpu, &nsig)) { | |
309 | - microcode_fini_cpu(cpu); | |
310 | - return -1; | |
311 | - } | |
312 | - | |
313 | - if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) { | |
314 | - microcode_fini_cpu(cpu); | |
315 | - /* Should we look for a new ucode here? */ | |
316 | - return 1; | |
317 | - } | |
318 | - | |
319 | - return 0; | |
320 | -} | |
321 | - | |
322 | -void microcode_update_cpu(int cpu) | |
323 | -{ | |
324 | - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
325 | - int err = 0; | |
326 | - | |
327 | - /* We should bind the task to the CPU */ | |
328 | - BUG_ON(raw_smp_processor_id() != cpu); | |
329 | - | |
330 | - mutex_lock(µcode_mutex); | |
331 | - /* | |
332 | - * Check if the system resume is in progress (uci->valid != NULL), | |
333 | - * otherwise just request a firmware: | |
334 | - */ | |
335 | - if (uci->valid) { | |
336 | - err = microcode_resume_cpu(cpu); | |
337 | - } else { | |
338 | - collect_cpu_info(cpu); | |
339 | - if (uci->valid && system_state == SYSTEM_RUNNING) | |
340 | - err = microcode_ops->request_microcode_fw(cpu, | |
341 | - µcode_pdev->dev); | |
342 | - } | |
343 | - | |
344 | - if (!err) | |
345 | - microcode_ops->apply_microcode(cpu); | |
346 | - | |
347 | - mutex_unlock(µcode_mutex); | |
348 | -} | |
349 | - | |
350 | -static void microcode_init_cpu(int cpu) | |
351 | -{ | |
352 | - cpumask_t old = current->cpus_allowed; | |
353 | - | |
354 | - set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | |
355 | - microcode_update_cpu(cpu); | |
356 | - set_cpus_allowed_ptr(current, &old); | |
357 | -} | |
358 | - | |
359 | -static int mc_sysdev_add(struct sys_device *sys_dev) | |
360 | -{ | |
361 | - int err, cpu = sys_dev->id; | |
362 | - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
363 | - | |
364 | - if (!cpu_online(cpu)) | |
365 | - return 0; | |
366 | - | |
367 | - pr_debug("microcode: CPU%d added\n", cpu); | |
368 | - memset(uci, 0, sizeof(*uci)); | |
369 | - | |
370 | - err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); | |
371 | - if (err) | |
372 | - return err; | |
373 | - | |
374 | - microcode_init_cpu(cpu); | |
375 | - return 0; | |
376 | -} | |
377 | - | |
378 | -static int mc_sysdev_remove(struct sys_device *sys_dev) | |
379 | -{ | |
380 | - int cpu = sys_dev->id; | |
381 | - | |
382 | - if (!cpu_online(cpu)) | |
383 | - return 0; | |
384 | - | |
385 | - pr_debug("microcode: CPU%d removed\n", cpu); | |
386 | - microcode_fini_cpu(cpu); | |
387 | - sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | |
388 | - return 0; | |
389 | -} | |
390 | - | |
391 | -static int mc_sysdev_resume(struct sys_device *dev) | |
392 | -{ | |
393 | - int cpu = dev->id; | |
394 | - | |
395 | - if (!cpu_online(cpu)) | |
396 | - return 0; | |
397 | - | |
398 | - /* only CPU 0 will apply ucode here */ | |
399 | - microcode_update_cpu(0); | |
400 | - return 0; | |
401 | -} | |
402 | - | |
403 | -static struct sysdev_driver mc_sysdev_driver = { | |
404 | - .add = mc_sysdev_add, | |
405 | - .remove = mc_sysdev_remove, | |
406 | - .resume = mc_sysdev_resume, | |
407 | -}; | |
408 | - | |
409 | -static __cpuinit int | |
410 | -mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |
411 | -{ | |
412 | - unsigned int cpu = (unsigned long)hcpu; | |
413 | - struct sys_device *sys_dev; | |
414 | - | |
415 | - sys_dev = get_cpu_sysdev(cpu); | |
416 | - switch (action) { | |
417 | - case CPU_ONLINE: | |
418 | - case CPU_ONLINE_FROZEN: | |
419 | - microcode_init_cpu(cpu); | |
420 | - case CPU_DOWN_FAILED: | |
421 | - case CPU_DOWN_FAILED_FROZEN: | |
422 | - pr_debug("microcode: CPU%d added\n", cpu); | |
423 | - if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group)) | |
424 | - printk(KERN_ERR "microcode: Failed to create the sysfs " | |
425 | - "group for CPU%d\n", cpu); | |
426 | - break; | |
427 | - case CPU_DOWN_PREPARE: | |
428 | - case CPU_DOWN_PREPARE_FROZEN: | |
429 | - /* Suspend is in progress, only remove the interface */ | |
430 | - sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | |
431 | - pr_debug("microcode: CPU%d removed\n", cpu); | |
432 | - break; | |
433 | - case CPU_DEAD: | |
434 | - case CPU_UP_CANCELED_FROZEN: | |
435 | - /* The CPU refused to come up during a system resume */ | |
436 | - microcode_fini_cpu(cpu); | |
437 | - break; | |
438 | - } | |
439 | - return NOTIFY_OK; | |
440 | -} | |
441 | - | |
442 | -static struct notifier_block __refdata mc_cpu_notifier = { | |
443 | - .notifier_call = mc_cpu_callback, | |
444 | -}; | |
445 | - | |
446 | -int microcode_init(void *opaque, struct module *module) | |
447 | -{ | |
448 | - struct microcode_ops *ops = (struct microcode_ops *)opaque; | |
449 | - int error; | |
450 | - | |
451 | - if (microcode_ops) { | |
452 | - printk(KERN_ERR "microcode: already loaded the other module\n"); | |
453 | - return -EEXIST; | |
454 | - } | |
455 | - | |
456 | - microcode_ops = ops; | |
457 | - | |
458 | - error = microcode_dev_init(); | |
459 | - if (error) | |
460 | - return error; | |
461 | - microcode_pdev = platform_device_register_simple("microcode", -1, | |
462 | - NULL, 0); | |
463 | - if (IS_ERR(microcode_pdev)) { | |
464 | - microcode_dev_exit(); | |
465 | - return PTR_ERR(microcode_pdev); | |
466 | - } | |
467 | - | |
468 | - get_online_cpus(); | |
469 | - error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver); | |
470 | - put_online_cpus(); | |
471 | - if (error) { | |
472 | - microcode_dev_exit(); | |
473 | - platform_device_unregister(microcode_pdev); | |
474 | - return error; | |
475 | - } | |
476 | - | |
477 | - register_hotcpu_notifier(&mc_cpu_notifier); | |
478 | - | |
479 | - printk(KERN_INFO | |
480 | - "Microcode Update Driver: v" MICROCODE_VERSION | |
481 | - " <tigran@aivazian.fsnet.co.uk>" | |
482 | - " <peter.oruba@amd.com>\n"); | |
483 | - | |
484 | - return 0; | |
485 | -} | |
486 | -EXPORT_SYMBOL_GPL(microcode_init); | |
487 | - | |
488 | -void __exit microcode_exit(void) | |
489 | -{ | |
490 | - microcode_dev_exit(); | |
491 | - | |
492 | - unregister_hotcpu_notifier(&mc_cpu_notifier); | |
493 | - | |
494 | - get_online_cpus(); | |
495 | - sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver); | |
496 | - put_online_cpus(); | |
497 | - | |
498 | - platform_device_unregister(microcode_pdev); | |
499 | - | |
500 | - microcode_ops = NULL; | |
501 | - | |
502 | - printk(KERN_INFO | |
503 | - "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n"); | |
504 | -} | |
505 | -EXPORT_SYMBOL_GPL(microcode_exit); |
arch/x86/kernel/microcode_amd.c
... | ... | @@ -46,6 +46,35 @@ |
46 | 46 | #define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000 |
47 | 47 | #define UCODE_UCODE_TYPE 0x00000001 |
48 | 48 | |
49 | +struct equiv_cpu_entry { | |
50 | + unsigned int installed_cpu; | |
51 | + unsigned int fixed_errata_mask; | |
52 | + unsigned int fixed_errata_compare; | |
53 | + unsigned int equiv_cpu; | |
54 | +}; | |
55 | + | |
56 | +struct microcode_header_amd { | |
57 | + unsigned int data_code; | |
58 | + unsigned int patch_id; | |
59 | + unsigned char mc_patch_data_id[2]; | |
60 | + unsigned char mc_patch_data_len; | |
61 | + unsigned char init_flag; | |
62 | + unsigned int mc_patch_data_checksum; | |
63 | + unsigned int nb_dev_id; | |
64 | + unsigned int sb_dev_id; | |
65 | + unsigned char processor_rev_id[2]; | |
66 | + unsigned char nb_rev_id; | |
67 | + unsigned char sb_rev_id; | |
68 | + unsigned char bios_api_rev; | |
69 | + unsigned char reserved1[3]; | |
70 | + unsigned int match_reg[8]; | |
71 | +}; | |
72 | + | |
73 | +struct microcode_amd { | |
74 | + struct microcode_header_amd hdr; | |
75 | + unsigned int mpb[0]; | |
76 | +}; | |
77 | + | |
49 | 78 | #define UCODE_MAX_SIZE (2048) |
50 | 79 | #define DEFAULT_UCODE_DATASIZE (896) |
51 | 80 | #define MC_HEADER_SIZE (sizeof(struct microcode_header_amd)) |
52 | 81 | |
53 | 82 | |
... | ... | @@ -189,17 +218,18 @@ |
189 | 218 | unsigned int rev; |
190 | 219 | int cpu_num = raw_smp_processor_id(); |
191 | 220 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; |
221 | + struct microcode_amd *mc_amd = uci->mc; | |
192 | 222 | unsigned long addr; |
193 | 223 | |
194 | 224 | /* We should bind the task to the CPU */ |
195 | 225 | BUG_ON(cpu_num != cpu); |
196 | 226 | |
197 | - if (uci->mc.mc_amd == NULL) | |
227 | + if (mc_amd == NULL) | |
198 | 228 | return; |
199 | 229 | |
200 | 230 | spin_lock_irqsave(µcode_update_lock, flags); |
201 | 231 | |
202 | - addr = (unsigned long)&uci->mc.mc_amd->hdr.data_code; | |
232 | + addr = (unsigned long)&mc_amd->hdr.data_code; | |
203 | 233 | edx = (unsigned int)(((unsigned long)upper_32_bits(addr))); |
204 | 234 | eax = (unsigned int)(((unsigned long)lower_32_bits(addr))); |
205 | 235 | |
206 | 236 | |
207 | 237 | |
... | ... | @@ -214,16 +244,16 @@ |
214 | 244 | spin_unlock_irqrestore(µcode_update_lock, flags); |
215 | 245 | |
216 | 246 | /* check current patch id and patch's id for match */ |
217 | - if (rev != uci->mc.mc_amd->hdr.patch_id) { | |
247 | + if (rev != mc_amd->hdr.patch_id) { | |
218 | 248 | printk(KERN_ERR "microcode: CPU%d update from revision " |
219 | 249 | "0x%x to 0x%x failed\n", cpu_num, |
220 | - uci->mc.mc_amd->hdr.patch_id, rev); | |
250 | + mc_amd->hdr.patch_id, rev); | |
221 | 251 | return; |
222 | 252 | } |
223 | 253 | |
224 | 254 | printk(KERN_INFO "microcode: CPU%d updated from revision " |
225 | 255 | "0x%x to 0x%x \n", |
226 | - cpu_num, uci->cpu_sig.rev, uci->mc.mc_amd->hdr.patch_id); | |
256 | + cpu_num, uci->cpu_sig.rev, mc_amd->hdr.patch_id); | |
227 | 257 | |
228 | 258 | uci->cpu_sig.rev = rev; |
229 | 259 | } |
230 | 260 | |
... | ... | @@ -355,12 +385,12 @@ |
355 | 385 | |
356 | 386 | if (new_mc) { |
357 | 387 | if (!leftover) { |
358 | - if (uci->mc.mc_amd) | |
359 | - vfree(uci->mc.mc_amd); | |
360 | - uci->mc.mc_amd = (struct microcode_amd *)new_mc; | |
388 | + if (uci->mc) | |
389 | + vfree(uci->mc); | |
390 | + uci->mc = new_mc; | |
361 | 391 | pr_debug("microcode: CPU%d found a matching microcode update with" |
362 | 392 | " version 0x%x (current=0x%x)\n", |
363 | - cpu, uci->mc.mc_amd->hdr.patch_id, uci->cpu_sig.rev); | |
393 | + cpu, new_rev, uci->cpu_sig.rev); | |
364 | 394 | } else |
365 | 395 | vfree(new_mc); |
366 | 396 | } |
... | ... | @@ -416,8 +446,8 @@ |
416 | 446 | { |
417 | 447 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
418 | 448 | |
419 | - vfree(uci->mc.mc_amd); | |
420 | - uci->mc.mc_amd = NULL; | |
449 | + vfree(uci->mc); | |
450 | + uci->mc = NULL; | |
421 | 451 | } |
422 | 452 | |
423 | 453 | static struct microcode_ops microcode_amd_ops = { |
424 | 454 | |
425 | 455 | |
... | ... | @@ -428,24 +458,8 @@ |
428 | 458 | .microcode_fini_cpu = microcode_fini_cpu_amd, |
429 | 459 | }; |
430 | 460 | |
431 | -static int __init microcode_amd_module_init(void) | |
461 | +struct microcode_ops * __init init_amd_microcode(void) | |
432 | 462 | { |
433 | - struct cpuinfo_x86 *c = &cpu_data(0); | |
434 | - | |
435 | - equiv_cpu_table = NULL; | |
436 | - if (c->x86_vendor != X86_VENDOR_AMD) { | |
437 | - printk(KERN_ERR "microcode: CPU platform is not AMD-capable\n"); | |
438 | - return -ENODEV; | |
439 | - } | |
440 | - | |
441 | - return microcode_init(µcode_amd_ops, THIS_MODULE); | |
463 | + return µcode_amd_ops; | |
442 | 464 | } |
443 | - | |
444 | -static void __exit microcode_amd_module_exit(void) | |
445 | -{ | |
446 | - microcode_exit(); | |
447 | -} | |
448 | - | |
449 | -module_init(microcode_amd_module_init) | |
450 | -module_exit(microcode_amd_module_exit) |
arch/x86/kernel/microcode_core.c
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 | |
59 | + * speculative 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 | +#include <linux/capability.h> | |
74 | +#include <linux/kernel.h> | |
75 | +#include <linux/init.h> | |
76 | +#include <linux/sched.h> | |
77 | +#include <linux/smp_lock.h> | |
78 | +#include <linux/cpumask.h> | |
79 | +#include <linux/module.h> | |
80 | +#include <linux/slab.h> | |
81 | +#include <linux/vmalloc.h> | |
82 | +#include <linux/miscdevice.h> | |
83 | +#include <linux/spinlock.h> | |
84 | +#include <linux/mm.h> | |
85 | +#include <linux/fs.h> | |
86 | +#include <linux/mutex.h> | |
87 | +#include <linux/cpu.h> | |
88 | +#include <linux/firmware.h> | |
89 | +#include <linux/platform_device.h> | |
90 | + | |
91 | +#include <asm/msr.h> | |
92 | +#include <asm/uaccess.h> | |
93 | +#include <asm/processor.h> | |
94 | +#include <asm/microcode.h> | |
95 | + | |
96 | +MODULE_DESCRIPTION("Microcode Update Driver"); | |
97 | +MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); | |
98 | +MODULE_LICENSE("GPL"); | |
99 | + | |
100 | +#define MICROCODE_VERSION "2.00" | |
101 | + | |
102 | +struct microcode_ops *microcode_ops; | |
103 | + | |
104 | +/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ | |
105 | +static DEFINE_MUTEX(microcode_mutex); | |
106 | + | |
107 | +struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | |
108 | +EXPORT_SYMBOL_GPL(ucode_cpu_info); | |
109 | + | |
110 | +#ifdef CONFIG_MICROCODE_OLD_INTERFACE | |
111 | +static int do_microcode_update(const void __user *buf, size_t size) | |
112 | +{ | |
113 | + cpumask_t old; | |
114 | + int error = 0; | |
115 | + int cpu; | |
116 | + | |
117 | + old = current->cpus_allowed; | |
118 | + | |
119 | + for_each_online_cpu(cpu) { | |
120 | + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
121 | + | |
122 | + if (!uci->valid) | |
123 | + continue; | |
124 | + | |
125 | + set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | |
126 | + error = microcode_ops->request_microcode_user(cpu, buf, size); | |
127 | + if (error < 0) | |
128 | + goto out; | |
129 | + if (!error) | |
130 | + microcode_ops->apply_microcode(cpu); | |
131 | + } | |
132 | +out: | |
133 | + set_cpus_allowed_ptr(current, &old); | |
134 | + return error; | |
135 | +} | |
136 | + | |
137 | +static int microcode_open(struct inode *unused1, struct file *unused2) | |
138 | +{ | |
139 | + cycle_kernel_lock(); | |
140 | + return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; | |
141 | +} | |
142 | + | |
143 | +static ssize_t microcode_write(struct file *file, const char __user *buf, | |
144 | + size_t len, loff_t *ppos) | |
145 | +{ | |
146 | + ssize_t ret; | |
147 | + | |
148 | + if ((len >> PAGE_SHIFT) > num_physpages) { | |
149 | + printk(KERN_ERR "microcode: too much data (max %ld pages)\n", | |
150 | + num_physpages); | |
151 | + return -EINVAL; | |
152 | + } | |
153 | + | |
154 | + get_online_cpus(); | |
155 | + mutex_lock(µcode_mutex); | |
156 | + | |
157 | + ret = do_microcode_update(buf, len); | |
158 | + if (!ret) | |
159 | + ret = (ssize_t)len; | |
160 | + | |
161 | + mutex_unlock(µcode_mutex); | |
162 | + put_online_cpus(); | |
163 | + | |
164 | + return ret; | |
165 | +} | |
166 | + | |
167 | +static const struct file_operations microcode_fops = { | |
168 | + .owner = THIS_MODULE, | |
169 | + .write = microcode_write, | |
170 | + .open = microcode_open, | |
171 | +}; | |
172 | + | |
173 | +static struct miscdevice microcode_dev = { | |
174 | + .minor = MICROCODE_MINOR, | |
175 | + .name = "microcode", | |
176 | + .fops = µcode_fops, | |
177 | +}; | |
178 | + | |
179 | +static int __init microcode_dev_init(void) | |
180 | +{ | |
181 | + int error; | |
182 | + | |
183 | + error = misc_register(µcode_dev); | |
184 | + if (error) { | |
185 | + printk(KERN_ERR | |
186 | + "microcode: can't misc_register on minor=%d\n", | |
187 | + MICROCODE_MINOR); | |
188 | + return error; | |
189 | + } | |
190 | + | |
191 | + return 0; | |
192 | +} | |
193 | + | |
194 | +static void microcode_dev_exit(void) | |
195 | +{ | |
196 | + misc_deregister(µcode_dev); | |
197 | +} | |
198 | + | |
199 | +MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); | |
200 | +#else | |
201 | +#define microcode_dev_init() 0 | |
202 | +#define microcode_dev_exit() do { } while (0) | |
203 | +#endif | |
204 | + | |
205 | +/* fake device for request_firmware */ | |
206 | +struct platform_device *microcode_pdev; | |
207 | + | |
208 | +static ssize_t reload_store(struct sys_device *dev, | |
209 | + struct sysdev_attribute *attr, | |
210 | + const char *buf, size_t sz) | |
211 | +{ | |
212 | + struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | |
213 | + char *end; | |
214 | + unsigned long val = simple_strtoul(buf, &end, 0); | |
215 | + int err = 0; | |
216 | + int cpu = dev->id; | |
217 | + | |
218 | + if (end == buf) | |
219 | + return -EINVAL; | |
220 | + if (val == 1) { | |
221 | + cpumask_t old = current->cpus_allowed; | |
222 | + | |
223 | + get_online_cpus(); | |
224 | + if (cpu_online(cpu)) { | |
225 | + set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | |
226 | + mutex_lock(µcode_mutex); | |
227 | + if (uci->valid) { | |
228 | + err = microcode_ops->request_microcode_fw(cpu, | |
229 | + µcode_pdev->dev); | |
230 | + if (!err) | |
231 | + microcode_ops->apply_microcode(cpu); | |
232 | + } | |
233 | + mutex_unlock(µcode_mutex); | |
234 | + set_cpus_allowed_ptr(current, &old); | |
235 | + } | |
236 | + put_online_cpus(); | |
237 | + } | |
238 | + if (err) | |
239 | + return err; | |
240 | + return sz; | |
241 | +} | |
242 | + | |
243 | +static ssize_t version_show(struct sys_device *dev, | |
244 | + struct sysdev_attribute *attr, char *buf) | |
245 | +{ | |
246 | + struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | |
247 | + | |
248 | + return sprintf(buf, "0x%x\n", uci->cpu_sig.rev); | |
249 | +} | |
250 | + | |
251 | +static ssize_t pf_show(struct sys_device *dev, | |
252 | + struct sysdev_attribute *attr, char *buf) | |
253 | +{ | |
254 | + struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; | |
255 | + | |
256 | + return sprintf(buf, "0x%x\n", uci->cpu_sig.pf); | |
257 | +} | |
258 | + | |
259 | +static SYSDEV_ATTR(reload, 0200, NULL, reload_store); | |
260 | +static SYSDEV_ATTR(version, 0400, version_show, NULL); | |
261 | +static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL); | |
262 | + | |
263 | +static struct attribute *mc_default_attrs[] = { | |
264 | + &attr_reload.attr, | |
265 | + &attr_version.attr, | |
266 | + &attr_processor_flags.attr, | |
267 | + NULL | |
268 | +}; | |
269 | + | |
270 | +static struct attribute_group mc_attr_group = { | |
271 | + .attrs = mc_default_attrs, | |
272 | + .name = "microcode", | |
273 | +}; | |
274 | + | |
275 | +static void microcode_fini_cpu(int cpu) | |
276 | +{ | |
277 | + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
278 | + | |
279 | + mutex_lock(µcode_mutex); | |
280 | + microcode_ops->microcode_fini_cpu(cpu); | |
281 | + uci->valid = 0; | |
282 | + mutex_unlock(µcode_mutex); | |
283 | +} | |
284 | + | |
285 | +static void collect_cpu_info(int cpu) | |
286 | +{ | |
287 | + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
288 | + | |
289 | + memset(uci, 0, sizeof(*uci)); | |
290 | + if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig)) | |
291 | + uci->valid = 1; | |
292 | +} | |
293 | + | |
294 | +static int microcode_resume_cpu(int cpu) | |
295 | +{ | |
296 | + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
297 | + struct cpu_signature nsig; | |
298 | + | |
299 | + pr_debug("microcode: CPU%d resumed\n", cpu); | |
300 | + | |
301 | + if (!uci->mc) | |
302 | + return 1; | |
303 | + | |
304 | + /* | |
305 | + * Let's verify that the 'cached' ucode does belong | |
306 | + * to this cpu (a bit of paranoia): | |
307 | + */ | |
308 | + if (microcode_ops->collect_cpu_info(cpu, &nsig)) { | |
309 | + microcode_fini_cpu(cpu); | |
310 | + return -1; | |
311 | + } | |
312 | + | |
313 | + if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) { | |
314 | + microcode_fini_cpu(cpu); | |
315 | + /* Should we look for a new ucode here? */ | |
316 | + return 1; | |
317 | + } | |
318 | + | |
319 | + return 0; | |
320 | +} | |
321 | + | |
322 | +void microcode_update_cpu(int cpu) | |
323 | +{ | |
324 | + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
325 | + int err = 0; | |
326 | + | |
327 | + /* We should bind the task to the CPU */ | |
328 | + BUG_ON(raw_smp_processor_id() != cpu); | |
329 | + | |
330 | + mutex_lock(µcode_mutex); | |
331 | + /* | |
332 | + * Check if the system resume is in progress (uci->valid != NULL), | |
333 | + * otherwise just request a firmware: | |
334 | + */ | |
335 | + if (uci->valid) { | |
336 | + err = microcode_resume_cpu(cpu); | |
337 | + } else { | |
338 | + collect_cpu_info(cpu); | |
339 | + if (uci->valid && system_state == SYSTEM_RUNNING) | |
340 | + err = microcode_ops->request_microcode_fw(cpu, | |
341 | + µcode_pdev->dev); | |
342 | + } | |
343 | + | |
344 | + if (!err) | |
345 | + microcode_ops->apply_microcode(cpu); | |
346 | + | |
347 | + mutex_unlock(µcode_mutex); | |
348 | +} | |
349 | + | |
350 | +static void microcode_init_cpu(int cpu) | |
351 | +{ | |
352 | + cpumask_t old = current->cpus_allowed; | |
353 | + | |
354 | + set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | |
355 | + microcode_update_cpu(cpu); | |
356 | + set_cpus_allowed_ptr(current, &old); | |
357 | +} | |
358 | + | |
359 | +static int mc_sysdev_add(struct sys_device *sys_dev) | |
360 | +{ | |
361 | + int err, cpu = sys_dev->id; | |
362 | + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
363 | + | |
364 | + if (!cpu_online(cpu)) | |
365 | + return 0; | |
366 | + | |
367 | + pr_debug("microcode: CPU%d added\n", cpu); | |
368 | + memset(uci, 0, sizeof(*uci)); | |
369 | + | |
370 | + err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); | |
371 | + if (err) | |
372 | + return err; | |
373 | + | |
374 | + microcode_init_cpu(cpu); | |
375 | + return 0; | |
376 | +} | |
377 | + | |
378 | +static int mc_sysdev_remove(struct sys_device *sys_dev) | |
379 | +{ | |
380 | + int cpu = sys_dev->id; | |
381 | + | |
382 | + if (!cpu_online(cpu)) | |
383 | + return 0; | |
384 | + | |
385 | + pr_debug("microcode: CPU%d removed\n", cpu); | |
386 | + microcode_fini_cpu(cpu); | |
387 | + sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | |
388 | + return 0; | |
389 | +} | |
390 | + | |
391 | +static int mc_sysdev_resume(struct sys_device *dev) | |
392 | +{ | |
393 | + int cpu = dev->id; | |
394 | + | |
395 | + if (!cpu_online(cpu)) | |
396 | + return 0; | |
397 | + | |
398 | + /* only CPU 0 will apply ucode here */ | |
399 | + microcode_update_cpu(0); | |
400 | + return 0; | |
401 | +} | |
402 | + | |
403 | +static struct sysdev_driver mc_sysdev_driver = { | |
404 | + .add = mc_sysdev_add, | |
405 | + .remove = mc_sysdev_remove, | |
406 | + .resume = mc_sysdev_resume, | |
407 | +}; | |
408 | + | |
409 | +static __cpuinit int | |
410 | +mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |
411 | +{ | |
412 | + unsigned int cpu = (unsigned long)hcpu; | |
413 | + struct sys_device *sys_dev; | |
414 | + | |
415 | + sys_dev = get_cpu_sysdev(cpu); | |
416 | + switch (action) { | |
417 | + case CPU_ONLINE: | |
418 | + case CPU_ONLINE_FROZEN: | |
419 | + microcode_init_cpu(cpu); | |
420 | + case CPU_DOWN_FAILED: | |
421 | + case CPU_DOWN_FAILED_FROZEN: | |
422 | + pr_debug("microcode: CPU%d added\n", cpu); | |
423 | + if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group)) | |
424 | + printk(KERN_ERR "microcode: Failed to create the sysfs " | |
425 | + "group for CPU%d\n", cpu); | |
426 | + break; | |
427 | + case CPU_DOWN_PREPARE: | |
428 | + case CPU_DOWN_PREPARE_FROZEN: | |
429 | + /* Suspend is in progress, only remove the interface */ | |
430 | + sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | |
431 | + pr_debug("microcode: CPU%d removed\n", cpu); | |
432 | + break; | |
433 | + case CPU_DEAD: | |
434 | + case CPU_UP_CANCELED_FROZEN: | |
435 | + /* The CPU refused to come up during a system resume */ | |
436 | + microcode_fini_cpu(cpu); | |
437 | + break; | |
438 | + } | |
439 | + return NOTIFY_OK; | |
440 | +} | |
441 | + | |
442 | +static struct notifier_block __refdata mc_cpu_notifier = { | |
443 | + .notifier_call = mc_cpu_callback, | |
444 | +}; | |
445 | + | |
446 | +static int __init microcode_init(void) | |
447 | +{ | |
448 | + struct cpuinfo_x86 *c = &cpu_data(0); | |
449 | + int error; | |
450 | + | |
451 | + if (c->x86_vendor == X86_VENDOR_INTEL) | |
452 | + microcode_ops = init_intel_microcode(); | |
453 | + else if (c->x86_vendor != X86_VENDOR_AMD) | |
454 | + microcode_ops = init_amd_microcode(); | |
455 | + | |
456 | + if (!microcode_ops) { | |
457 | + printk(KERN_ERR "microcode: no support for this CPU vendor\n"); | |
458 | + return -ENODEV; | |
459 | + } | |
460 | + | |
461 | + error = microcode_dev_init(); | |
462 | + if (error) | |
463 | + return error; | |
464 | + microcode_pdev = platform_device_register_simple("microcode", -1, | |
465 | + NULL, 0); | |
466 | + if (IS_ERR(microcode_pdev)) { | |
467 | + microcode_dev_exit(); | |
468 | + return PTR_ERR(microcode_pdev); | |
469 | + } | |
470 | + | |
471 | + get_online_cpus(); | |
472 | + error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver); | |
473 | + put_online_cpus(); | |
474 | + if (error) { | |
475 | + microcode_dev_exit(); | |
476 | + platform_device_unregister(microcode_pdev); | |
477 | + return error; | |
478 | + } | |
479 | + | |
480 | + register_hotcpu_notifier(&mc_cpu_notifier); | |
481 | + | |
482 | + printk(KERN_INFO | |
483 | + "Microcode Update Driver: v" MICROCODE_VERSION | |
484 | + " <tigran@aivazian.fsnet.co.uk>" | |
485 | + " <peter.oruba@amd.com>\n"); | |
486 | + | |
487 | + return 0; | |
488 | +} | |
489 | + | |
490 | +static void __exit microcode_exit(void) | |
491 | +{ | |
492 | + microcode_dev_exit(); | |
493 | + | |
494 | + unregister_hotcpu_notifier(&mc_cpu_notifier); | |
495 | + | |
496 | + get_online_cpus(); | |
497 | + sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver); | |
498 | + put_online_cpus(); | |
499 | + | |
500 | + platform_device_unregister(microcode_pdev); | |
501 | + | |
502 | + microcode_ops = NULL; | |
503 | + | |
504 | + printk(KERN_INFO | |
505 | + "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n"); | |
506 | +} | |
507 | + | |
508 | +module_init(microcode_init); | |
509 | +module_exit(microcode_exit); |
arch/x86/kernel/microcode_intel.c
... | ... | @@ -97,6 +97,38 @@ |
97 | 97 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); |
98 | 98 | MODULE_LICENSE("GPL"); |
99 | 99 | |
100 | +struct microcode_header_intel { | |
101 | + unsigned int hdrver; | |
102 | + unsigned int rev; | |
103 | + unsigned int date; | |
104 | + unsigned int sig; | |
105 | + unsigned int cksum; | |
106 | + unsigned int ldrver; | |
107 | + unsigned int pf; | |
108 | + unsigned int datasize; | |
109 | + unsigned int totalsize; | |
110 | + unsigned int reserved[3]; | |
111 | +}; | |
112 | + | |
113 | +struct microcode_intel { | |
114 | + struct microcode_header_intel hdr; | |
115 | + unsigned int bits[0]; | |
116 | +}; | |
117 | + | |
118 | +/* microcode format is extended from prescott processors */ | |
119 | +struct extended_signature { | |
120 | + unsigned int sig; | |
121 | + unsigned int pf; | |
122 | + unsigned int cksum; | |
123 | +}; | |
124 | + | |
125 | +struct extended_sigtable { | |
126 | + unsigned int count; | |
127 | + unsigned int cksum; | |
128 | + unsigned int reserved[3]; | |
129 | + struct extended_signature sigs[0]; | |
130 | +}; | |
131 | + | |
100 | 132 | #define DEFAULT_UCODE_DATASIZE (2000) |
101 | 133 | #define MC_HEADER_SIZE (sizeof(struct microcode_header_intel)) |
102 | 134 | #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) |
103 | 135 | |
... | ... | @@ -284,11 +316,12 @@ |
284 | 316 | unsigned int val[2]; |
285 | 317 | int cpu_num = raw_smp_processor_id(); |
286 | 318 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
319 | + struct microcode_intel *mc_intel = uci->mc; | |
287 | 320 | |
288 | 321 | /* We should bind the task to the CPU */ |
289 | 322 | BUG_ON(cpu_num != cpu); |
290 | 323 | |
291 | - if (uci->mc.mc_intel == NULL) | |
324 | + if (mc_intel == NULL) | |
292 | 325 | return; |
293 | 326 | |
294 | 327 | /* serialize access to the physical write to MSR 0x79 */ |
... | ... | @@ -296,8 +329,8 @@ |
296 | 329 | |
297 | 330 | /* write microcode via MSR 0x79 */ |
298 | 331 | wrmsr(MSR_IA32_UCODE_WRITE, |
299 | - (unsigned long) uci->mc.mc_intel->bits, | |
300 | - (unsigned long) uci->mc.mc_intel->bits >> 16 >> 16); | |
332 | + (unsigned long) mc_intel->bits, | |
333 | + (unsigned long) mc_intel->bits >> 16 >> 16); | |
301 | 334 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); |
302 | 335 | |
303 | 336 | /* see notes above for revision 1.07. Apparent chip bug */ |
... | ... | @@ -307,7 +340,7 @@ |
307 | 340 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); |
308 | 341 | |
309 | 342 | spin_unlock_irqrestore(µcode_update_lock, flags); |
310 | - if (val[1] != uci->mc.mc_intel->hdr.rev) { | |
343 | + if (val[1] != mc_intel->hdr.rev) { | |
311 | 344 | printk(KERN_ERR "microcode: CPU%d update from revision " |
312 | 345 | "0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]); |
313 | 346 | return; |
... | ... | @@ -315,9 +348,9 @@ |
315 | 348 | printk(KERN_INFO "microcode: CPU%d updated from revision " |
316 | 349 | "0x%x to 0x%x, date = %04x-%02x-%02x \n", |
317 | 350 | cpu_num, uci->cpu_sig.rev, val[1], |
318 | - uci->mc.mc_intel->hdr.date & 0xffff, | |
319 | - uci->mc.mc_intel->hdr.date >> 24, | |
320 | - (uci->mc.mc_intel->hdr.date >> 16) & 0xff); | |
351 | + mc_intel->hdr.date & 0xffff, | |
352 | + mc_intel->hdr.date >> 24, | |
353 | + (mc_intel->hdr.date >> 16) & 0xff); | |
321 | 354 | uci->cpu_sig.rev = val[1]; |
322 | 355 | } |
323 | 356 | |
324 | 357 | |
... | ... | @@ -367,12 +400,12 @@ |
367 | 400 | |
368 | 401 | if (new_mc) { |
369 | 402 | if (!leftover) { |
370 | - if (uci->mc.mc_intel) | |
371 | - vfree(uci->mc.mc_intel); | |
372 | - uci->mc.mc_intel = (struct microcode_intel *)new_mc; | |
403 | + if (uci->mc) | |
404 | + vfree(uci->mc); | |
405 | + uci->mc = (struct microcode_intel *)new_mc; | |
373 | 406 | pr_debug("microcode: CPU%d found a matching microcode update with" |
374 | 407 | " version 0x%x (current=0x%x)\n", |
375 | - cpu, uci->mc.mc_intel->hdr.rev, uci->cpu_sig.rev); | |
408 | + cpu, new_rev, uci->cpu_sig.rev); | |
376 | 409 | } else |
377 | 410 | vfree(new_mc); |
378 | 411 | } |
379 | 412 | |
... | ... | @@ -428,11 +461,11 @@ |
428 | 461 | { |
429 | 462 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
430 | 463 | |
431 | - vfree(uci->mc.mc_intel); | |
432 | - uci->mc.mc_intel = NULL; | |
464 | + vfree(uci->mc); | |
465 | + uci->mc = NULL; | |
433 | 466 | } |
434 | 467 | |
435 | -static struct microcode_ops microcode_intel_ops = { | |
468 | +struct microcode_ops microcode_intel_ops = { | |
436 | 469 | .request_microcode_user = request_microcode_user, |
437 | 470 | .request_microcode_fw = request_microcode_fw, |
438 | 471 | .collect_cpu_info = collect_cpu_info, |
439 | 472 | |
440 | 473 | |
... | ... | @@ -440,23 +473,8 @@ |
440 | 473 | .microcode_fini_cpu = microcode_fini_cpu, |
441 | 474 | }; |
442 | 475 | |
443 | -static int __init microcode_intel_module_init(void) | |
476 | +struct microcode_ops * __init init_intel_microcode(void) | |
444 | 477 | { |
445 | - struct cpuinfo_x86 *c = &cpu_data(0); | |
446 | - | |
447 | - if (c->x86_vendor != X86_VENDOR_INTEL) { | |
448 | - printk(KERN_ERR "microcode: CPU platform is not Intel-capable\n"); | |
449 | - return -ENODEV; | |
450 | - } | |
451 | - | |
452 | - return microcode_init(µcode_intel_ops, THIS_MODULE); | |
478 | + return µcode_intel_ops; | |
453 | 479 | } |
454 | - | |
455 | -static void __exit microcode_intel_module_exit(void) | |
456 | -{ | |
457 | - microcode_exit(); | |
458 | -} | |
459 | - | |
460 | -module_init(microcode_intel_module_init) | |
461 | -module_exit(microcode_intel_module_exit) |
include/asm-x86/microcode.h
1 | 1 | #ifndef ASM_X86__MICROCODE_H |
2 | 2 | #define ASM_X86__MICROCODE_H |
3 | 3 | |
4 | -extern int microcode_init(void *opaque, struct module *module); | |
5 | -extern void microcode_exit(void); | |
4 | +struct cpu_signature { | |
5 | + unsigned int sig; | |
6 | + unsigned int pf; | |
7 | + unsigned int rev; | |
8 | +}; | |
6 | 9 | |
7 | -struct cpu_signature; | |
8 | 10 | struct device; |
9 | 11 | |
10 | 12 | struct microcode_ops { |
11 | 13 | |
12 | 14 | |
... | ... | @@ -17,83 +19,30 @@ |
17 | 19 | void (*microcode_fini_cpu) (int cpu); |
18 | 20 | }; |
19 | 21 | |
20 | -struct microcode_header_intel { | |
21 | - unsigned int hdrver; | |
22 | - unsigned int rev; | |
23 | - unsigned int date; | |
24 | - unsigned int sig; | |
25 | - unsigned int cksum; | |
26 | - unsigned int ldrver; | |
27 | - unsigned int pf; | |
28 | - unsigned int datasize; | |
29 | - unsigned int totalsize; | |
30 | - unsigned int reserved[3]; | |
31 | -}; | |
32 | - | |
33 | -struct microcode_intel { | |
34 | - struct microcode_header_intel hdr; | |
35 | - unsigned int bits[0]; | |
36 | -}; | |
37 | - | |
38 | -/* microcode format is extended from prescott processors */ | |
39 | -struct extended_signature { | |
40 | - unsigned int sig; | |
41 | - unsigned int pf; | |
42 | - unsigned int cksum; | |
43 | -}; | |
44 | - | |
45 | -struct extended_sigtable { | |
46 | - unsigned int count; | |
47 | - unsigned int cksum; | |
48 | - unsigned int reserved[3]; | |
49 | - struct extended_signature sigs[0]; | |
50 | -}; | |
51 | - | |
52 | -struct equiv_cpu_entry { | |
53 | - unsigned int installed_cpu; | |
54 | - unsigned int fixed_errata_mask; | |
55 | - unsigned int fixed_errata_compare; | |
56 | - unsigned int equiv_cpu; | |
57 | -}; | |
58 | - | |
59 | -struct microcode_header_amd { | |
60 | - unsigned int data_code; | |
61 | - unsigned int patch_id; | |
62 | - unsigned char mc_patch_data_id[2]; | |
63 | - unsigned char mc_patch_data_len; | |
64 | - unsigned char init_flag; | |
65 | - unsigned int mc_patch_data_checksum; | |
66 | - unsigned int nb_dev_id; | |
67 | - unsigned int sb_dev_id; | |
68 | - unsigned char processor_rev_id[2]; | |
69 | - unsigned char nb_rev_id; | |
70 | - unsigned char sb_rev_id; | |
71 | - unsigned char bios_api_rev; | |
72 | - unsigned char reserved1[3]; | |
73 | - unsigned int match_reg[8]; | |
74 | -}; | |
75 | - | |
76 | -struct microcode_amd { | |
77 | - struct microcode_header_amd hdr; | |
78 | - unsigned int mpb[0]; | |
79 | -}; | |
80 | - | |
81 | -struct cpu_signature { | |
82 | - unsigned int sig; | |
83 | - unsigned int pf; | |
84 | - unsigned int rev; | |
85 | -}; | |
86 | - | |
87 | 22 | struct ucode_cpu_info { |
88 | 23 | struct cpu_signature cpu_sig; |
89 | 24 | int valid; |
90 | - union { | |
91 | - struct microcode_intel *mc_intel; | |
92 | - struct microcode_amd *mc_amd; | |
93 | - void *valid_mc; | |
94 | - } mc; | |
25 | + void *mc; | |
95 | 26 | }; |
96 | 27 | extern struct ucode_cpu_info ucode_cpu_info[]; |
28 | + | |
29 | +#ifdef CONFIG_MICROCODE_INTEL | |
30 | +extern struct microcode_ops * __init init_intel_microcode(void); | |
31 | +#else | |
32 | +static inline struct microcode_ops * __init init_intel_microcode(void) | |
33 | +{ | |
34 | + return NULL; | |
35 | +} | |
36 | +#endif /* CONFIG_MICROCODE_INTEL */ | |
37 | + | |
38 | +#ifdef CONFIG_MICROCODE_AMD | |
39 | +extern struct microcode_ops * __init init_amd_microcode(void); | |
40 | +#else | |
41 | +static inline struct microcode_ops * __init init_amd_microcode(void) | |
42 | +{ | |
43 | + return NULL; | |
44 | +} | |
45 | +#endif | |
97 | 46 | |
98 | 47 | #endif /* ASM_X86__MICROCODE_H */ |