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

Merge tag 'ras_core_for_v6.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 RAS updates from Borislav Petkov:

 - The second part of the AMD MCA interrupts rework after the
   last-minute show-stopper from the last merge window was sorted out.
   After this, the AMD MCA deferred errors, thresholding and corrected
   errors interrupt handlers use common MCA code and are tightly
   integrated into the core MCA code, thereby getting rid of
   considerable duplication. All culminating into allowing CMCI error
   thresholding storms to be detected at AMD too, using the common
   infrastructure

 - Add support for two new MCA bank bits on AMD Zen6 which denote
   whether the error address logged is a system physical address, which
   obviates the need for it to be translated before further error
   recovery can be done

* tag 'ras_core_for_v6.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/mce: Handle AMD threshold interrupt storms
  x86/mce: Do not clear bank's poll bit in mce_poll_banks on AMD SMCA systems
  x86/mce: Add support for physical address valid bit
  x86/mce: Save and use APEI corrected threshold limit
  x86/mce/amd: Define threshold restart function for banks
  x86/mce/amd: Remove redundant reset_block()
  x86/mce/amd: Support SMCA Corrected Error Interrupt
  x86/mce/amd: Enable interrupt vectors once per-CPU on SMCA systems
  x86/mce: Unify AMD DFR handler with MCA Polling
  x86/mce: Unify AMD THR handler with MCA Polling
parents 49219bba 5c4663ed
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@

/* AMD-specific bits */
#define MCI_STATUS_TCC		BIT_ULL(55)  /* Task context corrupt */
#define MCI_STATUS_PADDRV	BIT_ULL(54)  /* Valid System Physical Address */
#define MCI_STATUS_SYNDV	BIT_ULL(53)  /* synd reg. valid */
#define MCI_STATUS_DEFERRED	BIT_ULL(44)  /* uncorrected error, deferred exception */
#define MCI_STATUS_POISON	BIT_ULL(43)  /* access poisonous data */
@@ -62,6 +63,7 @@
 */
#define MCI_CONFIG_MCAX		0x1
#define MCI_CONFIG_FRUTEXT	BIT_ULL(9)
#define MCI_CONFIG_PADDRV	BIT_ULL(11)
#define MCI_IPID_MCATYPE	0xFFFF0000
#define MCI_IPID_HWID		0xFFF

@@ -165,6 +167,12 @@
 */
#define MCE_IN_KERNEL_COPYIN	BIT_ULL(7)

/*
 * Indicates that handler should check and clear Deferred error registers
 * rather than common ones.
 */
#define MCE_CHECK_DFR_REGS	BIT_ULL(8)

/*
 * This structure contains all data related to the MCE log.  Also
 * carries a signature to make it easier to find from external
@@ -302,6 +310,12 @@ DECLARE_PER_CPU(struct mce, injectm);
/* Disable CMCI/polling for MCA bank claimed by firmware */
extern void mce_disable_bank(int bank);

#ifdef CONFIG_X86_MCE_THRESHOLD
void mce_save_apei_thr_limit(u32 thr_limit);
#else
static inline void mce_save_apei_thr_limit(u32 thr_limit) { }
#endif /* CONFIG_X86_MCE_THRESHOLD */

/*
 * Exception handler
 */
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ int arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr, void *data)
	if (!cmc->enabled)
		return 0;

	mce_save_apei_thr_limit(cmc->notify.error_threshold_value);

	/*
	 * We expect HEST to provide a list of MC banks that report errors
	 * in firmware first mode. Otherwise, return non-zero value to
+142 −214
Original line number Diff line number Diff line
@@ -43,9 +43,6 @@
/* Deferred error settings */
#define MSR_CU_DEF_ERR		0xC0000410
#define MASK_DEF_LVTOFF		0x000000F0
#define MASK_DEF_INT_TYPE	0x00000006
#define DEF_LVT_OFF		0x2
#define DEF_INT_TYPE_APIC	0x2

/* Scalable MCA: */

@@ -54,6 +51,17 @@

static bool thresholding_irq_en;

struct mce_amd_cpu_data {
	mce_banks_t     thr_intr_banks;
	mce_banks_t     dfr_intr_banks;

	u32		thr_intr_en: 1,
			dfr_intr_en: 1,
			__resv: 30;
};

static DEFINE_PER_CPU_READ_MOSTLY(struct mce_amd_cpu_data, mce_amd_data);

static const char * const th_names[] = {
	"load_store",
	"insn_fetch",
@@ -79,6 +87,8 @@ struct smca_bank {
	const struct smca_hwid *hwid;
	u32 id;			/* Value of MCA_IPID[InstanceId]. */
	u8 sysfs_id;		/* Value used for sysfs name. */
	u64 paddrv	:1,	/* Physical Address Valid bit in MCA_CONFIG */
	    __reserved	:63;
};

static DEFINE_PER_CPU_READ_MOSTLY(struct smca_bank[MAX_NR_BANKS], smca_banks);
@@ -264,6 +274,7 @@ void (*deferred_error_int_vector)(void) = default_deferred_error_interrupt;

static void smca_configure(unsigned int bank, unsigned int cpu)
{
	struct mce_amd_cpu_data *data = this_cpu_ptr(&mce_amd_data);
	u8 *bank_counts = this_cpu_ptr(smca_bank_counts);
	const struct smca_hwid *s_hwid;
	unsigned int i, hwid_mcatype;
@@ -294,11 +305,33 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
		 * APIC based interrupt. First, check that no interrupt has been
		 * set.
		 */
		if ((low & BIT(5)) && !((high >> 5) & 0x3))
		if ((low & BIT(5)) && !((high >> 5) & 0x3) && data->dfr_intr_en) {
			__set_bit(bank, data->dfr_intr_banks);
			high |= BIT(5);
		}

		/*
		 * SMCA Corrected Error Interrupt
		 *
		 * MCA_CONFIG[IntPresent] is bit 10, and tells us if the bank can
		 * send an MCA Thresholding interrupt without the OS initializing
		 * this feature. This can be used if the threshold limit is managed
		 * by the platform.
		 *
		 * MCA_CONFIG[IntEn] is bit 40 (8 in the high portion of the MSR).
		 * The OS should set this to inform the platform that the OS is ready
		 * to handle the MCA Thresholding interrupt.
		 */
		if ((low & BIT(10)) && data->thr_intr_en) {
			__set_bit(bank, data->thr_intr_banks);
			high |= BIT(8);
		}

		this_cpu_ptr(mce_banks_array)[bank].lsb_in_status = !!(low & BIT(8));

		if (low & MCI_CONFIG_PADDRV)
			this_cpu_ptr(smca_banks)[bank].paddrv = 1;

		wrmsr(smca_config, low, high);
	}

@@ -368,14 +401,6 @@ static bool lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
{
	int msr = (hi & MASK_LVTOFF_HI) >> 20;

	if (apic < 0) {
		pr_err(FW_BUG "cpu %d, failed to setup threshold interrupt "
		       "for bank %d, block %d (MSR%08X=0x%x%08x)\n", b->cpu,
		       b->bank, b->block, b->address, hi, lo);
		return false;
	}

	if (apic != msr) {
	/*
	 * On SMCA CPUs, LVT offset is programmed at a different MSR, and
	 * the BIOS provides the value. The original field where LVT offset
@@ -384,6 +409,14 @@ static bool lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
	if (mce_flags.smca)
		return false;

	if (apic < 0) {
		pr_err(FW_BUG "cpu %d, failed to setup threshold interrupt "
		       "for bank %d, block %d (MSR%08X=0x%x%08x)\n", b->cpu,
		       b->bank, b->block, b->address, hi, lo);
		return false;
	}

	if (apic != msr) {
		pr_err(FW_BUG "cpu %d, invalid threshold interrupt offset %d "
		       "for bank %d, block %d (MSR%08X=0x%x%08x)\n",
		       b->cpu, apic, b->bank, b->block, b->address, hi, lo);
@@ -443,6 +476,36 @@ static void threshold_restart_block(void *_tr)
	wrmsr(tr->b->address, lo, hi);
}

static void threshold_restart_bank(unsigned int bank, bool intr_en)
{
	struct threshold_bank **thr_banks = this_cpu_read(threshold_banks);
	struct threshold_block *block, *tmp;
	struct thresh_restart tr;

	if (!thr_banks || !thr_banks[bank])
		return;

	memset(&tr, 0, sizeof(tr));

	list_for_each_entry_safe(block, tmp, &thr_banks[bank]->miscj, miscj) {
		tr.b = block;
		tr.b->interrupt_enable = intr_en;
		threshold_restart_block(&tr);
	}
}

/* Try to use the threshold limit reported through APEI. */
static u16 get_thr_limit(void)
{
	u32 thr_limit = mce_get_apei_thr_limit();

	/* Fallback to old default if APEI limit is not available. */
	if (!thr_limit)
		return THRESHOLD_MAX;

	return min(thr_limit, THRESHOLD_MAX);
}

static void mce_threshold_block_init(struct threshold_block *b, int offset)
{
	struct thresh_restart tr = {
@@ -451,7 +514,7 @@ static void mce_threshold_block_init(struct threshold_block *b, int offset)
		.lvt_off		= offset,
	};

	b->threshold_limit		= THRESHOLD_MAX;
	b->threshold_limit		= get_thr_limit();
	threshold_restart_block(&tr);
};

@@ -464,41 +527,6 @@ static int setup_APIC_mce_threshold(int reserved, int new)
	return reserved;
}

static int setup_APIC_deferred_error(int reserved, int new)
{
	if (reserved < 0 && !setup_APIC_eilvt(new, DEFERRED_ERROR_VECTOR,
					      APIC_EILVT_MSG_FIX, 0))
		return new;

	return reserved;
}

static void deferred_error_interrupt_enable(struct cpuinfo_x86 *c)
{
	u32 low = 0, high = 0;
	int def_offset = -1, def_new;

	if (rdmsr_safe(MSR_CU_DEF_ERR, &low, &high))
		return;

	def_new = (low & MASK_DEF_LVTOFF) >> 4;
	if (!(low & MASK_DEF_LVTOFF)) {
		pr_err(FW_BUG "Your BIOS is not setting up LVT offset 0x2 for deferred error IRQs correctly.\n");
		def_new = DEF_LVT_OFF;
		low = (low & ~MASK_DEF_LVTOFF) | (DEF_LVT_OFF << 4);
	}

	def_offset = setup_APIC_deferred_error(def_offset, def_new);
	if ((def_offset == def_new) &&
	    (deferred_error_int_vector != amd_deferred_error_interrupt))
		deferred_error_int_vector = amd_deferred_error_interrupt;

	if (!mce_flags.smca)
		low = (low & ~MASK_DEF_INT_TYPE) | DEF_INT_TYPE_APIC;

	wrmsr(MSR_CU_DEF_ERR, low, high);
}

static u32 get_block_address(u32 current_addr, u32 low, u32 high,
			     unsigned int bank, unsigned int block,
			     unsigned int cpu)
@@ -534,12 +562,10 @@ static u32 get_block_address(u32 current_addr, u32 low, u32 high,
	return addr;
}

static int
prepare_threshold_block(unsigned int bank, unsigned int block, u32 addr,
static int prepare_threshold_block(unsigned int bank, unsigned int block, u32 addr,
				   int offset, u32 misc_high)
{
	unsigned int cpu = smp_processor_id();
	u32 smca_low, smca_high;
	struct threshold_block b;
	int new;

@@ -556,20 +582,13 @@ prepare_threshold_block(unsigned int bank, unsigned int block, u32 addr,
	if (!b.interrupt_capable)
		goto done;

	__set_bit(bank, this_cpu_ptr(&mce_amd_data)->thr_intr_banks);
	b.interrupt_enable = 1;

	if (!mce_flags.smca) {
		new = (misc_high & MASK_LVTOFF_HI) >> 20;
		goto set_offset;
	}

	/* Gather LVT offset for thresholding: */
	if (rdmsr_safe(MSR_CU_DEF_ERR, &smca_low, &smca_high))
		goto out;

	new = (smca_low & SMCA_THR_LVT_OFF) >> 12;
	if (mce_flags.smca)
		goto done;

set_offset:
	new = (misc_high & MASK_LVTOFF_HI) >> 20;
	offset = setup_APIC_mce_threshold(offset, new);
	if (offset == new)
		thresholding_irq_en = true;
@@ -577,7 +596,6 @@ prepare_threshold_block(unsigned int bank, unsigned int block, u32 addr,
done:
	mce_threshold_block_init(&b, offset);

out:
	return offset;
}

@@ -668,6 +686,32 @@ static void amd_apply_cpu_quirks(struct cpuinfo_x86 *c)
		mce_banks[0].ctl = 0;
}

/*
 * Enable the APIC LVT interrupt vectors once per-CPU. This should be done before hardware is
 * ready to send interrupts.
 *
 * Individual error sources are enabled later during per-bank init.
 */
static void smca_enable_interrupt_vectors(void)
{
	struct mce_amd_cpu_data *data = this_cpu_ptr(&mce_amd_data);
	u64 mca_intr_cfg, offset;

	if (!mce_flags.smca || !mce_flags.succor)
		return;

	if (rdmsrq_safe(MSR_CU_DEF_ERR, &mca_intr_cfg))
		return;

	offset = (mca_intr_cfg & SMCA_THR_LVT_OFF) >> 12;
	if (!setup_APIC_eilvt(offset, THRESHOLD_APIC_VECTOR, APIC_EILVT_MSG_FIX, 0))
		data->thr_intr_en = 1;

	offset = (mca_intr_cfg & MASK_DEF_LVTOFF) >> 4;
	if (!setup_APIC_eilvt(offset, DEFERRED_ERROR_VECTOR, APIC_EILVT_MSG_FIX, 0))
		data->dfr_intr_en = 1;
}

/* cpu init entry point, called from mce.c with preempt off */
void mce_amd_feature_init(struct cpuinfo_x86 *c)
{
@@ -679,10 +723,16 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)

	mce_flags.amd_threshold	 = 1;

	smca_enable_interrupt_vectors();

	for (bank = 0; bank < this_cpu_read(mce_num_banks); ++bank) {
		if (mce_flags.smca)
		if (mce_flags.smca) {
			smca_configure(bank, cpu);

			if (!this_cpu_ptr(&mce_amd_data)->thr_intr_en)
				continue;
		}

		disable_err_thresholding(c, bank);

		for (block = 0; block < NR_BLOCKS; ++block) {
@@ -703,9 +753,6 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
			offset = prepare_threshold_block(bank, block, address, offset, high);
		}
	}

	if (mce_flags.succor)
		deferred_error_interrupt_enable(c);
}

void smca_bsp_init(void)
@@ -748,9 +795,9 @@ bool amd_mce_is_memory_error(struct mce *m)
}

/*
 * AMD systems do not have an explicit indicator that the value in MCA_ADDR is
 * a system physical address. Therefore, individual cases need to be detected.
 * Future cases and checks will be added as needed.
 * Some AMD systems have an explicit indicator that the value in MCA_ADDR is a
 * system physical address. Individual cases though, need to be detected for
 * other systems. Future cases will be added as needed.
 *
 * 1) General case
 *	a) Assume address is not usable.
@@ -764,6 +811,8 @@ bool amd_mce_is_memory_error(struct mce *m)
 *	a) Reported in legacy bank 4 with extended error code (XEC) 8.
 *	b) MCA_STATUS[43] is *not* defined as poison in legacy bank 4. Therefore,
 *	   this bit should not be checked.
 * 4) MCI_STATUS_PADDRVAL is set
 *	a) Will provide a valid system physical address.
 *
 * NOTE: SMCA UMC memory errors fall into case #1.
 */
@@ -777,6 +826,9 @@ bool amd_mce_usable_address(struct mce *m)
			return false;
	}

	if (this_cpu_ptr(smca_banks)[m->bank].paddrv)
		return m->status & MCI_STATUS_PADDRV;

	/* Check poison bit for all other bank types. */
	if (m->status & MCI_STATUS_POISON)
		return true;
@@ -785,37 +837,6 @@ bool amd_mce_usable_address(struct mce *m)
	return false;
}

static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc)
{
	struct mce_hw_err err;
	struct mce *m = &err.m;

	mce_prep_record(&err);

	m->status = status;
	m->misc   = misc;
	m->bank   = bank;
	m->tsc	 = rdtsc();

	if (m->status & MCI_STATUS_ADDRV) {
		m->addr = addr;

		smca_extract_err_addr(m);
	}

	if (mce_flags.smca) {
		rdmsrq(MSR_AMD64_SMCA_MCx_IPID(bank), m->ipid);

		if (m->status & MCI_STATUS_SYNDV) {
			rdmsrq(MSR_AMD64_SMCA_MCx_SYND(bank), m->synd);
			rdmsrq(MSR_AMD64_SMCA_MCx_SYND1(bank), err.vendor.amd.synd1);
			rdmsrq(MSR_AMD64_SMCA_MCx_SYND2(bank), err.vendor.amd.synd2);
		}
	}

	mce_log(&err);
}

DEFINE_IDTENTRY_SYSVEC(sysvec_deferred_error)
{
	trace_deferred_error_apic_entry(DEFERRED_ERROR_VECTOR);
@@ -825,103 +846,20 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_deferred_error)
	apic_eoi();
}

/*
 * Returns true if the logged error is deferred. False, otherwise.
 */
static inline bool
_log_error_bank(unsigned int bank, u32 msr_stat, u32 msr_addr, u64 misc)
{
	u64 status, addr = 0;

	rdmsrq(msr_stat, status);
	if (!(status & MCI_STATUS_VAL))
		return false;

	if (status & MCI_STATUS_ADDRV)
		rdmsrq(msr_addr, addr);

	__log_error(bank, status, addr, misc);

	wrmsrq(msr_stat, 0);

	return status & MCI_STATUS_DEFERRED;
}

