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 | #define RDRAND_RETRY_LOOPS 10 | 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 | /* Unconditional execution of RDRAND and RDSEED */ | 18 | /* Unconditional execution of RDRAND and RDSEED */ |
| 29 | 19 | ||
| 30 | static inline bool __must_check rdrand_long(unsigned long *v) | 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 | bool ok; | 22 | bool ok; |
| 33 | unsigned int retry = RDRAND_RETRY_LOOPS; | 23 | unsigned int retry = RDRAND_RETRY_LOOPS; |
| 34 | do { | 24 | do { |
| 35 | asm volatile(RDRAND_LONG | 25 | asm volatile("rdrand %[out]" |
| 36 | CC_SET(c) | 26 | CC_SET(c) |
| 37 | : CC_OUT(c) (ok), "=a" (*v)); | 27 | : CC_OUT(c) (ok), [out] "=r" (*v)); |
| 38 | if (ok) | 28 | if (ok) |
| 39 | return true; | 29 | return true; |
| 40 | } while (--retry); | 30 | } while (--retry); |
| @@ -46,9 +36,9 @@ static inline bool __must_check rdrand_int(unsigned int *v) · 5 unmodified lines | |||
| 46 | bool ok; | 36 | bool ok; |
| 47 | unsigned int retry = RDRAND_RETRY_LOOPS; | 37 | unsigned int retry = RDRAND_RETRY_LOOPS; |
| 48 | do { | 38 | do { |
| 49 | asm volatile(RDRAND_INT | 39 | asm volatile("rdrand %[out]" |
| 50 | CC_SET(c) | 40 | CC_SET(c) |
| 51 | : CC_OUT(c) (ok), "=a" (*v)); | 41 | : CC_OUT(c) (ok), [out] "=r" (*v)); |
| 52 | if (ok) | 42 | if (ok) |
| 53 | return true; | 43 | return true; |
| 54 | } while (--retry); | 44 | } while (--retry); |
| @@ -58,18 +48,18 @@ static inline bool __must_check rdrand_int(unsigned int *v) · 3 unmodified lines | |||
| 58 | static inline bool __must_check rdseed_long(unsigned long *v) | 48 | static inline bool __must_check rdseed_long(unsigned long *v) |
| 59 | { | 49 | { |
| 60 | bool ok; | 50 | bool ok; |
| 61 | asm volatile(RDSEED_LONG | 51 | asm volatile("rdseed %[out]" |
| 62 | CC_SET(c) | 52 | CC_SET(c) |
| 63 | : CC_OUT(c) (ok), "=a" (*v)); | 53 | : CC_OUT(c) (ok), [out] "=r" (*v)); |
| 64 | return ok; | 54 | return ok; |
| 65 | } | 55 | } |
| 66 | 56 | ||
| 67 | static inline bool __must_check rdseed_int(unsigned int *v) | 57 | static inline bool __must_check rdseed_int(unsigned int *v) |
| 68 | { | 58 | { |
| 69 | bool ok; | 59 | bool ok; |
| 70 | asm volatile(RDSEED_INT | 60 | asm volatile("rdseed %[out]" |
| 71 | CC_SET(c) | 61 | CC_SET(c) |
| 72 | : CC_OUT(c) (ok), "=a" (*v)); | 62 | : CC_OUT(c) (ok), [out] "=r" (*v)); |
| 73 | return ok; | 63 | return ok; |
| 74 | } | 64 | } |
| 75 | 65 | ||
| @@ -20,12 +20,14 @@ · 19 unmodified lines | |||
| 20 | #define X86_CENTAUR_FAM6_C7_D 0xd | 20 | #define X86_CENTAUR_FAM6_C7_D 0xd |
| 21 | #define X86_CENTAUR_FAM6_NANO 0xf | 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 | * @_vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY | 26 | * @_vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY |
| 26 | * The name is expanded to X86_VENDOR_@_vendor | 27 | * The name is expanded to X86_VENDOR_@_vendor |
| 27 | * @_family: The family number or X86_FAMILY_ANY | 28 | * @_family: The family number or X86_FAMILY_ANY |
| 28 | * @_model: The model number, model constant or X86_MODEL_ANY | 29 | * @_model: The model number, model constant or X86_MODEL_ANY |
| 30 | * @_steppings: Bitmask for steppings, stepping constant or X86_STEPPING_ANY | ||
| 29 | * @_feature: A X86_FEATURE bit or X86_FEATURE_ANY | 31 | * @_feature: A X86_FEATURE bit or X86_FEATURE_ANY |
| 30 | * @_data: Driver specific data or NULL. The internal storage | 32 | * @_data: Driver specific data or NULL. The internal storage |
| 31 | * format is unsigned long. The supplied value, pointer | 33 | * format is unsigned long. The supplied value, pointer |
| @@ -37,15 +39,34 @@ · 5 unmodified lines | |||
| 37 | * into another macro at the usage site for good reasons, then please | 39 | * into another macro at the usage site for good reasons, then please |
| 38 | * start this local macro with X86_MATCH to allow easy grepping. | 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, \ | 42 | #define X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(_vendor, _family, _model, \ |
| 41 | _feature, _data) { \ | 43 | _steppings, _feature, _data) { \ |
| 42 | .vendor = X86_VENDOR_##_vendor, \ | 44 | .vendor = X86_VENDOR_##_vendor, \ |
| 43 | .family = _family, \ | 45 | .family = _family, \ |
| 44 | .model = _model, \ | 46 | .model = _model, \ |
| 47 | .steppings = _steppings, \ | ||
| 45 | .feature = _feature, \ | 48 | .feature = _feature, \ |
| 46 | .driver_data = (unsigned long) _data \ | 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 | * X86_MATCH_VENDOR_FAM_FEATURE - Macro for matching vendor, family and CPU feature | 71 | * X86_MATCH_VENDOR_FAM_FEATURE - Macro for matching vendor, family and CPU feature |
| 51 | * @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY | 72 | * @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY |
| @@ -139,6 +160,10 @@ · 87 unmodified lines | |||
| 139 | #define X86_MATCH_INTEL_FAM6_MODEL(model, data) \ | 160 | #define X86_MATCH_INTEL_FAM6_MODEL(model, data) \ |
| 140 | X86_MATCH_VENDOR_FAM_MODEL(INTEL, 6, INTEL_FAM6_##model, data) | 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 | * Match specific microcode revisions. | 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 | * stale TLB entries and, especially if we're flushing global | 12 | * stale TLB entries and, especially if we're flushing global |
| 13 | * mappings, we don't want the compiler to reorder any subsequent | 13 | * mappings, we don't want the compiler to reorder any subsequent |
| 14 | * memory accesses before the TLB flush. | 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" | 16 | asm volatile("invpcid %[desc], %[type]" |
| 20 | : : "m" (desc), "a" (type), "c" (&desc) : "memory"); | 17 | :: [desc] "m" (desc), [type] "r" (type) : "memory"); |
| 21 | } | 18 | } |
| 22 | 19 | ||
| 23 | #define INVPCID_TYPE_INDIV_ADDR 0 | 20 | #define INVPCID_TYPE_INDIV_ADDR 0 |
| @@ -544,46 +544,20 @@ static struct clock_event_device lapic_clockevent = { · 543 unmodified lines | |||
| 544 | }; | 544 | }; |
| 545 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); | 545 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); |
| 546 | 546 | ||
| 547 | static __init u32 hsx_deadline_rev(void) | 547 | static const struct x86_cpu_id deadline_match[] __initconst = { |
| 548 | { | 548 | X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(HASWELL_X, X86_STEPPINGS(0x2, 0x2), 0x3a), /* EP */ |
| 549 | switch (boot_cpu_data.x86_stepping) { | 549 | X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(HASWELL_X, X86_STEPPINGS(0x4, 0x4), 0x0f), /* EX */ |
| 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 | } | ||
| 575 | 550 | ||
| 576 | if (boot_cpu_data.x86_stepping > 4) | 551 | X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020), |
| 577 | return 0; | ||
| 578 | 552 | ||
| 579 | return ~0U; | 553 | X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x2, 0x2), 0x00000011), |
| 580 | } | 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 = { | 558 | X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x3, 0x3), 0x01000136), |
| 583 | X86_MATCH_INTEL_FAM6_MODEL( HASWELL_X, &hsx_deadline_rev), | 559 | X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x4, 0x4), 0x02000014), |
| 584 | X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020), | 560 | X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x5, 0xf), 0), |
| 585 | X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_D, &bdx_deadline_rev), | ||
| 586 | X86_MATCH_INTEL_FAM6_MODEL( SKYLAKE_X, &skx_deadline_rev), | ||
| 587 | 561 | ||
| 588 | X86_MATCH_INTEL_FAM6_MODEL( HASWELL, 0x22), | 562 | X86_MATCH_INTEL_FAM6_MODEL( HASWELL, 0x22), |
| 589 | X86_MATCH_INTEL_FAM6_MODEL( HASWELL_L, 0x20), | 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 | if (!m) | 589 | if (!m) |
| 616 | return true; | 590 | return true; |
| 617 | 591 | ||
| 618 | /* | 592 | rev = (u32)m->driver_data; |
| 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; | ||
| 626 | 593 | ||
| 627 | if (boot_cpu_data.microcode >= rev) | 594 | if (boot_cpu_data.microcode >= rev) |
| 628 | return true; | 595 | return true; |
| @@ -1145,8 +1145,7 @@ static const int amd_erratum_383[] = · 1144 unmodified lines | |||
| 1145 | 1145 | ||
| 1146 | /* #1054: Instructions Retired Performance Counter May Be Inaccurate */ | 1146 | /* #1054: Instructions Retired Performance Counter May Be Inaccurate */ |
| 1147 | static const int amd_erratum_1054[] = | 1147 | static const int amd_erratum_1054[] = |
| 1148 | AMD_OSVW_ERRATUM(0, AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf)); | 1148 | AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf)); |
| 1149 | |||
| 1150 | 1149 | ||
| 1151 | static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) | 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 | const struct x86_cpu_id *m; | 39 | const struct x86_cpu_id *m; |
| 40 | struct cpuinfo_x86 *c = &boot_cpu_data; | 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 | if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor) | 45 | if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor) |
| 44 | continue; | 46 | continue; |
| 45 | if (m->family != X86_FAMILY_ANY && c->x86 != m->family) | 47 | if (m->family != X86_FAMILY_ANY && c->x86 != m->family) |
| 46 | continue; | 48 | continue; |
| 47 | if (m->model != X86_MODEL_ANY && c->x86_model != m->model) | 49 | if (m->model != X86_MODEL_ANY && c->x86_model != m->model) |
| 48 | continue; | 50 | continue; |
| 51 | if (m->steppings != X86_STEPPING_ANY && | ||
| 52 | !(BIT(c->x86_stepping) & m->steppings)) | ||
| 53 | continue; | ||
| 49 | if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature)) | 54 | if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature)) |
| 50 | continue; | 55 | continue; |
| 51 | return m; | 56 | return m; |
| @@ -663,6 +663,7 @@ struct x86_cpu_id { · 662 unmodified lines | |||
| 663 | __u16 vendor; | 663 | __u16 vendor; |
| 664 | __u16 family; | 664 | __u16 family; |
| 665 | __u16 model; | 665 | __u16 model; |
| 666 | __u16 steppings; | ||
| 666 | __u16 feature; /* bit index */ | 667 | __u16 feature; /* bit index */ |
| 667 | kernel_ulong_t driver_data; | 668 | kernel_ulong_t driver_data; |
| 668 | }; | 669 | }; |
| @@ -671,6 +672,7 @@ struct x86_cpu_id { · 2 unmodified lines | |||
| 671 | #define X86_VENDOR_ANY 0xffff | 672 | #define X86_VENDOR_ANY 0xffff |
| 672 | #define X86_FAMILY_ANY 0 | 673 | #define X86_FAMILY_ANY 0 |
| 673 | #define X86_MODEL_ANY 0 | 674 | #define X86_MODEL_ANY 0 |
| 675 | #define X86_STEPPING_ANY 0 | ||
| 674 | #define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */ | 676 | #define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */ |
| 675 | 677 | ||
| 676 | /* | 678 | /* |