Skip to content

Commit ffa6f55

Browse files
committed
Merge branch 'ras-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RAS updates from Borislav Petkov: - Support for varying MCA bank numbers per CPU: this is in preparation for future CPU enablement (Yazen Ghannam) - MCA banks read race fix (Tony Luck) - Facility to filter MCEs which should not be logged (Yazen Ghannam) - The usual round of cleanups and fixes * 'ras-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/MCE/AMD: Don't report L1 BTB MCA errors on some family 17h models x86/MCE: Add an MCE-record filtering function RAS/CEC: Increment cec_entered under the mutex lock x86/mce: Fix debugfs_simple_attr.cocci warnings x86/mce: Remove mce_report_event() x86/mce: Handle varying MCA bank counts x86/mce: Fix machine_check_poll() tests for error types MAINTAINERS: Fix file pattern for X86 MCE INFRASTRUCTURE x86/MCE: Group AMD function prototypes in <asm/mce.h>
2 parents 275b103 + 71a8440 commit ffa6f55

File tree

9 files changed

+132
-83
lines changed

9 files changed

+132
-83
lines changed

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16941,7 +16941,7 @@ M: Tony Luck <[email protected]>
1694116941
M: Borislav Petkov <[email protected]>
1694216942
1694316943
S: Maintained
16944-
F: arch/x86/kernel/cpu/mcheck/*
16944+
F: arch/x86/kernel/cpu/mce/*
1694516945

1694616946
X86 MICROCODE UPDATE SUPPORT
1694716947
M: Borislav Petkov <[email protected]>

arch/x86/include/asm/mce.h

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -210,16 +210,6 @@ static inline void cmci_rediscover(void) {}
210210
static inline void cmci_recheck(void) {}
211211
#endif
212212

213-
#ifdef CONFIG_X86_MCE_AMD
214-
void mce_amd_feature_init(struct cpuinfo_x86 *c);
215-
int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr);
216-
#else
217-
static inline void mce_amd_feature_init(struct cpuinfo_x86 *c) { }
218-
static inline int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) { return -EINVAL; };
219-
#endif
220-
221-
static inline void mce_hygon_feature_init(struct cpuinfo_x86 *c) { return mce_amd_feature_init(c); }
222-
223213
int mce_available(struct cpuinfo_x86 *c);
224214
bool mce_is_memory_error(struct mce *m);
225215
bool mce_is_correctable(struct mce *m);
@@ -345,12 +335,19 @@ extern bool amd_mce_is_memory_error(struct mce *m);
345335
extern int mce_threshold_create_device(unsigned int cpu);
346336
extern int mce_threshold_remove_device(unsigned int cpu);
347337

348-
#else
338+
void mce_amd_feature_init(struct cpuinfo_x86 *c);
339+
int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr);
349340

350-
static inline int mce_threshold_create_device(unsigned int cpu) { return 0; };
351-
static inline int mce_threshold_remove_device(unsigned int cpu) { return 0; };
352-
static inline bool amd_mce_is_memory_error(struct mce *m) { return false; };
341+
#else
353342

343+
static inline int mce_threshold_create_device(unsigned int cpu) { return 0; };
344+
static inline int mce_threshold_remove_device(unsigned int cpu) { return 0; };
345+
static inline bool amd_mce_is_memory_error(struct mce *m) { return false; };
346+
static inline void mce_amd_feature_init(struct cpuinfo_x86 *c) { }
347+
static inline int
348+
umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) { return -EINVAL; };
354349
#endif
355350

351+
static inline void mce_hygon_feature_init(struct cpuinfo_x86 *c) { return mce_amd_feature_init(c); }
352+
356353
#endif /* _ASM_X86_MCE_H */

arch/x86/kernel/cpu/mce/amd.c

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -563,33 +563,59 @@ prepare_threshold_block(unsigned int bank, unsigned int block, u32 addr,
563563
return offset;
564564
}
565565