static bool _log_error_deferred(unsigned int bank, u32 misc)
{
	if (!_log_error_bank(bank, mca_msr_reg(bank, MCA_STATUS),
			     mca_msr_reg(bank, MCA_ADDR), misc))
		return false;

	/*
	 * Non-SMCA systems don't have MCA_DESTAT/MCA_DEADDR registers.
	 * Return true here to avoid accessing these registers.
	 */
	if (!mce_flags.smca)
		return true;

	/* Clear MCA_DESTAT if the deferred error was logged from MCA_STATUS. */
	wrmsrq(MSR_AMD64_SMCA_MCx_DESTAT(bank), 0);
	return true;
}

/*
 * We have three scenarios for checking for Deferred errors:
 *
 * 1) Non-SMCA systems check MCA_STATUS and log error if found.
 * 2) SMCA systems check MCA_STATUS. If error is found then log it and also
 *    clear MCA_DESTAT.
 * 3) SMCA systems check MCA_DESTAT, if error was not found in MCA_STATUS, and
 *    log it.
 */
static void log_error_deferred(unsigned int bank)
{
	if (_log_error_deferred(bank, 0))
		return;

	/*
	 * Only deferred errors are logged in MCA_DE{STAT,ADDR} so just check
	 * for a valid error.
	 */
	_log_error_bank(bank, MSR_AMD64_SMCA_MCx_DESTAT(bank),
			      MSR_AMD64_SMCA_MCx_DEADDR(bank), 0);
}

