Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 36200
b: refs/heads/master
c: a30a6a2
h: refs/heads/master
v: v3
  • Loading branch information
Shaohua Li authored and Linus Torvalds committed Sep 27, 2006
1 parent 107ee6e commit 5e33602
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9a3110bf4bb0466b43b898533bfd4952001bc38f
refs/heads/master: a30a6a2cb0fdc2c9701d6ddfb21affeb8146c038
116 changes: 116 additions & 0 deletions trunk/arch/i386/kernel/microcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/cpu.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>

#include <asm/msr.h>
#include <asm/uaccess.h>
Expand Down Expand Up @@ -493,13 +496,125 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
#define microcode_dev_exit() do { } while(0)
#endif

static long get_next_ucode_from_buffer(void **mc, void *buf,
unsigned long size, long offset)
{
microcode_header_t *mc_header;
unsigned long total_size;

/* No more data */
if (offset >= size)
return 0;
mc_header = (microcode_header_t *)(buf + offset);
total_size = get_totalsize(mc_header);

if ((offset + total_size > size)
|| (total_size < DEFAULT_UCODE_TOTALSIZE)) {
printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
return -EINVAL;
}

*mc = vmalloc(total_size);
if (!*mc) {
printk(KERN_ERR "microcode: error! Can not allocate memory\n");
return -ENOMEM;
}
memcpy(*mc, buf + offset, total_size);
return offset + total_size;
}

/* fake device for request_firmware */
static struct platform_device *microcode_pdev;

static int cpu_request_microcode(int cpu)
{
char name[30];
struct cpuinfo_x86 *c = cpu_data + cpu;
const struct firmware *firmware;
void * buf;
unsigned long size;
long offset = 0;
int error;
void *mc;

/* We should bind the task to the CPU */
BUG_ON(cpu != raw_smp_processor_id());
sprintf(name,"intel-ucode/%02x-%02x-%02x",
c->x86, c->x86_model, c->x86_mask);
error = request_firmware(&firmware, name, &microcode_pdev->dev);
if (error) {
pr_debug("ucode data file %s load failed\n", name);
return error;
}
buf = (void *)firmware->data;
size = firmware->size;
while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
> 0) {
error = microcode_sanity_check(mc);
if (error)
break;
error = get_maching_microcode(mc, cpu);
if (error < 0)
break;
/*
* It's possible the data file has multiple matching ucode,
* lets keep searching till the latest version
*/
if (error == 1) {
apply_microcode(cpu);
error = 0;
}
vfree(mc);
}
if (offset > 0)
vfree(mc);
if (offset < 0)
error = offset;
release_firmware(firmware);

return error;
}

static void microcode_init_cpu(int cpu)
{
cpumask_t old;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;

old = current->cpus_allowed;

set_cpus_allowed(current, cpumask_of_cpu(cpu));
mutex_lock(&microcode_mutex);
collect_cpu_info(cpu);
if (uci->valid)
cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex);
set_cpus_allowed(current, old);
}

static void microcode_fini_cpu(int cpu)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;

mutex_lock(&microcode_mutex);
uci->valid = 0;
vfree(uci->mc);
uci->mc = NULL;
mutex_unlock(&microcode_mutex);
}

static int __init microcode_init (void)
{
int error;

error = microcode_dev_init();
if (error)
return error;
microcode_pdev = platform_device_register_simple("microcode", -1,
NULL, 0);
if (IS_ERR(microcode_pdev)) {
microcode_dev_exit();
return PTR_ERR(microcode_pdev);
}

printk(KERN_INFO
"IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
Expand All @@ -509,6 +624,7 @@ static int __init microcode_init (void)
static void __exit microcode_exit (void)
{
microcode_dev_exit();
platform_device_unregister(microcode_pdev);
}

module_init(microcode_init)
Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/base/firmware_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ firmware_class_exit(void)
class_unregister(&firmware_class);
}

module_init(firmware_class_init);
fs_initcall(firmware_class_init);
module_exit(firmware_class_exit);

EXPORT_SYMBOL(release_firmware);
Expand Down

0 comments on commit 5e33602

Please sign in to comment.