public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] irqchip/renesas-rzv2h: Add support to handle ICU error IRQ and add SWPE trigger
@ 2026-02-09 10:41 Prabhakar
  2026-02-09 10:41 ` [PATCH v3 1/6] irqchip/renesas-rzv2h: Use local node pointer Prabhakar
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: Prabhakar @ 2026-02-09 10:41 UTC (permalink / raw)
  To: Thomas Gleixner, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Hi All,

This patch series aims to enhance the Renesas RZ/V2H ICU irqchip driver by
adding support to handle ICU error IRQs and introducing a software
generated interrupts using SWPE and SWINT. The series includes the
following changes:
1. Use local node pointer
2. Use local device pointer in ICU probe
3. Switch to using dev_err_probe()
4. Make IRQ type handling range-aware
5. Add CA55 software interrupt support
6. Handle ICU error IRQ and add SWPE trigger

v2->v3:
- Updated the check in rzv2h_icu_alloc() to ensure hwirq is within the
  TINT range when extracting TINT information in patch 4/6.
- Replaced pr_debug with pr_info in the SWINT handler in patch 5/6
  and 6/6 to ensure  visibility of the message.

v1->v2:
- No changes for patches 1-3.
- Patch 4 is a new patch.
- Patch 5
  - Made CA55 SW interrupt as part of ICU IRQ domain.
  - Implemented rzv2h_icu_irq_set_irqchip_state() to trigger SWINT.
  - Updated commit message accordingly.
- Patch 6
  - Made Error interrupt as part of ICU IRQ domain.
  - Updated rzv2h_icu_irq_set_irqchip_state() to trigger pseudo interrupt.
  - Updated commit message accordingly.

Cheers,
Prabhakar

Lad Prabhakar (6):
  irqchip/renesas-rzv2h: Use local node pointer
  irqchip/renesas-rzv2h: Use local device pointer in ICU probe
  irqchip/renesas-rzv2h: Switch to using dev_err_probe()
  irqchip/renesas-rzv2h: Make IRQ type handling range-aware
  irqchip/renesas-rzv2h: Add CA55 software interrupt support
  irqchip/renesas-rzv2h: Handle ICU error IRQ and add SWPE trigger

 drivers/irqchip/irq-renesas-rzv2h.c | 337 +++++++++++++++++++++++-----
 1 file changed, 284 insertions(+), 53 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3 1/6] irqchip/renesas-rzv2h: Use local node pointer
  2026-02-09 10:41 [PATCH v3 0/6] irqchip/renesas-rzv2h: Add support to handle ICU error IRQ and add SWPE trigger Prabhakar
@ 2026-02-09 10:41 ` Prabhakar
  2026-02-09 10:41 ` [PATCH v3 2/6] irqchip/renesas-rzv2h: Use local device pointer in ICU probe Prabhakar
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Prabhakar @ 2026-02-09 10:41 UTC (permalink / raw)
  To: Thomas Gleixner, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Avoid dereferencing pdev->dev.of_node again in rzv2h_icu_probe_common().
Reuse the already available local node pointer when mapping the ICU
register space.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v2->v3:
- No change.

v1->v2:
- No change.
---
 drivers/irqchip/irq-renesas-rzv2h.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index da2bc43a0e12..20c0cd11ef25 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -570,7 +570,7 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 
 	platform_set_drvdata(pdev, rzv2h_icu_data);
 
-	rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
+	rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, node, 0, NULL);
 	if (IS_ERR(rzv2h_icu_data->base))
 		return PTR_ERR(rzv2h_icu_data->base);
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 2/6] irqchip/renesas-rzv2h: Use local device pointer in ICU probe
  2026-02-09 10:41 [PATCH v3 0/6] irqchip/renesas-rzv2h: Add support to handle ICU error IRQ and add SWPE trigger Prabhakar
  2026-02-09 10:41 ` [PATCH v3 1/6] irqchip/renesas-rzv2h: Use local node pointer Prabhakar
@ 2026-02-09 10:41 ` Prabhakar
  2026-02-09 10:41 ` [PATCH v3 3/6] irqchip/renesas-rzv2h: Switch to using dev_err_probe() Prabhakar
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Prabhakar @ 2026-02-09 10:41 UTC (permalink / raw)
  To: Thomas Gleixner, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Use a local struct device pointer in rzv2h_icu_probe_common() to avoid
repeated dereferencing of pdev->dev.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v2->v3:
- No change.

v1->v2:
- No change.
---
 drivers/irqchip/irq-renesas-rzv2h.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index 20c0cd11ef25..766b981cf3d8 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -555,57 +555,58 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 {
 	struct irq_domain *irq_domain, *parent_domain;
 	struct device_node *node = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
 	struct reset_control *resetn;
 	int ret;
 
 	parent_domain = irq_find_host(parent);
 	if (!parent_domain) {
-		dev_err(&pdev->dev, "cannot find parent domain\n");
+		dev_err(dev, "cannot find parent domain\n");
 		return -ENODEV;
 	}
 
-	rzv2h_icu_data = devm_kzalloc(&pdev->dev, sizeof(*rzv2h_icu_data), GFP_KERNEL);
+	rzv2h_icu_data = devm_kzalloc(dev, sizeof(*rzv2h_icu_data), GFP_KERNEL);
 	if (!rzv2h_icu_data)
 		return -ENOMEM;
 
 	platform_set_drvdata(pdev, rzv2h_icu_data);
 
-	rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, node, 0, NULL);
+	rzv2h_icu_data->base = devm_of_iomap(dev, node, 0, NULL);
 	if (IS_ERR(rzv2h_icu_data->base))
 		return PTR_ERR(rzv2h_icu_data->base);
 
 	ret = rzv2h_icu_parse_interrupts(rzv2h_icu_data, node);
 	if (ret) {
-		dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret);
+		dev_err(dev, "cannot parse interrupts: %d\n", ret);
 		return ret;
 	}
 
-	resetn = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL);
+	resetn = devm_reset_control_get_exclusive_deasserted(dev, NULL);
 	if (IS_ERR(resetn)) {
 		ret = PTR_ERR(resetn);
-		dev_err(&pdev->dev, "failed to acquire deasserted reset: %d\n", ret);
+		dev_err(dev, "failed to acquire deasserted reset: %d\n", ret);
 		return ret;
 	}
 
-	ret = devm_pm_runtime_enable(&pdev->dev);
+	ret = devm_pm_runtime_enable(dev);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "devm_pm_runtime_enable failed, %d\n", ret);
+		dev_err(dev, "devm_pm_runtime_enable failed, %d\n", ret);
 		return ret;
 	}
 
