From: Yazen Ghannam <yazen.ghannam@amd.com>
To: <x86@kernel.org>, Tony Luck <tony.luck@intel.com>
Cc: <linux-kernel@vger.kernel.org>, <linux-edac@vger.kernel.org>,
<Smita.KoralahalliChannabasappa@amd.com>,
Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Subject: [PATCH v3 13/17] x86/mce: Unify AMD DFR handler with MCA Polling
Date: Tue, 15 Apr 2025 14:55:08 +0000 [thread overview]
Message-ID: <20250415-wip-mca-updates-v3-13-8ffd9eb4aa56@amd.com> (raw)
In-Reply-To: <20250415-wip-mca-updates-v3-0-8ffd9eb4aa56@amd.com>
AMD systems optionally support a deferred error interrupt. The interrupt
should be used as another signal to trigger MCA polling. This is similar
to how other MCA interrupts are handled.
Deferred errors do not require any special handling related to the
interrupt, e.g. resetting or rearming the interrupt, etc.
However, Scalable MCA systems include a pair of registers, MCA_DESTAT
and MCA_DEADDR, that should be checked for valid errors. This check
should be done whenever MCA registers are polled. Currently, the
deferred error interrupt does this check, but the MCA polling function
does not.
Call the MCA polling function when handling the deferred error
interrupt. This keeps all "polling" cases in a common function.
Call the polling function only for banks that have the deferred error
interrupt enabled.
Add an SMCA status check helper. This will do the same status check and
register clearing that the interrupt handler has done. And it extends
the common polling flow to find AMD deferred errors.
Remove old code whose functionality is already covered in the common MCA
code.
Reviewed-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Tested-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
Notes:
Link:
https://lore.kernel.org/r/20250213-wip-mca-updates-v2-13-3636547fe05f@amd.com
v2->v3:
* Add tags from Qiuxu and Tony.
v1->v2:
* Keep code comment.
* Log directly from helper function rather than pass values.
arch/x86/kernel/cpu/mce/amd.c | 103 ++---------------------------------------
arch/x86/kernel/cpu/mce/core.c | 60 +++++++++++++++++++++++-
2 files changed, 64 insertions(+), 99 deletions(-)
diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c
index f8755a21fd48..62c4fe98d02a 100644
--- a/arch/x86/kernel/cpu/mce/amd.c
+++ b/arch/x86/kernel/cpu/mce/amd.c
@@ -56,6 +56,7 @@ static bool thresholding_irq_en;
struct mce_amd_cpu_data {
mce_banks_t thr_intr_banks;
+ mce_banks_t dfr_intr_banks;
};
static DEFINE_PER_CPU_READ_MOSTLY(struct mce_amd_cpu_data, mce_amd_data);
@@ -300,8 +301,10 @@ 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)) {
+ __set_bit(bank, this_cpu_ptr(&mce_amd_data)->dfr_intr_banks);
high |= BIT(5);
+ }
this_cpu_ptr(mce_banks_array)[bank].lsb_in_status = !!(low & BIT(8));
@@ -794,37 +797,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);
@@ -834,75 +806,10 @@ 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 reset_block(struct threshold_block *block)
diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
index de85b014653f..0a2a97681266 100644
--- a/arch/x86/kernel/cpu/mce/core.c
+++ b/arch/x86/kernel/cpu/mce/core.c
@@ -714,6 +714,61 @@ 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(enum mcp_flags flags, struct mce_hw_err *err)
+{
+ struct mce *m = &err->m;
+
+ /*
+ * If this is a deferred error found in MCA_STATUS, then clear
+ * the redundant data from the MCA_DESTAT register.
+ */
+ if (m->status & MCI_STATUS_VAL) {
+ if (m->status & MCI_STATUS_DEFERRED)
+ mce_wrmsrq(MSR_AMD64_SMCA_MCx_DESTAT(m->bank), 0);
+
+ return true;
+ }
+
+ /*
+ * If the MCA_DESTAT register has valid data, then use
+ * it as the status register.
+ */
+ m->status = mce_rdmsrq(MSR_AMD64_SMCA_MCx_DESTAT(m->bank));
+
+ if (!(m->status & MCI_STATUS_VAL))
+ return false;
+
+ /*
+ * Gather all relevant data now and log the record before clearing
+ * the deferred status register. This avoids needing to go back to
+ * the polling function for these actions.
+ */
+ mce_read_aux(err, m->bank);
+
+ if (m->status & MCI_STATUS_ADDRV)
+ m->addr = mce_rdmsrq(MSR_AMD64_SMCA_MCx_DEADDR(m->bank));
+
+ smca_extract_err_addr(m);
+ m->severity = mce_severity(m, NULL, NULL, false);
+
+ if (flags & MCP_QUEUE_LOG)
+ mce_gen_pool_add(err);
+ else
+ mce_log(err);
+
+ mce_wrmsrq(MSR_AMD64_SMCA_MCx_DESTAT(m->bank), 0);
+ return false;
+}
+
/*
* Newer Intel systems that support software error
* recovery need to make additional checks. Other
@@ -740,6 +795,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(flags, err);
+
/* If this entry is not valid, ignore it. */
if (!(m->status & MCI_STATUS_VAL))
return false;
@@ -2226,7 +2284,7 @@ void cpu_mca_init(struct cpuinfo_x86 *c)
if (mce_flags.smca)
mce_smca_cpu_init();
- rdmsrl(MSR_IA32_MCG_CAP, cap);
+ rdmsrq(MSR_IA32_MCG_CAP, cap);
/* Use accurate RIP reporting if available. */
if ((cap & MCG_EXT_P) && MCG_EXT_CNT(cap) >= 9)
--
2.49.0
next prev parent reply other threads:[~2025-04-15 14:55 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-15 14:54 [PATCH v3 00/17] AMD MCA interrupts rework Yazen Ghannam
2025-04-15 14:54 ` [PATCH v3 01/17] x86/mce: Don't remove sysfs if thresholding sysfs init fails Yazen Ghannam
2025-04-15 14:54 ` [PATCH v3 02/17] x86/mce/amd: Remove return value for mce_threshold_{create,remove}_device() Yazen Ghannam
2025-04-15 14:54 ` [PATCH v3 03/17] x86/mce/amd: Remove smca_banks_map Yazen Ghannam
2025-04-15 14:54 ` [PATCH v3 04/17] x86/mce/amd: Put list_head in threshold_bank Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 05/17] x86/mce: Cleanup bank processing on init Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 06/17] x86/mce: Remove __mcheck_cpu_init_early() Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 07/17] x86/mce: Define BSP-only init Yazen Ghannam
2025-04-17 2:18 ` Borislav Petkov
2025-05-01 17:07 ` Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 08/17] x86/mce: Define BSP-only SMCA init Yazen Ghannam
2025-04-17 9:52 ` Borislav Petkov
2025-05-01 17:12 ` Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 09/17] x86/mce: Do 'UNKNOWN' vendor check early Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 10/17] x86/mce: Separate global and per-CPU quirks Yazen Ghannam
2025-04-17 12:16 ` Borislav Petkov
2025-05-01 17:23 ` Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 11/17] x86/mce: Move machine_check_poll() status checks to helper functions Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 12/17] x86/mce: Unify AMD THR handler with MCA Polling Yazen Ghannam
2025-04-15 14:55 ` Yazen Ghannam [this message]
2025-05-07 9:20 ` [PATCH v3 13/17] x86/mce: Unify AMD DFR " Borislav Petkov
2025-05-08 15:37 ` Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 14/17] x86/mce/amd: Enable interrupt vectors once per-CPU on SMCA systems Yazen Ghannam
2025-05-07 19:35 ` Borislav Petkov
2025-05-08 15:53 ` Yazen Ghannam
2025-05-09 14:08 ` Borislav Petkov
2025-05-12 15:34 ` Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 15/17] x86/mce/amd: Support SMCA Corrected Error Interrupt Yazen Ghannam
2025-05-09 19:37 ` Borislav Petkov
2025-05-12 15:35 ` Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 16/17] x86/mce: Handle AMD threshold interrupt storms Yazen Ghannam
2025-04-15 14:55 ` [PATCH v3 17/17] x86/mce: Restore poll settings after storm subsides Yazen Ghannam
2025-05-12 7:46 ` Borislav Petkov
2025-05-12 15:43 ` Yazen Ghannam
2025-05-12 15:53 ` Luck, Tony
2025-05-13 17:44 ` Yazen Ghannam
2025-05-13 17:55 ` Borislav Petkov
2025-05-13 21:06 ` Yazen Ghannam
2025-05-13 22:07 ` Luck, Tony
2025-05-14 14:34 ` Yazen Ghannam
2025-05-15 12:37 ` Borislav Petkov
2025-05-15 15:47 ` Yazen Ghannam
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250415-wip-mca-updates-v3-13-8ffd9eb4aa56@amd.com \
--to=yazen.ghannam@amd.com \
--cc=Smita.KoralahalliChannabasappa@amd.com \
--cc=linux-edac@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=qiuxu.zhuo@intel.com \
--cc=tony.luck@intel.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox