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

Commit df8edfa9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull x86 cpuid changes from Ingo Molnar:
 "The biggest change is x86 CPU bug handling refactoring and cleanups,
  by Borislav Petkov"

* 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86, CPU, AMD: Drop useless label
  x86, AMD: Correct {rd,wr}msr_amd_safe warnings
  x86: Fold-in trivial check_config function
  x86, cpu: Convert AMD Erratum 400
  x86, cpu: Convert AMD Erratum 383
  x86, cpu: Convert Cyrix coma bug detection
  x86, cpu: Convert FDIV bug detection
  x86, cpu: Convert F00F bug detection
  x86, cpu: Expand cpufeature facility to include cpu bugs
parents 874f6d1b 1077c932
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#endif

#define NCAPINTS	10	/* N 32-bit words worth of info */
#define NBUGINTS	1	/* N 32-bit bug flags */

/*
 * Note: If the comment begins with a quoted string, that string is used
@@ -218,6 +219,17 @@
#define X86_FEATURE_ADX		(9*32+19) /* The ADCX and ADOX instructions */
#define X86_FEATURE_SMAP	(9*32+20) /* Supervisor Mode Access Prevention */

/*
 * BUG word(s)
 */
#define X86_BUG(x)		(NCAPINTS*32 + (x))

#define X86_BUG_F00F		X86_BUG(0) /* Intel F00F */
#define X86_BUG_FDIV		X86_BUG(1) /* FPU FDIV */
#define X86_BUG_COMA		X86_BUG(2) /* Cyrix 6x86 coma */
#define X86_BUG_AMD_TLB_MMATCH	X86_BUG(3) /* AMD Erratum 383 */
#define X86_BUG_AMD_APIC_C1E	X86_BUG(4) /* AMD Erratum 400 */

#if defined(__KERNEL__) && !defined(__ASSEMBLY__)

#include <asm/asm.h>
@@ -404,6 +416,13 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
#define static_cpu_has(bit) boot_cpu_has(bit)
#endif

#define cpu_has_bug(c, bit)	cpu_has(c, (bit))
#define set_cpu_bug(c, bit)	set_cpu_cap(c, (bit))
#define clear_cpu_bug(c, bit)	clear_cpu_cap(c, (bit));

#define static_cpu_has_bug(bit)	static_cpu_has((bit))
#define boot_cpu_has_bug(bit)	cpu_has_bug(&boot_cpu_data, (bit))

#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */

#endif /* _ASM_X86_CPUFEATURE_H */
+1 −24
Original line number Diff line number Diff line
@@ -91,9 +91,6 @@ struct cpuinfo_x86 {
	/* Problems on some 486Dx4's and old 386's: */
	char			hard_math;
	char			rfu;
	char			fdiv_bug;
	char			f00f_bug;
	char			coma_bug;
	char			pad0;
#else
	/* Number of 4K pages in DTLB/ITLB combined(in pages): */
@@ -107,7 +104,7 @@ struct cpuinfo_x86 {
	__u32			extended_cpuid_level;
	/* Maximum supported CPUID level, -1=no CPUID: */
	int			cpuid_level;
	__u32			x86_capability[NCAPINTS];
	__u32			x86_capability[NCAPINTS + NBUGINTS];
	char			x86_vendor_id[16];
	char			x86_model_id[64];
	/* in KB - valid for CPUS which support this call: */
@@ -973,26 +970,6 @@ unsigned long calc_aperfmperf_ratio(struct aperfmperf *old,
	return ratio;
}

/*
 * AMD errata checking
 */
#ifdef CONFIG_CPU_SUP_AMD
extern const int amd_erratum_383[];
extern const int amd_erratum_400[];
extern bool cpu_has_amd_erratum(const int *);

#define AMD_LEGACY_ERRATUM(...)		{ -1, __VA_ARGS__, 0 }
#define AMD_OSVW_ERRATUM(osvw_id, ...)	{ osvw_id, __VA_ARGS__, 0 }
#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
	((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
#define AMD_MODEL_RANGE_FAMILY(range)	(((range) >> 24) & 0xff)
#define AMD_MODEL_RANGE_START(range)	(((range) >> 12) & 0xfff)
#define AMD_MODEL_RANGE_END(range)	((range) & 0xfff)

#else
#define cpu_has_amd_erratum(x)	(false)
#endif /* CONFIG_CPU_SUP_AMD */

extern unsigned long arch_align_stack(unsigned long sp);
extern void free_init_pages(char *what, unsigned long begin, unsigned long end);

+1 −1
Original line number Diff line number Diff line
@@ -271,7 +271,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
		replacement = (u8 *)&a->repl_offset + a->repl_offset;
		BUG_ON(a->replacementlen > a->instrlen);
		BUG_ON(a->instrlen > sizeof(insnbuf));
		BUG_ON(a->cpuid >= NCAPINTS*32);
		BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32);
		if (!boot_cpu_has(a->cpuid))
			continue;

+29 −19
Original line number Diff line number Diff line
@@ -20,11 +20,11 @@

static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
{
	struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
	u32 gprs[8] = { 0 };
	int err;

	WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
	WARN_ONCE((boot_cpu_data.x86 != 0xf),
		  "%s should only be used on K8!\n", __func__);

	gprs[1] = msr;
	gprs[7] = 0x9c5a203a;
@@ -38,10 +38,10 @@ static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)

static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
{
	struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
	u32 gprs[8] = { 0 };

	WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
	WARN_ONCE((boot_cpu_data.x86 != 0xf),
		  "%s should only be used on K8!\n", __func__);

	gprs[0] = (u32)val;
	gprs[1] = msr;
@@ -192,11 +192,11 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
	/* Athlon 660/661 is valid. */
	if ((c->x86_model == 6) && ((c->x86_mask == 0) ||
	    (c->x86_mask == 1)))
		goto valid_k7;
		return;

	/* Duron 670 is valid */
	if ((c->x86_model == 7) && (c->x86_mask == 0))
		goto valid_k7;
		return;

	/*
	 * Athlon 662, Duron 671, and Athlon >model 7 have capability
@@ -209,7 +209,7 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
	    ((c->x86_model == 7) && (c->x86_mask >= 1)) ||
	     (c->x86_model > 7))
		if (cpu_has_mp)
			goto valid_k7;
			return;

	/* If we get here, not a certified SMP capable AMD system. */

@@ -220,9 +220,6 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
	WARN_ONCE(1, "WARNING: This combination of AMD"
		" processors is not suitable for SMP.\n");
	add_taint(TAINT_UNSAFE_SMP, LOCKDEP_NOW_UNRELIABLE);

valid_k7:
	;
}

static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c)
@@ -513,6 +510,10 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
#endif
}

static const int amd_erratum_383[];
static const int amd_erratum_400[];
static bool cpu_has_amd_erratum(const int *erratum);

static void __cpuinit init_amd(struct cpuinfo_x86 *c)
{
	u32 dummy;
@@ -727,8 +728,14 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
		rdmsrl_safe(MSR_AMD64_BU_CFG2, &value);
		value &= ~(1ULL << 24);
		wrmsrl_safe(MSR_AMD64_BU_CFG2, value);

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

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

	rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
}

@@ -847,8 +854,7 @@ cpu_dev_register(amd_cpu_dev);
 * AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
 * have an OSVW id assigned, which it takes as first argument. Both take a
 * variable number of family-specific model-stepping ranges created by
 * AMD_MODEL_RANGE(). Each erratum also has to be declared as extern const
 * int[] in arch/x86/include/asm/processor.h.
 * AMD_MODEL_RANGE().
 *
 * Example:
 *
@@ -858,16 +864,22 @@ cpu_dev_register(amd_cpu_dev);
 *			   AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
 */

const int amd_erratum_400[] =
#define AMD_LEGACY_ERRATUM(...)		{ -1, __VA_ARGS__, 0 }
#define AMD_OSVW_ERRATUM(osvw_id, ...)	{ osvw_id, __VA_ARGS__, 0 }
#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
	((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
#define AMD_MODEL_RANGE_FAMILY(range)	(((range) >> 24) & 0xff)
#define AMD_MODEL_RANGE_START(range)	(((range) >> 12) & 0xfff)
#define AMD_MODEL_RANGE_END(range)	((range) & 0xfff)

static const int amd_erratum_400[] =
	AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
			    AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
EXPORT_SYMBOL_GPL(amd_erratum_400);

const int amd_erratum_383[] =
static const int amd_erratum_383[] =
	AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
EXPORT_SYMBOL_GPL(amd_erratum_383);

bool cpu_has_amd_erratum(const int *erratum)
static bool cpu_has_amd_erratum(const int *erratum)
{
	struct cpuinfo_x86 *cpu = __this_cpu_ptr(&cpu_info);
	int osvw_id = *erratum++;
@@ -908,5 +920,3 @@ bool cpu_has_amd_erratum(const int *erratum)

	return false;
}

EXPORT_SYMBOL_GPL(cpu_has_amd_erratum);
+15 −19
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ static void __init check_fpu(void)
	 * trap_init() enabled FXSR and company _before_ testing for FP
	 * problems here.
	 *
	 * Test for the divl bug..
	 * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug
	 */
	__asm__("fninit\n\t"
		"fldl %1\n\t"
@@ -75,10 +75,19 @@ static void __init check_fpu(void)

	kernel_fpu_end();

	boot_cpu_data.fdiv_bug = fdiv_bug;
	if (boot_cpu_data.fdiv_bug)
	if (fdiv_bug) {
		set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV);
		pr_warn("Hmm, FPU with FDIV bug\n");
	}
}

void __init check_bugs(void)
{
	identify_boot_cpu();
#ifndef CONFIG_SMP
	pr_info("CPU: ");
	print_cpu_info(&boot_cpu_data);
#endif

	/*
	 * Check whether we are able to run this kernel safely on SMP.
@@ -87,22 +96,9 @@ static void __init check_fpu(void)
	 * - In order to run on anything without a TSC, we need to be
	 *   compiled for a i486.
	 */

static void __init check_config(void)
{
	if (boot_cpu_data.x86 < 4)
		panic("Kernel requires i486+ for 'invlpg' and other features");
}


void __init check_bugs(void)
{
	identify_boot_cpu();
#ifndef CONFIG_SMP
	pr_info("CPU: ");
	print_cpu_info(&boot_cpu_data);
#endif
	check_config();
	init_utsname()->machine[1] =
		'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
	alternative_instructions();
Loading