-	ret = pm_runtime_resume_and_get(&pdev->dev);
+	ret = pm_runtime_resume_and_get(dev);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret);
+		dev_err(dev, "pm_runtime_resume_and_get failed: %d\n", ret);
 		return ret;
 	}
 
 	raw_spin_lock_init(&rzv2h_icu_data->lock);
 
 	irq_domain = irq_domain_create_hierarchy(parent_domain, 0, ICU_NUM_IRQ,
-						 dev_fwnode(&pdev->dev), &rzv2h_icu_domain_ops,
+						 dev_fwnode(dev), &rzv2h_icu_domain_ops,
 						 rzv2h_icu_data);
 	if (!irq_domain) {
-		dev_err(&pdev->dev, "failed to add irq domain\n");
+		dev_err(dev, "failed to add irq domain\n");
 		ret = -ENOMEM;
 		goto pm_put;
 	}
@@ -616,12 +617,12 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 
 	/*
 	 * coccicheck complains about a missing put_device call before returning, but it's a false
-	 * positive. We still need &pdev->dev after successfully returning from this function.
+	 * positive. We still need dev after successfully returning from this function.
 	 */
 	return 0;
 
 pm_put:
-	pm_runtime_put(&pdev->dev);
+	pm_runtime_put(dev);
 
 	return ret;
 }
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 3/6] irqchip/renesas-rzv2h: Switch to using dev_err_probe()
  2026-02-09 10:41 [PATCH v3 0/6] irqchip/renesas-rzv2h: Add support to handle ICU error IRQ and add SWPE trigger Prabhakar
  2026-02-09 10:41 ` [PATCH v3 1/6] irqchip/renesas-rzv2h: Use local node pointer Prabhakar
  2026-02-09 10:41 ` [PATCH v3 2/6] irqchip/renesas-rzv2h: Use local device pointer in ICU probe Prabhakar
@ 2026-02-09 10:41 ` Prabhakar
  2026-02-09 10:41 ` [PATCH v3 4/6] irqchip/renesas-rzv2h: Make IRQ type handling range-aware Prabhakar
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Prabhakar @ 2026-02-09 10:41 UTC (permalink / raw)
  To: Thomas Gleixner, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Make use of dev_err_probe() to simplify rzv2h_icu_probe_common().

Keep dev_err() for -ENOMEM paths, as dev_err_probe() does not print for
allocation failures, ensuring they remain visible in logs.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v2->v3:
- No change.

v1->v2:
- No change.
---
 drivers/irqchip/irq-renesas-rzv2h.c | 32 ++++++++++-------------------
 1 file changed, 11 insertions(+), 21 deletions(-)

diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index 766b981cf3d8..4aa772ba1a1f 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -560,10 +560,8 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 	int ret;
 
 	parent_domain = irq_find_host(parent);
-	if (!parent_domain) {
-		dev_err(dev, "cannot find parent domain\n");
-		return -ENODEV;
-	}
+	if (!parent_domain)
+		return dev_err_probe(dev, -ENODEV, "cannot find parent domain\n");
 
 	rzv2h_icu_data = devm_kzalloc(dev, sizeof(*rzv2h_icu_data), GFP_KERNEL);
 	if (!rzv2h_icu_data)
@@ -576,29 +574,21 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 		return PTR_ERR(rzv2h_icu_data->base);
 
 	ret = rzv2h_icu_parse_interrupts(rzv2h_icu_data, node);
-	if (ret) {
-		dev_err(dev, "cannot parse interrupts: %d\n", ret);
-		return ret;
-	}
+	if (ret)
+		return dev_err_probe(dev, ret, "cannot parse interrupts\n");
 
 	resetn = devm_reset_control_get_exclusive_deasserted(dev, NULL);
-	if (IS_ERR(resetn)) {
-		ret = PTR_ERR(resetn);
-		dev_err(dev, "failed to acquire deasserted reset: %d\n", ret);
-		return ret;
-	}
+	if (IS_ERR(resetn))
+		return dev_err_probe(dev, PTR_ERR(resetn),
+				     "failed to acquire deasserted reset\n");
 
 	ret = devm_pm_runtime_enable(dev);
-	if (ret < 0) {
-		dev_err(dev, "devm_pm_runtime_enable failed, %d\n", ret);
-		return ret;
-	}
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "devm_pm_runtime_enable failed\n");
 
 	ret = pm_runtime_resume_and_get(dev);
-	if (ret < 0) {
-		dev_err(dev, "pm_runtime_resume_and_get failed: %d\n", ret);
-		return ret;
-	}
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "pm_runtime_resume_and_get failed\n");
 
 	raw_spin_lock_init(&rzv2h_icu_data->lock);
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 4/6] irqchip/renesas-rzv2h: Make IRQ type handling range-aware
  2026-02-09 10:41 [PATCH v3 0/6] irqchip/renesas-rzv2h: Add support to handle ICU error IRQ and add SWPE trigger Prabhakar
                   ` (2 preceding siblings ...)
  2026-02-09 10:41 ` [PATCH v3 3/6] irqchip/renesas-rzv2h: Switch to using dev_err_probe() Prabhakar
@ 2026-02-09 10:41 ` Prabhakar
  2026-02-24  7:30   ` Thomas Gleixner
  2026-02-09 10:41 ` [PATCH v3 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support Prabhakar
  2026-02-09 10:41 ` [PATCH v3 6/6] irqchip/renesas-rzv2h: Handle ICU error IRQ and add SWPE trigger Prabhakar
  5 siblings, 1 reply; 11+ messages in thread
From: Prabhakar @ 2026-02-09 10:41 UTC (permalink / raw)
  To: Thomas Gleixner, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Refine IRQ type handling to explicitly bound IRQ and TINT ranges and
dispatch based on the hardware IRQ number.

This restructures the logic to clearly separate NMI, IRQ, and TINT
handling and ensures out-of-range interrupts are ignored safely. The
change prepares the driver for adding CA55 interrupts into the IRQ
hierarchy domain by making the interrupt classification explicit and
extensible.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v2->v3:
- Updated the check in rzv2h_icu_alloc() to ensure hwirq is within the
  TINT range when extracting TINT information.

v1->v2:
- New patch.
---
 drivers/irqchip/irq-renesas-rzv2h.c | 60 +++++++++++++++++++----------
 1 file changed, 40 insertions(+), 20 deletions(-)

diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index 4aa772ba1a1f..d4a47df0e26e 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -25,9 +25,11 @@
 /* DT "interrupts" indexes */
 #define ICU_IRQ_START				1
 #define ICU_IRQ_COUNT				16
-#define ICU_TINT_START				(ICU_IRQ_START + ICU_IRQ_COUNT)
+#define ICU_IRQ_LAST				(ICU_IRQ_START + ICU_IRQ_COUNT - 1)
+#define ICU_TINT_START				(ICU_IRQ_LAST + 1)
 #define ICU_TINT_COUNT				32
-#define ICU_NUM_IRQ				(ICU_TINT_START + ICU_TINT_COUNT)
+#define ICU_TINT_LAST				(ICU_TINT_START + ICU_TINT_COUNT - 1)
+#define ICU_NUM_IRQ				(ICU_TINT_LAST + 1)
 
 /* Registers */
 #define ICU_NSCNT				0x00
@@ -175,18 +177,27 @@ static void rzv2h_icu_eoi(struct irq_data *d)
 	u32 bit;
 
 	scoped_guard(raw_spinlock, &priv->lock) {
-		if (hw_irq >= ICU_TINT_START) {
-			tintirq_nr = hw_irq - ICU_TINT_START;
-			bit = BIT(tintirq_nr);
-			if (!irqd_is_level_type(d))
-				writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR);
-		} else if (hw_irq >= ICU_IRQ_START) {
+		switch (hw_irq) {
+		case 0:
+			/* Clear NMI */
+			writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR);
+			break;
+		case ICU_IRQ_START ... ICU_IRQ_LAST:
+			/* Clear IRQ */
 			tintirq_nr = hw_irq - ICU_IRQ_START;
 			bit = BIT(tintirq_nr);
 			if (!irqd_is_level_type(d))
 				writel_relaxed(bit, priv->base + ICU_ISCLR);
-		} else {
-			writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR);
+			break;
+		case ICU_TINT_START ... ICU_TINT_LAST:
+			/* Clear TINT */
+			tintirq_nr = hw_irq - ICU_TINT_START;
+			bit = BIT(tintirq_nr);
+			if (!irqd_is_level_type(d))
+				writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR);
+			break;
+		default:
+			break;
 		}
 	}
 
@@ -200,7 +211,7 @@ static void rzv2h_tint_irq_endisable(struct irq_data *d, bool enable)
 	u32 tint_nr, tssel_n, k, tssr;
 	u8 nr_tint;
 
-	if (hw_irq < ICU_TINT_START)
+	if (hw_irq < ICU_TINT_START || hw_irq > ICU_TINT_LAST)
 		return;
 
 	tint_nr = hw_irq - ICU_TINT_START;
@@ -421,12 +432,22 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
 	unsigned int hw_irq = irqd_to_hwirq(d);
 	int ret;
 
-	if (hw_irq >= ICU_TINT_START)
-		ret = rzv2h_tint_set_type(d, type);
-	else if (hw_irq >= ICU_IRQ_START)
-		ret = rzv2h_irq_set_type(d, type);
-	else
+	switch (hw_irq) {
+	case 0:
+		/* NMI */
 		ret = rzv2h_nmi_set_type(d, type);
+		break;
+	case ICU_IRQ_START ... ICU_IRQ_LAST:
+		/* IRQ */
+		ret = rzv2h_irq_set_type(d, type);
+		break;
+	case ICU_TINT_START ... ICU_TINT_LAST:
+		/* TINT */
+		ret = rzv2h_tint_set_type(d, type);
+		break;
+	default:
+		ret = -EINVAL;
+	}
 
 	if (ret)
 		return ret;
@@ -508,11 +529,10 @@ static int rzv2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigne
 	 * hwirq is embedded in bits 0-15.
 	 * TINT is embedded in bits 16-31.
 	 */
