Commit 9a3110bf authored by Shaohua Li's avatar Shaohua Li Committed by Linus Torvalds

[PATCH] x86 microcode: microcode driver cleanup.

Clean up microcode update driver and make it more readable.

[akpm@osdl.org: cleanups]
Signed-off-by: default avatarShaohua Li <shaohua.li@intel.com>
Acked-by: default avatarTigran Aivazian <tigran@veritas.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 36b756f2
...@@ -416,6 +416,11 @@ config MICROCODE ...@@ -416,6 +416,11 @@ config MICROCODE
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called microcode. module will be called microcode.
config MICROCODE_OLD_INTERFACE
bool
depends on MICROCODE
default y
config X86_MSR config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support" tristate "/dev/cpu/*/msr - Model-specific register support"
help help
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Intel CPU Microcode Update Driver for Linux * Intel CPU Microcode Update Driver for Linux
* *
* Copyright (C) 2000-2004 Tigran Aivazian * Copyright (C) 2000-2004 Tigran Aivazian
* 2006 Shaohua Li <shaohua.li@intel.com>
* *
* This driver allows to upgrade microcode on Intel processors * This driver allows to upgrade microcode on Intel processors
* belonging to IA-32 family - PentiumPro, Pentium II, * belonging to IA-32 family - PentiumPro, Pentium II,
...@@ -91,9 +92,6 @@ MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); ...@@ -91,9 +92,6 @@ MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>"); MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int verbose;
module_param(verbose, int, 0644);
#define MICROCODE_VERSION "1.14a" #define MICROCODE_VERSION "1.14a"
#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ #define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
...@@ -120,47 +118,34 @@ static DEFINE_SPINLOCK(microcode_update_lock); ...@@ -120,47 +118,34 @@ static DEFINE_SPINLOCK(microcode_update_lock);
/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
static DEFINE_MUTEX(microcode_mutex); 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_IGNORED = 1,
MC_NOTFOUND = 2,
MC_MARKED = 3,
MC_ALLOCATED = 4,
} mc_error_code_t;
static struct ucode_cpu_info { static struct ucode_cpu_info {
int valid;
unsigned int sig; unsigned int sig;
unsigned int pf, orig_pf; unsigned int pf;
unsigned int rev; unsigned int rev;
unsigned int cksum;
mc_error_code_t err;
microcode_t *mc; microcode_t *mc;
} ucode_cpu_info[NR_CPUS]; } ucode_cpu_info[NR_CPUS];
static int microcode_open (struct inode *unused1, struct file *unused2) static void collect_cpu_info(int cpu_num)
{
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
static void collect_cpu_info (void *unused)
{ {
int cpu_num = smp_processor_id();
struct cpuinfo_x86 *c = cpu_data + cpu_num; struct cpuinfo_x86 *c = cpu_data + cpu_num;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
unsigned int val[2]; unsigned int val[2];
uci->sig = uci->pf = uci->rev = uci->cksum = 0; /* We should bind the task to the CPU */
uci->err = MC_NOTFOUND; BUG_ON(raw_smp_processor_id() != cpu_num);
uci->pf = uci->rev = 0;
uci->mc = NULL; uci->mc = NULL;
uci->valid = 1;
if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
cpu_has(c, X86_FEATURE_IA64)) { cpu_has(c, X86_FEATURE_IA64)) {
printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num); printk(KERN_ERR "microcode: CPU%d not a capable Intel "
"processor\n", cpu_num);
uci->valid = 0;
return; return;
} else { }
uci->sig = cpuid_eax(0x00000001); uci->sig = cpuid_eax(0x00000001);
if ((c->x86_model >= 5) || (c->x86 > 6)) { if ((c->x86_model >= 5) || (c->x86 > 6)) {
...@@ -168,8 +153,6 @@ static void collect_cpu_info (void *unused) ...@@ -168,8 +153,6 @@ static void collect_cpu_info (void *unused)
rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
uci->pf = 1 << ((val[1] >> 18) & 7); uci->pf = 1 << ((val[1] >> 18) & 7);
} }
uci->orig_pf = uci->pf;
}
wrmsr(MSR_IA32_UCODE_REV, 0, 0); wrmsr(MSR_IA32_UCODE_REV, 0, 0);
/* see notes above for revision 1.07. Apparent chip bug */ /* see notes above for revision 1.07. Apparent chip bug */
...@@ -180,218 +163,160 @@ static void collect_cpu_info (void *unused) ...@@ -180,218 +163,160 @@ static void collect_cpu_info (void *unused)
uci->sig, uci->pf, uci->rev); uci->sig, uci->pf, uci->rev);
} }
static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_header, int sig, int pf, int cksum) static inline int microcode_update_match(int cpu_num,
microcode_header_t *mc_header, int sig, int pf)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
pr_debug("Microcode Found.\n"); if (!sigmatch(sig, uci->sig, pf, uci->pf)
pr_debug(" Header Revision 0x%x\n", mc_header->hdrver); || mc_header->rev <= uci->rev)
pr_debug(" Loader Revision 0x%x\n", mc_header->ldrver); return 0;
pr_debug(" Revision 0x%x \n", mc_header->rev); return 1;
pr_debug(" Date %x/%x/%x\n",
((mc_header->date >> 24 ) & 0xff),
((mc_header->date >> 16 ) & 0xff),
(mc_header->date & 0xFFFF));
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)));
pr_debug(" Processor Flags 0x%x\n", pf);
pr_debug(" Checksum 0x%x\n", cksum);
if (mc_header->rev < uci->rev) {
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) {
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;
}
}
return;
} }
static int find_matching_ucodes (void) static int microcode_sanity_check(void *mc)
{ {
int cursor = 0; microcode_header_t *mc_header = mc;
int error = 0; struct extended_sigtable *ext_header = NULL;
struct extended_signature *ext_sig;
while (cursor + MC_HEADER_SIZE < user_buffer_size) { unsigned long total_size, data_size, ext_table_size;
microcode_header_t mc_header; int sum, orig_sum, ext_sigcount = 0, i;
void *newmc = NULL;
int i, sum, cpu_num, allocated_flag, total_size, data_size, ext_table_size; total_size = get_totalsize(mc_header);
data_size = get_datasize(mc_header);
if (copy_from_user(&mc_header, user_buffer + cursor, MC_HEADER_SIZE)) { if ((data_size + MC_HEADER_SIZE > total_size)
printk(KERN_ERR "microcode: error! Can not read user data\n"); || (data_size < DEFAULT_UCODE_DATASIZE)) {
error = -EFAULT; printk(KERN_ERR "microcode: error! "
goto out; "Bad data size in microcode data file\n");
} return -EINVAL;
total_size = get_totalsize(&mc_header);
if ((cursor + total_size > user_buffer_size) || (total_size < DEFAULT_UCODE_TOTALSIZE)) {
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)) {
printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
error = -EINVAL;
goto out;
}
if (mc_header.ldrver != 1 || mc_header.hdrver != 1) {
printk(KERN_ERR "microcode: error! Unknown microcode update format\n");
error = -EINVAL;
goto out;
} }
for_each_online_cpu(cpu_num) { if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; printk(KERN_ERR "microcode: error! "
"Unknown microcode update format\n");
if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->orig_pf)) return -EINVAL;
mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum);
} }
ext_table_size = total_size - (MC_HEADER_SIZE + data_size); ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
if (ext_table_size) { if (ext_table_size) {
struct extended_sigtable ext_header;
struct extended_signature ext_sig;
int ext_sigcount;
if ((ext_table_size < EXT_HEADER_SIZE) if ((ext_table_size < EXT_HEADER_SIZE)
|| ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) { || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); printk(KERN_ERR "microcode: error! "
error = -EINVAL; "Small exttable size in microcode data file\n");
goto out; return -EINVAL;
}
if (copy_from_user(&ext_header, user_buffer + cursor
+ MC_HEADER_SIZE + data_size, EXT_HEADER_SIZE)) {
printk(KERN_ERR "microcode: error! Can not read user data\n");
error = -EFAULT;
goto out;
} }
if (ext_table_size != exttable_size(&ext_header)) { ext_header = mc + MC_HEADER_SIZE + data_size;
printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); if (ext_table_size != exttable_size(ext_header)) {
error = -EFAULT; printk(KERN_ERR "microcode: error! "
goto out; "Bad exttable size in microcode data file\n");
return -EFAULT;
} }
ext_sigcount = ext_header->count;
ext_sigcount = ext_header.count;
for (i = 0; i < ext_sigcount; i++) {
if (copy_from_user(&ext_sig, user_buffer + cursor + MC_HEADER_SIZE + data_size + EXT_HEADER_SIZE
+ EXT_SIGNATURE_SIZE * i, EXT_SIGNATURE_SIZE)) {
printk(KERN_ERR "microcode: error! Can not read user data\n");
error = -EFAULT;
goto out;
} }
for_each_online_cpu(cpu_num) {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
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 */
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) {
allocated_flag = 1;
newmc = vmalloc(total_size);
if (!newmc) {
printk(KERN_ERR "microcode: error! Can not allocate memory\n");
error = -ENOMEM;
goto out;
}
if (copy_from_user(newmc + MC_HEADER_SIZE,
user_buffer + cursor + MC_HEADER_SIZE,
total_size - MC_HEADER_SIZE)) {
printk(KERN_ERR "microcode: error! Can not read user data\n");
vfree(newmc);
error = -EFAULT;
goto out;
}
memcpy(newmc, &mc_header, MC_HEADER_SIZE);
/* check extended table checksum */ /* check extended table checksum */
if (ext_table_size) { if (ext_table_size) {
int ext_table_sum = 0; int ext_table_sum = 0;
int * ext_tablep = (((void *) newmc) + MC_HEADER_SIZE + data_size); int * ext_tablep = (int *)ext_header;
i = ext_table_size / DWSIZE; i = ext_table_size / DWSIZE;
while (i--) ext_table_sum += ext_tablep[i]; while (i--)
ext_table_sum += ext_tablep[i];
if (ext_table_sum) { if (ext_table_sum) {
printk(KERN_WARNING "microcode: aborting, bad extended signature table checksum\n"); printk(KERN_WARNING "microcode: aborting, "
vfree(newmc); "bad extended signature table checksum\n");
error = -EINVAL; return -EINVAL;
goto out;
} }
} }
/* calculate the checksum */ /* calculate the checksum */
orig_sum = 0;
i = (MC_HEADER_SIZE + data_size) / DWSIZE; i = (MC_HEADER_SIZE + data_size) / DWSIZE;
while (i--) sum += ((int *)newmc)[i]; while (i--)
sum -= (mc_header.sig + mc_header.pf + mc_header.cksum); orig_sum += ((int *)mc)[i];
if (orig_sum) {
printk(KERN_ERR "microcode: aborting, bad checksum\n");
return -EINVAL;
} }
ucode_cpu_info[cpu_num].mc = newmc; if (!ext_table_size)
ucode_cpu_info[cpu_num].err = MC_ALLOCATED; /* mc updated */ return 0;
if (sum + uci->sig + uci->pf + uci->cksum != 0) { /* check extended signature checksum */
printk(KERN_ERR "microcode: CPU%d aborting, bad checksum\n", cpu_num); for (i = 0; i < ext_sigcount; i++) {
error = -EINVAL; ext_sig = (struct extended_signature *)((void *)ext_header
goto out; + EXT_HEADER_SIZE + EXT_SIGNATURE_SIZE * i);
sum = orig_sum
- (mc_header->sig + mc_header->pf + mc_header->cksum)
+ (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
if (sum) {
printk(KERN_ERR "microcode: aborting, bad checksum\n");
return -EINVAL;
} }
} }
return 0;
}
/*
* return 0 - no update found
* return 1 - found update
* return < 0 - error
*/
static int get_maching_microcode(void *mc, int cpu)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
microcode_header_t *mc_header = mc;
struct extended_sigtable *ext_header;
unsigned long total_size = get_totalsize(mc_header);
int ext_sigcount, i;
struct extended_signature *ext_sig;
void *new_mc;
if (microcode_update_match(cpu, mc_header,
mc_header->sig, mc_header->pf))
goto find;
if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
return 0;
ext_header = (struct extended_sigtable *)(mc +
get_datasize(mc_header) + MC_HEADER_SIZE);
ext_sigcount = ext_header->count;
ext_sig = (struct extended_signature *)((void *)ext_header
+ EXT_HEADER_SIZE);
for (i = 0; i < ext_sigcount; i++) {
if (microcode_update_match(cpu, mc_header,
ext_sig->sig, ext_sig->pf))
goto find;
ext_sig++;
}
return 0;
find:
pr_debug("microcode: CPU %d found a matching microcode update with"
" version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
new_mc = vmalloc(total_size);
if (!new_mc) {
printk(KERN_ERR "microcode: error! Can not allocate memory\n");
return -ENOMEM;
} }
cursor += total_size; /* goto the next update patch */
} /* end of while */ /* free previous update file */
out: vfree(uci->mc);
return error;
memcpy(new_mc, mc, total_size);
uci->mc = new_mc;
return 1;
} }
static void do_update_one (void * unused) static void apply_microcode(int cpu)
{ {
unsigned long flags; unsigned long flags;
unsigned int val[2]; unsigned int val[2];
int cpu_num = smp_processor_id(); int cpu_num = raw_smp_processor_id();
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
if (uci->mc == NULL) { /* We should bind the task to the CPU */
if (verbose) { BUG_ON(cpu_num != cpu);
if (uci->err == MC_SUCCESS)
printk(KERN_INFO "microcode: CPU%d already at revision 0x%x\n", if (uci->mc == NULL)
cpu_num, uci->rev);
else
printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num);
}
return; return;
}
/* serialize access to the physical write to MSR 0x79 */ /* serialize access to the physical write to MSR 0x79 */
spin_lock_irqsave(&microcode_update_lock, flags); spin_lock_irqsave(&microcode_update_lock, flags);
...@@ -408,54 +333,98 @@ static void do_update_one (void * unused) ...@@ -408,54 +333,98 @@ static void do_update_one (void * unused)
/* get the current revision from MSR 0x8B */ /* get the current revision from MSR 0x8B */
rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
/* notify the caller of success on this cpu */
uci->err = MC_SUCCESS;
spin_unlock_irqrestore(&microcode_update_lock, flags); spin_unlock_irqrestore(&microcode_update_lock, flags);
printk(KERN_INFO "microcode: CPU%d updated from revision " if (val[1] != uci->mc->hdr.rev) {
printk(KERN_ERR "microcode: CPU%d updated from revision "
"0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
return;
}
pr_debug("microcode: CPU%d updated from revision "
"0x%x to 0x%x, date = %08x \n", "0x%x to 0x%x, date = %08x \n",
cpu_num, uci->rev, val[1], uci->mc->hdr.date); cpu_num, uci->rev, val[1], uci->mc->hdr.date);
return; uci->rev = val[1];
} }
static int do_microcode_update (void) #ifdef CONFIG_MICROCODE_OLD_INTERFACE
static void __user *user_buffer; /* user area microcode data buffer */
static unsigned int user_buffer_size; /* it's size */
static long get_next_ucode(void **mc, long offset)
{ {
int i, error; microcode_header_t mc_header;
unsigned long total_size;
if (on_each_cpu(collect_cpu_info, NULL, 1, 1) != 0) { /* No more data */
printk(KERN_ERR "microcode: Error! Could not run on all processors\n"); if (offset >= user_buffer_size)
error = -EIO; return 0;
goto out; if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
printk(KERN_ERR "microcode: error! Can not read user data\n");
return -EFAULT;
} }
total_size = get_totalsize(&mc_header);
if ((error = find_matching_ucodes())) { if ((offset + total_size > user_buffer_size)
printk(KERN_ERR "microcode: Error in the microcode data\n"); || (total_size < DEFAULT_UCODE_TOTALSIZE)) {
goto out_free; printk(KERN_ERR "microcode: error! Bad total size in microcode "
"data file\n");
return -EINVAL;
} }
*mc = vmalloc(total_size);
if (on_each_cpu(do_update_one, NULL, 1, 1) != 0) { if (!*mc)
printk(KERN_ERR "microcode: Error! Could not run on all processors\n"); return -ENOMEM;
error = -EIO; if (copy_from_user(*mc, user_buffer + offset, total_size)) {
printk(KERN_ERR "microcode: error! Can not read user data\n");
vfree(*mc);
return -EFAULT;
} }
return offset + total_size;
}
out_free: static int do_microcode_update (void)
for_each_online_cpu(i) { {
if (ucode_cpu_info[i].mc) { long cursor = 0;
int j; int error = 0;
void *tmp = ucode_cpu_info[i].mc; void * new_mc;
vfree(tmp); int cpu;
for_each_online_cpu(j) { cpumask_t old;
if (ucode_cpu_info[j].mc == tmp)
ucode_cpu_info[j].mc = NULL; old = current->cpus_allowed;
}
while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
error = microcode_sanity_check(new_mc);
if (error)
goto out;
/*
* It's possible the data file has multiple matching ucode,
* lets keep searching till the latest version
*/
for_each_online_cpu(cpu) {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
if (!uci->valid)
continue;
set_cpus_allowed(current, cpumask_of_cpu(cpu));
error = get_maching_microcode(new_mc, cpu);
if (error < 0)
goto out;
if (error == 1)
apply_microcode(cpu);
} }
if (ucode_cpu_info[i].err == MC_IGNORED && verbose) vfree(new_mc);
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: out:
if (cursor > 0)
vfree(new_mc);
if (cursor < 0)
error = cursor;
set_cpus_allowed(current, old);
return error; return error;
} }
static int microcode_open (struct inode *unused1, struct file *unused2)
{
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos) static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
{ {
ssize_t ret; ssize_t ret;
...@@ -470,6 +439,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_ ...@@ -470,6 +439,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
return -EINVAL; return -EINVAL;
} }
lock_cpu_hotplug();
mutex_lock(&microcode_mutex); mutex_lock(&microcode_mutex);
user_buffer = (void __user *) buf; user_buffer = (void __user *) buf;
...@@ -480,6 +450,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_ ...@@ -480,6 +450,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
ret = (ssize_t)len; ret = (ssize_t)len;
mutex_unlock(&microcode_mutex); mutex_unlock(&microcode_mutex);
unlock_cpu_hotplug();
return ret; return ret;
} }
...@@ -496,7 +467,7 @@ static struct miscdevice microcode_dev = { ...@@ -496,7 +467,7 @@ static struct miscdevice microcode_dev = {
.fops = &microcode_fops, .fops = &microcode_fops,
}; };
static int __init microcode_init (void) static int __init microcode_dev_init (void)
{ {
int error; int error;
...@@ -508,6 +479,28 @@ static int __init microcode_init (void) ...@@ -508,6 +479,28 @@ static int __init microcode_init (void)
return error; return error;
} }
return 0;
}
static void __exit microcode_dev_exit (void)
{
misc_deregister(&microcode_dev);
}
MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
#else
#define microcode_dev_init() 0
#define microcode_dev_exit() do { } while(0)
#endif
static int __init microcode_init (void)
{
int error;
error = microcode_dev_init();
if (error)
return error;
printk(KERN_INFO printk(KERN_INFO
"IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n"); "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
return 0; return 0;
...@@ -515,9 +508,8 @@ static int __init microcode_init (void) ...@@ -515,9 +508,8 @@ static int __init microcode_init (void)
static void __exit microcode_exit (void) static void __exit microcode_exit (void)
{ {
misc_deregister(&microcode_dev); microcode_dev_exit();
} }
module_init(microcode_init) module_init(microcode_init)
module_exit(microcode_exit) module_exit(microcode_exit)
MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
...@@ -186,6 +186,11 @@ config MICROCODE ...@@ -186,6 +186,11 @@ config MICROCODE
If you use modprobe or kmod you may also want to add the line If you use modprobe or kmod you may also want to add the line
'alias char-major-10-184 microcode' to your /etc/modules.conf file. 'alias char-major-10-184 microcode' to your /etc/modules.conf file.
config MICROCODE_OLD_INTERFACE
bool
depends on MICROCODE
default y
config X86_MSR config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support" tristate "/dev/cpu/*/msr - Model-specific register support"
help help
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment