Commit eff5ddad authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86-cpu-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 cpu updates from Ingo Molnar:
 "Misc updates:

   - Extend the x86 family/model macros with a steppings dimension,
     because x86 life isn't complex enough and Intel uses steppings to
     differentiate between different CPUs. :-/

   - Convert the TSC deadline timer quirks to the steppings macros.

   - Clean up asm mnemonics.

   - Fix the handling of an AMD erratum, or in other words, fix a kernel
     erratum"

* tag 'x86-cpu-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/cpu: Use RDRAND and RDSEED mnemonics in archrandom.h
  x86/cpu: Use INVPCID mnemonic in invpcid.h
  x86/cpu/amd: Make erratum #1054 a legacy erratum
  x86/apic: Convert the TSC deadline timer matching to steppings macro
  x86/cpu: Add a X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS() macro
  x86/cpu: Add a steppings field to struct x86_cpu_id
parents 17e0a7cb 3d81b3d1
...@@ -15,16 +15,6 @@ ...@@ -15,16 +15,6 @@
#define RDRAND_RETRY_LOOPS 10 #define RDRAND_RETRY_LOOPS 10
#define RDRAND_INT ".byte 0x0f,0xc7,0xf0"
#define RDSEED_INT ".byte 0x0f,0xc7,0xf8"
#ifdef CONFIG_X86_64
# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0"
# define RDSEED_LONG ".byte 0x48,0x0f,0xc7,0xf8"
#else
# define RDRAND_LONG RDRAND_INT
# define RDSEED_LONG RDSEED_INT
#endif
/* Unconditional execution of RDRAND and RDSEED */ /* Unconditional execution of RDRAND and RDSEED */
static inline bool __must_check rdrand_long(unsigned long *v) static inline bool __must_check rdrand_long(unsigned long *v)
...@@ -32,9 +22,9 @@ static inline bool __must_check rdrand_long(unsigned long *v) ...@@ -32,9 +22,9 @@ static inline bool __must_check rdrand_long(unsigned long *v)
bool ok; bool ok;
unsigned int retry = RDRAND_RETRY_LOOPS; unsigned int retry = RDRAND_RETRY_LOOPS;
do { do {
asm volatile(RDRAND_LONG asm volatile("rdrand %[out]"
CC_SET(c) CC_SET(c)
: CC_OUT(c) (ok), "=a" (*v)); : CC_OUT(c) (ok), [out] "=r" (*v));
if (ok) if (ok)
return true; return true;
} while (--retry); } while (--retry);
...@@ -46,9 +36,9 @@ static inline bool __must_check rdrand_int(unsigned int *v) ...@@ -46,9 +36,9 @@ static inline bool __must_check rdrand_int(unsigned int *v)
bool ok; bool ok;
unsigned int retry = RDRAND_RETRY_LOOPS; unsigned int retry = RDRAND_RETRY_LOOPS;
do { do {
asm volatile(RDRAND_INT asm volatile("rdrand %[out]"
CC_SET(c) CC_SET(c)
: CC_OUT(c) (ok), "=a" (*v)); : CC_OUT(c) (ok), [out] "=r" (*v));
if (ok) if (ok)
return true; return true;
} while (--retry); } while (--retry);
...@@ -58,18 +48,18 @@ static inline bool __must_check rdrand_int(unsigned int *v) ...@@ -58,18 +48,18 @@ static inline bool __must_check rdrand_int(unsigned int *v)
static inline bool __must_check rdseed_long(unsigned long *v) static inline bool __must_check rdseed_long(unsigned long *v)
{ {
bool ok; bool ok;
asm volatile(RDSEED_LONG asm volatile("rdseed %[out]"
CC_SET(c) CC_SET(c)
: CC_OUT(c) (ok), "=a" (*v)); : CC_OUT(c) (ok), [out] "=r" (*v));
return ok; return ok;
} }
static inline bool __must_check rdseed_int(unsigned int *v) static inline bool __must_check rdseed_int(unsigned int *v)
{ {
bool ok; bool ok;
asm volatile(RDSEED_INT asm volatile("rdseed %[out]"
CC_SET(c) CC_SET(c)
: CC_OUT(c) (ok), "=a" (*v)); : CC_OUT(c) (ok), [out] "=r" (*v));
return ok; return ok;
} }
......
...@@ -20,12 +20,14 @@ ...@@ -20,12 +20,14 @@
#define X86_CENTAUR_FAM6_C7_D 0xd #define X86_CENTAUR_FAM6_C7_D 0xd
#define X86_CENTAUR_FAM6_NANO 0xf #define X86_CENTAUR_FAM6_NANO 0xf
#define X86_STEPPINGS(mins, maxs) GENMASK(maxs, mins)
/** /**
* X86_MATCH_VENDOR_FAM_MODEL_FEATURE - Base macro for CPU matching * X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE - Base macro for CPU matching
* @_vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY * @_vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
* The name is expanded to X86_VENDOR_@_vendor * The name is expanded to X86_VENDOR_@_vendor
* @_family: The family number or X86_FAMILY_ANY * @_family: The family number or X86_FAMILY_ANY
* @_model: The model number, model constant or X86_MODEL_ANY * @_model: The model number, model constant or X86_MODEL_ANY
* @_steppings: Bitmask for steppings, stepping constant or X86_STEPPING_ANY
* @_feature: A X86_FEATURE bit or X86_FEATURE_ANY * @_feature: A X86_FEATURE bit or X86_FEATURE_ANY
* @_data: Driver specific data or NULL. The internal storage * @_data: Driver specific data or NULL. The internal storage
* format is unsigned long. The supplied value, pointer * format is unsigned long. The supplied value, pointer
...@@ -37,15 +39,34 @@ ...@@ -37,15 +39,34 @@
* into another macro at the usage site for good reasons, then please * into another macro at the usage site for good reasons, then please
* start this local macro with X86_MATCH to allow easy grepping. * start this local macro with X86_MATCH to allow easy grepping.
*/ */
#define X86_MATCH_VENDOR_FAM_MODEL_FEATURE(_vendor, _family, _model, \ #define X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(_vendor, _family, _model, \
_feature, _data) { \ _steppings, _feature, _data) { \
.vendor = X86_VENDOR_##_vendor, \ .vendor = X86_VENDOR_##_vendor, \
.family = _family, \ .family = _family, \
.model = _model, \ .model = _model, \
.steppings = _steppings, \
.feature = _feature, \ .feature = _feature, \
.driver_data = (unsigned long) _data \ .driver_data = (unsigned long) _data \
} }
/**
* X86_MATCH_VENDOR_FAM_MODEL_FEATURE - Macro for CPU matching
* @_vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
* The name is expanded to X86_VENDOR_@_vendor
* @_family: The family number or X86_FAMILY_ANY
* @_model: The model number, model constant or X86_MODEL_ANY
* @_feature: A X86_FEATURE bit or X86_FEATURE_ANY
* @_data: Driver specific data or NULL. The internal storage
* format is unsigned long. The supplied value, pointer
* etc. is casted to unsigned long internally.
*
* The steppings arguments of X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE() is
* set to wildcards.
*/
#define X86_MATCH_VENDOR_FAM_MODEL_FEATURE(vendor, family, model, feature, data) \
X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(vendor, family, model, \
X86_STEPPING_ANY, feature, data)
/** /**
* X86_MATCH_VENDOR_FAM_FEATURE - Macro for matching vendor, family and CPU feature * X86_MATCH_VENDOR_FAM_FEATURE - Macro for matching vendor, family and CPU feature
* @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY * @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
...@@ -139,6 +160,10 @@ ...@@ -139,6 +160,10 @@
#define X86_MATCH_INTEL_FAM6_MODEL(model, data) \ #define X86_MATCH_INTEL_FAM6_MODEL(model, data) \
X86_MATCH_VENDOR_FAM_MODEL(INTEL, 6, INTEL_FAM6_##model, data) X86_MATCH_VENDOR_FAM_MODEL(INTEL, 6, INTEL_FAM6_##model, data)
#define X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(model, steppings, data) \
X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(INTEL, 6, INTEL_FAM6_##model, \
steppings, X86_FEATURE_ANY, data)
/* /*
* Match specific microcode revisions. * Match specific microcode revisions.
* *
......
...@@ -12,12 +12,9 @@ static inline void __invpcid(unsigned long pcid, unsigned long addr, ...@@ -12,12 +12,9 @@ static inline void __invpcid(unsigned long pcid, unsigned long addr,
* stale TLB entries and, especially if we're flushing global * stale TLB entries and, especially if we're flushing global
* mappings, we don't want the compiler to reorder any subsequent * mappings, we don't want the compiler to reorder any subsequent
* memory accesses before the TLB flush. * memory accesses before the TLB flush.
*
* The hex opcode is invpcid (%ecx), %eax in 32-bit mode and
* invpcid (%rcx), %rax in long mode.
*/ */
asm volatile (".byte 0x66, 0x0f, 0x38, 0x82, 0x01" asm volatile("invpcid %[desc], %[type]"
: : "m" (desc), "a" (type), "c" (&desc) : "memory"); :: [desc] "m" (desc), [type] "r" (type) : "memory");
} }
#define INVPCID_TYPE_INDIV_ADDR 0 #define INVPCID_TYPE_INDIV_ADDR 0
......
...@@ -544,46 +544,20 @@ static struct clock_event_device lapic_clockevent = { ...@@ -544,46 +544,20 @@ static struct clock_event_device lapic_clockevent = {
}; };
static DEFINE_PER_CPU(struct clock_event_device, lapic_events); static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
static __init u32 hsx_deadline_rev(void) static const struct x86_cpu_id deadline_match[] __initconst = {
{ X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(HASWELL_X, X86_STEPPINGS(0x2, 0x2), 0x3a), /* EP */
switch (boot_cpu_data.x86_stepping) { X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(HASWELL_X, X86_STEPPINGS(0x4, 0x4), 0x0f), /* EX */
case 0x02: return 0x3a; /* EP */
case 0x04: return 0x0f; /* EX */
}
return ~0U;
}
static __init u32 bdx_deadline_rev(void)
{
switch (boot_cpu_data.x86_stepping) {
case 0x02: return 0x00000011;
case 0x03: return 0x0700000e;
case 0x04: return 0x0f00000c;
case 0x05: return 0x0e000003;
}
return ~0U;
}
static __init u32 skx_deadline_rev(void)
{
switch (boot_cpu_data.x86_stepping) {
case 0x03: return 0x01000136;
case 0x04: return 0x02000014;
}
if (boot_cpu_data.x86_stepping > 4) X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020),
return 0;
return ~0U; X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x2, 0x2), 0x00000011),
} X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x3, 0x3), 0x0700000e),
X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x4, 0x4), 0x0f00000c),
X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x5, 0x5), 0x0e000003),
static const struct x86_cpu_id deadline_match[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x3, 0x3), 0x01000136),
X86_MATCH_INTEL_FAM6_MODEL( HASWELL_X, &hsx_deadline_rev), X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x4, 0x4), 0x02000014),
X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020), X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x5, 0xf), 0),
X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_D, &bdx_deadline_rev),
X86_MATCH_INTEL_FAM6_MODEL( SKYLAKE_X, &skx_deadline_rev),
X86_MATCH_INTEL_FAM6_MODEL( HASWELL, 0x22), X86_MATCH_INTEL_FAM6_MODEL( HASWELL, 0x22),
X86_MATCH_INTEL_FAM6_MODEL( HASWELL_L, 0x20), X86_MATCH_INTEL_FAM6_MODEL( HASWELL_L, 0x20),
...@@ -615,14 +589,7 @@ static __init bool apic_validate_deadline_timer(void) ...@@ -615,14 +589,7 @@ static __init bool apic_validate_deadline_timer(void)
if (!m) if (!m)
return true; return true;
/* rev = (u32)m->driver_data;
* Function pointers will have the MSB set due to address layout,
* immediate revisions will not.
*/
if ((long)m->driver_data < 0)
rev = ((u32 (*)(void))(m->driver_data))();
else
rev = (u32)m->driver_data;
if (boot_cpu_data.microcode >= rev) if (boot_cpu_data.microcode >= rev)
return true; return true;
......
...@@ -1145,8 +1145,7 @@ static const int amd_erratum_383[] = ...@@ -1145,8 +1145,7 @@ static const int amd_erratum_383[] =
/* #1054: Instructions Retired Performance Counter May Be Inaccurate */ /* #1054: Instructions Retired Performance Counter May Be Inaccurate */
static const int amd_erratum_1054[] = static const int amd_erratum_1054[] =
AMD_OSVW_ERRATUM(0, AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf)); AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf));
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
{ {
......
...@@ -39,13 +39,18 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match) ...@@ -39,13 +39,18 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match)
const struct x86_cpu_id *m; const struct x86_cpu_id *m;
struct cpuinfo_x86 *c = &boot_cpu_data; struct cpuinfo_x86 *c = &boot_cpu_data;
for (m = match; m->vendor | m->family | m->model | m->feature; m++) { for (m = match;
m->vendor | m->family | m->model | m->steppings | m->feature;
m++) {
if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor) if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor)
continue; continue;
if (m->family != X86_FAMILY_ANY && c->x86 != m->family) if (m->family != X86_FAMILY_ANY && c->x86 != m->family)
continue; continue;
if (m->model != X86_MODEL_ANY && c->x86_model != m->model) if (m->model != X86_MODEL_ANY && c->x86_model != m->model)
continue; continue;
if (m->steppings != X86_STEPPING_ANY &&
!(BIT(c->x86_stepping) & m->steppings))
continue;
if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature)) if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature))
continue; continue;
return m; return m;
......
...@@ -663,6 +663,7 @@ struct x86_cpu_id { ...@@ -663,6 +663,7 @@ struct x86_cpu_id {
__u16 vendor; __u16 vendor;
__u16 family; __u16 family;
__u16 model; __u16 model;
__u16 steppings;
__u16 feature; /* bit index */ __u16 feature; /* bit index */
kernel_ulong_t driver_data; kernel_ulong_t driver_data;
}; };
...@@ -671,6 +672,7 @@ struct x86_cpu_id { ...@@ -671,6 +672,7 @@ struct x86_cpu_id {
#define X86_VENDOR_ANY 0xffff #define X86_VENDOR_ANY 0xffff
#define X86_FAMILY_ANY 0 #define X86_FAMILY_ANY 0
#define X86_MODEL_ANY 0 #define X86_MODEL_ANY 0
#define X86_STEPPING_ANY 0
#define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */ #define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */
/* /*
......
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