X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Fmicrocode.c;h=e5520eb8702018b512c7f9169a8bb99969b4eec9;hb=e0ff8aa1acd079b70e796571917ae0449b7c465b;hp=aca20edc5ea1cebb69364dd726b09306742596cb;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index aca20edc5..e5520eb87 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -69,15 +69,19 @@ * Thanks to Stuart Swales for pointing out this bug. */ - +//#define DEBUG /* pr_debug */ +#include +#include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -87,13 +91,10 @@ MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); MODULE_AUTHOR("Tigran Aivazian "); MODULE_LICENSE("GPL"); -#define MICROCODE_VERSION "1.14" -#define MICRO_DEBUG 0 -#if MICRO_DEBUG -#define dprintk(x...) printk(KERN_INFO x) -#else -#define dprintk(x...) -#endif +static int verbose; +module_param(verbose, int, 0644); + +#define MICROCODE_VERSION "1.14a" #define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ #define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */ @@ -114,24 +115,25 @@ MODULE_LICENSE("GPL"); #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 */ typedef enum mc_error_code { MC_SUCCESS = 0, - MC_NOTFOUND = 1, - MC_MARKED = 2, - MC_ALLOCATED = 3, + MC_IGNORED = 1, + MC_NOTFOUND = 2, + MC_MARKED = 3, + MC_ALLOCATED = 4, } mc_error_code_t; static struct ucode_cpu_info { unsigned int sig; - unsigned int pf; + unsigned int pf, orig_pf; unsigned int rev; unsigned int cksum; mc_error_code_t err; @@ -166,13 +168,15 @@ static void collect_cpu_info (void *unused) rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); uci->pf = 1 << ((val[1] >> 18) & 7); } + uci->orig_pf = uci->pf; } 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); } @@ -180,41 +184,52 @@ 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" - " 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev); - goto out; + if (uci->err == MC_NOTFOUND) { + uci->err = MC_IGNORED; + uci->cksum = mc_header->rev; + } else if (uci->err == MC_IGNORED && uci->cksum < mc_header->rev) + uci->cksum = mc_header->rev; } 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; + if (uci->err < MC_MARKED) { + /* notify the caller of success on this cpu */ + uci->err = MC_SUCCESS; + } + } else if (uci->err != MC_ALLOCATED || mc_header->rev > uci->mc->hdr.rev) { + 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 */ + uci->err = MC_MARKED; /* found the match */ + for_each_online_cpu(cpu_num) { + if (ucode_cpu_info + cpu_num != uci + && ucode_cpu_info[cpu_num].mc == uci->mc) { + uci->mc = NULL; + break; + } + } + if (uci->mc != NULL) { + vfree(uci->mc); + uci->mc = NULL; + } } - - dprintk("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 */ - uci->err = MC_MARKED; /* found the match */ -out: return; } @@ -235,14 +250,14 @@ static int find_matching_ucodes (void) } total_size = get_totalsize(&mc_header); - if ((cursor + total_size > user_buffer_size) || (total_size < DEFAULT_UCODE_TOTALSIZE)) { + if (cursor + total_size > user_buffer_size) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); error = -EINVAL; goto out; } data_size = get_datasize(&mc_header); - if ((data_size + MC_HEADER_SIZE > total_size) || (data_size < DEFAULT_UCODE_DATASIZE)) { + if (data_size + MC_HEADER_SIZE > total_size) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); error = -EINVAL; goto out; @@ -253,13 +268,11 @@ 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; - if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->pf)) + if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->orig_pf)) mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum); } @@ -296,18 +309,19 @@ 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; - if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->pf)) { + + if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->orig_pf)) { mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum); } } } } /* 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) { @@ -369,7 +383,13 @@ 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 suitable data for CPU%d\n", cpu_num); + if (verbose) { + if (uci->err == MC_SUCCESS) + printk(KERN_INFO "microcode: CPU%d already at revision 0x%x\n", + cpu_num, uci->rev); + else + printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num); + } return; } @@ -382,7 +402,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]); @@ -416,16 +438,19 @@ 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; } } + if (ucode_cpu_info[i].err == MC_IGNORED && verbose) + printk(KERN_WARNING "microcode: CPU%d not 'upgrading' to earlier revision" + " 0x%x (current=0x%x)\n", i, ucode_cpu_info[i].cksum, ucode_cpu_info[i].rev); } out: return error; @@ -435,17 +460,12 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_ { ssize_t ret; - if (len < DEFAULT_UCODE_TOTALSIZE) { - printk(KERN_ERR "microcode: not enough data\n"); - return -EINVAL; - } - if ((len >> PAGE_SHIFT) > num_physpages) { printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages); return -EINVAL; } - down(µcode_sem); + mutex_lock(µcode_mutex); user_buffer = (void __user *) buf; user_buffer_size = (int) len; @@ -454,38 +474,20 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_ if (!ret) ret = (ssize_t)len; - up(µcode_sem); + mutex_unlock(µcode_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 = µcode_fops, }; @@ -509,7 +511,6 @@ static int __init microcode_init (void) static void __exit microcode_exit (void) { misc_deregister(µcode_dev); - printk(KERN_INFO "IA-32 Microcode Update Driver v" MICROCODE_VERSION " unregistered\n"); } module_init(microcode_init)