[patch-2.3.47-p3] small improvement of microcode driver

From: Tigran Aivazian (tigran@aivazian.fsnet.co.uk)
Date: Fri Feb 18 2000 - 18:22:39 EST


Hi Linus

a) made error handling robust, i.e. independent of which of N cpus failed
the update - the entire transaction is failed if at least one cpu failed.

b) reduced the amount of work (greatly!) done inside IPI handler, namely
got rid of memcpy() by having an abstract 'update request' structure.

regards,
Tigran.

--- microcode.c.0 Fri Feb 18 22:55:18 2000
+++ microcode.c Fri Feb 18 23:16:52 2000
@@ -88,7 +88,7 @@
         mc_applied = kmalloc(size, GFP_KERNEL);
         if (!mc_applied) {
                 remove_proc_entry("microcode", proc_root_driver);
- printk(KERN_ERR "microcode: can't allocate memory to hold applied microcode\n");
+ printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n");
                 return -ENOMEM;
         }
         memset(mc_applied, 0, size); /* so that reading from offsets corresponding to failed
@@ -132,28 +132,46 @@
         return 0;
 }
 
+/* a pointer to 'struct update_req' is passed to the IPI hanlder = do_update_one()
+ * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
+ * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
+ */
+struct update_req {
+ int err;
+ int slot;
+} update_req[NR_CPUS];
 
 static int do_microcode_update(void)
 {
- int err;
+ int i, error = 0, err;
+ struct microcode *m;
 
- if (smp_call_function(do_update_one, &err, 1, 1) != 0)
+ if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0)
                 panic("do_microcode_update(): timed out waiting for other CPUs\n");
- do_update_one(&err);
+ do_update_one((void *)update_req);
 
- return err;
+ for (i=0; i<smp_num_cpus; i++) {
+ err = update_req[i].err;
+ error += err;
+ if (!err) {
+ m = (struct microcode *)mc_applied + i;
+ memcpy(m, &microcode[update_req[i].slot], sizeof(struct microcode));
+ }
+ }
+ return error ? -EIO : 0;
 }
 
 static void do_update_one(void *arg)
 {
- int *err = (int *)arg;
+ struct update_req *req;
         struct cpuinfo_x86 * c;
         unsigned int pf = 0, val[2], rev, sig;
- int i, id;
+ int i, cpu_num;
 
- id = smp_processor_id();
- c = cpu_data + id;
- *err = 1; /* be pessimistic */
+ cpu_num = smp_processor_id();
+ c = cpu_data + cpu_num;
+ req = (struct update_req *)arg + cpu_num;
+ req->err = 1; /* be pessimistic */
 
         if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6)
                 return;
@@ -174,29 +192,29 @@
                         if (microcode[i].rev <= rev) {
                                 printk(KERN_ERR
                                         "microcode: CPU%d not 'upgrading' to earlier revision"
- " %d (current=%d)\n", id, microcode[i].rev, rev);
+ " %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
                         } else {
                                 int sum = 0;
- struct microcode *m, *mcslot;
- unsigned int *sump;
+ struct microcode *m = &microcode[i];
+ unsigned int *sump = (unsigned int *)(m+1);
 
- m = &microcode[i];
- sump = (unsigned int *)(m+1);
                                 while (--sump >= (unsigned int *)m)
                                         sum += *sump;
                                 if (sum != 0) {
                                         printk(KERN_ERR "microcode: CPU%d aborting, "
- "bad checksum\n", id);
+ "bad checksum\n", cpu_num);
                                         break;
                                 }
+
                                 wrmsr(0x79, (unsigned int)(m->bits), 0);
                                 __asm__ __volatile__ ("cpuid");
                                 rdmsr(0x8B, val[0], val[1]);
- *err = 0;
- mcslot = (struct microcode *)mc_applied + id;
- memcpy(mcslot, m, sizeof(struct microcode));
- printk(KERN_ERR "microcode: CPU%d updated from revision "
- "%d to %d, date=%08x\n", id, rev, val[1], m->date);
+
+ req->err = 0;
+ req->slot = i;
+ printk(KERN_ERR "microcode: CPU%d microcode updated "
+ "from revision %d to %d, date=%08x\n",
+ cpu_num, rev, val[1], m->date);
                         }
                         break;
                 }
@@ -218,7 +236,7 @@
 
 static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
 {
- int err;
+ ssize_t ret;
 
         if (len % sizeof(struct microcode) != 0) {
                 printk(KERN_ERR "microcode: can only write in N*%d bytes units\n",
@@ -237,12 +255,12 @@
                 unlock_kernel();
                 return -EFAULT;
         }
- err = do_microcode_update();
- if (err)
- len = (size_t)err;
- else
+ ret = do_microcode_update();
+ if (!ret) {
                 proc_microcode->size = smp_num_cpus * sizeof(struct microcode);
+ ret = (ssize_t)len;
+ }
         vfree(microcode);
         unlock_kernel();
- return len;
+ return ret;
 }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Feb 23 2000 - 21:00:22 EST