566+
bool amd_filter_mce(struct mce *m)
567+
{
568+
enum smca_bank_types bank_type = smca_get_bank_type(m->bank);
569+
struct cpuinfo_x86 *c = &boot_cpu_data;
570+
u8 xec = (m->status >> 16) & 0x3F;
571+
572+
/* See Family 17h Models 10h-2Fh Erratum #1114. */
573+
if (c->x86 == 0x17 &&
574+
c->x86_model >= 0x10 && c->x86_model <= 0x2F &&
575+
bank_type == SMCA_IF && xec == 10)
576+
return true;
577+
578+
return false;
579+
}
580+
566581
/*
567-
* Turn off MC4_MISC thresholding banks on all family 0x15 models since
568-
* they're not supported there.
582+
* Turn off thresholding banks for the following conditions:
583+
* - MC4_MISC thresholding is not supported on Family 0x15.
584+
* - Prevent possible spurious interrupts from the IF bank on Family 0x17
585+
* Models 0x10-0x2F due to Erratum #1114.
569586
*/
570-
void disable_err_thresholding(struct cpuinfo_x86 *c)
587+
void disable_err_thresholding(struct cpuinfo_x86 *c, unsigned int bank)
571588
{
572-
int i;
589+
int i, num_msrs;
573590
u64 hwcr;
574591
bool need_toggle;
575-
u32 msrs[] = {
576-
0x00000413, /* MC4_MISC0 */
577-
0xc0000408, /* MC4_MISC1 */
578-
};
592+
u32 msrs[NR_BLOCKS];
593+
594+
if (c->x86 == 0x15 && bank == 4) {
595+
msrs[0] = 0x00000413; /* MC4_MISC0 */
596+
msrs[1] = 0xc0000408; /* MC4_MISC1 */
597+
num_msrs = 2;
598+
} else if (c->x86 == 0x17 &&
599+
(c->x86_model >= 0x10 && c->x86_model <= 0x2F)) {
579600

580-
if (c->x86 != 0x15)
601+
if (smca_get_bank_type(bank) != SMCA_IF)
602+
return;
603+
604+
msrs[0] = MSR_AMD64_SMCA_MCx_MISC(bank);
605+
num_msrs = 1;
606+
} else {
581607
return;
608+
}
582609

583610
rdmsrl(MSR_K7_HWCR, hwcr);
584611

585612
/* McStatusWrEn has to be set */
586613
need_toggle = !(hwcr & BIT(18));
587-
588614
if (need_toggle)
589615
wrmsrl(MSR_K7_HWCR, hwcr | BIT(18));
590616

591617
/* Clear CntP bit safely */
592-
for (i = 0; i < ARRAY_SIZE(msrs); i++)
618+
for (i = 0; i < num_msrs; i++)
593619
msr_clear_bit(msrs[i], 62);
594620

595621
/* restore old settings */
@@ -604,12 +630,12 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
604630
unsigned int bank, block, cpu = smp_processor_id();
605631
int offset = -1;
606632

607-
disable_err_thresholding(c);
608-
609633
for (bank = 0; bank < mca_cfg.banks; ++bank) {
610634
if (mce_flags.smca)
611635
smca_configure(bank, cpu);
612636

637+
disable_err_thresholding(c, bank);
638+
613639
for (block = 0; block < NR_BLOCKS; ++block) {
614640
address = get_block_address(address, low, high, bank, block);
615641
if (!address)

arch/x86/kernel/cpu/mce/core.c

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -460,23 +460,6 @@ static void mce_irq_work_cb(struct irq_work *entry)
460460
mce_schedule_work();
461461
}
462462

463-
static void mce_report_event(struct pt_regs *regs)
464-
{
465-
if (regs->flags & (X86_VM_MASK|X86_EFLAGS_IF)) {
466-
mce_notify_irq();
467-
/*
468-
* Triggering the work queue here is just an insurance
469-
* policy in case the syscall exit notify handler
470-
* doesn't run soon enough or ends up running on the
471-
* wrong CPU (can happen when audit sleeps)
472-
*/
473-
mce_schedule_work();
474-
return;
475-
}
476-
477-
irq_work_queue(&mce_irq_work);
478-
}
479-
480463
/*
481464
* Check if the address reported by the CPU is in a format we can parse.
482465
* It would be possible to add code for most other cases, but all would
@@ -712,19 +695,49 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
712695

713696
barrier();
714697
m.status = mce_rdmsrl(msr_ops.status(i));
698+
699+
/* If this entry is not valid, ignore it */
715700
if (!(m.status & MCI_STATUS_VAL))
716701
continue;
717702

718703
/*
719-
* Uncorrected or signalled events are handled by the exception
720-
* handler when it is enabled, so don't process those here.
721-
*
722-
* TBD do the same check for MCI_STATUS_EN here?
704+
* If we are logging everything (at CPU online) or this
705+
* is a corrected error, then we must log it.
723706
*/
724-
if (!(flags & MCP_UC) &&
725-
(m.status & (mca_cfg.ser ? MCI_STATUS_S : MCI_STATUS_UC)))
726-
continue;
707+
if ((flags & MCP_UC) || !(m.status & MCI_STATUS_UC))
708+
goto log_it;
709+
710+
/*
711+
* Newer Intel systems that support software error
712+
* recovery need to make additional checks. Other
713+
* CPUs should skip over uncorrected errors, but log
714+
* everything else.
715+
*/
716+
if (!mca_cfg.ser) {
717+
if (m.status & MCI_STATUS_UC)
718+
continue;
719+
goto log_it;
720+
}
727721

722+
/* Log "not enabled" (speculative) errors */
723+
if (!(m.status & MCI_STATUS_EN))
724+
goto log_it;
725+
726+
/*
727+
* Log UCNA (SDM: 15.6.3 "UCR Error Classification")
728+
* UC == 1 && PCC == 0 && S == 0
729+
*/
730+
if (!(m.status & MCI_STATUS_PCC) && !(m.status & MCI_STATUS_S))
731+
goto log_it;
732+
733+
/*
734+
* Skip anything else. Presumption is that our read of this
735+
* bank is racing with a machine check. Leave the log alone
736+
* for do_machine_check() to deal with it.
737+
*/
738+
continue;
739+
740+
log_it:
728741
error_seen = true;
729742

730743
mce_read_aux(&m, i);
@@ -1301,7 +1314,8 @@ void do_machine_check(struct pt_regs *regs, long error_code)
13011314
mce_panic("Fatal machine check on current CPU", &m, msg);
13021315

13031316
if (worst > 0)
1304-
mce_report_event(regs);
1317+
irq_work_queue(&mce_irq_work);
1318+
13051319
mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
13061320

13071321
sync_core();
@@ -1451,13 +1465,12 @@ EXPORT_SYMBOL_GPL(mce_notify_irq);
14511465
static int __mcheck_cpu_mce_banks_init(void)
14521466
{
14531467
int i;
1454-
u8 num_banks = mca_cfg.banks;
14551468

1456-
mce_banks = kcalloc(num_banks, sizeof(struct mce_bank), GFP_KERNEL);
1469+
mce_banks = kcalloc(MAX_NR_BANKS, sizeof(struct mce_bank), GFP_KERNEL);
14571470
if (!mce_banks)
14581471
return -ENOMEM;
14591472

1460-
for (i = 0; i < num_banks; i++) {
1473+
for (i = 0; i < MAX_NR_BANKS; i++) {
14611474
struct mce_bank *b = &mce_banks[i];
14621475

14631476
b->ctl = -1ULL;
@@ -1471,28 +1484,19 @@ static int __mcheck_cpu_mce_banks_init(void)
14711484
*/
14721485
static int __mcheck_cpu_cap_init(void)
14731486
{
1474-
unsigned b;
14751487
u64 cap;
1488+
u8 b;
14761489

14771490
rdmsrl(MSR_IA32_MCG_CAP, cap);
14781491

14791492
b = cap & MCG_BANKCNT_MASK;
1480-
if (!mca_cfg.banks)
1481-
pr_info("CPU supports %d MCE banks\n", b);
1482-
1483-
if (b > MAX_NR_BANKS) {
1484-
pr_warn("Using only %u machine check banks out of %u\n",
1485-
MAX_NR_BANKS, b);
1493+
if (WARN_ON_ONCE(b > MAX_NR_BANKS))
14861494
b = MAX_NR_BANKS;
1487-
}
14881495

1489-
/* Don't support asymmetric configurations today */
1490-
WARN_ON(mca_cfg.banks != 0 && b != mca_cfg.banks);
1491-
mca_cfg.banks = b;
1496+
mca_cfg.banks = max(mca_cfg.banks, b);
14921497

14931498
if (!mce_banks) {
14941499
int err = __mcheck_cpu_mce_banks_init();
1495-
14961500
if (err)
14971501
return err;
14981502
}
@@ -1771,6 +1775,14 @@ static void __mcheck_cpu_init_timer(void)
17711775
mce_start_timer(t);
17721776
}
17731777

1778+
bool filter_mce(struct mce *m)
1779+
{
1780+
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
1781+
return amd_filter_mce(m);
1782+
1783+
return false;
1784+
}
1785+
17741786
/* Handle unconfigured int18 (should never happen) */
17751787
static void unexpected_machine_check(struct pt_regs *regs, long error_code)
17761788
{
@@ -2425,8 +2437,8 @@ static int fake_panic_set(void *data, u64 val)
24252437
return 0;
24262438
}
24272439

2428-
DEFINE_SIMPLE_ATTRIBUTE(fake_panic_fops, fake_panic_get,
2429-
fake_panic_set, "%llu\n");
2440+
DEFINE_DEBUGFS_ATTRIBUTE(fake_panic_fops, fake_panic_get, fake_panic_set,
2441+
"%llu\n");
24302442

24312443
static int __init mcheck_debugfs_init(void)
24322444
{
@@ -2435,8 +2447,8 @@ static int __init mcheck_debugfs_init(void)
24352447
dmce = mce_get_debugfs_dir();
24362448
if (!dmce)
24372449
return -ENOMEM;
2438-
ffake_panic = debugfs_create_file("fake_panic", 0444, dmce, NULL,
2439-
&fake_panic_fops);
2450+
ffake_panic = debugfs_create_file_unsafe("fake_panic", 0444, dmce,
2451+
NULL, &fake_panic_fops);
24402452
if (!ffake_panic)
24412453
return -ENOMEM;
24422454

@@ -2451,6 +2463,8 @@ EXPORT_SYMBOL_GPL(mcsafe_key);
24512463

24522464
static int __init mcheck_late_init(void)
24532465
{
2466+
pr_info("Using %d MCE banks\n", mca_cfg.banks);
2467+
24542468
if (mca_cfg.recovery)
24552469
static_branch_inc(&mcsafe_key);
24562470

arch/x86/kernel/cpu/mce/genpool.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ int mce_gen_pool_add(struct mce *mce)
9999
{
100100
struct mce_evt_llist *node;
101101

102+
if (filter_mce(mce))
103+
return -EINVAL;
104+
102105
if (!mce_evt_pool)
103106
return -EINVAL;
104107

arch/x86/kernel/cpu/mce/inject.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@
4646
static struct mce i_mce;
4747
static struct dentry *dfs_inj;
4848

49-
static u8 n_banks;
50-
5149
#define MAX_FLAG_OPT_SIZE 4
5250
#define NBCFG 0x44
5351

@@ -570,9 +568,15 @@ static void do_inject(void)
570568
static int inj_bank_set(void *data, u64 val)
571569
{
572570
struct mce *m = (struct mce *)data;
571+
u8 n_banks;
572+
u64 cap;
573+
574+
/* Get bank count on target CPU so we can handle non-uniform values. */
575+
rdmsrl_on_cpu(m->extcpu, MSR_IA32_MCG_CAP, &cap);
576+
n_banks = cap & MCG_BANKCNT_MASK;
573577

574578
if (val >= n_banks) {
575-
pr_err("Non-existent MCE bank: %llu\n", val);
579+
pr_err("MCA bank %llu non-existent on CPU%d\n", val, m->extcpu);
576580
return -EINVAL;
577581
}
578582

@@ -665,10 +669,6 @@ static struct dfs_node {
665669
static int __init debugfs_init(void)
666670
{
667671
unsigned int i;
668-
u64 cap;
669-
670-
rdmsrl(MSR_IA32_MCG_CAP, cap);
671-
n_banks = cap & MCG_BANKCNT_MASK;
672672

673673
dfs_inj = debugfs_create_dir("mce-inject", NULL);
674674
if (!dfs_inj)

arch/x86/kernel/cpu/mce/internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,13 @@ struct mca_msr_regs {
173173

174174
extern struct mca_msr_regs msr_ops;
175175

176+
/* Decide whether to add MCE record to MCE event pool or filter it out. */
177+
extern bool filter_mce(struct mce *m);
178+
179+
#ifdef CONFIG_X86_MCE_AMD
180+
extern bool amd_filter_mce(struct mce *m);
181+
#else
182+
static inline bool amd_filter_mce(struct mce *m) { return false; };
183+
#endif
184+
176185
#endif /* __X86_MCE_INTERNAL_H__ */

drivers/edac/mce_amd.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,7 @@ static inline void amd_decode_err_code(u16 ec)
10041004
/*
10051005
* Filter out unwanted MCE signatures here.
10061006
*/
1007-
static bool amd_filter_mce(struct mce *m)
1007+
static bool ignore_mce(struct mce *m)
10081008
{
10091009
/*
10101010
* NB GART TLB error reporting is disabled by default.
@@ -1038,7 +1038,7 @@ amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
10381038
unsigned int fam = x86_family(m->cpuid);
10391039
int ecc;
10401040

1041-
if (amd_filter_mce(m))
1041+
if (ignore_mce(m))
10421042
return NOTIFY_STOP;
10431043

10441044
pr_emerg(HW_ERR "%s\n", decode_error_status(m));

0 commit comments

Comments
 (0)