Commit 0246725d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull RAS updates from Borislav Petkov:

 - Add support for reporting more bits of the physical address on error,
   on newer AMD CPUs

 - Mask out bits which don't belong to the address of the error being
   reported

* tag 'ras_core_for_v6.3_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/mce: Mask out non-address bits from machine check bank
  x86/mce: Add support for Extended Physical Address MCA changes
  x86/mce: Define a function to extract ErrorAddr from MCA_ADDR
parents 89f5349e 8a01ec97
...@@ -88,6 +88,9 @@ ...@@ -88,6 +88,9 @@
#define MCI_MISC_ADDR_MEM 3 /* memory address */ #define MCI_MISC_ADDR_MEM 3 /* memory address */
#define MCI_MISC_ADDR_GENERIC 7 /* generic */ #define MCI_MISC_ADDR_GENERIC 7 /* generic */
/* MCi_ADDR register defines */
#define MCI_ADDR_PHYSADDR GENMASK_ULL(boot_cpu_data.x86_phys_bits - 1, 0)
/* CTL2 register defines */ /* CTL2 register defines */
#define MCI_CTL2_CMCI_EN BIT_ULL(30) #define MCI_CTL2_CMCI_EN BIT_ULL(30)
#define MCI_CTL2_CMCI_THRESHOLD_MASK 0x7fffULL #define MCI_CTL2_CMCI_THRESHOLD_MASK 0x7fffULL
......
...@@ -306,6 +306,8 @@ static void smca_configure(unsigned int bank, unsigned int cpu) ...@@ -306,6 +306,8 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
if ((low & BIT(5)) && !((high >> 5) & 0x3)) if ((low & BIT(5)) && !((high >> 5) & 0x3))
high |= BIT(5); high |= BIT(5);
this_cpu_ptr(mce_banks_array)[bank].lsb_in_status = !!(low & BIT(8));
wrmsr(smca_config, low, high); wrmsr(smca_config, low, high);
} }
...@@ -736,15 +738,7 @@ static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc) ...@@ -736,15 +738,7 @@ static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc)
if (m.status & MCI_STATUS_ADDRV) { if (m.status & MCI_STATUS_ADDRV) {
m.addr = addr; m.addr = addr;
/* smca_extract_err_addr(&m);
* Extract [55:<lsb>] where lsb is the least significant
* *valid* bit of the address bits.
*/
if (mce_flags.smca) {
u8 lsb = (m.addr >> 56) & 0x3f;
m.addr &= GENMASK_ULL(55, lsb);
}
} }
if (mce_flags.smca) { if (mce_flags.smca) {
......
...@@ -67,13 +67,7 @@ DEFINE_PER_CPU(unsigned, mce_exception_count); ...@@ -67,13 +67,7 @@ DEFINE_PER_CPU(unsigned, mce_exception_count);
DEFINE_PER_CPU_READ_MOSTLY(unsigned int, mce_num_banks); DEFINE_PER_CPU_READ_MOSTLY(unsigned int, mce_num_banks);
struct mce_bank { DEFINE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array);
u64 ctl; /* subevents to enable */
__u64 init : 1, /* initialise bank? */
__reserved_1 : 63;
};
static DEFINE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array);
#define ATTR_LEN 16 #define ATTR_LEN 16
/* One object for each MCE bank, shared by all CPUs */ /* One object for each MCE bank, shared by all CPUs */
...@@ -579,7 +573,7 @@ static int uc_decode_notifier(struct notifier_block *nb, unsigned long val, ...@@ -579,7 +573,7 @@ static int uc_decode_notifier(struct notifier_block *nb, unsigned long val,
mce->severity != MCE_DEFERRED_SEVERITY) mce->severity != MCE_DEFERRED_SEVERITY)
return NOTIFY_DONE; return NOTIFY_DONE;
pfn = mce->addr >> PAGE_SHIFT; pfn = (mce->addr & MCI_ADDR_PHYSADDR) >> PAGE_SHIFT;
if (!memory_failure(pfn, 0)) { if (!memory_failure(pfn, 0)) {
set_mce_nospec(pfn); set_mce_nospec(pfn);
mce->kflags |= MCE_HANDLED_UC; mce->kflags |= MCE_HANDLED_UC;
...@@ -633,15 +627,7 @@ static noinstr void mce_read_aux(struct mce *m, int i) ...@@ -633,15 +627,7 @@ static noinstr void mce_read_aux(struct mce *m, int i)
m->addr <<= shift; m->addr <<= shift;
} }
/* smca_extract_err_addr(m);
* Extract [55:<lsb>] where lsb is the least significant
* *valid* bit of the address bits.
*/
if (mce_flags.smca) {
u8 lsb = (m->addr >> 56) & 0x3f;
m->addr &= GENMASK_ULL(55, lsb);
}
} }
if (mce_flags.smca) { if (mce_flags.smca) {
...@@ -1308,6 +1294,7 @@ static void kill_me_maybe(struct callback_head *cb) ...@@ -1308,6 +1294,7 @@ static void kill_me_maybe(struct callback_head *cb)
{ {
struct task_struct *p = container_of(cb, struct task_struct, mce_kill_me); struct task_struct *p = container_of(cb, struct task_struct, mce_kill_me);
int flags = MF_ACTION_REQUIRED; int flags = MF_ACTION_REQUIRED;
unsigned long pfn;
int ret; int ret;
p->mce_count = 0; p->mce_count = 0;
...@@ -1316,9 +1303,10 @@ static void kill_me_maybe(struct callback_head *cb) ...@@ -1316,9 +1303,10 @@ static void kill_me_maybe(struct callback_head *cb)
if (!p->mce_ripv) if (!p->mce_ripv)
flags |= MF_MUST_KILL; flags |= MF_MUST_KILL;
ret = memory_failure(p->mce_addr >> PAGE_SHIFT, flags); pfn = (p->mce_addr & MCI_ADDR_PHYSADDR) >> PAGE_SHIFT;
ret = memory_failure(pfn, flags);
if (!ret) { if (!ret) {
set_mce_nospec(p->mce_addr >> PAGE_SHIFT); set_mce_nospec(pfn);
sync_core(); sync_core();
return; return;
} }
...@@ -1340,11 +1328,13 @@ static void kill_me_maybe(struct callback_head *cb) ...@@ -1340,11 +1328,13 @@ static void kill_me_maybe(struct callback_head *cb)
static void kill_me_never(struct callback_head *cb) static void kill_me_never(struct callback_head *cb)
{ {
struct task_struct *p = container_of(cb, struct task_struct, mce_kill_me); struct task_struct *p = container_of(cb, struct task_struct, mce_kill_me);
unsigned long pfn;
p->mce_count = 0; p->mce_count = 0;
pr_err("Kernel accessed poison in user space at %llx\n", p->mce_addr); pr_err("Kernel accessed poison in user space at %llx\n", p->mce_addr);
if (!memory_failure(p->mce_addr >> PAGE_SHIFT, 0)) pfn = (p->mce_addr & MCI_ADDR_PHYSADDR) >> PAGE_SHIFT;
set_mce_nospec(p->mce_addr >> PAGE_SHIFT); if (!memory_failure(pfn, 0))
set_mce_nospec(pfn);
} }
static void queue_task_work(struct mce *m, char *msg, void (*func)(struct callback_head *)) static void queue_task_work(struct mce *m, char *msg, void (*func)(struct callback_head *))
......
...@@ -177,6 +177,24 @@ struct mce_vendor_flags { ...@@ -177,6 +177,24 @@ struct mce_vendor_flags {
extern struct mce_vendor_flags mce_flags; extern struct mce_vendor_flags mce_flags;
struct mce_bank {
/* subevents to enable */
u64 ctl;
/* initialise bank? */
__u64 init : 1,
/*
* (AMD) MCA_CONFIG[McaLsbInStatusSupported]: When set, this bit indicates
* the LSB field is found in MCA_STATUS and not in MCA_ADDR.
*/
lsb_in_status : 1,
__reserved_1 : 62;
};
DECLARE_PER_CPU_READ_MOSTLY(struct mce_bank[MAX_NR_BANKS], mce_banks_array);
enum mca_msr { enum mca_msr {
MCA_CTL, MCA_CTL,
MCA_STATUS, MCA_STATUS,
...@@ -189,8 +207,34 @@ extern bool filter_mce(struct mce *m); ...@@ -189,8 +207,34 @@ extern bool filter_mce(struct mce *m);
#ifdef CONFIG_X86_MCE_AMD #ifdef CONFIG_X86_MCE_AMD
extern bool amd_filter_mce(struct mce *m); extern bool amd_filter_mce(struct mce *m);
/*
* If MCA_CONFIG[McaLsbInStatusSupported] is set, extract ErrAddr in bits
* [56:0] of MCA_STATUS, else in bits [55:0] of MCA_ADDR.
*/
static __always_inline void smca_extract_err_addr(struct mce *m)
{
u8 lsb;
if (!mce_flags.smca)
return;
if (this_cpu_ptr(mce_banks_array)[m->bank].lsb_in_status) {
lsb = (m->status >> 24) & 0x3f;
m->addr &= GENMASK_ULL(56, lsb);
return;
}
lsb = (m->addr >> 56) & 0x3f;
m->addr &= GENMASK_ULL(55, lsb);
}
#else #else
static inline bool amd_filter_mce(struct mce *m) { return false; } static inline bool amd_filter_mce(struct mce *m) { return false; }
static inline void smca_extract_err_addr(struct mce *m) { }
#endif #endif
#ifdef CONFIG_X86_ANCIENT_MCE #ifdef CONFIG_X86_ANCIENT_MCE
......
...@@ -657,7 +657,7 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val, ...@@ -657,7 +657,7 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
memset(&res, 0, sizeof(res)); memset(&res, 0, sizeof(res));
res.mce = mce; res.mce = mce;
res.addr = mce->addr; res.addr = mce->addr & MCI_ADDR_PHYSADDR;
/* Try driver decoder first */ /* Try driver decoder first */
if (!(driver_decode && driver_decode(&res))) { if (!(driver_decode && driver_decode(&res))) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment