Skip to content

Commit 750fd23

Browse files
Avadhut Naikbp3tk0v
authored andcommitted
x86/mce: Add wrapper for struct mce to export vendor specific info
Currently, exporting new additional machine check error information involves adding new fields for the same at the end of the struct mce. This additional information can then be consumed through mcelog or tracepoint. However, as new MSRs are being added (and will be added in the future) by CPU vendors on their newer CPUs with additional machine check error information to be exported, the size of struct mce will balloon on some CPUs, unnecessarily, since those fields are vendor-specific. Moreover, different CPU vendors may export the additional information in varying sizes. The problem particularly intensifies since struct mce is exposed to userspace as part of UAPI. It's bloating through vendor-specific data should be avoided to limit the information being sent out to userspace. Add a new structure mce_hw_err to wrap the existing struct mce. The same will prevent its ballooning since vendor-specifc data, if any, can now be exported through a union within the wrapper structure and through __dynamic_array in mce_record tracepoint. Furthermore, new internal kernel fields can be added to the wrapper struct without impacting the user space API. [ bp: Restore reverse x-mas tree order of function vars declarations. ] Suggested-by: Borislav Petkov (AMD) <[email protected]> Signed-off-by: Avadhut Naik <[email protected]> Signed-off-by: Yazen Ghannam <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Qiuxu Zhuo <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 754269c commit 750fd23

File tree

8 files changed

+202
-161
lines changed

8 files changed

+202
-161
lines changed

arch/x86/include/asm/mce.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,16 @@ enum mce_notifier_prios {
187187
MCE_PRIO_HIGHEST = MCE_PRIO_CEC
188188
};
189189

190+
/**
191+
* struct mce_hw_err - Hardware Error Record.
192+
* @m: Machine Check record.
193+
*/
194+
struct mce_hw_err {
195+
struct mce m;
196+
};
197+
198+
#define to_mce_hw_err(mce) container_of(mce, struct mce_hw_err, m)
199+
190200
struct notifier_block;
191201
extern void mce_register_decode_chain(struct notifier_block *nb);
192202
extern void mce_unregister_decode_chain(struct notifier_block *nb);
@@ -221,8 +231,8 @@ static inline int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info,
221231
u64 lapic_id) { return -EINVAL; }
222232
#endif
223233

224-
void mce_prep_record(struct mce *m);
225-
void mce_log(struct mce *m);
234+
void mce_prep_record(struct mce_hw_err *err);
235+
void mce_log(struct mce_hw_err *err);
226236
DECLARE_PER_CPU(struct device *, mce_device);
227237

228238
/* Maximum number of MCA banks per CPU. */

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

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -778,29 +778,30 @@ bool amd_mce_usable_address(struct mce *m)
778778

779779
static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc)
780780
{
781-
struct mce m;
781+
struct mce_hw_err err;
782+
struct mce *m = &err.m;
782783

783-
mce_prep_record(&m);
784+
mce_prep_record(&err);
784785

785-
m.status = status;
786-
m.misc = misc;
787-
m.bank = bank;
788-
m.tsc = rdtsc();
786+
m->status = status;
787+
m->misc = misc;
788+
m->bank = bank;
789+
m->tsc = rdtsc();
789790

790-
if (m.status & MCI_STATUS_ADDRV) {
791-
m.addr = addr;
791+
if (m->status & MCI_STATUS_ADDRV) {
792+
m->addr = addr;
792793

793-
smca_extract_err_addr(&m);
794+
smca_extract_err_addr(m);
794795
}
795796

796797
if (mce_flags.smca) {
797-
rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), m.ipid);
798+
rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), m->ipid);
798799

799-
if (m.status & MCI_STATUS_SYNDV)
800-
rdmsrl(MSR_AMD64_SMCA_MCx_SYND(bank), m.synd);
800+
if (m->status & MCI_STATUS_SYNDV)
801+
rdmsrl(MSR_AMD64_SMCA_MCx_SYND(bank), m->synd);
801802
}
802803

803-
mce_log(&m);
804+
mce_log(&err);
804805
}
805806

806807
DEFINE_IDTENTRY_SYSVEC(sysvec_deferred_error)

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

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828

2929
void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err)
3030
{
31-
struct mce m;
31+
struct mce_hw_err err;
32+
struct mce *m;
3233
int lsb;
3334

3435
if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
@@ -44,31 +45,33 @@ void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err)
4445
else
4546
lsb = PAGE_SHIFT;
4647

47-
mce_prep_record(&m);
48-
m.bank = -1;
48+
mce_prep_record(&err);
49+
m = &err.m;
50+
m->bank = -1;
4951
/* Fake a memory read error with unknown channel */
50-
m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | MCI_STATUS_MISCV | 0x9f;
51-
m.misc = (MCI_MISC_ADDR_PHYS << 6) | lsb;
52+
m->status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | MCI_STATUS_MISCV | 0x9f;
53+
m->misc = (MCI_MISC_ADDR_PHYS << 6) | lsb;
5254

5355
if (severity >= GHES_SEV_RECOVERABLE)
54-
m.status |= MCI_STATUS_UC;
56+
m->status |= MCI_STATUS_UC;
5557

5658
if (severity >= GHES_SEV_PANIC) {
57-
m.status |= MCI_STATUS_PCC;
58-
m.tsc = rdtsc();
59+
m->status |= MCI_STATUS_PCC;
60+
m->tsc = rdtsc();
5961
}
6062

61-
m.addr = mem_err->physical_addr;
62-
mce_log(&m);
63+
m->addr = mem_err->physical_addr;
64+
mce_log(&err);
6365
}
6466
EXPORT_SYMBOL_GPL(apei_mce_report_mem_error);
6567

6668
int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, u64 lapic_id)
6769
{
6870
const u64 *i_mce = ((const u64 *) (ctx_info + 1));
6971
bool apicid_found = false;
72+
struct mce_hw_err err;
7073
unsigned int cpu;
71-
struct mce m;
74+
struct mce *m;
7275

7376
if (!boot_cpu_has(X86_FEATURE_SMCA))
7477
return -EINVAL;
@@ -108,18 +111,20 @@ int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, u64 lapic_id)
108111
if (!apicid_found)
109112
return -EINVAL;
110113

111-
mce_prep_record_common(&m);
112-
mce_prep_record_per_cpu(cpu, &m);
114+
m = &err.m;
115+
memset(&err, 0, sizeof(struct mce_hw_err));
116+
mce_prep_record_common(m);
117+
mce_prep_record_per_cpu(cpu, m);
113118

114-
m.bank = (ctx_info->msr_addr >> 4) & 0xFF;
115-
m.status = *i_mce;
116-
m.addr = *(i_mce + 1);
117-
m.misc = *(i_mce + 2);
119+
m->bank = (ctx_info->msr_addr >> 4) & 0xFF;
120+
m->status = *i_mce;
121+
m->addr = *(i_mce + 1);
122+
m->misc = *(i_mce + 2);
118123
/* Skipping MCA_CONFIG */
119-
m.ipid = *(i_mce + 4);
120-
m.synd = *(i_mce + 5);
124+
m->ipid = *(i_mce + 4);
125+
m->synd = *(i_mce + 5);
121126

122-
mce_log(&m);
127+
mce_log(&err);
123128

124129
return 0;
125130
}

0 commit comments

Comments
 (0)