Commit b3eda8d0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86/microcode changes from Ingo Molnar:
 "The biggest changes are to AMD microcode patching: add code for
  caching all microcode patches which belong to the current family on
  which we're running, in the kernel.

  We look up the patch needed for each core from the cache at
  patch-application time instead of holding a single patch per-system"

* 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86, microcode, AMD: Fix use after free in free_cache()
  x86, microcode, AMD: Rewrite patch application procedure
  x86, microcode, AMD: Add a small, per-family patches cache
  x86, microcode, AMD: Add reverse equiv table search
  x86, microcode: Add a refresh firmware flag to ->request_microcode_fw
  x86, microcode, AMD: Read CPUID(1).EAX on the correct cpu
  x86, microcode, AMD: Check before applying a patch
  x86, microcode, AMD: Remove useless get_ucode_data wrapper
  x86, microcode: Straighten out Kconfig text
  x86, microcode: Cleanup cpu hotplug notifier callback
  x86, microcode: Drop uci->mc check on resume path
  x86, microcode: Save an indentation level in reload_for_cpu
parents a5fa7b7d bd131781
...@@ -986,25 +986,25 @@ config X86_REBOOTFIXUPS ...@@ -986,25 +986,25 @@ config X86_REBOOTFIXUPS
Say N otherwise. Say N otherwise.
config MICROCODE config MICROCODE
tristate "/dev/cpu/microcode - microcode support" tristate "CPU microcode loading support"
select FW_LOADER select FW_LOADER
---help--- ---help---
If you say Y here, you will be able to update the microcode on If you say Y here, you will be able to update the microcode on
certain Intel and AMD processors. The Intel support is for the certain Intel and AMD processors. The Intel support is for the
IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4,
Pentium 4, Xeon etc. The AMD support is for family 0x10 and Xeon etc. The AMD support is for families 0x10 and later. You will
0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra. obviously need the actual microcode binary data itself which is not
You will obviously need the actual microcode binary data itself shipped with the Linux kernel.
which is not shipped with the Linux kernel.
This option selects the general module only, you need to select This option selects the general module only, you need to select
at least one vendor specific module as well. at least one vendor specific module as well.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the module
module will be called microcode. will be called microcode.
config MICROCODE_INTEL config MICROCODE_INTEL
bool "Intel microcode patch loading support" bool "Intel microcode loading support"
depends on MICROCODE depends on MICROCODE
default MICROCODE default MICROCODE
select FW_LOADER select FW_LOADER
...@@ -1017,7 +1017,7 @@ config MICROCODE_INTEL ...@@ -1017,7 +1017,7 @@ config MICROCODE_INTEL
<http://www.urbanmyth.org/microcode/>. <http://www.urbanmyth.org/microcode/>.
config MICROCODE_AMD config MICROCODE_AMD
bool "AMD microcode patch loading support" bool "AMD microcode loading support"
depends on MICROCODE depends on MICROCODE
select FW_LOADER select FW_LOADER
---help--- ---help---
......
...@@ -15,8 +15,8 @@ struct microcode_ops { ...@@ -15,8 +15,8 @@ struct microcode_ops {
enum ucode_state (*request_microcode_user) (int cpu, enum ucode_state (*request_microcode_user) (int cpu,
const void __user *buf, size_t size); const void __user *buf, size_t size);
enum ucode_state (*request_microcode_fw) (int cpu, enum ucode_state (*request_microcode_fw) (int cpu, struct device *,
struct device *device); bool refresh_fw);
void (*microcode_fini_cpu) (int cpu); void (*microcode_fini_cpu) (int cpu);
...@@ -49,12 +49,6 @@ static inline struct microcode_ops * __init init_intel_microcode(void) ...@@ -49,12 +49,6 @@ static inline struct microcode_ops * __init init_intel_microcode(void)
#ifdef CONFIG_MICROCODE_AMD #ifdef CONFIG_MICROCODE_AMD
extern struct microcode_ops * __init init_amd_microcode(void); extern struct microcode_ops * __init init_amd_microcode(void);
extern void __exit exit_amd_microcode(void); extern void __exit exit_amd_microcode(void);
static inline void get_ucode_data(void *to, const u8 *from, size_t n)
{
memcpy(to, from, n);
}
#else #else
static inline struct microcode_ops * __init init_amd_microcode(void) static inline struct microcode_ops * __init init_amd_microcode(void)
{ {
......
This diff is collapsed.
...@@ -279,19 +279,18 @@ static struct platform_device *microcode_pdev; ...@@ -279,19 +279,18 @@ static struct platform_device *microcode_pdev;
static int reload_for_cpu(int cpu) static int reload_for_cpu(int cpu)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
enum ucode_state ustate;
int err = 0; int err = 0;
if (uci->valid) { if (!uci->valid)
enum ucode_state ustate; return err;
ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev);
if (ustate == UCODE_OK)
apply_microcode_on_target(cpu);
else
if (ustate == UCODE_ERROR)
err = -EINVAL;
}
ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev, true);
if (ustate == UCODE_OK)
apply_microcode_on_target(cpu);
else
if (ustate == UCODE_ERROR)
err = -EINVAL;
return err; return err;
} }
...@@ -373,18 +372,15 @@ static void microcode_fini_cpu(int cpu) ...@@ -373,18 +372,15 @@ static void microcode_fini_cpu(int cpu)
static enum ucode_state microcode_resume_cpu(int cpu) static enum ucode_state microcode_resume_cpu(int cpu)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
if (!uci->mc)
return UCODE_NFOUND;
pr_debug("CPU%d updated upon resume\n", cpu); pr_debug("CPU%d updated upon resume\n", cpu);
apply_microcode_on_target(cpu);
if (apply_microcode_on_target(cpu))
return UCODE_ERROR;
return UCODE_OK; return UCODE_OK;
} }
static enum ucode_state microcode_init_cpu(int cpu) static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
{ {
enum ucode_state ustate; enum ucode_state ustate;
...@@ -395,7 +391,8 @@ static enum ucode_state microcode_init_cpu(int cpu) ...@@ -395,7 +391,8 @@ static enum ucode_state microcode_init_cpu(int cpu)
if (system_state != SYSTEM_RUNNING) if (system_state != SYSTEM_RUNNING)
return UCODE_NFOUND; return UCODE_NFOUND;
ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev); ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev,
refresh_fw);
if (ustate == UCODE_OK) { if (ustate == UCODE_OK) {
pr_debug("CPU%d updated upon init\n", cpu); pr_debug("CPU%d updated upon init\n", cpu);
...@@ -408,14 +405,11 @@ static enum ucode_state microcode_init_cpu(int cpu) ...@@ -408,14 +405,11 @@ static enum ucode_state microcode_init_cpu(int cpu)
static enum ucode_state microcode_update_cpu(int cpu) static enum ucode_state microcode_update_cpu(int cpu)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
enum ucode_state ustate;
if (uci->valid) if (uci->valid)
ustate = microcode_resume_cpu(cpu); return microcode_resume_cpu(cpu);
else
ustate = microcode_init_cpu(cpu);
return ustate; return microcode_init_cpu(cpu, false);
} }
static int mc_device_add(struct device *dev, struct subsys_interface *sif) static int mc_device_add(struct device *dev, struct subsys_interface *sif)
...@@ -431,7 +425,7 @@ static int mc_device_add(struct device *dev, struct subsys_interface *sif) ...@@ -431,7 +425,7 @@ static int mc_device_add(struct device *dev, struct subsys_interface *sif)
if (err) if (err)
return err; return err;
if (microcode_init_cpu(cpu) == UCODE_ERROR) if (microcode_init_cpu(cpu, true) == UCODE_ERROR)
return -EINVAL; return -EINVAL;
return err; return err;
...@@ -480,34 +474,41 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) ...@@ -480,34 +474,41 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
struct device *dev; struct device *dev;
dev = get_cpu_device(cpu); dev = get_cpu_device(cpu);
switch (action) {
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE: case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
microcode_update_cpu(cpu); microcode_update_cpu(cpu);
case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN:
pr_debug("CPU%d added\n", cpu); pr_debug("CPU%d added\n", cpu);
/*
* "break" is missing on purpose here because we want to fall
* through in order to create the sysfs group.
*/
case CPU_DOWN_FAILED:
if (sysfs_create_group(&dev->kobj, &mc_attr_group)) if (sysfs_create_group(&dev->kobj, &mc_attr_group))
pr_err("Failed to create group for CPU%d\n", cpu); pr_err("Failed to create group for CPU%d\n", cpu);
break; break;
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
/* Suspend is in progress, only remove the interface */ /* Suspend is in progress, only remove the interface */
sysfs_remove_group(&dev->kobj, &mc_attr_group); sysfs_remove_group(&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 * 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 * the microcode in kernel memory, so that we can reuse it when the
* CPU comes back online without unnecessarily requesting the userspace * CPU comes back online without unnecessarily requesting the userspace
* for it again. * for it again.
*/ */
case CPU_UP_CANCELED_FROZEN:
/* The CPU refused to come up during a system resume */
microcode_fini_cpu(cpu);
break;
} }
/* The CPU refused to come up during a system resume */
if (action == CPU_UP_CANCELED_FROZEN)
microcode_fini_cpu(cpu);
return NOTIFY_OK; return NOTIFY_OK;
} }
......
...@@ -405,7 +405,8 @@ static int get_ucode_fw(void *to, const void *from, size_t n) ...@@ -405,7 +405,8 @@ static int get_ucode_fw(void *to, const void *from, size_t n)
return 0; return 0;
} }
static enum ucode_state request_microcode_fw(int cpu, struct device *device) static enum ucode_state request_microcode_fw(int cpu, struct device *device,
bool refresh_fw)
{ {
char name[30]; char name[30];
struct cpuinfo_x86 *c = &cpu_data(cpu); struct cpuinfo_x86 *c = &cpu_data(cpu);
......
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