-	if (hwirq >= ICU_TINT_START) {
-		tint = ICU_TINT_EXTRACT_GPIOINT(hwirq);
+	tint = ICU_TINT_EXTRACT_GPIOINT(hwirq);
+	if (tint || (hwirq >= ICU_TINT_START && hwirq <= ICU_TINT_LAST)) {
 		hwirq = ICU_TINT_EXTRACT_HWIRQ(hwirq);
-
-		if (hwirq < ICU_TINT_START)
+		if (hwirq < ICU_TINT_START || hwirq > ICU_TINT_LAST)
 			return -EINVAL;
 	}
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support
  2026-02-09 10:41 [PATCH v3 0/6] irqchip/renesas-rzv2h: Add support to handle ICU error IRQ and add SWPE trigger Prabhakar
                   ` (3 preceding siblings ...)
  2026-02-09 10:41 ` [PATCH v3 4/6] irqchip/renesas-rzv2h: Make IRQ type handling range-aware Prabhakar
@ 2026-02-09 10:41 ` Prabhakar
  2026-02-24  7:34   ` Thomas Gleixner
  2026-02-09 10:41 ` [PATCH v3 6/6] irqchip/renesas-rzv2h: Handle ICU error IRQ and add SWPE trigger Prabhakar
  5 siblings, 1 reply; 11+ messages in thread
From: Prabhakar @ 2026-02-09 10:41 UTC (permalink / raw)
  To: Thomas Gleixner, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

The Renesas RZ/V2H ICU provides a software interrupt register (ICU_SWINT)
that allows software to explicitly assert interrupts toward individual
CA55 cores. Writing BIT(n) to ICU_SWINT triggers the corresponding
interrupt.

Extend the RZ/V2H ICU IRQ domain to include CA55 software interrupts as
part of the hierarchical IRQ numbering, backed by the ICU_SWINT
register.

SW interrupts can now be triggered when GENERIC_IRQ_INJECTION is enabled.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v2->v3:
- Replaced pr_debug with pr_info in the SWINT handler to ensure
  visibility of the message.

v1->v2:
- Made CA55 SW interrupt as part of ICU IRQ domain.
- Implemented rzv2h_icu_irq_set_irqchip_state() to trigger SWINT.
- Updated commit message accordingly.
---
 drivers/irqchip/irq-renesas-rzv2h.c | 89 ++++++++++++++++++++++++++++-
 1 file changed, 86 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index d4a47df0e26e..bfb975f7e370 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -12,6 +12,7 @@
 #include <linux/bitfield.h>
 #include <linux/cleanup.h>
 #include <linux/err.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irqchip.h>
 #include <linux/irqchip/irq-renesas-rzv2h.h>
@@ -29,7 +30,10 @@
 #define ICU_TINT_START				(ICU_IRQ_LAST + 1)
 #define ICU_TINT_COUNT				32
 #define ICU_TINT_LAST				(ICU_TINT_START + ICU_TINT_COUNT - 1)
-#define ICU_NUM_IRQ				(ICU_TINT_LAST + 1)
+#define ICU_CA55_INT_START                      (ICU_TINT_LAST + 1)
+#define ICU_CA55_INT_COUNT                      4
+#define ICU_CA55_INT_LAST                       (ICU_CA55_INT_START + ICU_CA55_INT_COUNT - 1)
+#define ICU_NUM_IRQ                             (ICU_CA55_INT_LAST + 1)
 
 /* Registers */
 #define ICU_NSCNT				0x00
@@ -42,6 +46,7 @@
 #define ICU_TSCLR				0x24
 #define ICU_TITSR(k)				(0x28 + (k) * 4)
 #define ICU_TSSR(k)				(0x30 + (k) * 4)
+#define ICU_SWINT				0x130
 #define ICU_DMkSELy(k, y)			(0x420 + (k) * 0x20 + (y) * 4)
 #define ICU_DMACKSELk(k)			(0x500 + (k) * 4)
 
@@ -248,6 +253,30 @@ static void rzv2h_icu_irq_enable(struct irq_data *d)
 	irq_chip_enable_parent(d);
 }
 
+static int rzv2h_icu_irq_set_irqchip_state(struct irq_data *d,
+					   enum irqchip_irq_state which,
+					   bool state)
+{
+	unsigned int hwirq = irqd_to_hwirq(d);
+	struct rzv2h_icu_priv *priv;
+	unsigned int bit;
+
+	if (hwirq < ICU_CA55_INT_START || hwirq > ICU_CA55_INT_LAST ||
+	    which != IRQCHIP_STATE_PENDING)
+		return irq_chip_set_parent_state(d, which, state);
+
+	if (!state)
+		return 0;
+
+	priv = irq_data_to_priv(d);
+	bit = BIT(hwirq - ICU_CA55_INT_START);
+
+	guard(raw_spinlock)(&priv->lock);
+	/* Trigger the software interrupt */
+	writel_relaxed(bit, priv->base + ICU_SWINT);
+	return 0;
+}
+
 static int rzv2h_nmi_set_type(struct irq_data *d, unsigned int type)
 {
 	struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
@@ -429,6 +458,7 @@ static int rzv2h_tint_set_type(struct irq_data *d, unsigned int type)
 
 static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
 {
+	unsigned int gic_type = IRQ_TYPE_LEVEL_HIGH;
 	unsigned int hw_irq = irqd_to_hwirq(d);
 	int ret;
 
@@ -445,6 +475,11 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
 		/* TINT */
 		ret = rzv2h_tint_set_type(d, type);
 		break;
+	case ICU_CA55_INT_START ... ICU_CA55_INT_LAST:
+		/* CA55 Software Interrupts have EDGE_RISING type */
+		gic_type = IRQ_TYPE_EDGE_RISING;
+		ret = 0;
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -452,7 +487,7 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
 	if (ret)
 		return ret;
 
-	return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
+	return irq_chip_set_type_parent(d, gic_type);
 }
 
 static int rzv2h_irqc_irq_suspend(void *data)
@@ -501,7 +536,7 @@ static const struct irq_chip rzv2h_icu_chip = {
 	.irq_disable		= rzv2h_icu_irq_disable,
 	.irq_enable		= rzv2h_icu_irq_enable,
 	.irq_get_irqchip_state	= irq_chip_get_parent_state,
-	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_irqchip_state	= rzv2h_icu_irq_set_irqchip_state,
 	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.irq_set_type		= rzv2h_icu_set_type,
 	.irq_set_affinity	= irq_chip_set_affinity_parent,
@@ -570,6 +605,50 @@ static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device
 	return 0;
 }
 
+static irqreturn_t rzv2h_icu_swint_irq(int irq, void *data)
+{
+	u8 cpu = *(u8 *)data;
+
+	pr_info("SWINT interrupt for CA55 core %u\n", cpu);
+	return IRQ_HANDLED;
+}
+
+static int rzv2h_icu_setup_irqs(struct platform_device *pdev,
+				struct irq_domain *irq_domain)
+{
+	bool irq_inject = IS_ENABLED(CONFIG_GENERIC_IRQ_INJECTION);
+	static const char * const rzv2h_swint_names[] = {
+		"int-ca55-0", "int-ca55-1",
+		"int-ca55-2", "int-ca55-3",
+	};
+	static const u8 swint_idx[] = { 0, 1, 2, 3 };
+	struct device *dev = &pdev->dev;
+	struct irq_fwspec fwspec;
+	unsigned int virq;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ICU_CA55_INT_COUNT && irq_inject; i++) {
+		fwspec.fwnode = irq_domain->fwnode;
+		fwspec.param_count = 2;
+		fwspec.param[0] = ICU_CA55_INT_START + i;
+		fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
+
+		virq = irq_create_fwspec_mapping(&fwspec);
+		if (!virq)
+			return dev_err_probe(dev, -EINVAL, "failed to create IRQ mapping for %s\n",
+					     rzv2h_swint_names[i]);
+
+		ret = devm_request_irq(dev, virq, rzv2h_icu_swint_irq, 0, dev_name(dev),
+				       (void *)&swint_idx[i]);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to request %s IRQ\n",
+					     rzv2h_swint_names[i]);
+	}
+
+	return 0;
+}
+
 static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_node *parent,
 				  const struct rzv2h_hw_info *hw_info)
 {
@@ -625,6 +704,10 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 
 	register_syscore(&rzv2h_irqc_syscore);
 
+	ret = rzv2h_icu_setup_irqs(pdev, irq_domain);
+	if (ret)
+		goto pm_put;
+
 	/*
 	 * coccicheck complains about a missing put_device call before returning, but it's a false
 	 * positive. We still need dev after successfully returning from this function.
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 6/6] irqchip/renesas-rzv2h: Handle ICU error IRQ and add SWPE trigger
  2026-02-09 10:41 [PATCH v3 0/6] irqchip/renesas-rzv2h: Add support to handle ICU error IRQ and add SWPE trigger Prabhakar
                   ` (4 preceding siblings ...)
  2026-02-09 10:41 ` [PATCH v3 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support Prabhakar
@ 2026-02-09 10:41 ` Prabhakar
  5 siblings, 0 replies; 11+ messages in thread
From: Prabhakar @ 2026-02-09 10:41 UTC (permalink / raw)
  To: Thomas Gleixner, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Handle the RZ/V2H ICU error interrupt to help diagnose latched bus,
ECC RAM, and CA55/IP error conditions.

Extend the hardware IRQ numbering to include a single error interrupt
line and route IRQCHIP_STATE_PENDING requests to hardware-triggered
error injection via ICU_SWPE.

Account for SoC differences in ECC RAM error register coverage so the
handler only iterates over valid ECC status/clear banks, and route the
RZ/V2N compatible to a probe path with the correct ECC range while
keeping the existing RZ/V2H and RZ/G3E handling.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v2->v3:
- Updated pr_debug to pr_info in the error IRQ handler to ensure
  visibility of the messages.

v1->v2:
- Made Error interrupt as part of ICU IRQ domain.
- Updated rzv2h_icu_irq_set_irqchip_state() to trigger pseudo interrupt.
- Updated commit message accordingly.
---
 drivers/irqchip/irq-renesas-rzv2h.c | 149 ++++++++++++++++++++++++++--
 1 file changed, 143 insertions(+), 6 deletions(-)

diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index bfb975f7e370..d4e8aab46412 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -33,7 +33,10 @@
 #define ICU_CA55_INT_START                      (ICU_TINT_LAST + 1)
 #define ICU_CA55_INT_COUNT                      4
 #define ICU_CA55_INT_LAST                       (ICU_CA55_INT_START + ICU_CA55_INT_COUNT - 1)
-#define ICU_NUM_IRQ                             (ICU_CA55_INT_LAST + 1)
+#define ICU_ERR_INT_START                      (ICU_CA55_INT_LAST + 1)
+#define ICU_ERR_INT_COUNT                      1
+#define ICU_ERR_INT_LAST                       (ICU_ERR_INT_START + ICU_ERR_INT_COUNT - 1)
+#define ICU_NUM_IRQ                             (ICU_ERR_INT_LAST + 1)
 
 /* Registers */
 #define ICU_NSCNT				0x00
@@ -46,7 +49,15 @@
 #define ICU_TSCLR				0x24
 #define ICU_TITSR(k)				(0x28 + (k) * 4)
 #define ICU_TSSR(k)				(0x30 + (k) * 4)
+#define ICU_BEISR(k)				(0x70 + (k) * 4)
+#define ICU_BECLR(k)				(0x80 + (k) * 4)
+#define ICU_EREISR(k)				(0x90 + (k) * 4)
+#define ICU_ERCLR(k)				(0xE0 + (k) * 4)
 #define ICU_SWINT				0x130
+#define ICU_ERINTA55CTL(k)			(0x338 + (k) * 4)
+#define ICU_ERINTA55CRL(k)			(0x348 + (k) * 4)
+#define ICU_ERINTA55MSK(k)			(0x358 + (k) * 4)
+#define ICU_SWPE				0x370
 #define ICU_DMkSELy(k, y)			(0x420 + (k) * 0x20 + (y) * 4)
 #define ICU_DMACKSELk(k)			(0x500 + (k) * 4)
 
@@ -97,6 +108,10 @@
 #define ICU_RZG3E_TSSEL_MAX_VAL			0x8c
 #define ICU_RZV2H_TSSEL_MAX_VAL			0x55
 
+#define ICU_SWPE_NUM				16
+#define ICU_NUM_BE				4
+#define ICU_NUM_A55ERR				4
+
 /**
  * struct rzv2h_irqc_reg_cache - registers cache (necessary for suspend/resume)
  * @nitsr: ICU_NITSR register
@@ -115,12 +130,16 @@ struct rzv2h_irqc_reg_cache {
  * @t_offs:		TINT offset
  * @max_tssel:		TSSEL max value
  * @field_width:	TSSR field width
+ * @ecc_start:		Start index of ECC RAM interrupts
+ * @ecc_end:		End index of ECC RAM interrupts
  */
 struct rzv2h_hw_info {
 	const u8	*tssel_lut;
 	u16		t_offs;
 	u8		max_tssel;
 	u8		field_width;
+	u8		ecc_start;
+	u8		ecc_end;
 };
 
 /* DMAC */
@@ -259,10 +278,10 @@ static int rzv2h_icu_irq_set_irqchip_state(struct irq_data *d,
 {
 	unsigned int hwirq = irqd_to_hwirq(d);
 	struct rzv2h_icu_priv *priv;
+	void __iomem *offset;
 	unsigned int bit;
 
-	if (hwirq < ICU_CA55_INT_START || hwirq > ICU_CA55_INT_LAST ||
-	    which != IRQCHIP_STATE_PENDING)
+	if (which != IRQCHIP_STATE_PENDING)
 		return irq_chip_set_parent_state(d, which, state);
 
 	if (!state)
@@ -271,9 +290,33 @@ static int rzv2h_icu_irq_set_irqchip_state(struct irq_data *d,
 	priv = irq_data_to_priv(d);
 	bit = BIT(hwirq - ICU_CA55_INT_START);
 
+	switch (hwirq) {
+	case ICU_CA55_INT_START ... ICU_CA55_INT_LAST:
+		bit = BIT(hwirq - ICU_CA55_INT_START);
+		offset = priv->base + ICU_SWINT;
+		break;
+	case ICU_ERR_INT_START ... ICU_ERR_INT_LAST: {
+		static u8 swpe;
+
+		bit = BIT(swpe);
+		/*
+		 * SWPE has 16 bits; the bit position is rotated on each trigger
+		 * and wraps around once all bits have been used.
+		 */
+		if (++swpe >= ICU_SWPE_NUM)
+			swpe = 0;
+
+		offset = priv->base + ICU_SWPE;
+		break;
+	}
+	default:
+		return irq_chip_set_parent_state(d, which, state);
+	}
+
 	guard(raw_spinlock)(&priv->lock);
-	/* Trigger the software interrupt */
-	writel_relaxed(bit, priv->base + ICU_SWINT);
+	/* Trigger the error/software interrupt */
+	writel_relaxed(bit, offset);
+
 	return 0;
 }
 
@@ -480,6 +523,10 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
 		gic_type = IRQ_TYPE_EDGE_RISING;
 		ret = 0;
 		break;
+	case ICU_ERR_INT_START ... ICU_ERR_INT_LAST:
+		/* Error Interrupts */
+		ret = 0;
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -605,6 +652,48 @@ static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device
 	return 0;
 }
 
+static irqreturn_t rzv2h_icu_error_irq(int irq, void *data)
+{
+	struct rzv2h_icu_priv *priv = data;
+	const struct rzv2h_hw_info *hw_info = priv->info;
+	void __iomem *base = priv->base;
+	unsigned int k;
+	u32 st;
+
+	/* 1) Bus errors (BEISR0..3) */
+	for (k = 0; k < ICU_NUM_BE; k++) {
+		st = readl(base + ICU_BEISR(k));
+		if (!st)
+			continue;
+
+		writel_relaxed(st, base + ICU_BECLR(k));
+		pr_info("rzv2h-icu: BUS error k=%u status=0x%08x\n", k, st);
+	}
+
+	/* 2) ECC RAM errors (EREISR0..X) */
+	for (k = hw_info->ecc_start; k <= hw_info->ecc_end; k++) {
+		st = readl(base + ICU_EREISR(k));
+		if (!st)
+			continue;
+
+		writel_relaxed(st, base + ICU_ERCLR(k));
+		pr_info("rzv2h-icu: ECC error k=%u status=0x%08x\n", k, st);
+	}
+
+	/* 3) IP/CA55 error interrupt status (ERINTA55CTL0..3) */
+	for (k = 0; k < ICU_NUM_A55ERR; k++) {
+		st = readl(base + ICU_ERINTA55CTL(k));
+		if (!st)
+			continue;
+
+		/* there is no relation with status bits so clear all the interrupts */
+		writel_relaxed(0xffffffff, base + ICU_ERINTA55CRL(k));
+		pr_info("rzv2h-icu: IP/CA55 error k=%u status=0x%08x\n", k, st);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rzv2h_icu_swint_irq(int irq, void *data)
 {
 	u8 cpu = *(u8 *)data;
@@ -616,12 +705,15 @@ static irqreturn_t rzv2h_icu_swint_irq(int irq, void *data)
 static int rzv2h_icu_setup_irqs(struct platform_device *pdev,
 				struct irq_domain *irq_domain)
 {
+	const struct rzv2h_hw_info *hw_info = rzv2h_icu_data->info;
 	bool irq_inject = IS_ENABLED(CONFIG_GENERIC_IRQ_INJECTION);
 	static const char * const rzv2h_swint_names[] = {
 		"int-ca55-0", "int-ca55-1",
 		"int-ca55-2", "int-ca55-3",
 	};
+	static const char *icu_err = "icu-error-ca55";
 	static const u8 swint_idx[] = { 0, 1, 2, 3 };
+	void __iomem *base = rzv2h_icu_data->base;
 	struct device *dev = &pdev->dev;
 	struct irq_fwspec fwspec;
 	unsigned int virq;
@@ -646,6 +738,34 @@ static int rzv2h_icu_setup_irqs(struct platform_device *pdev,
 					     rzv2h_swint_names[i]);
 	}
 
+	/* Unmask and clear all IP/CA55 error interrupts */
+	for (i = 0; i < ICU_NUM_A55ERR; i++) {
+		writel_relaxed(0xffffff, base + ICU_ERINTA55CRL(i));
+		writel_relaxed(0x0, base + ICU_ERINTA55MSK(i));
+	}
+
+	/* Clear all Bus errors */
+	for (i = 0; i < ICU_NUM_BE; i++)
+		writel_relaxed(0xffffffff, base + ICU_BECLR(i));
+
+	/* Clear all ECCRAM errors */
+	for (i = hw_info->ecc_start; i <= hw_info->ecc_end; i++)
+		writel_relaxed(0xffffffff, base + ICU_ERCLR(i));
+
+	fwspec.fwnode = irq_domain->fwnode;
+	fwspec.param_count = 2;
+	fwspec.param[0] = ICU_ERR_INT_START;
+	fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
+
+	virq = irq_create_fwspec_mapping(&fwspec);
+	if (!virq)
+		return dev_err_probe(dev, -EINVAL, "failed to create IRQ mapping for %s\n",
+				     icu_err);
+
+	ret = devm_request_irq(dev, virq, rzv2h_icu_error_irq, 0, dev_name(dev), rzv2h_icu_data);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to request %s IRQ\n", icu_err);
+
 	return 0;
 }
 
@@ -751,12 +871,24 @@ static const struct rzv2h_hw_info rzg3e_hw_params = {
 	.t_offs		= ICU_RZG3E_TINT_OFFSET,
 	.max_tssel	= ICU_RZG3E_TSSEL_MAX_VAL,
 	.field_width	= 16,
+	.ecc_start	= 1,
+	.ecc_end	= 4,
+};
+
+static const struct rzv2h_hw_info rzv2n_hw_params = {
+	.t_offs		= 0,
+	.max_tssel	= ICU_RZV2H_TSSEL_MAX_VAL,
+	.field_width	= 8,
+	.ecc_start	= 0,
+	.ecc_end	= 2,
 };
 
 static const struct rzv2h_hw_info rzv2h_hw_params = {
 	.t_offs		= 0,
 	.max_tssel	= ICU_RZV2H_TSSEL_MAX_VAL,
 	.field_width	= 8,
+	.ecc_start	= 0,
+	.ecc_end	= 11,
 };
 
 static int rzg3e_icu_probe(struct platform_device *pdev, struct device_node *parent)
@@ -764,6 +896,11 @@ static int rzg3e_icu_probe(struct platform_device *pdev, struct device_node *par
 	return rzv2h_icu_probe_common(pdev, parent, &rzg3e_hw_params);
 }
 
+static int rzv2n_icu_probe(struct platform_device *pdev, struct device_node *parent)
+{
+	return rzv2h_icu_probe_common(pdev, parent, &rzv2n_hw_params);
+}
+
 static int rzv2h_icu_probe(struct platform_device *pdev, struct device_node *parent)
 {
 	return rzv2h_icu_probe_common(pdev, parent, &rzv2h_hw_params);
@@ -771,7 +908,7 @@ static int rzv2h_icu_probe(struct platform_device *pdev, struct device_node *par
 
 IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu)
 IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_probe)
-IRQCHIP_MATCH("renesas,r9a09g056-icu", rzv2h_icu_probe)
+IRQCHIP_MATCH("renesas,r9a09g056-icu", rzv2n_icu_probe)
 IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_probe)
 IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu)
 MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>");
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 4/6] irqchip/renesas-rzv2h: Make IRQ type handling range-aware
  2026-02-09 10:41 ` [PATCH v3 4/6] irqchip/renesas-rzv2h: Make IRQ type handling range-aware Prabhakar
@ 2026-02-24  7:30   ` Thomas Gleixner
  2026-02-24 13:41     ` Lad, Prabhakar
  0 siblings, 1 reply; 11+ messages in thread
From: Thomas Gleixner @ 2026-02-24  7:30 UTC (permalink / raw)
  To: Prabhakar, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

On Mon, Feb 09 2026 at 10:41, Prabhakar wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Refine IRQ type handling to explicitly bound IRQ and TINT ranges and
> dispatch based on the hardware IRQ number.

Changelog should not start with an explanation of the what. See

https://www.kernel.org/doc/html/latest/process/maintainer-tip.html#changelog

> This restructures the logic to clearly separate NMI, IRQ, and TINT

Restructure the ...


> @@ -175,18 +177,27 @@ static void rzv2h_icu_eoi(struct irq_data *d)
>  	u32 bit;
>  
>  	scoped_guard(raw_spinlock, &priv->lock) {
> -		if (hw_irq >= ICU_TINT_START) {
> -			tintirq_nr = hw_irq - ICU_TINT_START;
> -			bit = BIT(tintirq_nr);
> -			if (!irqd_is_level_type(d))
> -				writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR);
> -		} else if (hw_irq >= ICU_IRQ_START) {
> +		switch (hw_irq) {
> +		case 0:
> +			/* Clear NMI */
> +			writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR);
> +			break;
> +		case ICU_IRQ_START ... ICU_IRQ_LAST:
> +			/* Clear IRQ */
>  			tintirq_nr = hw_irq - ICU_IRQ_START;
>  			bit = BIT(tintirq_nr);
>  			if (!irqd_is_level_type(d))
>  				writel_relaxed(bit, priv->base + ICU_ISCLR);
> -		} else {
> -			writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR);
> +			break;
> +		case ICU_TINT_START ... ICU_TINT_LAST:
> +			/* Clear TINT */
> +			tintirq_nr = hw_irq - ICU_TINT_START;
> +			bit = BIT(tintirq_nr);
> +			if (!irqd_is_level_type(d))
> +				writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR);
> +			break;
> +		default:
> +			break;
>  		}
>  	}

TBH, I personally do not care about the performance of your platform at
all, but are you really serious about having a switch case like that in
a hotpath function?

Instead of sprinkling this switch case gunk all over the place you can
simply have separate interrupt chips for each region and install the
proper one at setup time. Then the functions are clearly separated and
just handling the type they are written for and nothing else. No?

Thanks,

        tglx

 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support
  2026-02-09 10:41 ` [PATCH v3 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support Prabhakar
@ 2026-02-24  7:34   ` Thomas Gleixner
  2026-02-24 15:36     ` Lad, Prabhakar
  0 siblings, 1 reply; 11+ messages in thread
From: Thomas Gleixner @ 2026-02-24  7:34 UTC (permalink / raw)
  To: Prabhakar, Philipp Zabel, Geert Uytterhoeven, Magnus Damm
  Cc: linux-kernel, linux-renesas-soc, Prabhakar, Biju Das,
	Fabrizio Castro, Lad Prabhakar

On Mon, Feb 09 2026 at 10:41, Prabhakar wrote:
>  static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
>  {
> +	unsigned int gic_type = IRQ_TYPE_LEVEL_HIGH;
>  	unsigned int hw_irq = irqd_to_hwirq(d);
>  	int ret;
>  
> @@ -445,6 +475,11 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
>  		/* TINT */
>  		ret = rzv2h_tint_set_type(d, type);
>  		break;
> +	case ICU_CA55_INT_START ... ICU_CA55_INT_LAST:
> +		/* CA55 Software Interrupts have EDGE_RISING type */
> +		gic_type = IRQ_TYPE_EDGE_RISING;

So this unconditionally selects EDGE_RISING independent of the type
provided by the caller. Interesting choice and compatible with the rest
of the code - _not_.

> +
> +static int rzv2h_icu_setup_irqs(struct platform_device *pdev,
> +				struct irq_domain *irq_domain)

I told you before that you have 100 characters. Get rid of these line breaks.

> +{
> +	bool irq_inject = IS_ENABLED(CONFIG_GENERIC_IRQ_INJECTION);
> +	static const char * const rzv2h_swint_names[] = {
> +		"int-ca55-0", "int-ca55-1",
> +		"int-ca55-2", "int-ca55-3",
> +	};
> +	static const u8 swint_idx[] = { 0, 1, 2, 3 };
> +	struct device *dev = &pdev->dev;
> +	struct irq_fwspec fwspec;
> +	unsigned int virq;
> +	unsigned int i;

Coalesce same types into a single line. See Documentation/....

> +	int ret;
> +
> +	for (i = 0; i < ICU_CA55_INT_COUNT && irq_inject; i++) {
> +		fwspec.fwnode = irq_domain->fwnode;
> +		fwspec.param_count = 2;
> +		fwspec.param[0] = ICU_CA55_INT_START + i;
> +		fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
> +
> +		virq = irq_create_fwspec_mapping(&fwspec);
> +		if (!virq)
> +			return dev_err_probe(dev, -EINVAL, "failed to create IRQ mapping for %s\n",
> +					     rzv2h_swint_names[i]);

This lacks curly brackets on the if(). See Documentation/.....


> +		ret = devm_request_irq(dev, virq, rzv2h_icu_swint_irq, 0, dev_name(dev),
> +				       (void *)&swint_idx[i]);
> +		if (ret)
> +			return dev_err_probe(dev, ret, "Failed to request %s IRQ\n",
> +					     rzv2h_swint_names[i]);

Ditto.

> +	}

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 4/6] irqchip/renesas-rzv2h: Make IRQ type handling range-aware
  2026-02-24  7:30   ` Thomas Gleixner
@ 2026-02-24 13:41     ` Lad, Prabhakar
  0 siblings, 0 replies; 11+ messages in thread
From: Lad, Prabhakar @ 2026-02-24 13:41 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Philipp Zabel, Geert Uytterhoeven, Magnus Damm, linux-kernel,
	linux-renesas-soc, Biju Das, Fabrizio Castro, Lad Prabhakar

Hi Thomas,

Thank you for the review.

On Tue, Feb 24, 2026 at 7:30 AM Thomas Gleixner <tglx@kernel.org> wrote:
>
> On Mon, Feb 09 2026 at 10:41, Prabhakar wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Refine IRQ type handling to explicitly bound IRQ and TINT ranges and
> > dispatch based on the hardware IRQ number.
>
> Changelog should not start with an explanation of the what. See
>
> https://www.kernel.org/doc/html/latest/process/maintainer-tip.html#changelog
>
> > This restructures the logic to clearly separate NMI, IRQ, and TINT
>
> Restructure the ...
>
Sure, I will update it.

>
> > @@ -175,18 +177,27 @@ static void rzv2h_icu_eoi(struct irq_data *d)
> >       u32 bit;
> >
> >       scoped_guard(raw_spinlock, &priv->lock) {
> > -             if (hw_irq >= ICU_TINT_START) {
> > -                     tintirq_nr = hw_irq - ICU_TINT_START;
> > -                     bit = BIT(tintirq_nr);
> > -                     if (!irqd_is_level_type(d))
> > -                             writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR);
> > -             } else if (hw_irq >= ICU_IRQ_START) {
> > +             switch (hw_irq) {
> > +             case 0:
> > +                     /* Clear NMI */
> > +                     writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR);
> > +                     break;
> > +             case ICU_IRQ_START ... ICU_IRQ_LAST:
> > +                     /* Clear IRQ */
> >                       tintirq_nr = hw_irq - ICU_IRQ_START;
> >                       bit = BIT(tintirq_nr);
> >                       if (!irqd_is_level_type(d))
> >                               writel_relaxed(bit, priv->base + ICU_ISCLR);
> > -             } else {
> > -                     writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR);
> > +                     break;
> > +             case ICU_TINT_START ... ICU_TINT_LAST:
> > +                     /* Clear TINT */
> > +                     tintirq_nr = hw_irq - ICU_TINT_START;
> > +                     bit = BIT(tintirq_nr);
> > +                     if (!irqd_is_level_type(d))
> > +                             writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR);
> > +                     break;
> > +             default:
> > +                     break;
> >               }
> >       }
>
> TBH, I personally do not care about the performance of your platform at
> all, but are you really serious about having a switch case like that in
> a hotpath function?
>
> Instead of sprinkling this switch case gunk all over the place you can
> simply have separate interrupt chips for each region and install the
> proper one at setup time. Then the functions are clearly separated and
> just handling the type they are written for and nothing else. No?
>
Agreed, I will split them up in separate irq chips, thank you for the
suggestion.

Cheers,
Prabhakar

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support
  2026-02-24  7:34   ` Thomas Gleixner
@ 2026-02-24 15:36     ` Lad, Prabhakar
  0 siblings, 0 replies; 11+ messages in thread
From: Lad, Prabhakar @ 2026-02-24 15:36 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Philipp Zabel, Geert Uytterhoeven, Magnus Damm, linux-kernel,
	linux-renesas-soc, Biju Das, Fabrizio Castro, Lad Prabhakar

Hi Thomas,

Thank you for the review.

On Tue, Feb 24, 2026 at 7:34 AM Thomas Gleixner <tglx@kernel.org> wrote:
>
> On Mon, Feb 09 2026 at 10:41, Prabhakar wrote:
> >  static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
> >  {
> > +     unsigned int gic_type = IRQ_TYPE_LEVEL_HIGH;
> >       unsigned int hw_irq = irqd_to_hwirq(d);
> >       int ret;
> >
> > @@ -445,6 +475,11 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
> >               /* TINT */
> >               ret = rzv2h_tint_set_type(d, type);
> >               break;
> > +     case ICU_CA55_INT_START ... ICU_CA55_INT_LAST:
> > +             /* CA55 Software Interrupts have EDGE_RISING type */
> > +             gic_type = IRQ_TYPE_EDGE_RISING;
>
> So this unconditionally selects EDGE_RISING independent of the type
> provided by the caller. Interesting choice and compatible with the rest
> of the code - _not_.
>
Ok, I will update it to use the type which has been passed.

> > +
> > +static int rzv2h_icu_setup_irqs(struct platform_device *pdev,
> > +                             struct irq_domain *irq_domain)
>
> I told you before that you have 100 characters. Get rid of these line breaks.
>
Ok.

> > +{
> > +     bool irq_inject = IS_ENABLED(CONFIG_GENERIC_IRQ_INJECTION);
> > +     static const char * const rzv2h_swint_names[] = {
> > +             "int-ca55-0", "int-ca55-1",
> > +             "int-ca55-2", "int-ca55-3",
> > +     };
> > +     static const u8 swint_idx[] = { 0, 1, 2, 3 };
> > +     struct device *dev = &pdev->dev;
> > +     struct irq_fwspec fwspec;
> > +     unsigned int virq;
> > +     unsigned int i;
>
> Coalesce same types into a single line. See Documentation/....
>
Ok.

> > +     int ret;
> > +
> > +     for (i = 0; i < ICU_CA55_INT_COUNT && irq_inject; i++) {
> > +             fwspec.fwnode = irq_domain->fwnode;
> > +             fwspec.param_count = 2;
> > +             fwspec.param[0] = ICU_CA55_INT_START + i;
> > +             fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
> > +
> > +             virq = irq_create_fwspec_mapping(&fwspec);
> > +             if (!virq)
> > +                     return dev_err_probe(dev, -EINVAL, "failed to create IRQ mapping for %s\n",
> > +                                          rzv2h_swint_names[i]);
>
> This lacks curly brackets on the if(). See Documentation/.....
>
Ok.

Cheers,
Prabhakar

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-02-24 15:37 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-09 10:41 [PATCH v3 0/6] irqchip/renesas-rzv2h: Add support to handle ICU error IRQ and add SWPE trigger Prabhakar
2026-02-09 10:41 ` [PATCH v3 1/6] irqchip/renesas-rzv2h: Use local node pointer Prabhakar
2026-02-09 10:41 ` [PATCH v3 2/6] irqchip/renesas-rzv2h: Use local device pointer in ICU probe Prabhakar
2026-02-09 10:41 ` [PATCH v3 3/6] irqchip/renesas-rzv2h: Switch to using dev_err_probe() Prabhakar
2026-02-09 10:41 ` [PATCH v3 4/6] irqchip/renesas-rzv2h: Make IRQ type handling range-aware Prabhakar
2026-02-24  7:30   ` Thomas Gleixner
2026-02-24 13:41     ` Lad, Prabhakar
2026-02-09 10:41 ` [PATCH v3 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support Prabhakar
2026-02-24  7:34   ` Thomas Gleixner
2026-02-24 15:36     ` Lad, Prabhakar
2026-02-09 10:41 ` [PATCH v3 6/6] irqchip/renesas-rzv2h: Handle ICU error IRQ and add SWPE trigger Prabhakar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox