Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7067552d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull x86 fixes from Ingo Molnar:
 "Two AMD microcode loader fixes and an OLPC firmware support fix"

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86, microcode, AMD: Fix early microcode loading
  x86, microcode, AMD: Make cpu_has_amd_erratum() use the correct struct cpuinfo_x86
  x86: Don't clear olpc_ofw_header when sentinel is detected
parents e91dade5 ccb1f55e
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -35,9 +35,9 @@ static void sanitize_boot_params(struct boot_params *boot_params)
	 */
	 */
	if (boot_params->sentinel) {
	if (boot_params->sentinel) {
		/* fields in boot_params are left uninitialized, clear them */
		/* fields in boot_params are left uninitialized, clear them */
		memset(&boot_params->olpc_ofw_header, 0,
		memset(&boot_params->ext_ramdisk_image, 0,
		       (char *)&boot_params->efi_info -
		       (char *)&boot_params->efi_info -
			(char *)&boot_params->olpc_ofw_header);
			(char *)&boot_params->ext_ramdisk_image);
		memset(&boot_params->kbd_status, 0,
		memset(&boot_params->kbd_status, 0,
		       (char *)&boot_params->hdr -
		       (char *)&boot_params->hdr -
		       (char *)&boot_params->kbd_status);
		       (char *)&boot_params->kbd_status);
+1 −1
Original line number Original line Diff line number Diff line
@@ -59,7 +59,7 @@ static inline u16 find_equiv_id(struct equiv_cpu_entry *equiv_cpu_table,


extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
extern int apply_microcode_amd(int cpu);
extern int apply_microcode_amd(int cpu);
extern enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size);
extern enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);


#ifdef CONFIG_MICROCODE_AMD_EARLY
#ifdef CONFIG_MICROCODE_AMD_EARLY
#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32
+5 −15
Original line number Original line Diff line number Diff line
@@ -512,7 +512,7 @@ static void early_init_amd(struct cpuinfo_x86 *c)


static const int amd_erratum_383[];
static const int amd_erratum_383[];
static const int amd_erratum_400[];
static const int amd_erratum_400[];
static bool cpu_has_amd_erratum(const int *erratum);
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum);


static void init_amd(struct cpuinfo_x86 *c)
static void init_amd(struct cpuinfo_x86 *c)
{
{
@@ -729,11 +729,11 @@ static void init_amd(struct cpuinfo_x86 *c)
		value &= ~(1ULL << 24);
		value &= ~(1ULL << 24);
		wrmsrl_safe(MSR_AMD64_BU_CFG2, value);
		wrmsrl_safe(MSR_AMD64_BU_CFG2, value);


		if (cpu_has_amd_erratum(amd_erratum_383))
		if (cpu_has_amd_erratum(c, amd_erratum_383))
			set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
			set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
	}
	}


	if (cpu_has_amd_erratum(amd_erratum_400))
	if (cpu_has_amd_erratum(c, amd_erratum_400))
		set_cpu_bug(c, X86_BUG_AMD_APIC_C1E);
		set_cpu_bug(c, X86_BUG_AMD_APIC_C1E);


	rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
	rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
@@ -878,23 +878,13 @@ static const int amd_erratum_400[] =
static const int amd_erratum_383[] =
static const int amd_erratum_383[] =
	AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
	AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));


static bool cpu_has_amd_erratum(const int *erratum)

