Commit f9bbb8ad authored by Yazen Ghannam's avatar Yazen Ghannam Committed by Borislav Petkov (AMD)
Browse files

x86/mce: Define mce_prep_record() helpers for common and per-CPU fields



Generally, MCA information for an error is gathered on the CPU that
reported the error. In this case, CPU-specific information from the
running CPU will be correct.

However, this will be incorrect if the MCA information is gathered while
running on a CPU that didn't report the error. One example is creating
an MCA record using mce_prep_record() for errors reported from ACPI.

Split mce_prep_record() so that there is a helper function to gather
common, i.e. not CPU-specific, information and another helper for
CPU-specific information.

Leave mce_prep_record() defined as-is for the common case when running
on the reporting CPU.

Get MCG_CAP in the global helper even though the register is per-CPU.
This value is not already cached per-CPU like other values. And it does
not assist with any per-CPU decoding or handling.

Signed-off-by: default avatarYazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: default avatarNikolay Borisov <nik.borisov@suse.com>
Link: https://lore.kernel.org/r/20240730182958.4117158-3-yazen.ghannam@amd.com


Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
parent 5ad21a24
Loading
Loading
Loading
Loading
+23 −11
Original line number Diff line number Diff line
@@ -117,20 +117,32 @@ static struct irq_work mce_irq_work;
 */
BLOCKING_NOTIFIER_HEAD(x86_mce_decoder_chain);

/* Do initial initialization of a struct mce */
void mce_prep_record(struct mce *m)
void mce_prep_record_common(struct mce *m)
{
	memset(m, 0, sizeof(struct mce));
	m->cpu = m->extcpu = smp_processor_id();
	/* need the internal __ version to avoid deadlocks */
	m->time = __ktime_get_real_seconds();
	m->cpuvendor = boot_cpu_data.x86_vendor;

	m->cpuid	= cpuid_eax(1);
	m->socketid = cpu_data(m->extcpu).topo.pkg_id;
	m->apicid = cpu_data(m->extcpu).topo.initial_apicid;
	m->cpuvendor	= boot_cpu_data.x86_vendor;
	m->mcgcap	= __rdmsr(MSR_IA32_MCG_CAP);
	m->ppin = cpu_data(m->extcpu).ppin;
	m->microcode = boot_cpu_data.microcode;
	/* need the internal __ version to avoid deadlocks */
	m->time		= __ktime_get_real_seconds();
}

void mce_prep_record_per_cpu(unsigned int cpu, struct mce *m)
{
	m->cpu		= cpu;
	m->extcpu	= cpu;
	m->apicid	= cpu_data(cpu).topo.initial_apicid;
	m->microcode	= cpu_data(cpu).microcode;
	m->ppin		= topology_ppin(cpu);
	m->socketid	= topology_physical_package_id(cpu);
}

/* Do initial initialization of a struct mce */
void mce_prep_record(struct mce *m)
{
	mce_prep_record_common(m);
	mce_prep_record_per_cpu(smp_processor_id(), m);
}

DEFINE_PER_CPU(struct mce, injectm);
+2 −0
Original line number Diff line number Diff line
@@ -261,6 +261,8 @@ enum mca_msr {

/* Decide whether to add MCE record to MCE event pool or filter it out. */
extern bool filter_mce(struct mce *m);
void mce_prep_record_common(struct mce *m);
void mce_prep_record_per_cpu(unsigned int cpu, struct mce *m);

#ifdef CONFIG_X86_MCE_AMD
extern bool amd_filter_mce(struct mce *m);