/* APIC interrupt handler for deferred errors */
static void amd_deferred_error_interrupt(void)
{
	unsigned int bank;

	for (bank = 0; bank < this_cpu_read(mce_num_banks); ++bank)
		log_error_deferred(bank);
	machine_check_poll(MCP_TIMESTAMP, &this_cpu_ptr(&mce_amd_data)->dfr_intr_banks);
}

static void log_error_thresholding(unsigned int bank, u64 misc)
void mce_amd_handle_storm(unsigned int bank, bool on)
{
	_log_error_deferred(bank, misc);
	threshold_restart_bank(bank, on);
}

static void log_and_reset_block(struct threshold_block *block)
static void amd_reset_thr_limit(unsigned int bank)
{
	struct thresh_restart tr;
	u32 low = 0, high = 0;

	if (!block)
		return;

	if (rdmsr_safe(block->address, &low, &high))
		return;

	if (!(high & MASK_OVERFLOW_HI))
		return;

	/* Log the MCE which caused the threshold event. */
	log_error_thresholding(block->bank, ((u64)high << 32) | low);

	/* Reset threshold block after logging error. */
	memset(&tr, 0, sizeof(tr));
	tr.b = block;
	threshold_restart_block(&tr);
	threshold_restart_bank(bank, true);
}

