Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / arch / i386 / kernel / microcode.c
index 07ddfdf..e7c138f 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *     Intel CPU Microcode Update driver for Linux
+ *     Intel CPU Microcode Update Driver for Linux
  *
- *     Copyright (C) 2000 Tigran Aivazian
+ *     Copyright (C) 2000-2004 Tigran Aivazian
  *
  *     This driver allows to upgrade microcode on Intel processors
  *     belonging to IA-32 family - PentiumPro, Pentium II, 
@@ -32,7 +32,7 @@
  *             Added misc device support (now uses both devfs and misc).
  *             Added MICROCODE_IOCFREE ioctl to clear memory.
  *     1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
- *             Messages for error cases (non intel & no suitable microcode).
+ *             Messages for error cases (non Intel & no suitable microcode).
  *     1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
  *             Removed ->release(). Removed exclusive open and status bitmap.
  *             Added microcode_rwsem to serialize read()/write()/ioctl().
  *             Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
  *             because we no longer hold a copy of applied microcode 
  *             in kernel memory.
+ *     1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ *             Fix sigmatch() macro to handle old CPUs with pf == 0.
+ *             Thanks to Stuart Swales for pointing out this bug.
  */
 
-
+//#define DEBUG /* pr_debug */
+#include <linux/capability.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/cpumask.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/mutex.h>
 
 #include <asm/msr.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 
-MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
+MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
 MODULE_LICENSE("GPL");
 
-#define MICROCODE_VERSION      "1.13"
-#define MICRO_DEBUG            0
-#if MICRO_DEBUG
-#define dprintk(x...) printk(KERN_INFO x)
-#else
-#define dprintk(x...)
-#endif
+#define MICROCODE_VERSION      "1.14"
 
 #define DEFAULT_UCODE_DATASIZE         (2000)    /* 2000 bytes */
 #define MC_HEADER_SIZE         (sizeof (microcode_header_t))     /* 48 bytes */
@@ -104,14 +105,17 @@ MODULE_LICENSE("GPL");
 #define get_datasize(mc) \
        (((microcode_t *)mc)->hdr.datasize ? \
         ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-#define sigmatch(s1, s2, p1, p2) (((s1) == (s2)) && ((p1) & (p2)))
+
+#define sigmatch(s1, s2, p1, p2) \
+       (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
+
 #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
 
 /* serialize access to the physical write to MSR 0x79 */
-static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(microcode_update_lock);
 
 /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
-static DECLARE_MUTEX(microcode_sem);
+static DEFINE_MUTEX(microcode_mutex);
 
 static void __user *user_buffer;       /* user area microcode data buffer */
 static unsigned int user_buffer_size;  /* it's size */
@@ -163,10 +167,11 @@ static void collect_cpu_info (void *unused)
        }
 
        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-       __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+       /* see notes above for revision 1.07.  Apparent chip bug */
+       sync_core();
        /* get the current revision from MSR 0x8B */
        rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
-       dprintk("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n", 
+       pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
                        uci->sig, uci->pf, uci->rev);
 }
 
