150 lines
3.9 KiB
Diff
150 lines
3.9 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1221568859 -3600
|
|
# Node ID 879330497672d96ee966c9774d21c437895f6839
|
|
# Parent 88445b184dc666fc196cffab19eac75cd9c10b87
|
|
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>
|
|
|
|
Index: xen-3.3.1-testing/xen/arch/x86/microcode.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/xen/arch/x86/microcode.c
|
|
+++ xen-3.3.1-testing/xen/arch/x86/microcode.c
|
|
@@ -45,14 +45,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;
|
|
@@ -110,14 +109,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);
|
|
|
|
/*
|
|
@@ -140,72 +137,50 @@ static int microcode_update_cpu(int cpu,
|
|
return err;
|
|
}
|
|
|
|
-static void do_microcode_update_one(void *info)
|
|
+static long do_microcode_update(void *_info)
|
|
{
|
|
+ struct microcode_info *info = _info;
|
|
int error;
|
|
|
|
- error = microcode_update_cpu(
|
|
- smp_processor_id(), microcode_buffer.buf, microcode_buffer.size);
|
|
+ BUG_ON(info->cpu != smp_processor_id());
|
|
|
|
- if ( error )
|
|
- microcode_error = error;
|
|
-}
|
|
+ error = microcode_update_cpu(info->buffer, info->buffer_size);
|
|
|
|
-static int do_microcode_update(void)
|
|
-{
|
|
- int error = 0;
|
|
-
|
|
- microcode_error = 0;
|
|
-
|
|
- if ( on_each_cpu(do_microcode_update_one, NULL, 1, 1) != 0 )
|
|
- {
|
|
- printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
|
|
- error = -EIO;
|
|
- goto out;
|
|
- }
|
|
+ if ( error )
|
|
+ info->error = error;
|
|
|
|
- if ( microcode_error )
|
|
- {
|
|
- error = microcode_error;
|
|
- goto out;
|
|
- }
|
|
+ info->cpu = next_cpu(info->cpu, cpu_online_map);
|
|
+ if ( info->cpu >= NR_CPUS )
|
|
+ return info->error;
|
|
|
|
- out:
|
|
- return 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);
|
|
}
|