Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 113334
b: refs/heads/master
c: d45de40
h: refs/heads/master
v: v3
  • Loading branch information
Dmitry Adamushko authored and Ingo Molnar committed Aug 20, 2008
1 parent c5d56c4 commit 17486ea
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 199 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: 8343ef2437c599d30568e6b5a257a40bf2f4902b
refs/heads/master: d45de40934897c6ee5b05141f7895bbb28512395
155 changes: 102 additions & 53 deletions trunk/arch/x86/kernel/microcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
* Thanks to Stuart Swales for pointing out this bug.
*/

/*#define DEBUG pr_debug */
/* #define DEBUG pr_debug */
#include <linux/capability.h>
#include <linux/kernel.h>
#include <linux/init.h>
Expand Down Expand Up @@ -104,8 +104,7 @@ MODULE_LICENSE("GPL");
struct microcode_ops *microcode_ops;

/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
DEFINE_MUTEX(microcode_mutex);
EXPORT_SYMBOL_GPL(microcode_mutex);
static DEFINE_MUTEX(microcode_mutex);

struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
EXPORT_SYMBOL_GPL(ucode_cpu_info);
Expand Down Expand Up @@ -234,22 +233,6 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
struct platform_device *microcode_pdev;
EXPORT_SYMBOL_GPL(microcode_pdev);

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

old = current->cpus_allowed;

set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
mutex_lock(&microcode_mutex);
microcode_ops->collect_cpu_info(cpu);
if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
microcode_ops->cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex);
set_cpus_allowed_ptr(current, &old);
}

static ssize_t reload_store(struct sys_device *dev,
struct sysdev_attribute *attr,
const char *buf, size_t sz)
Expand All @@ -266,14 +249,15 @@ static ssize_t reload_store(struct sys_device *dev,
cpumask_t old = current->cpus_allowed;

get_online_cpus();
set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));

mutex_lock(&microcode_mutex);
if (uci->valid)
err = microcode_ops->cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex);
if (cpu_online(cpu)) {
set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
mutex_lock(&microcode_mutex);
if (uci->valid)
err = microcode_ops->cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex);
set_cpus_allowed_ptr(current, &old);
}
put_online_cpus();
set_cpus_allowed_ptr(current, &old);
}
if (err)
return err;
Expand All @@ -285,15 +269,15 @@ static ssize_t version_show(struct sys_device *dev,
{
struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;

return sprintf(buf, "0x%x\n", uci->rev);
return sprintf(buf, "0x%x\n", uci->cpu_sig.rev);
}

static ssize_t pf_show(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf)
{
struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;

return sprintf(buf, "0x%x\n", uci->pf);
return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
}

static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
Expand All @@ -312,7 +296,85 @@ static struct attribute_group mc_attr_group = {
.name = "microcode",
};

static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
static void microcode_fini_cpu(int cpu)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;

mutex_lock(&microcode_mutex);
microcode_ops->microcode_fini_cpu(cpu);
uci->valid = 0;
mutex_unlock(&microcode_mutex);
}

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

memset(uci, 0, sizeof(*uci));
if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig))
uci->valid = 1;
}

static void microcode_resume_cpu(int cpu)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
struct cpu_signature nsig;

pr_debug("microcode: CPU%d resumed\n", cpu);

if (!uci->mc.valid_mc)
return;

/*
* Let's verify that the 'cached' ucode does belong
* to this cpu (a bit of paranoia):
*/
if (microcode_ops->collect_cpu_info(cpu, &nsig)) {
microcode_fini_cpu(cpu);
return;
}

if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) {
microcode_fini_cpu(cpu);
/* Should we look for a new ucode here? */
return;
}

microcode_ops->apply_microcode(cpu);
}

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

/* We should bind the task to the CPU */
BUG_ON(raw_smp_processor_id() != cpu);

mutex_lock(&microcode_mutex);
/*
* Check if the system resume is in progress (uci->valid != NULL),
* otherwise just request a firmware:
*/
if (uci->valid) {
microcode_resume_cpu(cpu);
} else {
collect_cpu_info(cpu);
if (uci->valid && system_state == SYSTEM_RUNNING)
microcode_ops->cpu_request_microcode(cpu);
}
mutex_unlock(&microcode_mutex);
}

static void microcode_init_cpu(int cpu)
{
cpumask_t old = current->cpus_allowed;

set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
microcode_update_cpu(cpu);
set_cpus_allowed_ptr(current, &old);
}

static int mc_sysdev_add(struct sys_device *sys_dev)
{
int err, cpu = sys_dev->id;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
Expand All @@ -327,16 +389,10 @@ static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
if (err)
return err;

microcode_init_cpu(cpu, resume);

microcode_init_cpu(cpu);
return 0;
}

static int mc_sysdev_add(struct sys_device *sys_dev)
{
return __mc_sysdev_add(sys_dev, 0);
}

static int mc_sysdev_remove(struct sys_device *sys_dev)
{
int cpu = sys_dev->id;
Expand All @@ -345,7 +401,7 @@ static int mc_sysdev_remove(struct sys_device *sys_dev)
return 0;

pr_debug("microcode: CPU%d removed\n", cpu);
microcode_ops->microcode_fini_cpu(cpu);
microcode_fini_cpu(cpu);
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
return 0;
}
Expand Down Expand Up @@ -376,33 +432,26 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)

