File 18487-microcode-update-irq-context.patch of Package xen

# 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(&microcode_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);
 }
openSUSE Build Service is sponsored by