/*
@@ -930,33 +868,21 @@ static void log_and_reset_block(struct threshold_block *block)
 */
static void amd_threshold_interrupt(void)
{
	struct threshold_bank **bp = this_cpu_read(threshold_banks), *thr_bank;
	unsigned int bank, cpu = smp_processor_id();
	struct threshold_block *block, *tmp;

	/*
	 * Validate that the threshold bank has been initialized already. The
	 * handler is installed at boot time, but on a hotplug event the
	 * interrupt might fire before the data has been initialized.
	 */
	if (!bp)
		return;

	for (bank = 0; bank < this_cpu_read(mce_num_banks); ++bank) {
		if (!(per_cpu(bank_map, cpu) & BIT_ULL(bank)))
			continue;

		thr_bank = bp[bank];
		if (!thr_bank)
			continue;

		list_for_each_entry_safe(block, tmp, &thr_bank->miscj, miscj)
			log_and_reset_block(block);
	}
	machine_check_poll(MCP_TIMESTAMP, &this_cpu_ptr(&mce_amd_data)->thr_intr_banks);
}

void amd_clear_bank(struct mce *m)
{
	amd_reset_thr_limit(m->bank);

	/* Clear MCA_DESTAT for all deferred errors even those logged in MCA_STATUS. */
	if (m->status & MCI_STATUS_DEFERRED)
		mce_wrmsrq(MSR_AMD64_SMCA_MCx_DESTAT(m->bank), 0);

	/* Don't clear MCA_STATUS if MCA_DESTAT was used exclusively. */
	if (m->kflags & MCE_CHECK_DFR_REGS)
		return;

	mce_wrmsrq(mca_msr_reg(m->bank, MCA_STATUS), 0);
}

