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
Unified · Split
| @@ -15,16 +15,6 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | #define RDRAND_RETRY_LOOPS 10 |
| 17 | 17 | |
| 18 | −#define RDRAND_INT ".byte 0x0f,0xc7,0xf0" | |
| 19 | −#define RDSEED_INT ".byte 0x0f,0xc7,0xf8" | |
| 20 | −#ifdef CONFIG_X86_64 | |
| 21 | −# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0" | |
| 22 | −# define RDSEED_LONG ".byte 0x48,0x0f,0xc7,0xf8" | |
| 23 | −#else | |
| 24 | −# define RDRAND_LONG RDRAND_INT | |
| 25 | −# define RDSEED_LONG RDSEED_INT | |
| 26 | −#endif | |
| 27 | − | |
| 28 | 18 | /* Unconditional execution of RDRAND and RDSEED */ |
| 29 | 19 | |
| 30 | 20 | static inline bool __must_check rdrand_long(unsigned long *v) |
| @@ -32,9 +22,9 @@ static inline bool __must_check rdrand_long(unsigned long *v) · 1 unmodified line | ||
| 32 | 22 | bool ok; |
| 33 | 23 | unsigned int retry = RDRAND_RETRY_LOOPS; |
| 34 | 24 | do { |
| 35 | − asm volatile(RDRAND_LONG | |
| 25 | + asm volatile("rdrand %[out]" | |
| 36 | 26 | CC_SET(c) |
| 37 | − : CC_OUT(c) (ok), "=a" (*v)); | |
| 27 | + : CC_OUT(c) (ok), [out] "=r" (*v)); | |
| 38 | 28 | if (ok) |
| 39 | 29 | return true; |
| 40 | 30 | } while (--retry); |
| @@ -46,9 +36,9 @@ static inline bool __must_check rdrand_int(unsigned int *v) · 5 unmodified lines | ||
| 46 | 36 | bool ok; |
| 47 | 37 | unsigned int retry = RDRAND_RETRY_LOOPS; |
| 48 | 38 | do { |
| 49 | − asm volatile(RDRAND_INT | |
| 39 | + asm volatile("rdrand %[out]" | |
| 50 | 40 | CC_SET(c) |
| 51 | − : CC_OUT(c) (ok), "=a" (*v)); | |
| 41 | + : CC_OUT(c) (ok), [out] "=r" (*v)); | |
| 52 | 42 | if (ok) |
| 53 | 43 | return true; |
| 54 | 44 | } while (--retry); |
| @@ -58,18 +48,18 @@ static inline bool __must_check rdrand_int(unsigned int *v) · 3 unmodified lines | ||
| 58 | 48 | static inline bool __must_check rdseed_long(unsigned long *v) |
| 59 | 49 | { |
| 60 | 50 | bool ok; |
| 61 | − asm volatile(RDSEED_LONG | |
| 51 | + asm volatile("rdseed %[out]" | |
| 62 | 52 | CC_SET(c) |
| 63 | − : CC_OUT(c) (ok), "=a" (*v)); | |
| 53 | + : CC_OUT(c) (ok), [out] "=r" (*v)); | |
| 64 | 54 | return ok; |
| 65 | 55 | } |
| 66 | 56 | |
| 67 | 57 | static inline bool __must_check rdseed_int(unsigned int *v) |
| 68 | 58 | { |
| 69 | 59 | bool ok; |
| 70 | − asm volatile(RDSEED_INT | |
| 60 | + asm volatile("rdseed %[out]" | |
| 71 | 61 | CC_SET(c) |
| 72 | − : CC_OUT(c) (ok), "=a" (*v)); | |
| 62 | + : CC_OUT(c) (ok), [out] "=r" (*v)); | |
| 73 | 63 | return ok; |
| 74 | 64 | } |
| 75 | 65 | |
| @@ -20,12 +20,14 @@ · 19 unmodified lines | ||
| 20 | 20 | #define X86_CENTAUR_FAM6_C7_D 0xd |
| 21 | 21 | #define X86_CENTAUR_FAM6_NANO 0xf |
| 22 | 22 | |
| 23 | +#define X86_STEPPINGS(mins, maxs) GENMASK(maxs, mins) | |
| 23 | 24 | /** |
| 24 | − * X86_MATCH_VENDOR_FAM_MODEL_FEATURE - Base macro for CPU matching | |
| 25 | + * X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE - Base macro for CPU matching | |
| 25 | 26 | * @_vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY |
| 26 | 27 | * The name is expanded to X86_VENDOR_@_vendor |
| 27 | 28 | * @_family: The family number or X86_FAMILY_ANY |
| 28 | 29 | * @_model: The model number, model constant or X86_MODEL_ANY |
| 30 | + * @_steppings: Bitmask for steppings, stepping constant or X86_STEPPING_ANY | |
| 29 | 31 | * @_feature: A X86_FEATURE bit or X86_FEATURE_ANY |
| 30 | 32 | * @_data: Driver specific data or NULL. The internal storage |
| 31 | 33 | * format is unsigned long. The supplied value, pointer |
| @@ -37,15 +39,34 @@ · 5 unmodified lines | ||
| 37 | 39 | * into another macro at the usage site for good reasons, then please |
| 38 | 40 | * start this local macro with X86_MATCH to allow easy grepping. |
| 39 | 41 | */ |
| 40 | −#define X86_MATCH_VENDOR_FAM_MODEL_FEATURE(_vendor, _family, _model, \ | |
| 41 | − _feature, _data) { \ | |
| 42 | +#define X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(_vendor, _family, _model, \ | |
| 43 | + _steppings, _feature, _data) { \ | |
| 42 | 44 | .vendor = X86_VENDOR_##_vendor, \ |
| 43 | 45 | .family = _family, \ |
| 44 | 46 | .model = _model, \ |
| 47 | + .steppings = _steppings, \ | |
| 45 | 48 | .feature = _feature, \ |
| 46 | 49 | .driver_data = (unsigned long) _data \ |
| 47 | 50 | } |
| 48 | 51 | |
| 52 | +/** | |
| 53 | + * X86_MATCH_VENDOR_FAM_MODEL_FEATURE - Macro for CPU matching | |
| 54 | + * @_vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY | |
| 55 | + * The name is expanded to X86_VENDOR_@_vendor | |
| 56 | + * @_family: The family number or X86_FAMILY_ANY | |
| 57 | + * @_model: The model number, model constant or X86_MODEL_ANY | |
| 58 | + * @_feature: A X86_FEATURE bit or X86_FEATURE_ANY | |
| 59 | + * @_data: Driver specific data or NULL. The internal storage | |
| 60 | + * format is unsigned long. The supplied value, pointer | |
| 61 | + * etc. is casted to unsigned long internally. | |
| 62 | + * | |
| 63 | + * The steppings arguments of X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE() is | |
| 64 | + * set to wildcards. | |
| 65 | + */ | |
| 66 | +#define X86_MATCH_VENDOR_FAM_MODEL_FEATURE(vendor, family, model, feature, data) \ | |
| 67 | + X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(vendor, family, model, \ | |
| 68 | + X86_STEPPING_ANY, feature, data) | |
| 69 | + | |
| 49 | 70 | /** |
| 50 | 71 | * X86_MATCH_VENDOR_FAM_FEATURE - Macro for matching vendor, family and CPU feature |
| 51 | 72 | * @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY |
| @@ -139,6 +160,10 @@ · 87 unmodified lines | ||
| 139 | 160 | #define X86_MATCH_INTEL_FAM6_MODEL(model, data) \ |
| 140 | 161 | X86_MATCH_VENDOR_FAM_MODEL(INTEL, 6, INTEL_FAM6_##model, data) |
| 141 | 162 | |
| 163 | +#define X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(model, steppings, data) \ | |
| 164 | + X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(INTEL, 6, INTEL_FAM6_##model, \ | |
| 165 | + steppings, X86_FEATURE_ANY, data) | |
| 166 | + | |
| 142 | 167 | /* |
| 143 | 168 | * Match specific microcode revisions. |
| 144 | 169 | * |
| @@ -12,12 +12,9 @@ static inline void __invpcid(unsigned long pcid, unsigned long addr, · 11 unmodified lines | ||
| 12 | 12 | * stale TLB entries and, especially if we're flushing global |
| 13 | 13 | * mappings, we don't want the compiler to reorder any subsequent |
| 14 | 14 | * memory accesses before the TLB flush. |
| 15 | − * | |
| 16 | − * The hex opcode is invpcid (%ecx), %eax in 32-bit mode and | |
| 17 | − * invpcid (%rcx), %rax in long mode. | |
| 18 | 15 | */ |
| 19 | − asm volatile (".byte 0x66, 0x0f, 0x38, 0x82, 0x01" | |
| 20 | − : : "m" (desc), "a" (type), "c" (&desc) : "memory"); | |
| 16 | + asm volatile("invpcid %[desc], %[type]" | |
| 17 | + :: [desc] "m" (desc), [type] "r" (type) : "memory"); | |
| 21 | 18 | } |
| 22 | 19 | |
| 23 | 20 | #define INVPCID_TYPE_INDIV_ADDR 0 |
| @@ -544,46 +544,20 @@ static struct clock_event_device lapic_clockevent = { · 543 unmodified lines | ||
| 544 | 544 | }; |
| 545 | 545 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); |
| 546 | 546 | |
| 547 | −static __init u32 hsx_deadline_rev(void) | |
| 548 | −{ | |
| 549 | − switch (boot_cpu_data.x86_stepping) { | |
| 550 | − case 0x02: return 0x3a; /* EP */ | |
| 551 | − case 0x04: return 0x0f; /* EX */ | |
| 552 | − } | |
| 553 | − | |
| 554 | − return ~0U; | |
| 555 | −} | |
| 556 | − | |
| 557 | −static __init u32 bdx_deadline_rev(void) | |
| 558 | −{ | |
| 559 | − switch (boot_cpu_data.x86_stepping) { | |
| 560 | − case 0x02: return 0x00000011; | |
| 561 | − case 0x03: return 0x0700000e; | |
| 562 | − case 0x04: return 0x0f00000c; | |
| 563 | − case 0x05: return 0x0e000003; | |
| 564 | − } | |
| 565 | − | |
| 566 | − return ~0U; | |
| 567 | −} | |
| 568 | − | |
| 569 | −static __init u32 skx_deadline_rev(void) | |
| 570 | −{ | |
| 571 | − switch (boot_cpu_data.x86_stepping) { | |
| 572 | − case 0x03: return 0x01000136; | |
| 573 | − case 0x04: return 0x02000014; | |
| 574 | − } | |
| 547 | +static const struct x86_cpu_id deadline_match[] __initconst = { | |
| 548 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(HASWELL_X, X86_STEPPINGS(0x2, 0x2), 0x3a), /* EP */ | |
| 549 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(HASWELL_X, X86_STEPPINGS(0x4, 0x4), 0x0f), /* EX */ | |
| 575 | 550 | |
| 576 | − if (boot_cpu_data.x86_stepping > 4) | |
| 577 | − return 0; | |
| 551 | + X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020), | |
| 578 | 552 | |
| 579 | − return ~0U; | |
| 580 | −} | |
| 553 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x2, 0x2), 0x00000011), | |
| 554 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x3, 0x3), 0x0700000e), | |
| 555 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x4, 0x4), 0x0f00000c), | |
| 556 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x5, 0x5), 0x0e000003), | |
| 581 | 557 | |
| 582 | −static const struct x86_cpu_id deadline_match[] __initconst = { | |
| 583 | − X86_MATCH_INTEL_FAM6_MODEL( HASWELL_X, &hsx_deadline_rev), | |
| 584 | − X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020), | |
| 585 | − X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_D, &bdx_deadline_rev), | |
| 586 | − X86_MATCH_INTEL_FAM6_MODEL( SKYLAKE_X, &skx_deadline_rev), | |
| 558 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x3, 0x3), 0x01000136), | |
| 559 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x4, 0x4), 0x02000014), | |
| 560 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x5, 0xf), 0), | |
| 587 | 561 | |
| 588 | 562 | X86_MATCH_INTEL_FAM6_MODEL( HASWELL, 0x22), |
| 589 | 563 | X86_MATCH_INTEL_FAM6_MODEL( HASWELL_L, 0x20), |
| @@ -615,14 +589,7 @@ static __init bool apic_validate_deadline_timer(void) · 25 unmodified lines | ||
| 615 | 589 | if (!m) |
| 616 | 590 | return true; |
| 617 | 591 | |
| 618 | − /* | |
| 619 | − * Function pointers will have the MSB set due to address layout, | |
| 620 | − * immediate revisions will not. | |
| 621 | − */ | |
| 622 | − if ((long)m->driver_data < 0) | |
| 623 | − rev = ((u32 (*)(void))(m->driver_data))(); | |
| 624 | − else | |
| 625 | − rev = (u32)m->driver_data; | |
| 592 | + rev = (u32)m->driver_data; | |
| 626 | 593 | |
| 627 | 594 | if (boot_cpu_data.microcode >= rev) |
| 628 | 595 | return true; |
| @@ -1145,8 +1145,7 @@ static const int amd_erratum_383[] = · 1144 unmodified lines | ||
| 1145 | 1145 | |
| 1146 | 1146 | /* #1054: Instructions Retired Performance Counter May Be Inaccurate */ |
| 1147 | 1147 | static const int amd_erratum_1054[] = |
| 1148 | − AMD_OSVW_ERRATUM(0, AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf)); | |
| 1149 | − | |
| 1148 | + AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf)); | |
| 1150 | 1149 | |
| 1151 | 1150 | static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) |
| 1152 | 1151 | { |
| @@ -39,13 +39,18 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match) · 38 unmodified lines | ||
| 39 | 39 | const struct x86_cpu_id *m; |
| 40 | 40 | struct cpuinfo_x86 *c = &boot_cpu_data; |
| 41 | 41 | |
| 42 | − for (m = match; m->vendor | m->family | m->model | m->feature; m++) { | |
| 42 | + for (m = match; | |
| 43 | + m->vendor | m->family | m->model | m->steppings | m->feature; | |
| 44 | + m++) { | |
| 43 | 45 | if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor) |
| 44 | 46 | continue; |
| 45 | 47 | if (m->family != X86_FAMILY_ANY && c->x86 != m->family) |
| 46 | 48 | continue; |
| 47 | 49 | if (m->model != X86_MODEL_ANY && c->x86_model != m->model) |
| 48 | 50 | continue; |
| 51 | + if (m->steppings != X86_STEPPING_ANY && | |
| 52 | + !(BIT(c->x86_stepping) & m->steppings)) | |
| 53 | + continue; | |
| 49 | 54 | if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature)) |
| 50 | 55 | continue; |
| 51 | 56 | return m; |
| @@ -663,6 +663,7 @@ struct x86_cpu_id { · 662 unmodified lines | ||
| 663 | 663 | __u16 vendor; |
| 664 | 664 | __u16 family; |
| 665 | 665 | __u16 model; |
| 666 | + __u16 steppings; | |
| 666 | 667 | __u16 feature; /* bit index */ |
| 667 | 668 | kernel_ulong_t driver_data; |
| 668 | 669 | }; |
| @@ -671,6 +672,7 @@ struct x86_cpu_id { · 2 unmodified lines | ||
| 671 | 672 | #define X86_VENDOR_ANY 0xffff |
| 672 | 673 | #define X86_FAMILY_ANY 0 |
| 673 | 674 | #define X86_MODEL_ANY 0 |
| 675 | +#define X86_STEPPING_ANY 0 | |
| 674 | 676 | #define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */ |
| 675 | 677 | |
| 676 | 678 | /* |