@@ -338,6 +338,7 @@ extern int mce_threshold_remove_device(unsigned int cpu);
void mce_amd_feature_init(struct cpuinfo_x86 *c);
enum smca_bank_types smca_get_bank_type(unsigned int cpu, unsigned int bank);
void smca_extract_err_addr(struct mce *m);
+void smca_feature_init(void);
#else
static inline int mce_threshold_create_device(unsigned int cpu) { return 0; };
@@ -345,6 +346,7 @@ static inline int mce_threshold_remove_device(unsigned int cpu) { return 0; };
static inline bool amd_mce_is_memory_error(struct mce *m) { return false; };
static inline void mce_amd_feature_init(struct cpuinfo_x86 *c) { }
static inline void smca_extract_err_addr(struct mce *m) { }
+static inline void smca_feature_init(void) { }
#endif
static inline void mce_hygon_feature_init(struct cpuinfo_x86 *c) { return mce_amd_feature_init(c); }
@@ -724,9 +724,26 @@ bool amd_mce_is_memory_error(struct mce *m)
void smca_extract_err_addr(struct mce *m)
{
- u8 lsb = (m->addr >> 56) & 0x3f;
+ if (this_cpu_ptr(mce_banks_array)[m->bank].lsb_in_status) {
+ u8 lsb = (m->status >> 24) & 0x3f;
- m->addr &= GENMASK_ULL(55, lsb);
+ m->addr &= GENMASK_ULL(56, lsb);
+ } else {
+ u8 lsb = (m->addr >> 56) & 0x3f;
+
+ m->addr &= GENMASK_ULL(55, lsb);
+ }
+}
+
+void smca_feature_init(void)
+{
+ unsigned int bank;
+ u64 mca_cfg;
+
+ for (bank = 0; bank < this_cpu_read(mce_num_banks); ++bank) {
+ rdmsrl(MSR_AMD64_SMCA_MCx_CONFIG(bank), mca_cfg);
+ this_cpu_ptr(mce_banks_array)[bank].lsb_in_status = !!(mca_cfg & BIT(8));
+ }
}
static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc)
@@ -743,10 +760,6 @@ static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc)
if (m.status & MCI_STATUS_ADDRV) {
m.addr = addr;
- /*
- * Extract [55:<lsb>] where lsb is the least significant
- * *valid* bit of the address bits.
- */
if (mce_flags.smca)
smca_extract_err_addr(&m);
}
@@ -67,11 +67,7 @@ DEFINE_PER_CPU(unsigned, mce_exception_count);
DEFINE_PER_CPU_READ_MOSTLY(unsigned int, mce_num_banks);
-struct mce_bank {
- u64 ctl; /* subevents to enable */
- bool init; /* initialise bank? */
-};
-static DEFINE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array);
+DEFINE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array);
#define ATTR_LEN 16
/* One object for each MCE bank, shared by all CPUs */
@@ -660,10 +656,6 @@ static noinstr void mce_read_aux(struct mce *m, int i)
m->addr <<= shift;
}
- /*
- * Extract [55:<lsb>] where lsb is the least significant
- * *valid* bit of the address bits.
- */
if (mce_flags.smca)
smca_extract_err_addr(m);
}
@@ -1902,6 +1894,9 @@ static void __mcheck_cpu_init_early(struct cpuinfo_x86 *c)
mce_flags.succor = !!cpu_has(c, X86_FEATURE_SUCCOR);
mce_flags.smca = !!cpu_has(c, X86_FEATURE_SMCA);
mce_flags.amd_threshold = 1;
+
+ if (mce_flags.smca)
+ smca_feature_init();
}
}
@@ -175,6 +175,20 @@ struct mce_vendor_flags {
extern struct mce_vendor_flags mce_flags;
+struct mce_bank {
+ u64 ctl; /* subevents to enable */
+ bool init; /* initialise bank? */
+
+ /*
+ * (AMD) MCA_CONFIG[McaLsbInStatusSupported]: This bit indicates
+ * the LSB field is found in MCA_STATUS, when set.
+ */
+ __u64 lsb_in_status : 1,
+ __reserved_1 : 63;
+};
+
+DECLARE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array);
+
enum mca_msr {
MCA_CTL,
MCA_STATUS,