diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-09-16 13:40:59 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-09-16 13:40:59 +0100 |
commit | 524c71bcb77031cb8e3b2c170f5d7c31320b9d08 (patch) | |
tree | b00811272b9809ef13f27786097920313bc962b0 /xen/arch/x86/microcode.c | |
parent | 7441a335e4dc8b0a4f22bd22e37c793145d89aaf (diff) | |
download | xen-524c71bcb77031cb8e3b2c170f5d7c31320b9d08.tar.gz xen-524c71bcb77031cb8e3b2c170f5d7c31320b9d08.tar.bz2 xen-524c71bcb77031cb8e3b2c170f5d7c31320b9d08.zip |
x86, microcode: Do not run microcode update in IRQ context.
It's unnecessary, and also invalid since the update process tries to
allocate memory.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/microcode.c')
-rw-r--r-- | xen/arch/x86/microcode.c | 77 |
1 files changed, 32 insertions, 45 deletions
diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c index f39153997a..0d97db531d 100644 --- a/xen/arch/x86/microcode.c +++ b/xen/arch/x86/microcode.c @@ -42,14 +42,13 @@ static DEFINE_SPINLOCK(microcode_mutex); struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; -struct microcode_buffer { - void *buf; - size_t size; +struct microcode_info { + unsigned int cpu; + uint32_t buffer_size; + int error; + char buffer[1]; }; -static struct microcode_buffer microcode_buffer; -static bool_t microcode_error; - static void microcode_fini_cpu(int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; @@ -108,14 +107,12 @@ static int microcode_resume_cpu(int cpu) return err; } -static int microcode_update_cpu(int cpu, const void *buf, size_t size) +static int microcode_update_cpu(const void *buf, size_t size) { - int err = 0; + int err; + unsigned int cpu = smp_processor_id(); struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - /* We should bind the task to the CPU */ - BUG_ON(raw_smp_processor_id() != cpu); - spin_lock(µcode_mutex); /* @@ -138,59 +135,49 @@ static int microcode_update_cpu(int cpu, const void *buf, size_t size) return err; } -static void do_microcode_update_one(void *info) +static long do_microcode_update(void *_info) { - int error = microcode_update_cpu( - smp_processor_id(), microcode_buffer.buf, microcode_buffer.size); - if ( error ) - microcode_error = error; -} + struct microcode_info *info = _info; + int error; -static int do_microcode_update(void) -{ - microcode_error = 0; + BUG_ON(info->cpu != smp_processor_id()); - if ( on_each_cpu(do_microcode_update_one, NULL, 1, 1) != 0 ) - { - printk(KERN_ERR "microcode: Error! Could not run on all processors\n"); - return -EIO; - } + error = microcode_update_cpu(info->buffer, info->buffer_size); + if ( error ) + info->error = error; + + info->cpu = next_cpu(info->cpu, cpu_online_map); + if ( info->cpu >= NR_CPUS ) + return info->error; - return microcode_error; + return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info); } int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len) { int ret; + struct microcode_info *info; - /* XXX FIXME: No allocations in interrupt context. */ - return -EINVAL; - - if ( len != (typeof(microcode_buffer.size))len ) - { - printk(KERN_ERR "microcode: too much data\n"); + if ( len != (uint32_t)len ) return -E2BIG; - } if ( microcode_ops == NULL ) return -EINVAL; - microcode_buffer.buf = xmalloc_array(uint8_t, len); - if ( microcode_buffer.buf == NULL ) + info = xmalloc_bytes(sizeof(*info) + len); + if ( info == NULL ) return -ENOMEM; - ret = copy_from_guest(microcode_buffer.buf, buf, len); + ret = copy_from_guest(info->buffer, buf, len); if ( ret != 0 ) + { + xfree(info); return ret; + } - microcode_buffer.size = len; - wmb(); - - ret = do_microcode_update(); - - xfree(microcode_buffer.buf); - microcode_buffer.buf = NULL; - microcode_buffer.size = 0; + info->buffer_size = len; + info->error = 0; + info->cpu = first_cpu(cpu_online_map); - return ret; + return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info); } |