@@ -1172,7 +1098,7 @@ static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb
	b->address		= address;
	b->interrupt_enable	= 0;
	b->interrupt_capable	= lvt_interrupt_supported(bank, high);
	b->threshold_limit	= THRESHOLD_MAX;
	b->threshold_limit	= get_thr_limit();

	if (b->interrupt_capable) {
		default_attrs[2] = &interrupt_enable.attr;
@@ -1183,6 +1109,8 @@ static int allocate_threshold_blocks(unsigned int cpu, struct threshold_bank *tb

	list_add(&b->miscj, &tb->miscj);

	mce_threshold_block_init(b, (high & MASK_LVTOFF_HI) >> 20);

	err = kobject_init_and_add(&b->kobj, &threshold_ktype, tb->kobj, get_name(cpu, bank, b));
	if (err)
		goto out_free;
+30 −1
Original line number Diff line number Diff line
@@ -687,6 +687,9 @@ static noinstr void mce_read_aux(struct mce_hw_err *err, int i)
		m->misc = mce_rdmsrq(mca_msr_reg(i, MCA_MISC));

	if (m->status & MCI_STATUS_ADDRV) {
		if (m->kflags & MCE_CHECK_DFR_REGS)
			m->addr = mce_rdmsrq(MSR_AMD64_SMCA_MCx_DEADDR(i));
		else
			m->addr = mce_rdmsrq(mca_msr_reg(i, MCA_ADDR));

		/*
@@ -714,6 +717,29 @@ static noinstr void mce_read_aux(struct mce_hw_err *err, int i)

DEFINE_PER_CPU(unsigned, mce_poll_count);

/*
 * We have three scenarios for checking for Deferred errors:
 *
 * 1) Non-SMCA systems check MCA_STATUS and log error if found.
 * 2) SMCA systems check MCA_STATUS. If error is found then log it and also
 *    clear MCA_DESTAT.
 * 3) SMCA systems check MCA_DESTAT, if error was not found in MCA_STATUS, and
 *    log it.
 */
static bool smca_should_log_poll_error(struct mce *m)
{
	if (m->status & MCI_STATUS_VAL)
		return true;

	m->status = mce_rdmsrq(MSR_AMD64_SMCA_MCx_DESTAT(m->bank));
	if ((m->status & MCI_STATUS_VAL) && (m->status & MCI_STATUS_DEFERRED)) {
		m->kflags |= MCE_CHECK_DFR_REGS;
		return true;
	}

	return false;
}

/*
 * Newer Intel systems that support software error
 * recovery need to make additional checks. Other
@@ -740,6 +766,9 @@ static bool should_log_poll_error(enum mcp_flags flags, struct mce_hw_err *err)
{
	struct mce *m = &err->m;

	if (mce_flags.smca)
		return smca_should_log_poll_error(m);

	/* If this entry is not valid, ignore it. */
	if (!(m->status & MCI_STATUS_VAL))
		return false;
+4 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ void mce_track_storm(struct mce *mce);
void mce_inherit_storm(unsigned int bank);
bool mce_get_storm_mode(void);
void mce_set_storm_mode(bool storm);
u32  mce_get_apei_thr_limit(void);
#else
static inline void cmci_storm_begin(unsigned int bank) {}
static inline void cmci_storm_end(unsigned int bank) {}
@@ -74,6 +75,7 @@ static inline void mce_track_storm(struct mce *mce) {}
static inline void mce_inherit_storm(unsigned int bank) {}
static inline bool mce_get_storm_mode(void) { return false; }
static inline void mce_set_storm_mode(bool storm) {}
static inline u32  mce_get_apei_thr_limit(void) { return 0; }
#endif

/*
@@ -267,6 +269,7 @@ void mce_prep_record_per_cpu(unsigned int cpu, struct mce *m);
#ifdef CONFIG_X86_MCE_AMD
void mce_threshold_create_device(unsigned int cpu);
void mce_threshold_remove_device(unsigned int cpu);
void mce_amd_handle_storm(unsigned int bank, bool on);
extern bool amd_filter_mce(struct mce *m);
bool amd_mce_usable_address(struct mce *m);
void amd_clear_bank(struct mce *m);
@@ -299,6 +302,7 @@ void smca_bsp_init(void);
#else
static inline void mce_threshold_create_device(unsigned int cpu)	{ }
static inline void mce_threshold_remove_device(unsigned int cpu)	{ }
static inline void mce_amd_handle_storm(unsigned int bank, bool on)	{ }
static inline bool amd_filter_mce(struct mce *m) { return false; }
static inline bool amd_mce_usable_address(struct mce *m) { return false; }
static inline void amd_clear_bank(struct mce *m) { }
Loading