ia64/xen-unstable

view xen/arch/x86/microcode.c @ 18499:3eb7a0cfffc2

x86, microcode: More code cleanups.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Sep 16 13:09:04 2008 +0100 (2008-09-16)
parents 087b8b29b6b2
children 879330497672
line source
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 * This driver allows to upgrade microcode on Intel processors
7 * belonging to IA-32 family - PentiumPro, Pentium II,
8 * Pentium III, Xeon, Pentium 4, etc.
9 *
10 * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
11 * Software Developer's Manual
12 * Order Number 253668 or free download from:
13 *
14 * http://developer.intel.com/design/pentium4/manuals/253668.htm
15 *
16 * For more information, go to http://www.urbanmyth.org/microcode
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version
21 * 2 of the License, or (at your option) any later version.
22 */
24 #include <xen/config.h>
25 #include <xen/lib.h>
26 #include <xen/kernel.h>
27 #include <xen/init.h>
28 #include <xen/sched.h>
29 #include <xen/smp.h>
30 #include <xen/spinlock.h>
31 #include <xen/guest_access.h>
33 #include <asm/current.h>
34 #include <asm/msr.h>
35 #include <asm/uaccess.h>
36 #include <asm/processor.h>
37 #include <asm/microcode.h>
39 const struct microcode_ops *microcode_ops;
41 static DEFINE_SPINLOCK(microcode_mutex);
43 struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
45 struct microcode_buffer {
46 void *buf;
47 size_t size;
48 };
50 static struct microcode_buffer microcode_buffer;
51 static bool_t microcode_error;
53 static void microcode_fini_cpu(int cpu)
54 {
55 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
57 spin_lock(&microcode_mutex);
58 xfree(uci->mc.valid_mc);
59 uci->mc.valid_mc = NULL;
60 uci->valid = 0;
61 spin_unlock(&microcode_mutex);
62 }
64 static int collect_cpu_info(int cpu)
65 {
66 int err = 0;
67 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
69 memset(uci, 0, sizeof(*uci));
70 err = microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
71 if ( !err )
72 uci->valid = 1;
74 return err;
75 }
77 static int microcode_resume_cpu(int cpu)
78 {
79 int err = 0;
80 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
81 struct cpu_signature nsig;
83 gdprintk(XENLOG_INFO, "microcode: CPU%d resumed\n", cpu);
85 if ( !uci->mc.valid_mc )
86 return -EIO;
88 /*
89 * Let's verify that the 'cached' ucode does belong
90 * to this cpu (a bit of paranoia):
91 */
92 err = microcode_ops->collect_cpu_info(cpu, &nsig);
93 if ( err )
94 {
95 microcode_fini_cpu(cpu);
96 return err;
97 }
99 if ( memcmp(&nsig, &uci->cpu_sig, sizeof(nsig)) )
100 {
101 microcode_fini_cpu(cpu);
102 /* Should we look for a new ucode here? */
103 return -EIO;
104 }
106 err = microcode_ops->apply_microcode(cpu);
108 return err;
109 }
111 static int microcode_update_cpu(int cpu, const void *buf, size_t size)
112 {
113 int err = 0;
114 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
116 /* We should bind the task to the CPU */
117 BUG_ON(raw_smp_processor_id() != cpu);
119 spin_lock(&microcode_mutex);
121 /*
122 * Check if the system resume is in progress (uci->valid != NULL),
123 * otherwise just request a firmware:
124 */
125 if ( uci->valid )
126 {
127 err = microcode_resume_cpu(cpu);
128 }
129 else
130 {
131 err = collect_cpu_info(cpu);
132 if ( !err && uci->valid )
133 err = microcode_ops->cpu_request_microcode(cpu, buf, size);
134 }
136 spin_unlock(&microcode_mutex);
138 return err;
139 }
141 static void do_microcode_update_one(void *info)
142 {
143 int error = microcode_update_cpu(
144 smp_processor_id(), microcode_buffer.buf, microcode_buffer.size);
145 if ( error )
146 microcode_error = error;
147 }
149 static int do_microcode_update(void)
150 {
151 microcode_error = 0;
153 if ( on_each_cpu(do_microcode_update_one, NULL, 1, 1) != 0 )
154 {
155 printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
156 return -EIO;
157 }
159 return microcode_error;
160 }
162 int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len)
163 {
164 int ret;
166 /* XXX FIXME: No allocations in interrupt context. */
167 return -EINVAL;
169 if ( len != (typeof(microcode_buffer.size))len )
170 {
171 printk(KERN_ERR "microcode: too much data\n");
172 return -E2BIG;
173 }
175 if ( microcode_ops == NULL )
176 return -EINVAL;
178 microcode_buffer.buf = xmalloc_array(uint8_t, len);
179 if ( microcode_buffer.buf == NULL )
180 return -ENOMEM;
182 ret = copy_from_guest(microcode_buffer.buf, buf, len);
183 if ( ret != 0 )
184 return ret;
186 microcode_buffer.size = len;
187 wmb();
189 ret = do_microcode_update();
191 xfree(microcode_buffer.buf);
192 microcode_buffer.buf = NULL;
193 microcode_buffer.size = 0;
195 return ret;
196 }