git: 996a832d2e01 - main - mca: Allow for passing ECC error record to memory controller driver

From: Stephen J. Kiernan <stevek_at_FreeBSD.org>
Date: Wed, 18 Sep 2024 14:37:24 UTC
The branch main has been updated by stevek:

URL: https://cgit.FreeBSD.org/src/commit/?id=996a832d2e01fceb5a3bbfd33df585bd778e6288

commit 996a832d2e01fceb5a3bbfd33df585bd778e6288
Author:     Stephen J. Kiernan <stevek@FreeBSD.org>
AuthorDate: 2024-09-18 14:37:14 +0000
Commit:     Stephen J. Kiernan <stevek@FreeBSD.org>
CommitDate: 2024-09-18 14:37:14 +0000

    mca: Allow for passing ECC error record to memory controller driver
    
    Added (de)registration functions for memory controller driver to be
    notified when ECC errors occur. This allows for decoding of the
    specific error by the driver.
    
    Submitted by:   Lakshman Likith Nudurupati <lnlakshman@juniper.net>
    Sponsored by:   Juniper Networks, Inc.
    Obtained from:  Semihalf
---
 sys/x86/include/mca.h |  5 +++++
 sys/x86/x86/mca.c     | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/sys/x86/include/mca.h b/sys/x86/include/mca.h
index 183480625f6d..d8b8da86523d 100644
--- a/sys/x86/include/mca.h
+++ b/sys/x86/include/mca.h
@@ -46,6 +46,11 @@ struct mca_record {
 
 #ifdef _KERNEL
 
+typedef void (*mca_decode_func)(void *, const struct mca_record *);
+
+int	mca_register_decode_func(mca_decode_func func, void *aux);
+int	mca_deregister_decode_func(mca_decode_func func);
+
 void	cmc_intr(void);
 void	mca_init(void);
 void	mca_intr(void);
diff --git a/sys/x86/x86/mca.c b/sys/x86/x86/mca.c
index b293fcedbd84..89ab59639882 100644
--- a/sys/x86/x86/mca.c
+++ b/sys/x86/x86/mca.c
@@ -99,6 +99,8 @@ static MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture");
 static volatile int mca_count;	/* Number of records stored. */
 static int mca_banks;		/* Number of per-CPU register banks. */
 static int mca_maxcount = -1;	/* Limit on records stored. (-1 = unlimited) */
+static mca_decode_func mca_func;
+static void *mca_decode_arg;
 
 static SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
     "Machine Check Architecture");
@@ -421,6 +423,50 @@ mca_mute(const struct mca_record *rec)
 	return (0);
 }
 
+/*
+ * Pass mca_record to a memory controller driver so that it can decode
+ * the address and possibly do some more work.
+ */
+static void
+mca_decode_record(const struct mca_record *rec)
+{
+
+	if (mca_func != NULL)
+		mca_func(mca_decode_arg, rec);
+}
+
+int
+mca_register_decode_func(mca_decode_func func, void *aux)
+{
+	int error;
+
+	if (func == NULL)
+		return (EINVAL);
+
+	error = 0;
+	mtx_lock_spin(&mca_lock);
+	if (mca_func != NULL)
+		error = EEXIST;
+
+	if (error == 0) {
+		mca_func = func;
+		mca_decode_arg = aux;
+	}
+
+	mtx_unlock_spin(&mca_lock);
+	return (error);
+}
+
+int
+mca_deregister_decode_func(mca_decode_func func)
+{
+	if (func == NULL || func != mca_func)
+		return (EINVAL);
+
+	mca_func = NULL;
+	return (0);
+}
+
 /* Dump details about a single machine check. */
 static void
 mca_log(const struct mca_record *rec)
@@ -613,6 +659,8 @@ mca_log(const struct mca_record *rec)
 	}
 	if (rec->mr_status & MC_STATUS_MISCV)
 		printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc);
+
+	mca_decode_record(rec);
 }
 
 static bool