ia64/xen-unstable

view xen/arch/x86/microcode_amd.c @ 19835:edfdeb150f27

Fix buildsystem to detect udev > version 124

udev removed the udevinfo symlink from versions higher than 123 and
xen's build-system could not detect if udev is in place and has the
required version.

Signed-off-by: Marc-A. Dahlhaus <mad@wol.de>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 25 13:02:37 2009 +0100 (2009-06-25)
parents 9f9ba1a7cc92
children
line source
1 /*
2 * AMD CPU Microcode Update Driver for Linux
3 * Copyright (C) 2008 Advanced Micro Devices Inc.
4 *
5 * Author: Peter Oruba <peter.oruba@amd.com>
6 *
7 * Based on work by:
8 * Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
9 *
10 * This driver allows to upgrade microcode on AMD
11 * family 0x10 and 0x11 processors.
12 *
13 * Licensed unter the terms of the GNU General Public
14 * License version 2. See file COPYING for details.
15 */
17 #include <xen/config.h>
18 #include <xen/lib.h>
19 #include <xen/kernel.h>
20 #include <xen/init.h>
21 #include <xen/sched.h>
22 #include <xen/smp.h>
23 #include <xen/spinlock.h>
25 #include <asm/msr.h>
26 #include <asm/uaccess.h>
27 #include <asm/processor.h>
28 #include <asm/microcode.h>
30 #define pr_debug(x...) ((void)0)
32 #define UCODE_MAGIC 0x00414d44
33 #define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
34 #define UCODE_UCODE_TYPE 0x00000001
36 #define UCODE_MAX_SIZE (2048)
37 #define DEFAULT_UCODE_DATASIZE (896)
38 #define MC_HEADER_SIZE (sizeof(struct microcode_header_amd))
39 #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
40 #define DWSIZE (sizeof(uint32_t))
42 /* serialize access to the physical write */
43 static DEFINE_SPINLOCK(microcode_update_lock);
45 struct equiv_cpu_entry *equiv_cpu_table;
47 static int collect_cpu_info(int cpu, struct cpu_signature *csig)
48 {
49 struct cpuinfo_x86 *c = &cpu_data[cpu];
50 uint32_t dummy;
52 memset(csig, 0, sizeof(*csig));
54 if ( (c->x86_vendor != X86_VENDOR_AMD) || (c->x86 < 0x10) )
55 {
56 printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
57 cpu);
58 return -EINVAL;
59 }
61 rdmsr(MSR_AMD_PATCHLEVEL, csig->rev, dummy);
63 printk(KERN_INFO "microcode: collect_cpu_info: patch_id=0x%x\n",
64 csig->rev);
66 return 0;
67 }
69 static int microcode_fits(void *mc, int cpu)
70 {
71 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
72 struct microcode_header_amd *mc_header = mc;
73 unsigned int current_cpu_id;
74 unsigned int equiv_cpu_id = 0x0;
75 unsigned int i;
77 /* We should bind the task to the CPU */
78 BUG_ON(cpu != raw_smp_processor_id());
80 if ( equiv_cpu_table == NULL )
81 {
82 printk(KERN_INFO "microcode: CPU%d microcode update with "
83 "version 0x%x (current=0x%x)\n",
84 cpu, mc_header->patch_id, uci->cpu_sig.rev);
85 goto out;
86 }
88 current_cpu_id = cpuid_eax(0x00000001);
90 for ( i = 0; equiv_cpu_table[i].installed_cpu != 0; i++ )
91 {
92 if ( current_cpu_id == equiv_cpu_table[i].installed_cpu )
93 {
94 equiv_cpu_id = equiv_cpu_table[i].equiv_cpu & 0xffff;
95 break;
96 }
97 }
99 if ( !equiv_cpu_id )
100 {
101 printk(KERN_ERR "microcode: CPU%d cpu_id "
102 "not found in equivalent cpu table\n", cpu);
103 return -EINVAL;
104 }
106 if ( (mc_header->processor_rev_id) != equiv_cpu_id )
107 {
108 printk(KERN_INFO "microcode: CPU%d patch does not match "
109 "(patch is %x, cpu base id is %x) \n",
110 cpu, mc_header->processor_rev_id, equiv_cpu_id);
111 return -EINVAL;
112 }
114 if ( mc_header->patch_id <= uci->cpu_sig.rev )
115 return -EINVAL;
117 printk(KERN_INFO "microcode: CPU%d found a matching microcode "
118 "update with version 0x%x (current=0x%x)\n",
119 cpu, mc_header->patch_id, uci->cpu_sig.rev);
121 out:
122 return 0;
123 }
125 static int apply_microcode(int cpu)
126 {
127 unsigned long flags;
128 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
129 uint32_t rev, dummy;
130 struct microcode_amd *mc_amd = uci->mc.mc_amd;
132 /* We should bind the task to the CPU */
133 BUG_ON(raw_smp_processor_id() != cpu);
135 if ( mc_amd == NULL )
136 return -EINVAL;
138 spin_lock_irqsave(&microcode_update_lock, flags);
140 wrmsrl(MSR_AMD_PATCHLOADER, (unsigned long)&mc_amd->hdr.data_code);
142 /* get patch id after patching */
143 rdmsr(MSR_AMD_PATCHLEVEL, rev, dummy);
145 spin_unlock_irqrestore(&microcode_update_lock, flags);
147 /* check current patch id and patch's id for match */
148 if ( rev != mc_amd->hdr.patch_id )
149 {
150 printk(KERN_ERR "microcode: CPU%d update from revision "
151 "0x%x to 0x%x failed\n", cpu,
152 mc_amd->hdr.patch_id, rev);
153 return -EIO;
154 }
156 printk("microcode: CPU%d updated from revision "
157 "0x%x to 0x%x \n",
158 cpu, uci->cpu_sig.rev, mc_amd->hdr.patch_id);
160 uci->cpu_sig.rev = rev;
162 return 0;
163 }
165 static int get_next_ucode_from_buffer_amd(void *mc, const void *buf,
166 size_t size, unsigned long *offset)
167 {
168 struct microcode_header_amd *mc_header;
169 size_t total_size;
170 const uint8_t *bufp = buf;
171 unsigned long off;
173 off = *offset;
175 /* No more data */
176 if ( off >= size )
177 return 1;
179 if ( bufp[off] != UCODE_UCODE_TYPE )
180 {
181 printk(KERN_ERR "microcode: error! "
182 "Wrong microcode payload type field\n");
183 return -EINVAL;
184 }
186 mc_header = (struct microcode_header_amd *)(&bufp[off+8]);
188 total_size = (unsigned long) (bufp[off+4] + (bufp[off+5] << 8));
190 printk(KERN_INFO "microcode: size %lu, total_size %lu, offset %ld\n",
191 (unsigned long)size, total_size, off);
193 if ( (off + total_size) > size )
194 {
195 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
196 return -EINVAL;
197 }
199 memset(mc, 0, UCODE_MAX_SIZE);
200 memcpy(mc, (const void *)(&bufp[off + 8]), total_size);
202 *offset = off + total_size + 8;
204 return 0;
205 }
207 static int install_equiv_cpu_table(const void *buf, uint32_t size,
208 unsigned long *offset)
209 {
210 const uint32_t *buf_pos = buf;
211 unsigned long off;
213 off = *offset;
214 *offset = 0;
216 /* No more data */
217 if ( off >= size )
218 return -EINVAL;
220 if ( buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE )
221 {
222 printk(KERN_ERR "microcode: error! "
223 "Wrong microcode equivalent cpu table type field\n");
224 return -EINVAL;
225 }
227 if ( size == 0 )
228 {
229 printk(KERN_ERR "microcode: error! "
230 "Wrong microcode equivalnet cpu table length\n");
231 return -EINVAL;
232 }
234 equiv_cpu_table = xmalloc_bytes(size);
235 if ( equiv_cpu_table == NULL )
236 {
237 printk(KERN_ERR "microcode: error, can't allocate "
238 "memory for equiv CPU table\n");
239 return -ENOMEM;
240 }
242 memset(equiv_cpu_table, 0, size);
243 memcpy(equiv_cpu_table, (const void *)&buf_pos[3], size);
245 *offset = size + 12; /* add header length */
247 return 0;
248 }
250 static int cpu_request_microcode(int cpu, const void *buf, size_t size)
251 {
252 const uint32_t *buf_pos;
253 unsigned long offset = 0;
254 int error = 0;
255 int ret;
256 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
257 void *mc;
259 /* We should bind the task to the CPU */
260 BUG_ON(cpu != raw_smp_processor_id());
262 buf_pos = (const uint32_t *)buf;
264 if ( buf_pos[0] != UCODE_MAGIC )
265 {
266 printk(KERN_ERR "microcode: error! Wrong "
267 "microcode patch file magic\n");
268 return -EINVAL;
269 }
271 error = install_equiv_cpu_table(buf, (uint32_t)(buf_pos[2]), &offset);
272 if ( error )
273 {
274 printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
275 return -EINVAL;
276 }
278 mc = xmalloc_bytes(UCODE_MAX_SIZE);
279 if ( mc == NULL )
280 {
281 printk(KERN_ERR "microcode: error! "
282 "Can not allocate memory for microcode patch\n");
283 error = -ENOMEM;
284 goto out;
285 }
287 /* implicitely validates uci->mc.mc_valid */
288 uci->mc.mc_amd = mc;
290 /*
291 * It's possible the data file has multiple matching ucode,
292 * lets keep searching till the latest version
293 */
294 while ( (ret = get_next_ucode_from_buffer_amd(mc, buf, size, &offset)) == 0)
295 {
296 error = microcode_fits(mc, cpu);
297 if (error != 0)
298 continue;
300 error = apply_microcode(cpu);
301 if (error == 0)
302 break;
303 }
305 /* On success keep the microcode patch for
306 * re-apply on resume.
307 */
308 if (error) {
309 xfree(mc);
310 mc = NULL;
311 }
312 uci->mc.mc_amd = mc;
314 out:
315 xfree(equiv_cpu_table);
316 equiv_cpu_table = NULL;
318 return error;
319 }
321 static int microcode_resume_match(int cpu, struct cpu_signature *nsig)
322 {
323 return 0;
324 }
326 static struct microcode_ops microcode_amd_ops = {
327 .microcode_resume_match = microcode_resume_match,
328 .cpu_request_microcode = cpu_request_microcode,
329 .collect_cpu_info = collect_cpu_info,
330 .apply_microcode = apply_microcode,
331 };
333 static __init int microcode_init_amd(void)
334 {
335 if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
336 microcode_ops = &microcode_amd_ops;
337 return 0;
338 }
339 __initcall(microcode_init_amd);