static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
{
{
	struct cpuinfo_x86 *cpu = __this_cpu_ptr(&cpu_info);
	int osvw_id = *erratum++;
	int osvw_id = *erratum++;
	u32 range;
	u32 range;
	u32 ms;
	u32 ms;


	/*
	 * If called early enough that current_cpu_data hasn't been initialized
	 * yet, fall back to boot_cpu_data.
	 */
	if (cpu->x86 == 0)
		cpu = &boot_cpu_data;

	if (cpu->x86_vendor != X86_VENDOR_AMD)
		return false;

	if (osvw_id >= 0 && osvw_id < 65536 &&
	if (osvw_id >= 0 && osvw_id < 65536 &&
	    cpu_has(cpu, X86_FEATURE_OSVW)) {
	    cpu_has(cpu, X86_FEATURE_OSVW)) {
		u64 osvw_len;
		u64 osvw_len;
+13 −14
Original line number Original line Diff line number Diff line
@@ -145,10 +145,9 @@ static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
	return 0;
	return 0;
}
}


static unsigned int verify_patch_size(int cpu, u32 patch_size,
static unsigned int verify_patch_size(u8 family, u32 patch_size,
				      unsigned int size)
				      unsigned int size)
{
{
	struct cpuinfo_x86 *c = &cpu_data(cpu);
	u32 max_size;
	u32 max_size;


#define F1XH_MPB_MAX_SIZE 2048
#define F1XH_MPB_MAX_SIZE 2048
@@ -156,7 +155,7 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size,
#define F15H_MPB_MAX_SIZE 4096
#define F15H_MPB_MAX_SIZE 4096
#define F16H_MPB_MAX_SIZE 3458
#define F16H_MPB_MAX_SIZE 3458


	switch (c->x86) {
	switch (family) {
	case 0x14:
	case 0x14:
		max_size = F14H_MPB_MAX_SIZE;
		max_size = F14H_MPB_MAX_SIZE;
		break;
		break;
@@ -277,9 +276,8 @@ static void cleanup(void)
 * driver cannot continue functioning normally. In such cases, we tear
 * driver cannot continue functioning normally. In such cases, we tear
 * down everything we've used up so far and exit.
 * down everything we've used up so far and exit.
 */
 */
static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover)
{
{
	struct cpuinfo_x86 *c = &cpu_data(cpu);
	struct microcode_header_amd *mc_hdr;
	struct microcode_header_amd *mc_hdr;
	struct ucode_patch *patch;
	struct ucode_patch *patch;
	unsigned int patch_size, crnt_size, ret;
	unsigned int patch_size, crnt_size, ret;
@@ -299,7 +297,7 @@ static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)


	/* check if patch is for the current family */
	/* check if patch is for the current family */
	proc_fam = ((proc_fam >> 8) & 0xf) + ((proc_fam >> 20) & 0xff);
	proc_fam = ((proc_fam >> 8) & 0xf) + ((proc_fam >> 20) & 0xff);
	if (proc_fam != c->x86)
	if (proc_fam != family)
		return crnt_size;
		return crnt_size;


	if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
	if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
@@ -308,7 +306,7 @@ static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
		return crnt_size;
		return crnt_size;
	}
	}


	ret = verify_patch_size(cpu, patch_size, leftover);
	ret = verify_patch_size(family, patch_size, leftover);
	if (!ret) {
	if (!ret) {
		pr_err("Patch-ID 0x%08x: size mismatch.\n", mc_hdr->patch_id);
		pr_err("Patch-ID 0x%08x: size mismatch.\n", mc_hdr->patch_id);
		return crnt_size;
		return crnt_size;
@@ -339,7 +337,8 @@ static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
	return crnt_size;
	return crnt_size;
}
}


static enum ucode_state __load_microcode_amd(int cpu, const u8 *data, size_t size)
static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
					     size_t size)
{
{
	enum ucode_state ret = UCODE_ERROR;
	enum ucode_state ret = UCODE_ERROR;
	unsigned int leftover;
	unsigned int leftover;
@@ -362,7 +361,7 @@ static enum ucode_state __load_microcode_amd(int cpu, const u8 *data, size_t siz
	}
	}


	while (leftover) {
	while (leftover) {
		crnt_size = verify_and_add_patch(cpu, fw, leftover);
		crnt_size = verify_and_add_patch(family, fw, leftover);
		if (crnt_size < 0)
		if (crnt_size < 0)
			return ret;
			return ret;


@@ -373,22 +372,22 @@ static enum ucode_state __load_microcode_amd(int cpu, const u8 *data, size_t siz
	return UCODE_OK;
	return UCODE_OK;
}
}


enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
{
{
	enum ucode_state ret;
	enum ucode_state ret;


	/* free old equiv table */
	/* free old equiv table */
	free_equiv_cpu_table();
	free_equiv_cpu_table();


	ret = __load_microcode_amd(cpu, data, size);
	ret = __load_microcode_amd(family, data, size);


	if (ret != UCODE_OK)
	if (ret != UCODE_OK)
		cleanup();
		cleanup();


#if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32)
#if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32)
	/* save BSP's matching patch for early load */
	/* save BSP's matching patch for early load */
	if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
	if (cpu_data(smp_processor_id()).cpu_index == boot_cpu_data.cpu_index) {
		struct ucode_patch *p = find_patch(cpu);
		struct ucode_patch *p = find_patch(smp_processor_id());
		if (p) {
		if (p) {
			memset(amd_bsp_mpb, 0, MPB_MAX_SIZE);
			memset(amd_bsp_mpb, 0, MPB_MAX_SIZE);
			memcpy(amd_bsp_mpb, p->data, min_t(u32, ksize(p->data),
			memcpy(amd_bsp_mpb, p->data, min_t(u32, ksize(p->data),
@@ -441,7 +440,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
		goto fw_release;
		goto fw_release;
	}
	}


	ret = load_microcode_amd(cpu, fw->data, fw->size);
	ret = load_microcode_amd(c->x86, fw->data, fw->size);


 fw_release:
 fw_release:
	release_firmware(fw);
	release_firmware(fw);
+13 −14
Original line number Original line Diff line number Diff line
@@ -238,25 +238,17 @@ static void __init collect_cpu_sig_on_bsp(void *arg)
	uci->cpu_sig.sig = cpuid_eax(0x00000001);
	uci->cpu_sig.sig = cpuid_eax(0x00000001);
}
}
#else
#else
static void collect_cpu_info_amd_early(struct cpuinfo_x86 *c,
void load_ucode_amd_ap(void)
						 struct ucode_cpu_info *uci)
{
{
	unsigned int cpu = smp_processor_id();
	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
	u32 rev, eax;
	u32 rev, eax;


	rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
	rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
	eax = cpuid_eax(0x00000001);
	eax = cpuid_eax(0x00000001);


	uci->cpu_sig.sig = eax;
	uci->cpu_sig.rev = rev;
	uci->cpu_sig.rev = rev;
	c->microcode = rev;
	uci->cpu_sig.sig = eax;
	c->x86 = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
}

void load_ucode_amd_ap(void)
{
	unsigned int cpu = smp_processor_id();

	collect_cpu_info_amd_early(&cpu_data(cpu), ucode_cpu_info + cpu);


	if (cpu && !ucode_loaded) {
	if (cpu && !ucode_loaded) {
		void *ucode;
		void *ucode;
@@ -265,8 +257,10 @@ void load_ucode_amd_ap(void)
			return;
			return;


		ucode = (void *)(initrd_start + ucode_offset);
		ucode = (void *)(initrd_start + ucode_offset);
		if (load_microcode_amd(0, ucode, ucode_size) != UCODE_OK)
		eax   = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
		if (load_microcode_amd(eax, ucode, ucode_size) != UCODE_OK)
			return;
			return;

		ucode_loaded = true;
		ucode_loaded = true;
	}
	}


@@ -278,6 +272,8 @@ int __init save_microcode_in_initrd_amd(void)
{
{
	enum ucode_state ret;
	enum ucode_state ret;
	void *ucode;
	void *ucode;
	u32 eax;

#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32
	unsigned int bsp = boot_cpu_data.cpu_index;
	unsigned int bsp = boot_cpu_data.cpu_index;
	struct ucode_cpu_info *uci = ucode_cpu_info + bsp;
	struct ucode_cpu_info *uci = ucode_cpu_info + bsp;
@@ -293,7 +289,10 @@ int __init save_microcode_in_initrd_amd(void)
		return 0;
		return 0;


	ucode = (void *)(initrd_start + ucode_offset);
	ucode = (void *)(initrd_start + ucode_offset);
	ret = load_microcode_amd(0, ucode, ucode_size);
	eax   = cpuid_eax(0x00000001);
	eax   = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);

	ret = load_microcode_amd(eax, ucode, ucode_size);
	if (ret != UCODE_OK)
	if (ret != UCODE_OK)
		return -EINVAL;
		return -EINVAL;