Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Ruidong Tian <tianruidong@linux.alibaba.com>
To: Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	Lorenzo Pieralisi <lpieralisi@kernel.org>,
	Hanjun Guo <guohanjun@huawei.com>,
	Sudeep Holla <sudeep.holla@kernel.org>,
	"Rafael J . Wysocki" <rafael@kernel.org>,
	Len Brown <lenb@kernel.org>, Tony Luck <tony.luck@intel.com>,
	Borislav Petkov <bp@alien8.de>, Thomas Gleixner <tglx@kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Robin Murphy <robin.murphy@arm.com>,
	Umang Chheda <umang.chheda@oss.qualcomm.com>
Cc: linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-edac@vger.kernel.org,
	zhuo.song@linux.alibaba.com, oliver.yang@linux.alibaba.com,
	Ruidong Tian <tianruidong@linux.alibaba.com>
Subject: [PATCH v7 06/16] arm64: ras: Enable error reporting
Date: Tue,  2 Jun 2026 15:15:29 +0800	[thread overview]
Message-ID: <20260602071540.3711528-7-tianruidong@linux.alibaba.com> (raw)
In-Reply-To: <20260602071540.3711528-1-tianruidong@linux.alibaba.com>

Until now, AEST nodes were registered but never had interrupt routing
programmed, so probe finished without actually arming any error source.
Both shared and PE (oncore) nodes need this bring-up; the difference
is only that oncore state is percpu and must follow CPU online/offline.

Signed-off-by: Ruidong Tian <tianruidong@linux.alibaba.com>
---
 arch/arm64/include/asm/ras.h |  10 +++
 drivers/acpi/arm64/aest.c    |   4 +-
 drivers/ras/arm64/ras-core.c | 159 ++++++++++++++++++++++++++++++++++-
 drivers/ras/arm64/ras.h      |  32 +++++++
 include/linux/cpuhotplug.h   |   1 +
 5 files changed, 204 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/ras.h b/arch/arm64/include/asm/ras.h
index b6640b9972bf..a992610d7755 100644
--- a/arch/arm64/include/asm/ras.h
+++ b/arch/arm64/include/asm/ras.h
@@ -2,8 +2,18 @@
 #ifndef __ASM_RAS_H
 #define __ASM_RAS_H
 
+#include <linux/bits.h>
 #include <linux/types.h>
 
+/* ERR<n>CTLR */
+#define ERR_CTLR_CFI			BIT(8)
+#define ERR_CTLR_FI			BIT(3)
+#define ERR_CTLR_UI			BIT(2)
+
+/* ERRIRQCR<n> */
+#define ERRFHICR0_OFFSET		0x0
+#define ERRERICR0_OFFSET		0x10
+
 struct ras_ext_regs {
 	u64 err_fr;
 	u64 err_ctlr;
diff --git a/drivers/acpi/arm64/aest.c b/drivers/acpi/arm64/aest.c
index af03f4365cfa..5733c91c8e0d 100644
--- a/drivers/acpi/arm64/aest.c
+++ b/drivers/acpi/arm64/aest.c
@@ -157,6 +157,8 @@ aest_init_node_props(struct acpi_aest_hdr *hdr, struct property_entry *props,
 					   common->error_group_register_base);
 	props[(*p)++] = PROPERTY_ENTRY_U64("arm,fault-inject-base",
 					   common->fault_inject_register_base);
+	props[(*p)++] = PROPERTY_ENTRY_U64("arm,interrupt-config-base",
+					   common->interrupt_config_register_base);
 	props[(*p)++] = PROPERTY_ENTRY_U32("arm,fhi-gsiv", fhi_gsiv);
 	props[(*p)++] = PROPERTY_ENTRY_U32("arm,eri-gsiv", eri_gsiv);
 
@@ -171,7 +173,7 @@ aest_init_node_props(struct acpi_aest_hdr *hdr, struct property_entry *props,
 static int __init
 aest_create_node_fwnode(struct acpi_aest_hdr *hdr, struct platform_device *pdev)
 {
-	struct property_entry props[14] = { };
+	struct property_entry props[15] = { };
 	int p = 0;
 	int ret;
 
diff --git a/drivers/ras/arm64/ras-core.c b/drivers/ras/arm64/ras-core.c
index 9520415df8cb..98f274b9731d 100644
--- a/drivers/ras/arm64/ras-core.c
+++ b/drivers/ras/arm64/ras-core.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2025, Alibaba Group.
  */
 
+#include <linux/cpu.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -45,6 +46,21 @@ const struct ras_group ras_group_config[] = {
 	},
 };
 
+static void ras_node_foreach_record(void (*func)(struct ras_record *, void *),
+				    struct ras_node *node, void *data,
+				    unsigned long *bitmap)
+{
+	int i;
+
+	for_each_clear_bit(i, bitmap, node->record_count) {
+		ras_select_record(node, i);
+
+		func(&node->records[i], data);
+
+		ras_sync(node);
+	}
+	}
+
 static irqreturn_t ras_irq_func(int irq, void *input)
 {
 	struct ras_node *node = input;
@@ -52,6 +68,23 @@ static irqreturn_t ras_irq_func(int irq, void *input)
 	return IRQ_HANDLED;
 }
 
+static void ras_config_irq(struct ras_node *node)
+{
+	u32 fhi_gsi, eri_gsi;
+
+	if (!node->irq_config)
+		return;
+
+	if (!device_property_read_u32(node->dev, "arm,fhi-gsiv", &fhi_gsi))
+		writeq_relaxed(fhi_gsi, node->irq_config + ERRFHICR0_OFFSET);
+
+	if (!device_property_read_u32(node->dev, "arm,eri-gsiv", &eri_gsi))
+		writeq_relaxed(eri_gsi, node->irq_config + ERRERICR0_OFFSET);
+
+	ras_node_dbg(node, "config irq fhi_gsi %u eri_gsi %u at %pK",
+		     fhi_gsi, eri_gsi, node->irq_config);
+}
+
 static int ras_register_irq(struct ras_node *node)
 {
 	int i, irq, ret;
@@ -94,6 +127,21 @@ static int ras_register_irq(struct ras_node *node)
 	return ret;
 }
 
+static void ras_enable_irq(struct ras_record *record)
+{
+	struct ras_node *node = record->node;
+	u64 err_ctlr;
+
+	err_ctlr = record_read(record, ERXCTLR);
+
+	if (node->irq[0])
+		err_ctlr |= (ERR_CTLR_FI | ERR_CTLR_CFI);
+	if (node->irq[1])
+		err_ctlr |= ERR_CTLR_UI;
+
+	record_write(record, ERXCTLR, err_ctlr);
+}
+
 static int ras_init_record(struct ras_record *record, int i, struct ras_node *node)
 {
 	record->name = devm_kasprintf(node->dev, GFP_KERNEL, "record%d", i);
@@ -110,6 +158,85 @@ static int ras_init_record(struct ras_record *record, int i, struct ras_node *no
 	return 0;
 }
 
+static void ras_online_record(struct ras_record *record, void *data)
+{
+	ras_enable_irq(record);
+}
+
+static void ras_online_node(struct ras_node *node)
+{
+	if (!node->name)
+		return;
+
+	ras_config_irq(node);
+
+	ras_node_foreach_record(ras_online_record, node, NULL,
+				node->record_implemented);
+}
+
+static void ras_online_oncore_dev(void *data)
+{
+	int fhi_irq, eri_irq;
+	struct ras_node *node = this_cpu_ptr(data);
+
+	ras_online_node(node);
+
+	fhi_irq = node->irq[ACPI_AEST_NODE_FAULT_HANDLING];
+	if (fhi_irq > 0)
+		enable_percpu_irq(fhi_irq, IRQ_TYPE_NONE);
+	eri_irq = node->irq[ACPI_AEST_NODE_ERROR_RECOVERY];
+	if (eri_irq > 0)
+		enable_percpu_irq(eri_irq, IRQ_TYPE_NONE);
+}
+
+static void ras_offline_oncore_dev(void *data)
+{
+	int fhi_irq, eri_irq;
+	struct ras_node *node = this_cpu_ptr(data);
+
+	fhi_irq = node->irq[ACPI_AEST_NODE_FAULT_HANDLING];
+	if (fhi_irq > 0)
+		disable_percpu_irq(fhi_irq);
+	eri_irq = node->irq[ACPI_AEST_NODE_ERROR_RECOVERY];
+	if (eri_irq > 0)
+		disable_percpu_irq(eri_irq);
+}
+
+static int ras_starting_cpu(unsigned int cpu)
+{
+	pr_debug("CPU%d starting\n", cpu);
+	ras_online_oncore_dev(&percpu_ras_node);
+
+	return 0;
+}
+
+static int ras_dying_cpu(unsigned int cpu)
+{
+	pr_debug("CPU%d dying\n", cpu);
+	ras_offline_oncore_dev(&percpu_ras_node);
+
+	return 0;
+}
+
+static void arm64_ras_remove(struct platform_device *pdev)
+{
+	struct ras_node *node = platform_get_drvdata(pdev);
+	int i;
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (node->type != ACPI_AEST_PROCESSOR_ERROR_NODE)
+		return;
+
+	cpuhp_remove_state(CPUHP_AP_ARM_RAS_STARTING);
+	on_each_cpu(ras_offline_oncore_dev, node->oncore_node, 1);
+
+	for (i = 0; i < AEST_MAX_INTERRUPT_PER_NODE; i++) {
+		if (node->irq[i])
+			free_percpu_irq(node->irq[i], node->oncore_node);
+	}
+}
+
 static char *alloc_ras_node_name(struct ras_node *node)
 {
 	char *name;
@@ -208,6 +335,23 @@ static int ras_node_set_inj_base(struct ras_node *node, phys_addr_t base)
 	return 0;
 }
 
+static int ras_node_set_irq_base(struct ras_node *node, phys_addr_t base)
+{
+	phys_addr_t irq_base;
+	int ret;
+
+	if (!(node->flags & AEST_XFACE_FLAG_INT_CONFIG))
+		return 0;
+
+	ret = device_property_read_u64(node->dev, "arm,interrupt-config-base",
+				       &irq_base);
+	if (ret || !irq_base)
+		return 0;
+
+	node->irq_config = irq_base - base + node->base;
+	return 0;
+}
+
 static struct ras_node *ras_init_node(struct platform_device *pdev)
 {
 	int i, ret = 0;
@@ -276,6 +420,9 @@ static struct ras_node *ras_init_node(struct platform_device *pdev)
 		ret = ras_node_set_inj_base(node, mem->start);
 		if (ret)
 			return ERR_PTR(ret);
+		ret = ras_node_set_irq_base(node, mem->start);
+		if (ret)
+			return ERR_PTR(ret);
 	} else if (node->access_type == ACPI_AEST_NODE_MEMORY_MAPPED) {
 		return ERR_PTR(-EINVAL);
 	}
@@ -372,6 +519,15 @@ static int arm64_ras_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (ras_node_is_oncore(node))
+		ret = cpuhp_setup_state(CPUHP_AP_ARM_RAS_STARTING,
+					"drivers/ras/arm64/ras:starting",
+					ras_starting_cpu, ras_dying_cpu);
+	else
+		ras_online_node(node);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, node);
 
 	return 0;
@@ -381,7 +537,8 @@ static struct platform_driver arm64_ras_driver = {
 	.driver	= {
 		.name	= "arm64_ras",
 	},
-	.probe	= arm64_ras_probe,
+	.probe		= arm64_ras_probe,
+	.remove		= arm64_ras_remove,
 };
 
 static int __init arm64_ras_init(void)
diff --git a/drivers/ras/arm64/ras.h b/drivers/ras/arm64/ras.h
index b64eae59b6ac..c26a0aae26c5 100644
--- a/drivers/ras/arm64/ras.h
+++ b/drivers/ras/arm64/ras.h
@@ -90,6 +90,7 @@ struct ras_node {
 	void __iomem *base;
 	void __iomem *errgsr;
 	void __iomem *inj;
+	void __iomem *irq_config;
 	phys_addr_t addr;
 
 	u8 *specific_data;
@@ -126,6 +127,7 @@ struct ras_node {
 	u8 access_type;
 	u8 group_format;
 	u32 irq[AEST_MAX_INTERRUPT_PER_NODE];
+	u32 gsi[AEST_MAX_INTERRUPT_PER_NODE];
 };
 
 #define CASE_READ(res, x)                           \
@@ -207,4 +209,34 @@ static const struct ras_access ras_access[] = {
 	},
 };
 
+static inline bool ras_node_is_oncore(struct ras_node *node)
+{
+	/*
+	 * A processor node is "on-core" (uses PPI + cpuhp) only when its
+	 * interrupt is a per-CPU PPI.  A shared processor node (e.g. cluster
+	 * L3 cache, DSU) uses an SPI and must follow the non-oncore path
+	 * (aest_online_dev) so that aest_config_irq and aest_online_dev are
+	 * called instead of cpuhp_setup_state.
+	 */
+	if (node->type != ACPI_AEST_PROCESSOR_ERROR_NODE)
+		return false;
+	return irq_is_percpu(node->irq[ACPI_AEST_NODE_FAULT_HANDLING]) ||
+	       irq_is_percpu(node->irq[ACPI_AEST_NODE_ERROR_RECOVERY]);
+}
+
+static inline void ras_select_record(struct ras_node *node, int index)
+{
+	if (node->type == ACPI_AEST_PROCESSOR_ERROR_NODE) {
+		write_sysreg_s(index, SYS_ERRSELR_EL1);
+		isb();
+	}
+}
+
+/* Ensure all writes has taken effect. */
+static inline void ras_sync(struct ras_node *node)
+{
+	if (node->type == ACPI_AEST_PROCESSOR_ERROR_NODE)
+		isb();
+}
+
 #endif /* _DRIVERS_RAS_ARM64_RAS_H_ */
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 62cd7b35a29c..ef55c10f6c71 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -179,6 +179,7 @@ enum cpuhp_state {
 	CPUHP_AP_HYPERV_TIMER_STARTING,
 	/* Must be the last timer callback */
 	CPUHP_AP_DUMMY_TIMER_STARTING,
+	CPUHP_AP_ARM_RAS_STARTING,
 	CPUHP_AP_ARM_XEN_STARTING,
 	CPUHP_AP_ARM_XEN_RUNSTATE_STARTING,
 	CPUHP_AP_ARM_CORESIGHT_STARTING,
-- 
2.51.2.612.gdc70283dfc



  parent reply	other threads:[~2026-06-02  7:16 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-02  7:15 [PATCH v7 00/16] Support Armv8 RAS Extensions for Kernel-first error handling Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 01/16] ACPI/AEST: Register arm64_ras platform devices from AEST v2 Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 02/16] arm64: ras: Add probe/remove for arm64_ras driver Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 03/16] arm64: ras: Unify the read/write interface for system and MMIO registers Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 04/16] arm64: ras: Support RAS Common Fault Injection Model Extension Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 05/16] arm64: ras: Plumb AEST interrupts as platform IRQ resources Ruidong Tian
2026-06-02  7:15 ` Ruidong Tian [this message]
2026-06-02  7:15 ` [PATCH v7 07/16] arm64: ras: Add error record processing and interrupt handling Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 08/16] arm64: ras: Handle memory failure for uncorrectable errors Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 09/16] arm64: ras: Probe RAS architecture version Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 10/16] arm64: ras: Support CE threshold of error record Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 11/16] arm64: ras: Add RAS decode notifier chain Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 12/16] arm64: ras: Expose config abi through debugfs Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 13/16] arm64: ras: Introduce ras inject interface Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 14/16] arm64: ras: support vendor node CMN700 Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 15/16] arm64: ras: Introduce ras error storm mitigation Ruidong Tian
2026-06-02  7:15 ` [PATCH v7 16/16] trace, ras: add ARM RAS extension trace event Ruidong Tian
2026-07-08  2:41 ` [PATCH v7 00/16] Support Armv8 RAS Extensions for Kernel-first error handling Borislav Petkov
2026-07-08 17:22   ` Catalin Marinas

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=20260602071540.3711528-7-tianruidong@linux.alibaba.com \
    --to=tianruidong@linux.alibaba.com \
    --cc=bp@alien8.de \
    --cc=catalin.marinas@arm.com \
    --cc=guohanjun@huawei.com \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-edac@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lpieralisi@kernel.org \
    --cc=oliver.yang@linux.alibaba.com \
    --cc=peterz@infradead.org \
    --cc=rafael@kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=sudeep.holla@kernel.org \
    --cc=tglx@kernel.org \
    --cc=tony.luck@intel.com \
    --cc=umang.chheda@oss.qualcomm.com \
    --cc=will@kernel.org \
    --cc=zhuo.song@linux.alibaba.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