@@ -174,22 +179,22 @@ static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_he
 {
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
 
-       dprintk("Microcode Found.\n");
-       dprintk("   Header Revision 0x%x\n", mc_header->hdrver);
-       dprintk("   Loader Revision 0x%x\n", mc_header->ldrver);
-       dprintk("   Revision 0x%x \n", mc_header->rev);
-       dprintk("   Date %x/%x/%x\n",
+       pr_debug("Microcode Found.\n");
+       pr_debug("   Header Revision 0x%x\n", mc_header->hdrver);
+       pr_debug("   Loader Revision 0x%x\n", mc_header->ldrver);
+       pr_debug("   Revision 0x%x \n", mc_header->rev);
+       pr_debug("   Date %x/%x/%x\n",
                ((mc_header->date >> 24 ) & 0xff),
                ((mc_header->date >> 16 ) & 0xff),
                (mc_header->date & 0xFFFF));
-       dprintk("   Signature 0x%x\n", sig);
-       dprintk("   Type 0x%x Family 0x%x Model 0x%x Stepping 0x%x\n",
+       pr_debug("   Signature 0x%x\n", sig);
+       pr_debug("   Type 0x%x Family 0x%x Model 0x%x Stepping 0x%x\n",
                ((sig >> 12) & 0x3),
                ((sig >> 8) & 0xf),
                ((sig >> 4) & 0xf),
                ((sig & 0xf)));
-       dprintk("   Processor Flags 0x%x\n", pf);
-       dprintk("   Checksum 0x%x\n", cksum);
+       pr_debug("   Processor Flags 0x%x\n", pf);
+       pr_debug("   Checksum 0x%x\n", cksum);
 
        if (mc_header->rev < uci->rev) {
                printk(KERN_ERR "microcode: CPU%d not 'upgrading' to earlier revision"
@@ -198,12 +203,10 @@ static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_he
        } else if (mc_header->rev == uci->rev) {
                /* notify the caller of success on this cpu */
                uci->err = MC_SUCCESS;
-               printk(KERN_ERR "microcode: CPU%d already at revision"
-                       " 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
                goto out;
        }
 
-       dprintk("microcode: CPU%d found a matching microcode update with "
+       pr_debug("microcode: CPU%d found a matching microcode update with "
                " revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
        uci->cksum = cksum;
        uci->pf = pf; /* keep the original mc pf for cksum calculation */
@@ -247,8 +250,8 @@ static int find_matching_ucodes (void)
                        error = -EINVAL;
                        goto out;
                }
-               
-               for (cpu_num = 0; cpu_num < num_online_cpus(); cpu_num++) {
+
+               for_each_online_cpu(cpu_num) {
                        struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
                        if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/
                                continue;
@@ -290,7 +293,7 @@ static int find_matching_ucodes (void)
                                        error = -EFAULT;
                                        goto out;
                                }
-                               for (cpu_num = 0; cpu_num < num_online_cpus(); cpu_num++) {
+                               for_each_online_cpu(cpu_num) {
                                        struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
                                        if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/
                                                continue;
@@ -301,7 +304,9 @@ static int find_matching_ucodes (void)
                        }
                }
                /* now check if any cpu has matched */
-               for (cpu_num = 0, allocated_flag = 0, sum = 0; cpu_num < num_online_cpus(); cpu_num++) {
+               allocated_flag = 0;
+               sum = 0;
+               for_each_online_cpu(cpu_num) {
                        if (ucode_cpu_info[cpu_num].err == MC_MARKED) { 
                                struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
                                if (!allocated_flag) {
@@ -363,7 +368,6 @@ static void do_update_one (void * unused)
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
 
        if (uci->mc == NULL) {
-               printk(KERN_INFO "microcode: No new microdata for cpu %d\n", cpu_num);
                return;
        }
 
@@ -376,7 +380,9 @@ static void do_update_one (void * unused)
                (unsigned long) uci->mc->bits >> 16 >> 16);
        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
 
-       __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+       /* see notes above for revision 1.07.  Apparent chip bug */
+       sync_core();
+
        /* get the current revision from MSR 0x8B */
        rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
 
@@ -410,12 +416,12 @@ static int do_microcode_update (void)
        }
 
 out_free:
-       for (i = 0; i < num_online_cpus(); i++) {
+       for_each_online_cpu(i) {
                if (ucode_cpu_info[i].mc) {
                        int j;
                        void *tmp = ucode_cpu_info[i].mc;
                        vfree(tmp);
-                       for (j = i; j < num_online_cpus(); j++) {
+                       for_each_online_cpu(j) {
                                if (ucode_cpu_info[j].mc == tmp)
                                        ucode_cpu_info[j].mc = NULL;
                        }
@@ -439,7 +445,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
                return -EINVAL;
        }
 
-       down(&microcode_sem);
+       mutex_lock(&microcode_mutex);
 
        user_buffer = (void __user *) buf;
        user_buffer_size = (int) len;
@@ -448,37 +454,21 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
        if (!ret)
                ret = (ssize_t)len;
 
-       up(&microcode_sem);
+       mutex_unlock(&microcode_mutex);
 
        return ret;
 }
 
-static int microcode_ioctl (struct inode *inode, struct file *file, 
-               unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-               /* 
-                *  XXX: will be removed after microcode_ctl 
-                *  is updated to ignore failure of this ioctl()
-                */
-               case MICROCODE_IOCFREE:
-                       return 0;
-               default:
-                       return -EINVAL;
-       }
-       return -EINVAL;
-}
-
 static struct file_operations microcode_fops = {
        .owner          = THIS_MODULE,
        .write          = microcode_write,
-       .ioctl          = microcode_ioctl,
        .open           = microcode_open,
 };
 
 static struct miscdevice microcode_dev = {
        .minor          = MICROCODE_MINOR,
        .name           = "microcode",
+       .devfs_name     = "cpu/microcode",
        .fops           = &microcode_fops,
 };
 
@@ -495,16 +485,13 @@ static int __init microcode_init (void)
        }
 
        printk(KERN_INFO 
-               "IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n", 
-               MICROCODE_VERSION);
+               "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
        return 0;
 }
 
 static void __exit microcode_exit (void)
 {
        misc_deregister(&microcode_dev);
-       printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n", 
-                       MICROCODE_VERSION);
 }
 
 module_init(microcode_init)