From: santino.wang <santino.wang@mediatek.com>
To: Matthias Brugger <matthias.bgg@gmail.com>,
AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com>
Cc: <linux-mediatek@lists.infradead.org>,
<linux-arm-kernel@lists.infradead.org>,
<linux-kernel@vger.kernel.org>, <light.chen@mediatek.com>,
<Fred-WY.Chen@mediatek.com>, <arnab.layek@mediatek.com>,
Santino Wang <santino.wang@mediatek.com>
Subject: [RFC PATCH 04/11] soc: mediatek: dram-ecc: handle GHES vendor records from the firmware
Date: Mon, 2 Nov 2026 17:23:26 +0800 [thread overview]
Message-ID: <20261102092334.138759-5-santino.wang@mediatek.com> (raw)
In-Reply-To: <20261102092334.138759-1-santino.wang@mediatek.com>
From: Santino Wang <santino.wang@mediatek.com>
The secure firmware reports an error as a CPER record that carries,
next to the standard memory error section, a MediaTek vendor section
with the raw DRAM controller error registers. Register a GHES vendor
record notifier that decodes the most severe entry of that dump and
then:
- tallies corrected and uncorrectable errors since boot and keeps
the first addresses of each kind,
- for a recoverable uncorrectable error on memory that Linux manages,
isolates the page with memory_failure() and panics if that fails,
while memory owned by a device (a carveout) is only reported to
its owner,
- passes the decoded event to in-kernel clients through a notifier
chain, for drivers such as a GPU driver that must react to errors
in memory they own.
Signed-off-by: Santino Wang <santino.wang@mediatek.com>
---
drivers/soc/mediatek/dram-ecc/core/Makefile | 1 +
.../mediatek/dram-ecc/core/ghes_notifier.c | 364 ++++++++++++++++++
.../mediatek/dram-ecc/core/ghes_notifier.h | 22 ++
drivers/soc/mediatek/dram-ecc/core/main.c | 10 +-
.../dram-ecc/core/mtk_dram_ecc_event.h | 47 +++
5 files changed, 443 insertions(+), 1 deletion(-)
create mode 100644 drivers/soc/mediatek/dram-ecc/core/ghes_notifier.c
create mode 100644 drivers/soc/mediatek/dram-ecc/core/ghes_notifier.h
create mode 100644 drivers/soc/mediatek/dram-ecc/core/mtk_dram_ecc_event.h
diff --git a/drivers/soc/mediatek/dram-ecc/core/Makefile b/drivers/soc/mediatek/dram-ecc/core/Makefile
index 66ce5d306a45..304117845420 100644
--- a/drivers/soc/mediatek/dram-ecc/core/Makefile
+++ b/drivers/soc/mediatek/dram-ecc/core/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_MTK_DRAM_ECC) += mtk_dram_ecc.o
mtk_dram_ecc-y := \
main.o \
smc.o \
+ ghes_notifier.o \
trace.o
CFLAGS_trace.o := -I$(src)
diff --git a/drivers/soc/mediatek/dram-ecc/core/ghes_notifier.c b/drivers/soc/mediatek/dram-ecc/core/ghes_notifier.c
new file mode 100644
index 000000000000..4ba65875e427
--- /dev/null
+++ b/drivers/soc/mediatek/dram-ecc/core/ghes_notifier.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026 MediaTek Inc.
+ */
+/*
+ * GHES vendor-section consumer for DRAM ECC CE/UCE notifications
+ * (delivered via ACPI_HEST_NOTIFY_GSIV, SPI 248 - not SDEI).
+ *
+ * ATF's dram_ecc/mt8992/fiq.c only makes a minimal CE-vs-UCE call itself (to
+ * pick the GHES instance); it hands off the full raw
+ * ECCERR_INFO0~31/INFO32/DB0~DB4 dump for both sub-channels via the
+ * vendor section instead of throwing away everything but one entry. So
+ * this driver makes the same adjustment ATF made: it independently scans
+ * that raw dump for the worst (MBE > SBE) entry and decodes it itself,
+ * using the exact same algorithm as ATF's dram_ecc/mt8992/fiq.c
+ * (get_error_type()/decode_physical_address()) - kernel and ATF must agree on
+ * what "the" error for this notification is.
+ */
+#include <linux/notifier.h>
+#include <linux/atomic.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/panic.h>
+#include <acpi/ghes.h>
+
+#include "mtk_dram_ecc.h"
+#include "mtk_dram_ecc_event.h"
+#include "ghes_notifier.h"
+#include "trace.h"
+
+static ATOMIC_NOTIFIER_HEAD(mtk_dram_ecc_notifier_chain);
+
+int mtk_dram_ecc_register_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&mtk_dram_ecc_notifier_chain, nb);
+}
+EXPORT_SYMBOL_GPL(mtk_dram_ecc_register_notifier);
+
+int mtk_dram_ecc_unregister_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&mtk_dram_ecc_notifier_chain, nb);
+}
+EXPORT_SYMBOL_GPL(mtk_dram_ecc_unregister_notifier);
+
+static atomic64_t volatile_ce_count = ATOMIC64_INIT(0);
+static atomic64_t volatile_uce_inline_count = ATOMIC64_INIT(0);
+static atomic64_t volatile_uce_ondie_count = ATOMIC64_INIT(0);
+
+static u64 ce_addrs[MTK_ECC_MAX_BOOT_ADDRS];
+static u64 uce_addrs[MTK_ECC_MAX_BOOT_ADDRS];
+static int ce_addr_count;
+static int uce_addr_count;
+static DEFINE_SPINLOCK(addr_lock);
+
+static const guid_t mtk_vendor_guid =
+ GUID_INIT(0x4E117621, 0x9725, 0x48E4,
+ 0xA3, 0xA0, 0xD2, 0xE5, 0xB1, 0x64, 0x8C, 0x5A);
+
+/*
+ * Raw ECCERR_INFO0~31 + INFO32 + DB0~DB4 dump for one sub-channel - must
+ * match ATF apei/ghes.h's struct mtk_dram_ecc_subch_dump exactly, byte
+ * for byte (ATF is the writer, ACPI GHES entry data is opaque bytes).
+ */
+struct mtk_vendor_subch_dump {
+ u32 info[16][2];
+ u32 info32;
+ u32 db0;
+ u32 db1;
+ u32 db2;
+ u32 db3;
+ u32 db4;
+};
+
+/*
+ * Must match ATF apei/ghes.h's struct mtk_dram_ecc_raw_dump exactly.
+ *
+ * physical_addr is decoded by ATF, which already needs it for the standard
+ * memory-error section. Consuming it here avoids keeping a second copy of the
+ * DRAMC bit-scatter map in sync with ATF's decode_physical_address(). The raw
+ * dump is retained for engineer post-mortem via the CPER hex dump.
+ */
+struct mtk_vendor_section {
+ u64 physical_addr;
+ u32 ch_idx;
+ /*
+ * Inline ECC sees every UCE, so from_inline_ecc is 1; from_ondie_ecc is
+ * also 1 when the error originated in the DRAM die.
+ */
+ u16 from_inline_ecc;
+ u16 from_ondie_ecc;
+ struct mtk_vendor_subch_dump subch[2];
+};
+
+/* ERR_TYPE_DLEP/LECC encoding (info0[31:30]/[29:28]): 0=no err, 1=SBE, 2=MBE, 3=parity SBE */
+#define MTK_ECC_ERR_TYPE_NONE 0U
+#define MTK_ECC_ERR_TYPE_SBE 1U
+#define MTK_ECC_ERR_TYPE_MBE 2U
+
+/* Worse of ERR_TYPE_DLEP/ERR_TYPE_LECC for one entry; 0 if neither reports an error. */
+static u32 entry_err_type(u32 info0)
+{
+ u32 t_dlep = (info0 >> 30) & 0x3U;
+ u32 t_lecc = (info0 >> 28) & 0x3U;
+
+ if (t_dlep == MTK_ECC_ERR_TYPE_MBE || t_lecc == MTK_ECC_ERR_TYPE_MBE)
+ return MTK_ECC_ERR_TYPE_MBE;
+ if (t_dlep != 0U || t_lecc != 0U)
+ return MTK_ECC_ERR_TYPE_SBE;
+ return MTK_ECC_ERR_TYPE_NONE;
+}
+
+/*
+ * Scan both sub-channels' ECCERR_INFO0~31 for the single worst (MBE > SBE)
+ * entry and fill @evt from it. Mirrors ATF dram_ecc/mt8992/fiq.c's
+ * scan_subchannel()/get_error_type() selection order, so the entry picked here
+ * is the same one ATF decoded. Returns MTK_ECC_ERR_TYPE_NONE if every entry in
+ * the dump is empty.
+ *
+ * rank/bank/row/column are plain field extractions from the selected entry.
+ * The physical address is not re-derived: ATF publishes the value it already
+ * decoded for the standard memory-error section in vs->physical_addr, which
+ * keeps the DRAMC bit-scatter map in exactly one place.
+ */
+static u32 decode_worst_entry(const struct mtk_vendor_section *vs,
+ struct mtk_dram_ecc_event *evt)
+{
+ u32 severity = MTK_ECC_ERR_TYPE_NONE;
+ u32 sel_info0 = 0, sel_info1 = 0;
+ int sel_subch = 0;
+ int subch, e;
+
+ for (subch = 0; subch < 2; subch++) {
+ const struct mtk_vendor_subch_dump *d = &vs->subch[subch];
+
+ for (e = 0; e < 16; e++) {
+ u32 info0 = d->info[e][0];
+ u32 info1 = d->info[e][1];
+ u32 type = entry_err_type(info0);
+
+ if (type > severity) {
+ severity = type;
+ sel_info0 = info0;
+ sel_info1 = info1;
+ sel_subch = subch;
+ }
+ }
+ }
+
+ if (severity == MTK_ECC_ERR_TYPE_NONE)
+ return severity;
+
+ evt->spa = vs->physical_addr;
+ evt->rank = (u16)(sel_info0 & 0x3U);
+ evt->bank = (u16)((sel_info0 >> 2) & 0x1fU);
+ evt->row = (sel_info1 >> 11) & 0x3ffffU;
+ evt->column = (u16)(sel_info1 & 0x7ffU);
+ evt->channel = (u8)vs->ch_idx;
+ evt->subchannel = (u8)sel_subch;
+
+ return severity;
+}
+
+/*
+ * Is this PFN memory Linux itself manages, i.e. memory we are entitled to
+ * poison?
+ *
+ * page_is_ram() on its own is not an ownership test: a device carveout
+ * reserved out of a System RAM resource still satisfies it. Such a carveout
+ * keeps PageReserved set, so additionally require a struct page that is not
+ * reserved. Everything else belongs to its device owner - a recoverable UCE
+ * there is only reported to the owner, never isolated here.
+ */
+static bool pfn_is_linux_managed(unsigned long pfn)
+{
+ if (!pfn_valid(pfn) || !page_is_ram(pfn))
+ return false;
+
+ return !PageReserved(pfn_to_page(pfn));
+}
+
+static int mtk_ghes_vendor_cb(struct notifier_block *nb, unsigned long severity,
+ void *data)
+{
+ struct acpi_hest_generic_data *gdata = data;
+ const struct mtk_vendor_section *vs;
+ struct mtk_dram_ecc_event evt = { 0 };
+ guid_t *sec_type;
+ int ret;
+
+ sec_type = (guid_t *)gdata->section_type;
+ if (!guid_equal(sec_type, &mtk_vendor_guid)) {
+ /* Not our vendor record - log the GUID (rate-limited) so a
+ * GUID mismatch between ATF and this driver is not a silent
+ * "nothing happened".
+ */
+ pr_warn_ratelimited("mtk-dram-ecc: GHES vendor record with non-MTK section GUID %pUl, ignoring\n",
+ sec_type);
+ return NOTIFY_DONE;
+ }
+
+ if (severity == GHES_SEV_CORRECTED) {
+ evt.severity = MTK_DRAM_ECC_NOTIFY_CE;
+ } else if (severity == GHES_SEV_RECOVERABLE) {
+ evt.severity = MTK_DRAM_ECC_NOTIFY_UCE;
+ } else {
+ pr_warn_ratelimited("mtk-dram-ecc: unsupported GHES vendor-record severity %lu, ignoring\n",
+ severity);
+ return NOTIFY_DONE;
+ }
+
+ /*
+ * Generic GHES only guarantees the declared section fits inside the
+ * copied error-status block; it knows nothing about this MTK-specific
+ * minimum. Reject a truncated record before the decoder reads past the
+ * section.
+ */
+ if (acpi_hest_get_error_length(gdata) < sizeof(struct mtk_vendor_section)) {
+ pr_warn_ratelimited("mtk-dram-ecc: MTK vendor section too short: %d < %zu, ignoring\n",
+ acpi_hest_get_error_length(gdata),
+ sizeof(struct mtk_vendor_section));
+ return NOTIFY_DONE;
+ }
+
+ vs = acpi_hest_get_payload(gdata);
+
+ if (decode_worst_entry(vs, &evt) == MTK_ECC_ERR_TYPE_NONE) {
+ pr_warn("mtk-dram-ecc: GHES vendor section CH%u has no non-zero ECCERR_INFO entry\n",
+ vs->ch_idx);
+ return NOTIFY_OK;
+ }
+
+ /* Announce the decoded event before taking any action, independent of
+ * tracepoints / the optional notify_sink modules, so the path is
+ * observable in dmesg even if a downstream step fails.
+ */
+ pr_info("mtk-dram-ecc: %s CH%u subch%u spa=0x%llx rank=%u bank=%u row=%u col=%u\n",
+ (evt.severity == MTK_DRAM_ECC_NOTIFY_CE) ? "CE" : "UCE",
+ vs->ch_idx, evt.subchannel, evt.spa, evt.rank, evt.bank, evt.row,
+ evt.column);
+
+ if (evt.severity == MTK_DRAM_ECC_NOTIFY_CE) {
+ atomic64_inc(&volatile_ce_count);
+ spin_lock(&addr_lock);
+ if (ce_addr_count < MTK_ECC_MAX_BOOT_ADDRS)
+ ce_addrs[ce_addr_count++] = evt.spa;
+ spin_unlock(&addr_lock);
+ trace_mtk_dram_ecc_ce(evt.spa, evt.channel, evt.subchannel, evt.rank,
+ evt.bank, evt.row, evt.column);
+ ret = atomic_notifier_call_chain(&mtk_dram_ecc_notifier_chain,
+ MTK_DRAM_ECC_NOTIFY_CE, &evt);
+ if (ret == NOTIFY_BAD)
+ pr_warn_ratelimited("mtk-dram-ecc: kernel client rejected CE event for spa=0x%llx\n",
+ evt.spa);
+ } else {
+ unsigned long pfn = evt.spa >> PAGE_SHIFT;
+
+ /* Inline ECC detects every UCE, including an on-die one. */
+ atomic64_inc(&volatile_uce_inline_count);
+ if (vs->from_ondie_ecc)
+ atomic64_inc(&volatile_uce_ondie_count);
+ spin_lock(&addr_lock);
+ if (uce_addr_count < MTK_ECC_MAX_BOOT_ADDRS)
+ uce_addrs[uce_addr_count++] = evt.spa;
+ spin_unlock(&addr_lock);
+ trace_mtk_dram_ecc_uce(evt.spa, evt.channel, evt.subchannel, evt.rank,
+ evt.bank, evt.row, evt.column);
+ /*
+ * memory_failure() owns Linux-managed memory only. A device
+ * carveout is recovered by the subscriber that owns the SPA
+ * range, so this path only notifies for it. Generic GHES
+ * cannot pre-empt that decision either: with
+ * CONFIG_ACPI_APEI_MEMORY_FAILURE=y it does call
+ * memory_failure() off the standard section, but
+ * pfn_to_online_page() returns NULL for a carveout, so that
+ * call fails with -ENXIO without poisoning anything. On
+ * Linux-managed memory the two paths race benignly; see the
+ * -EHWPOISON handling in mtk_dram_ecc_record_retired_page().
+ */
+ if (pfn_is_linux_managed(pfn)) {
+ ret = memory_failure(pfn, 0);
+ pr_info("mtk-dram-ecc: memory_failure(pfn=0x%lx) returned %d\n",
+ pfn, ret);
+ if (ret != 0 && ret != -EHWPOISON) {
+ pr_emerg("mtk-dram-ecc: recoverable UCE isolation failed: pfn=0x%lx ret=%d\n",
+ pfn, ret);
+ panic("DRAM ECC recoverable UCE isolation failed");
+ }
+ } else {
+ pr_info("mtk-dram-ecc: notify-only UCE spa=0x%llx (not Linux-managed memory)\n",
+ evt.spa);
+ }
+ ret = atomic_notifier_call_chain(&mtk_dram_ecc_notifier_chain,
+ MTK_DRAM_ECC_NOTIFY_UCE, &evt);
+ if (ret == NOTIFY_BAD)
+ pr_warn_ratelimited("mtk-dram-ecc: kernel client rejected UCE event for spa=0x%llx\n",
+ evt.spa);
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block mtk_ghes_vendor_nb = {
+ .notifier_call = mtk_ghes_vendor_cb,
+};
+
+u64 mtk_dram_ecc_get_volatile_ce(void)
+{
+ return atomic64_read(&volatile_ce_count);
+}
+EXPORT_SYMBOL_GPL(mtk_dram_ecc_get_volatile_ce);
+
+u64 mtk_dram_ecc_get_volatile_uce_inline(void)
+{
+ return atomic64_read(&volatile_uce_inline_count);
+}
+EXPORT_SYMBOL_GPL(mtk_dram_ecc_get_volatile_uce_inline);
+
+u64 mtk_dram_ecc_get_volatile_uce_ondie(void)
+{
+ return atomic64_read(&volatile_uce_ondie_count);
+}
+EXPORT_SYMBOL_GPL(mtk_dram_ecc_get_volatile_uce_ondie);
+
+/* Total UCE count: every UCE is seen by inline ECC (on-die is a subset). */
+u64 mtk_dram_ecc_get_volatile_uce(void)
+{
+ return mtk_dram_ecc_get_volatile_uce_inline();
+}
+EXPORT_SYMBOL_GPL(mtk_dram_ecc_get_volatile_uce);
+
+int mtk_dram_ecc_get_ce_addrs(u64 *buf, int max)
+{
+ int count;
+
+ spin_lock(&addr_lock);
+ count = min(ce_addr_count, max);
+ memcpy(buf, ce_addrs, count * sizeof(u64));
+ spin_unlock(&addr_lock);
+ return count;
+}
+EXPORT_SYMBOL_GPL(mtk_dram_ecc_get_ce_addrs);
+
+int mtk_dram_ecc_get_uce_addrs(u64 *buf, int max)
+{
+ int count;
+
+ spin_lock(&addr_lock);
+ count = min(uce_addr_count, max);
+ memcpy(buf, uce_addrs, count * sizeof(u64));
+ spin_unlock(&addr_lock);
+ return count;
+}
+EXPORT_SYMBOL_GPL(mtk_dram_ecc_get_uce_addrs);
+
+int mtk_dram_ecc_ghes_init(void)
+{
+ return ghes_register_vendor_record_notifier(&mtk_ghes_vendor_nb);
+}
+
+void mtk_dram_ecc_ghes_exit(void)
+{
+ ghes_unregister_vendor_record_notifier(&mtk_ghes_vendor_nb);
+}
diff --git a/drivers/soc/mediatek/dram-ecc/core/ghes_notifier.h b/drivers/soc/mediatek/dram-ecc/core/ghes_notifier.h
new file mode 100644
index 000000000000..649e2d5fe928
--- /dev/null
+++ b/drivers/soc/mediatek/dram-ecc/core/ghes_notifier.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 MediaTek Inc.
+ */
+#ifndef _MTK_DRAM_ECC_GHES_NOTIFIER_H_
+#define _MTK_DRAM_ECC_GHES_NOTIFIER_H_
+
+#include <linux/types.h>
+
+#define MTK_ECC_MAX_BOOT_ADDRS 256
+
+int mtk_dram_ecc_ghes_init(void);
+void mtk_dram_ecc_ghes_exit(void);
+
+u64 mtk_dram_ecc_get_volatile_ce(void);
+u64 mtk_dram_ecc_get_volatile_uce_inline(void);
+u64 mtk_dram_ecc_get_volatile_uce_ondie(void);
+u64 mtk_dram_ecc_get_volatile_uce(void);
+int mtk_dram_ecc_get_ce_addrs(u64 *buf, int max);
+int mtk_dram_ecc_get_uce_addrs(u64 *buf, int max);
+
+#endif /* _MTK_DRAM_ECC_GHES_NOTIFIER_H_ */
diff --git a/drivers/soc/mediatek/dram-ecc/core/main.c b/drivers/soc/mediatek/dram-ecc/core/main.c
index ce6bd39fa303..3232046394e3 100644
--- a/drivers/soc/mediatek/dram-ecc/core/main.c
+++ b/drivers/soc/mediatek/dram-ecc/core/main.c
@@ -7,6 +7,7 @@
#include <linux/device/class.h>
#include "mtk_dram_ecc.h"
+#include "ghes_notifier.h"
#include "trace.h"
static struct class *mtk_dram_ecc_class;
@@ -34,10 +35,16 @@ static int __init mtk_dram_ecc_init(void)
goto err_class;
}
+ ret = mtk_dram_ecc_ghes_init();
+ if (ret)
+ goto err_dev;
+
trace_mtk_dram_ecc_lifecycle(0);
- dev_info(mtk_dram_ecc_dev, "initialized\n");
+ dev_info(mtk_dram_ecc_dev, "initialized (GHES vendor notifier registered)\n");
return 0;
+err_dev:
+ device_destroy(mtk_dram_ecc_class, MKDEV(0, 0));
err_class:
class_destroy(mtk_dram_ecc_class);
return ret;
@@ -45,6 +52,7 @@ static int __init mtk_dram_ecc_init(void)
static void __exit mtk_dram_ecc_exit(void)
{
+ mtk_dram_ecc_ghes_exit();
device_destroy(mtk_dram_ecc_class, MKDEV(0, 0));
class_destroy(mtk_dram_ecc_class);
trace_mtk_dram_ecc_lifecycle(1);
diff --git a/drivers/soc/mediatek/dram-ecc/core/mtk_dram_ecc_event.h b/drivers/soc/mediatek/dram-ecc/core/mtk_dram_ecc_event.h
new file mode 100644
index 000000000000..ae7bd7c3abfa
--- /dev/null
+++ b/drivers/soc/mediatek/dram-ecc/core/mtk_dram_ecc_event.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 MediaTek Inc.
+ */
+#ifndef _MTK_DRAM_ECC_EVENT_H_
+#define _MTK_DRAM_ECC_EVENT_H_
+
+#include <linux/types.h>
+#include <linux/notifier.h>
+
+/**
+ * struct mtk_dram_ecc_event - payload passed to notifier chain subscribers
+ * @spa: System Physical Address of the error, decoded from the
+ * ECCERR_INFO0/1 entry that determined severity (see
+ * ghes_notifier.c) - mirrors ATF dram_ecc/mt8992/fiq.c's decode.
+ * @rank: DRAMC rank address (RANK_ADDR, info0[1:0])
+ * @bank: DRAMC bank address (BANK_ADDR, info0[6:2])
+ * @row: DRAMC row address (ROW_ADDR, info1[28:11])
+ * @column: DRAMC column address (COL_ADDR, info1[10:0])
+ * @severity: MTK_DRAM_ECC_NOTIFY_CE or MTK_DRAM_ECC_NOTIFY_UCE
+ * @channel: DRAM channel index reported by the firmware for this record
+ * @subchannel: sub-channel (0 or 1) of the ECCERR_INFO0/1 entry
+ *
+ * No agent/master ID fields: ATF's GHES vendor section no longer computes
+ * them (see ATF apei/ghes.c) - MASTER_ID/RID are still in the raw
+ * ECCERR_INFO0/1 dump the vendor section carries, just not surfaced here
+ * yet.
+ */
+struct mtk_dram_ecc_event {
+ u64 spa;
+ u16 rank;
+ u16 bank;
+ u32 row;
+ u16 column;
+ u8 severity;
+ u8 channel;
+ u8 subchannel;
+};
+
+/* notifier_call val argument */
+#define MTK_DRAM_ECC_NOTIFY_CE 0
+#define MTK_DRAM_ECC_NOTIFY_UCE 1
+
+int mtk_dram_ecc_register_notifier(struct notifier_block *nb);
+int mtk_dram_ecc_unregister_notifier(struct notifier_block *nb);
+
+#endif /* _MTK_DRAM_ECC_EVENT_H_ */
--
2.45.2
next prev parent reply other threads:[~2026-11-02 9:25 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 9:23 [RFC PATCH 00/11] soc: mediatek: add a DRAM ECC error handling driver santino.wang
2026-11-02 9:23 ` [RFC PATCH 01/11] soc: mediatek: dram-ecc: add the DRAM ECC driver skeleton santino.wang
2026-11-02 13:41 ` Krzysztof Kozlowski
2026-11-02 9:23 ` [RFC PATCH 02/11] soc: mediatek: dram-ecc: add the SMC interface to the secure firmware santino.wang
2026-11-02 9:23 ` [RFC PATCH 03/11] soc: mediatek: dram-ecc: add tracepoints santino.wang
2026-11-02 9:23 ` santino.wang [this message]
2026-11-02 9:23 ` [RFC PATCH 05/11] soc: mediatek: dram-ecc: add error counters and the address lists santino.wang
2026-11-02 13:42 ` Krzysztof Kozlowski
2026-11-02 9:23 ` [RFC PATCH 06/11] soc: mediatek: dram-ecc: keep error counters across boots santino.wang
2026-11-02 9:23 ` [RFC PATCH 07/11] soc: mediatek: dram-ecc: add containment policy and storm protection santino.wang
2026-11-02 9:23 ` [RFC PATCH 08/11] soc: mediatek: dram-ecc: add the corrected error leaky bucket santino.wang
2026-11-02 9:23 ` [RFC PATCH 09/11] soc: mediatek: dram-ecc: add a generic netlink event interface santino.wang
2026-11-02 9:23 ` [RFC PATCH 10/11] soc: mediatek: dram-ecc: report an uncorrectable error of the previous boot santino.wang
2026-11-02 13:44 ` Krzysztof Kozlowski
2026-11-02 9:23 ` [RFC PATCH 11/11] Documentation: ABI: add the sysfs attributes of the MediaTek DRAM ECC driver santino.wang
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=20261102092334.138759-5-santino.wang@mediatek.com \
--to=santino.wang@mediatek.com \
--cc=Fred-WY.Chen@mediatek.com \
--cc=angelogioacchino.delregno@collabora.com \
--cc=arnab.layek@mediatek.com \
--cc=light.chen@mediatek.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=matthias.bgg@gmail.com \
/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
all inboxes | Powered by JetHome®