dect
/
linux-2.6
Archived
13
0
Fork 0

[PATCH] x86 microcode: microcode driver cleanup.

Clean up microcode update driver and make it more readable.

[akpm@osdl.org: cleanups]
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Acked-by: Tigran Aivazian <tigran@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Shaohua Li 2006-09-27 01:50:51 -07:00 committed by Linus Torvalds
parent 36b756f2b5
commit 9a3110bf4b
3 changed files with 260 additions and 258 deletions

View File

@ -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

View File

@ -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");
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,55 +118,40 @@ 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)
{
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
static void collect_cpu_info (void *unused) static void collect_cpu_info(int cpu_num)
{ {
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);
if ((c->x86_model >= 5) || (c->x86 > 6)) { uci->sig = cpuid_eax(0x00000001);
/* get processor flags from MSR 0x17 */
rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); if ((c->x86_model >= 5) || (c->x86 > 6)) {
uci->pf = 1 << ((val[1] >> 18) & 7); /* get processor flags from MSR 0x17 */
} rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
uci->orig_pf = uci->pf; uci->pf = 1 << ((val[1] >> 18) & 7);
} }
wrmsr(MSR_IA32_UCODE_REV, 0, 0); wrmsr(MSR_IA32_UCODE_REV, 0, 0);
@ -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) { static int microcode_sanity_check(void *mc)
if (uci->err == MC_NOTFOUND) { {
uci->err = MC_IGNORED; microcode_header_t *mc_header = mc;
uci->cksum = mc_header->rev; struct extended_sigtable *ext_header = NULL;
} else if (uci->err == MC_IGNORED && uci->cksum < mc_header->rev) struct extended_signature *ext_sig;
uci->cksum = mc_header->rev; unsigned long total_size, data_size, ext_table_size;
} else if (mc_header->rev == uci->rev) { int sum, orig_sum, ext_sigcount = 0, i;
if (uci->err < MC_MARKED) {
/* notify the caller of success on this cpu */ total_size = get_totalsize(mc_header);
uci->err = MC_SUCCESS; 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 size in microcode data file\n");
return -EINVAL;
}
if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
printk(KERN_ERR "microcode: error! "
"Unknown microcode update format\n");
return -EINVAL;
}
ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
if (ext_table_size) {
if ((ext_table_size < EXT_HEADER_SIZE)
|| ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
printk(KERN_ERR "microcode: error! "
"Small exttable size in microcode data file\n");
return -EINVAL;
} }
} else if (uci->err != MC_ALLOCATED || mc_header->rev > uci->mc->hdr.rev) { ext_header = mc + MC_HEADER_SIZE + data_size;
pr_debug("microcode: CPU%d found a matching microcode update with " if (ext_table_size != exttable_size(ext_header)) {
" revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev); printk(KERN_ERR "microcode: error! "
uci->cksum = cksum; "Bad exttable size in microcode data file\n");
uci->pf = pf; /* keep the original mc pf for cksum calculation */ return -EFAULT;
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) { ext_sigcount = ext_header->count;
vfree(uci->mc); }
uci->mc = NULL;
/* check extended table checksum */
if (ext_table_size) {
int ext_table_sum = 0;
int * ext_tablep = (int *)ext_header;
i = ext_table_size / DWSIZE;
while (i--)
ext_table_sum += ext_tablep[i];
if (ext_table_sum) {
printk(KERN_WARNING "microcode: aborting, "
"bad extended signature table checksum\n");
return -EINVAL;
} }
} }
return;
/* calculate the checksum */
orig_sum = 0;
i = (MC_HEADER_SIZE + data_size) / DWSIZE;
while (i--)
orig_sum += ((int *)mc)[i];
if (orig_sum) {
printk(KERN_ERR "microcode: aborting, bad checksum\n");
return -EINVAL;
}
if (!ext_table_size)
return 0;
/* check extended signature checksum */
for (i = 0; i < ext_sigcount; i++) {
ext_sig = (struct extended_signature *)((void *)ext_header
+ 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;
} }
static int find_matching_ucodes (void) /*
* return 0 - no update found
* return 1 - found update
* return < 0 - error
*/
static int get_maching_microcode(void *mc, int cpu)
{ {
int cursor = 0; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
int error = 0; 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;
while (cursor + MC_HEADER_SIZE < user_buffer_size) { if (microcode_update_match(cpu, mc_header,
microcode_header_t mc_header; mc_header->sig, mc_header->pf))
void *newmc = NULL; goto find;
int i, sum, cpu_num, allocated_flag, total_size, data_size, ext_table_size;
if (copy_from_user(&mc_header, user_buffer + cursor, MC_HEADER_SIZE)) { if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
printk(KERN_ERR "microcode: error! Can not read user data\n"); return 0;
error = -EFAULT;
goto out;
}
total_size = get_totalsize(&mc_header); ext_header = (struct extended_sigtable *)(mc +
if ((cursor + total_size > user_buffer_size) || (total_size < DEFAULT_UCODE_TOTALSIZE)) { get_datasize(mc_header) + MC_HEADER_SIZE);
printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); ext_sigcount = ext_header->count;
error = -EINVAL; ext_sig = (struct extended_signature *)((void *)ext_header
goto out; + 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;
}
data_size = get_datasize(&mc_header); /* free previous update file */
if ((data_size + MC_HEADER_SIZE > total_size) || (data_size < DEFAULT_UCODE_DATASIZE)) { vfree(uci->mc);
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) { memcpy(new_mc, mc, total_size);
printk(KERN_ERR "microcode: error! Unknown microcode update format\n"); uci->mc = new_mc;
error = -EINVAL; return 1;
goto out;
}
for_each_online_cpu(cpu_num) {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
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);
}
ext_table_size = total_size - (MC_HEADER_SIZE + data_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)
|| ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
error = -EINVAL;
goto out;
}
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)) {
printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
error = -EFAULT;
goto out;
}
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 */
if (ext_table_size) {
int ext_table_sum = 0;
int * ext_tablep = (((void *) newmc) + MC_HEADER_SIZE + data_size);
i = ext_table_size / DWSIZE;
while (i--) ext_table_sum += ext_tablep[i];
if (ext_table_sum) {
printk(KERN_WARNING "microcode: aborting, bad extended signature table checksum\n");
vfree(newmc);
error = -EINVAL;
goto out;
}
}
/* calculate the checksum */
i = (MC_HEADER_SIZE + data_size) / DWSIZE;
while (i--) sum += ((int *)newmc)[i];
sum -= (mc_header.sig + mc_header.pf + mc_header.cksum);
}
ucode_cpu_info[cpu_num].mc = newmc;
ucode_cpu_info[cpu_num].err = MC_ALLOCATED; /* mc updated */
if (sum + uci->sig + uci->pf + uci->cksum != 0) {
printk(KERN_ERR "microcode: CPU%d aborting, bad checksum\n", cpu_num);
error = -EINVAL;
goto out;
}
}
}
cursor += total_size; /* goto the next update patch */
} /* end of while */
out:
return error;
} }
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)
/* 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];
}
#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)
{
microcode_header_t mc_header;
unsigned long total_size;
/* No more data */
if (offset >= user_buffer_size)
return 0;
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 ((offset + total_size > user_buffer_size)
|| (total_size < DEFAULT_UCODE_TOTALSIZE)) {
printk(KERN_ERR "microcode: error! Bad total size in microcode "
"data file\n");
return -EINVAL;
}
*mc = vmalloc(total_size);
if (!*mc)
return -ENOMEM;
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;
} }
static int do_microcode_update (void) static int do_microcode_update (void)
{ {
int i, error; long cursor = 0;
int error = 0;
void * new_mc;
int cpu;
cpumask_t old;
if (on_each_cpu(collect_cpu_info, NULL, 1, 1) != 0) { old = current->cpus_allowed;
printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
error = -EIO;
goto out;
}
if ((error = find_matching_ucodes())) { while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
printk(KERN_ERR "microcode: Error in the microcode data\n"); error = microcode_sanity_check(new_mc);
goto out_free; 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 (on_each_cpu(do_update_one, NULL, 1, 1) != 0) { if (!uci->valid)
printk(KERN_ERR "microcode: Error! Could not run on all processors\n"); continue;
error = -EIO; set_cpus_allowed(current, cpumask_of_cpu(cpu));
} error = get_maching_microcode(new_mc, cpu);
if (error < 0)
out_free: goto out;
for_each_online_cpu(i) { if (error == 1)
if (ucode_cpu_info[i].mc) { apply_microcode(cpu);
int j;
void *tmp = ucode_cpu_info[i].mc;
vfree(tmp);
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) 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_
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_
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 = {
.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)
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)
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);

View File

@ -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