sys_dev = get_cpu_sysdev(cpu);
switch (action) {
case CPU_UP_CANCELED_FROZEN:
/* The CPU refused to come up during a system resume */
microcode_ops->microcode_fini_cpu(cpu);
break;
case CPU_ONLINE:
case CPU_DOWN_FAILED:
mc_sysdev_add(sys_dev);
break;
case CPU_ONLINE_FROZEN:
/* System-wide resume is in progress, try to apply microcode */
if (microcode_ops->apply_microcode_check_cpu(cpu)) {
/* The application of microcode failed */
microcode_ops->microcode_fini_cpu(cpu);
__mc_sysdev_add(sys_dev, 1);
break;
}
microcode_init_cpu(cpu);
case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN:
pr_debug("microcode: CPU%d added\n", cpu);
if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
printk(KERN_ERR "microcode: Failed to create the sysfs "
"group for CPU%d\n", cpu);
break;
case CPU_DOWN_PREPARE:
mc_sysdev_remove(sys_dev);
break;
case CPU_DOWN_PREPARE_FROZEN:
/* Suspend is in progress, only remove the interface */
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
pr_debug("microcode: CPU%d removed\n", cpu);
break;
case CPU_DEAD:
case CPU_UP_CANCELED_FROZEN:
/* The CPU refused to come up during a system resume */
microcode_fini_cpu(cpu);
break;
}
return NOTIFY_OK;
Expand Down
77 changes: 12 additions & 65 deletions trunk/arch/x86/kernel/microcode_amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,38 +59,28 @@ MODULE_LICENSE("GPL v2");
/* serialize access to the physical write */
static DEFINE_SPINLOCK(microcode_update_lock);

/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
extern struct mutex (microcode_mutex);

struct equiv_cpu_entry *equiv_cpu_table;

extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS];

static void collect_cpu_info_amd(int cpu)
static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
{
struct cpuinfo_x86 *c = &cpu_data(cpu);
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;

/* We should bind the task to the CPU */
BUG_ON(raw_smp_processor_id() != cpu);
uci->rev = 0;
uci->pf = 0;
uci->mc.mc_amd = NULL;
uci->valid = 1;
memset(csig, 0, sizeof(*csig));

if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
cpu);
uci->valid = 0;
return;
return -1;
}

asm volatile("movl %1, %%ecx; rdmsr"
: "=a" (uci->rev)
: "=a" (csig->rev)
: "i" (0x0000008B) : "ecx");

printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n",
uci->rev);
csig->rev);

return 0;
}

static int get_matching_microcode_amd(void *mc, int cpu)
Expand Down Expand Up @@ -119,7 +109,7 @@ static int get_matching_microcode_amd(void *mc, int cpu)
if (equiv_cpu_table == NULL) {
printk(KERN_INFO "microcode: CPU%d microcode update with "
"version 0x%x (current=0x%x)\n",
cpu, mc_header->patch_id, uci->rev);
cpu, mc_header->patch_id, uci->cpu_sig.rev);
goto out;
}

Expand Down Expand Up @@ -185,12 +175,12 @@ static int get_matching_microcode_amd(void *mc, int cpu)
pci_dev_put(sb_pci_dev);
}

if (mc_header->patch_id <= uci->rev)
if (mc_header->patch_id <= uci->cpu_sig.rev)
return 0;

printk(KERN_INFO "microcode: CPU%d found a matching microcode "
"update with version 0x%x (current=0x%x)\n",
cpu, mc_header->patch_id, uci->rev);
cpu, mc_header->patch_id, uci->cpu_sig.rev);

out:
new_mc = vmalloc(UCODE_MAX_SIZE);
Expand Down Expand Up @@ -250,9 +240,9 @@ static void apply_microcode_amd(int cpu)

printk(KERN_INFO "microcode: CPU%d updated from revision "
"0x%x to 0x%x \n",
cpu_num, uci->rev, uci->mc.mc_amd->hdr.patch_id);
cpu_num, uci->cpu_sig.rev, uci->mc.mc_amd->hdr.patch_id);

uci->rev = rev;
uci->cpu_sig.rev = rev;
}

#ifdef CONFIG_MICROCODE_OLD_INTERFACE
Expand Down Expand Up @@ -437,61 +427,18 @@ static int cpu_request_microcode_amd(int cpu)
return error;
}

static int apply_microcode_check_cpu_amd(int cpu)
{
struct cpuinfo_x86 *c = &cpu_data(cpu);
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
unsigned int rev;
cpumask_t old;
int err = 0;

/* Check if the microcode is available */
if (!uci->mc.mc_amd)
return 0;

old = current->cpus_allowed;
set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));

/* Check if the microcode we have in memory matches the CPU */
if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 16)
err = -EINVAL;

if (!err) {
asm volatile("movl %1, %%ecx; rdmsr"
: "=a" (rev)
: "i" (0x0000008B) : "ecx");

if (uci->rev != rev)
err = -EINVAL;
}

if (!err)
apply_microcode_amd(cpu);
else
printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
" rev=0x%x\n",
cpu, uci->rev);

set_cpus_allowed(current, old);
return err;
}

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

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

static struct microcode_ops microcode_amd_ops = {
.get_next_ucode = get_next_ucode_amd,
.get_matching_microcode = get_matching_microcode_amd,
.microcode_sanity_check = NULL,
.apply_microcode_check_cpu = apply_microcode_check_cpu_amd,
.cpu_request_microcode = cpu_request_microcode_amd,
.collect_cpu_info = collect_cpu_info_amd,
.apply_microcode = apply_microcode_amd,
Expand Down
Loading

0 comments on commit 17486ea

Please sign in to comment.