ia64/xen-unstable

annotate xen/arch/x86/microcode.c @ 18497:087b8b29b6b2

x86, microcode: Clean up for Xen coding style, and disable for now
(until allocations in irq context are fixed).

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Sep 16 11:26:19 2008 +0100 (2008-09-16)
parents 15b1c3d4459a
children 3eb7a0cfffc2
rev   line source
kaf24@3362 1 /*
keir@18497 2 * Intel CPU Microcode Update Driver for Linux
keir@18489 3 *
keir@18497 4 * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
keir@18497 5 * 2006 Shaohua Li <shaohua.li@intel.com> *
keir@18497 6 * This driver allows to upgrade microcode on Intel processors
keir@18497 7 * belonging to IA-32 family - PentiumPro, Pentium II,
keir@18497 8 * Pentium III, Xeon, Pentium 4, etc.
keir@18497 9 *
keir@18497 10 * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
keir@18497 11 * Software Developer's Manual
keir@18497 12 * Order Number 253668 or free download from:
keir@18497 13 *
keir@18497 14 * http://developer.intel.com/design/pentium4/manuals/253668.htm
keir@18497 15 *
keir@18497 16 * For more information, go to http://www.urbanmyth.org/microcode
keir@18497 17 *
keir@18497 18 * This program is free software; you can redistribute it and/or
keir@18497 19 * modify it under the terms of the GNU General Public License
keir@18497 20 * as published by the Free Software Foundation; either version
keir@18497 21 * 2 of the License, or (at your option) any later version.
kaf24@3362 22 */
kaf24@3362 23
kaf24@3362 24 #include <xen/config.h>
cl349@5285 25 #include <xen/lib.h>
kaf24@3362 26 #include <xen/kernel.h>
kaf24@3362 27 #include <xen/init.h>
kaf24@3362 28 #include <xen/sched.h>
cl349@5287 29 #include <xen/smp.h>
kaf24@3362 30 #include <xen/spinlock.h>
keir@18489 31 #include <xen/guest_access.h>
kaf24@3362 32
cl349@5291 33 #include <asm/current.h>
kaf24@3362 34 #include <asm/msr.h>
kaf24@3362 35 #include <asm/uaccess.h>
kaf24@3362 36 #include <asm/processor.h>
keir@18489 37 #include <asm/microcode.h>
kaf24@3362 38
kfraser@10545 39 static int verbose;
kfraser@10545 40 boolean_param("microcode.verbose", verbose);
kfraser@10545 41
keir@18489 42 const struct microcode_ops *microcode_ops;
kaf24@3362 43
keir@18489 44 static DEFINE_SPINLOCK(microcode_mutex);
kaf24@3362 45
keir@18489 46 struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
keir@18489 47
keir@18489 48 struct microcode_buffer {
keir@18497 49 void *buf;
keir@18497 50 size_t size;
keir@18489 51 };
keir@18489 52
keir@18489 53 static struct microcode_buffer microcode_buffer;
keir@18489 54 static bool_t microcode_error;
keir@18489 55
keir@18489 56 static void microcode_fini_cpu(int cpu)
kaf24@3362 57 {
keir@18497 58 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
kaf24@3362 59
keir@18497 60 spin_lock(&microcode_mutex);
keir@18497 61 microcode_ops->microcode_fini_cpu(cpu);
keir@18497 62 uci->valid = 0;
keir@18497 63 spin_unlock(&microcode_mutex);
keir@18489 64 }
kaf24@3362 65
keir@18489 66 static int collect_cpu_info(int cpu)
keir@18489 67 {
keir@18497 68 int err = 0;
keir@18497 69 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
keir@18489 70
keir@18497 71 memset(uci, 0, sizeof(*uci));
keir@18497 72 err = microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
keir@18497 73 if ( !err )
keir@18497 74 uci->valid = 1;
keir@18489 75
keir@18497 76 return err;
keir@18489 77 }
keir@18489 78
keir@18489 79 static int microcode_resume_cpu(int cpu)
keir@18489 80 {
keir@18497 81 int err = 0;
keir@18497 82 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
keir@18497 83 struct cpu_signature nsig;
keir@18489 84
keir@18497 85 gdprintk(XENLOG_INFO, "microcode: CPU%d resumed\n", cpu);
kaf24@3362 86
keir@18497 87 if ( !uci->mc.valid_mc )
keir@18497 88 return -EIO;
keir@18489 89
keir@18497 90 /*
keir@18497 91 * Let's verify that the 'cached' ucode does belong
keir@18497 92 * to this cpu (a bit of paranoia):
keir@18497 93 */
keir@18497 94 err = microcode_ops->collect_cpu_info(cpu, &nsig);
keir@18497 95 if ( err )
keir@18497 96 {
keir@18497 97 microcode_fini_cpu(cpu);
keir@18497 98 return err;
keir@18497 99 }
keir@18489 100
keir@18497 101 if ( memcmp(&nsig, &uci->cpu_sig, sizeof(nsig)) )
keir@18497 102 {
keir@18497 103 microcode_fini_cpu(cpu);
keir@18497 104 /* Should we look for a new ucode here? */
keir@18497 105 return -EIO;
keir@18497 106 }
keir@18497 107
keir@18497 108 err = microcode_ops->apply_microcode(cpu);
keir@18497 109
keir@18497 110 return err;
kaf24@3362 111 }
kaf24@3362 112
keir@18489 113 static int microcode_update_cpu(int cpu, const void *buf, size_t size)
kaf24@3362 114 {
keir@18497 115 int err = 0;
keir@18497 116 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
keir@18489 117
keir@18497 118 /* We should bind the task to the CPU */
keir@18497 119 BUG_ON(raw_smp_processor_id() != cpu);
keir@18489 120
keir@18497 121 spin_lock(&microcode_mutex);
keir@18489 122
keir@18497 123 /*
keir@18497 124 * Check if the system resume is in progress (uci->valid != NULL),
keir@18497 125 * otherwise just request a firmware:
keir@18497 126 */
keir@18497 127 if ( uci->valid )
keir@18497 128 {
keir@18497 129 err = microcode_resume_cpu(cpu);
keir@18497 130 }
keir@18497 131 else
keir@18497 132 {
keir@18497 133 err = collect_cpu_info(cpu);
keir@18497 134 if ( !err && uci->valid )
keir@18497 135 err = microcode_ops->cpu_request_microcode(cpu, buf, size);
keir@18497 136 }
keir@18497 137
keir@18497 138 spin_unlock(&microcode_mutex);
keir@18497 139
keir@18497 140 return err;
kaf24@3362 141 }
kaf24@3362 142
keir@18489 143 static void do_microcode_update_one(void *info)
kaf24@3362 144 {
keir@18497 145 int error;
kaf24@3362 146
keir@18497 147 error = microcode_update_cpu(
keir@18497 148 smp_processor_id(), microcode_buffer.buf, microcode_buffer.size);
kaf24@3362 149
keir@18497 150 if ( error )
keir@18497 151 microcode_error = error;
kaf24@3362 152 }
kaf24@3362 153
keir@18489 154 static int do_microcode_update(void)
kaf24@3362 155 {
keir@18497 156 int error = 0;
kaf24@3362 157
keir@18497 158 microcode_error = 0;
kaf24@3362 159
keir@18497 160 if ( on_each_cpu(do_microcode_update_one, NULL, 1, 1) != 0 )
keir@18497 161 {
keir@18497 162 printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
keir@18497 163 error = -EIO;
keir@18497 164 goto out;
keir@18497 165 }
kaf24@3362 166
keir@18497 167 if ( microcode_error )
keir@18497 168 {
keir@18497 169 error = microcode_error;
keir@18497 170 goto out;
keir@18497 171 }
keir@18497 172
keir@18497 173 out:
keir@18497 174 return error;
kaf24@3362 175 }
kaf24@3362 176
keir@18417 177 int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len)
kaf24@3362 178 {
keir@18497 179 int ret;
keir@18489 180
keir@18497 181 /* XXX FIXME: No allocations in interrupt context. */
keir@18497 182 return -EINVAL;
keir@18489 183
keir@18497 184 if ( len != (typeof(microcode_buffer.size))len )
keir@18497 185 {
keir@18497 186 printk(KERN_ERR "microcode: too much data\n");
keir@18497 187 return -E2BIG;
keir@18497 188 }
kfraser@10545 189
keir@18497 190 if (microcode_ops == NULL)
keir@18497 191 return -EINVAL;
kfraser@10545 192
keir@18497 193 microcode_buffer.buf = xmalloc_array(uint8_t, len);
keir@18497 194 if ( microcode_buffer.buf == NULL )
keir@18497 195 return -ENOMEM;
keir@18497 196
keir@18497 197 ret = copy_from_guest(microcode_buffer.buf, buf, len);
keir@18497 198 if ( ret != 0 )
keir@18497 199 return ret;
keir@18497 200
keir@18497 201 microcode_buffer.size = len;
keir@18497 202 wmb();
keir@18497 203
keir@18497 204 ret = do_microcode_update();
keir@18497 205
keir@18497 206 xfree(microcode_buffer.buf);
keir@18497 207 microcode_buffer.buf = NULL;
keir@18497 208 microcode_buffer.size = 0;
keir@18497 209
keir@18497 210 return ret;
kaf24@3362 211 }