Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, microcode, AMD: Add microcode revision to /proc/cpuinfo x86, microcode: Correct microcode revision format coretemp: Get microcode revision from cpu_data x86, intel: Use c->microcode for Atom errata check x86, intel: Output microcode revision in /proc/cpuinfo x86, microcode: Don't request microcode from userspace unnecessarily Fix up trivial conflicts in arch/x86/kernel/cpu/amd.c (conflict between moving AMD BSP code to cpu_dev helper function and adding AMD microcode revision to /proc/cpuinfo code)
This commit is contained in:
commit
8237eb946a
@ -111,6 +111,7 @@ struct cpuinfo_x86 {
|
|||||||
/* Index into per_cpu list: */
|
/* Index into per_cpu list: */
|
||||||
u16 cpu_index;
|
u16 cpu_index;
|
||||||
#endif
|
#endif
|
||||||
|
u32 microcode;
|
||||||
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
|
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
|
||||||
|
|
||||||
#define X86_VENDOR_INTEL 0
|
#define X86_VENDOR_INTEL 0
|
||||||
@ -179,7 +180,8 @@ static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
|
|||||||
"=b" (*ebx),
|
"=b" (*ebx),
|
||||||
"=c" (*ecx),
|
"=c" (*ecx),
|
||||||
"=d" (*edx)
|
"=d" (*edx)
|
||||||
: "0" (*eax), "2" (*ecx));
|
: "0" (*eax), "2" (*ecx)
|
||||||
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void load_cr3(pgd_t *pgdir)
|
static inline void load_cr3(pgd_t *pgdir)
|
||||||
|
@ -441,6 +441,8 @@ static void __cpuinit bsp_init_amd(struct cpuinfo_x86 *c)
|
|||||||
|
|
||||||
static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
|
static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
|
||||||
{
|
{
|
||||||
|
u32 dummy;
|
||||||
|
|
||||||
early_init_amd_mc(c);
|
early_init_amd_mc(c);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -470,6 +472,8 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
|
|||||||
set_cpu_cap(c, X86_FEATURE_EXTD_APICID);
|
set_cpu_cap(c, X86_FEATURE_EXTD_APICID);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
||||||
|
@ -47,6 +47,15 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
|
|||||||
(c->x86 == 0x6 && c->x86_model >= 0x0e))
|
(c->x86 == 0x6 && c->x86_model >= 0x0e))
|
||||||
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
|
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
|
||||||
|
|
||||||
|
if (c->x86 >= 6 && !cpu_has(c, X86_FEATURE_IA64)) {
|
||||||
|
unsigned lower_word;
|
||||||
|
|
||||||
|
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
|
||||||
|
/* Required by the SDM */
|
||||||
|
sync_core();
|
||||||
|
rdmsr(MSR_IA32_UCODE_REV, lower_word, c->microcode);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Atom erratum AAE44/AAF40/AAG38/AAH41:
|
* Atom erratum AAE44/AAF40/AAG38/AAH41:
|
||||||
*
|
*
|
||||||
@ -55,17 +64,10 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
|
|||||||
* need the microcode to have already been loaded... so if it is
|
* need the microcode to have already been loaded... so if it is
|
||||||
* not, recommend a BIOS update and disable large pages.
|
* not, recommend a BIOS update and disable large pages.
|
||||||
*/
|
*/
|
||||||
if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_mask <= 2) {
|
if (c->x86 == 6 && c->x86_model == 0x1c && c->x86_mask <= 2 &&
|
||||||
u32 ucode, junk;
|
c->microcode < 0x20e) {
|
||||||
|
printk(KERN_WARNING "Atom PSE erratum detected, BIOS microcode update recommended\n");
|
||||||
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
|
clear_cpu_cap(c, X86_FEATURE_PSE);
|
||||||
sync_core();
|
|
||||||
rdmsr(MSR_IA32_UCODE_REV, junk, ucode);
|
|
||||||
|
|
||||||
if (ucode < 0x20e) {
|
|
||||||
printk(KERN_WARNING "Atom PSE erratum detected, BIOS microcode update recommended\n");
|
|
||||||
clear_cpu_cap(c, X86_FEATURE_PSE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
@ -217,8 +217,13 @@ static void print_mce(struct mce *m)
|
|||||||
pr_cont("MISC %llx ", m->misc);
|
pr_cont("MISC %llx ", m->misc);
|
||||||
|
|
||||||
pr_cont("\n");
|
pr_cont("\n");
|
||||||
pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
|
/*
|
||||||
m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid);
|
* Note this output is parsed by external tools and old fields
|
||||||
|
* should not be changed.
|
||||||
|
*/
|
||||||
|
pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
|
||||||
|
m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
|
||||||
|
cpu_data(m->extcpu).microcode);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print out human-readable details about the MCE error,
|
* Print out human-readable details about the MCE error,
|
||||||
|
@ -85,6 +85,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
|||||||
seq_printf(m, "stepping\t: %d\n", c->x86_mask);
|
seq_printf(m, "stepping\t: %d\n", c->x86_mask);
|
||||||
else
|
else
|
||||||
seq_printf(m, "stepping\t: unknown\n");
|
seq_printf(m, "stepping\t: unknown\n");
|
||||||
|
if (c->microcode)
|
||||||
|
seq_printf(m, "microcode\t: 0x%x\n", c->microcode);
|
||||||
|
|
||||||
if (cpu_has(c, X86_FEATURE_TSC)) {
|
if (cpu_has(c, X86_FEATURE_TSC)) {
|
||||||
unsigned int freq = cpufreq_quick_get(cpu);
|
unsigned int freq = cpufreq_quick_get(cpu);
|
||||||
|
@ -74,14 +74,13 @@ static struct equiv_cpu_entry *equiv_cpu_table;
|
|||||||
static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
|
static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
|
||||||
{
|
{
|
||||||
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||||
u32 dummy;
|
|
||||||
|
|
||||||
if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
|
if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
|
||||||
pr_warning("CPU%d: family %d not supported\n", cpu, c->x86);
|
pr_warning("CPU%d: family %d not supported\n", cpu, c->x86);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdmsr(MSR_AMD64_PATCH_LEVEL, csig->rev, dummy);
|
csig->rev = c->microcode;
|
||||||
pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev);
|
pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -130,6 +129,7 @@ static int apply_microcode_amd(int cpu)
|
|||||||
int cpu_num = raw_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;
|
||||||
struct microcode_amd *mc_amd = uci->mc;
|
struct microcode_amd *mc_amd = uci->mc;
|
||||||
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||||
|
|
||||||
/* We should bind the task to the CPU */
|
/* We should bind the task to the CPU */
|
||||||
BUG_ON(cpu_num != cpu);
|
BUG_ON(cpu_num != cpu);
|
||||||
@ -150,6 +150,7 @@ static int apply_microcode_amd(int cpu)
|
|||||||
|
|
||||||
pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev);
|
pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev);
|
||||||
uci->cpu_sig.rev = rev;
|
uci->cpu_sig.rev = rev;
|
||||||
|
c->microcode = rev;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,13 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
|
|||||||
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
|
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
|
||||||
pr_debug("CPU%d removed\n", cpu);
|
pr_debug("CPU%d removed\n", cpu);
|
||||||
break;
|
break;
|
||||||
case CPU_DEAD:
|
|
||||||
|
/*
|
||||||
|
* When a CPU goes offline, don't free up or invalidate the copy of
|
||||||
|
* the microcode in kernel memory, so that we can reuse it when the
|
||||||
|
* CPU comes back online without unnecessarily requesting the userspace
|
||||||
|
* for it again.
|
||||||
|
*/
|
||||||
case CPU_UP_CANCELED_FROZEN:
|
case CPU_UP_CANCELED_FROZEN:
|
||||||
/* The CPU refused to come up during a system resume */
|
/* The CPU refused to come up during a system resume */
|
||||||
microcode_fini_cpu(cpu);
|
microcode_fini_cpu(cpu);
|
||||||
|
@ -161,12 +161,7 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
|
|||||||
csig->pf = 1 << ((val[1] >> 18) & 7);
|
csig->pf = 1 << ((val[1] >> 18) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
|
csig->rev = c->microcode;
|
||||||
/* 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], csig->rev);
|
|
||||||
|
|
||||||
pr_info("CPU%d sig=0x%x, pf=0x%x, revision=0x%x\n",
|
pr_info("CPU%d sig=0x%x, pf=0x%x, revision=0x%x\n",
|
||||||
cpu_num, csig->sig, csig->pf, csig->rev);
|
cpu_num, csig->sig, csig->pf, csig->rev);
|
||||||
|
|
||||||
@ -299,9 +294,9 @@ static int apply_microcode(int cpu)
|
|||||||
struct microcode_intel *mc_intel;
|
struct microcode_intel *mc_intel;
|
||||||
struct ucode_cpu_info *uci;
|
struct ucode_cpu_info *uci;
|
||||||
unsigned int val[2];
|
unsigned int val[2];
|
||||||
int cpu_num;
|
int cpu_num = raw_smp_processor_id();
|
||||||
|
struct cpuinfo_x86 *c = &cpu_data(cpu_num);
|
||||||
|
|
||||||
cpu_num = raw_smp_processor_id();
|
|
||||||
uci = ucode_cpu_info + cpu;
|
uci = ucode_cpu_info + cpu;
|
||||||
mc_intel = uci->mc;
|
mc_intel = uci->mc;
|
||||||
|
|
||||||
@ -317,7 +312,7 @@ static int apply_microcode(int cpu)
|
|||||||
(unsigned long) mc_intel->bits >> 16 >> 16);
|
(unsigned long) mc_intel->bits >> 16 >> 16);
|
||||||
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
|
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
|
||||||
|
|
||||||
/* see notes above for revision 1.07. Apparent chip bug */
|
/* As documented in the SDM: Do a CPUID 1 here */
|
||||||
sync_core();
|
sync_core();
|
||||||
|
|
||||||
/* get the current revision from MSR 0x8B */
|
/* get the current revision from MSR 0x8B */
|
||||||
@ -335,6 +330,7 @@ static int apply_microcode(int cpu)
|
|||||||
(mc_intel->hdr.date >> 16) & 0xff);
|
(mc_intel->hdr.date >> 16) & 0xff);
|
||||||
|
|
||||||
uci->cpu_sig.rev = val[1];
|
uci->cpu_sig.rev = val[1];
|
||||||
|
c->microcode = val[1];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -325,15 +325,6 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
|
|||||||
return adjust_tjmax(c, id, dev);
|
return adjust_tjmax(c, id, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __devinit get_ucode_rev_on_cpu(void *edx)
|
|
||||||
{
|
|
||||||
u32 eax;
|
|
||||||
|
|
||||||
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
|
|
||||||
sync_core();
|
|
||||||
rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_name_attr(struct platform_data *pdata, struct device *dev)
|
static int create_name_attr(struct platform_data *pdata, struct device *dev)
|
||||||
{
|
{
|
||||||
sysfs_attr_init(&pdata->name_attr.attr);
|
sysfs_attr_init(&pdata->name_attr.attr);
|
||||||
@ -380,27 +371,16 @@ exit_free:
|
|||||||
static int __cpuinit chk_ucode_version(unsigned int cpu)
|
static int __cpuinit chk_ucode_version(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||||
int err;
|
|
||||||
u32 edx;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we have problem with errata AE18 of Core processors:
|
* Check if we have problem with errata AE18 of Core processors:
|
||||||
* Readings might stop update when processor visited too deep sleep,
|
* Readings might stop update when processor visited too deep sleep,
|
||||||
* fixed for stepping D0 (6EC).
|
* fixed for stepping D0 (6EC).
|
||||||
*/
|
*/
|
||||||
if (c->x86_model == 0xe && c->x86_mask < 0xc) {
|
if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
|
||||||
/* check for microcode update */
|
pr_err("Errata AE18 not fixed, update BIOS or "
|
||||||
err = smp_call_function_single(cpu, get_ucode_rev_on_cpu,
|
"microcode of the CPU!\n");
|
||||||
&edx, 1);
|
return -ENODEV;
|
||||||
if (err) {
|
|
||||||
pr_err("Cannot determine microcode revision of "
|
|
||||||
"CPU#%u (%d)!\n", cpu, err);
|
|
||||||
return -ENODEV;
|
|
||||||
} else if (edx < 0x39) {
|
|
||||||
pr_err("Errata AE18 not fixed, update BIOS or "
|
|
||||||
"microcode of the CPU!\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user