lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID:
 <TY3PR01MB11346DB069193A06BB45DC62A8697A@TY3PR01MB11346.jpnprd01.prod.outlook.com>
Date: Thu, 22 Jan 2026 08:20:30 +0000
From: Biju Das <biju.das.jz@...renesas.com>
To: Prabhakar <prabhakar.csengg@...il.com>, Thomas Gleixner <tglx@...nel.org>,
	Philipp Zabel <p.zabel@...gutronix.de>, Geert Uytterhoeven
	<geert+renesas@...der.be>, magnus.damm <magnus.damm@...il.com>
CC: "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
	"linux-renesas-soc@...r.kernel.org" <linux-renesas-soc@...r.kernel.org>,
	Fabrizio Castro <fabrizio.castro.jz@...esas.com>, Prabhakar Mahadev Lad
	<prabhakar.mahadev-lad.rj@...renesas.com>
Subject: RE: [PATCH 5/6] irqchip/renesas-rzv2h: Handle ICU error IRQ and add
 SWPE trigger

Hi Prabhakar,

> -----Original Message-----
> From: Prabhakar <prabhakar.csengg@...il.com>
> Sent: 21 January 2026 15:02
> Subject: [PATCH 5/6] irqchip/renesas-rzv2h: Handle ICU error IRQ and add SWPE trigger
> 
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
> 
> Handle the RZ/V2H ICU error interrupt to help diagnose latched bus, ECC RAM, and CA55/IP error
> conditions during bring-up and debugging.


Just a question,
If the irq handler is meant for debugging/bring-up, can this irq handler activated only for debug session
instead of unconditionally enabling it?

Cheers,
Biju
> 
> When debug support is enabled, register the error IRQ handler and provide a debugfs write interface to
> trigger pseudo error generation via ICU_SWPE for validation.
> 
> 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@...renesas.com>
> ---
>  drivers/irqchip/irq-renesas-rzv2h.c | 141 +++++++++++++++++++++++++++-
>  1 file changed, 140 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
> index 7d3ce1d762f0..6dc297220f05 100644
> --- a/drivers/irqchip/irq-renesas-rzv2h.c
> +++ b/drivers/irqchip/irq-renesas-rzv2h.c
> @@ -21,6 +21,7 @@
>  #include <linux/irqdomain.h>
>  #include <linux/kconfig.h>
>  #include <linux/kstrtox.h>
> +#include <linux/minmax.h>
>  #include <linux/moduleparam.h>
>  #include <linux/of_platform.h>
>  #include <linux/pm_runtime.h>
> @@ -47,7 +48,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)
> 
> @@ -99,6 +108,9 @@
>  #define ICU_RZV2H_TSSEL_MAX_VAL			0x55
> 
>  #define ICU_SWINT_NUM				4
> +#define ICU_SWPE_NUM				16
> +#define ICU_NUM_BE				4
> +#define ICU_NUM_A55ERR				4
> 
>  static bool enable_icu_debug;
>  module_param_named(debug, enable_icu_debug, bool, 0644); @@ -123,12 +135,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 */
> @@ -565,6 +581,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(st, base + ICU_BECLR(k));
> +		pr_debug("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(st, base + ICU_ERCLR(k));
> +		pr_debug("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(0xffffffff, base + ICU_ERINTA55CRL(k));
> +		pr_debug("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;
> @@ -611,13 +669,47 @@ static const struct file_operations rzv2h_icu_swint_fops = {
>  	.llseek	= noop_llseek,
>  };
> 
> +static ssize_t rzv2h_icu_swpe_write(struct file *file,
> +				    const char __user *ubuf,
> +				    size_t len, loff_t *ppos)
> +{
> +	struct rzv2h_icu_priv *priv = file->private_data;
> +	unsigned long swpe;
> +	char buf[32];
> +	int ret;
> +
> +	len = min(len, sizeof(buf) - 1);
> +	if (copy_from_user(buf, ubuf, len))
> +		return -EFAULT;
> +	buf[len] = '\0';
> +
> +	ret = kstrtoul(strim(buf), 0, &swpe);
> +	if (ret)
> +		return ret;
> +
> +	if (swpe >= ICU_SWPE_NUM)
> +		return -EINVAL;
> +
> +	writel(BIT(swpe), priv->base + ICU_SWPE);
> +	return len;
> +}
> +
> +static const struct file_operations rzv2h_icu_swpe_fops = {
> +	.open	= simple_open,
> +	.write	= rzv2h_icu_swpe_write,
> +	.llseek	= noop_llseek,
> +};
> +
>  static int rzv2h_icu_setup_debug_irqs(struct platform_device *pdev)  {
> +	const struct rzv2h_hw_info *hw_info = rzv2h_icu_data->info;
>  	static const u8 swint_idx[ICU_SWINT_NUM] = { 0, 1, 2, 3 };
>  	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";
> +	void __iomem *base = rzv2h_icu_data->base;
>  	struct device *dev = &pdev->dev;
>  	struct dentry *dentry;
>  	struct dentry *dir;
> @@ -654,6 +746,36 @@ static int rzv2h_icu_setup_debug_irqs(struct platform_device *pdev)
>  	if (IS_ERR(dentry))
>  		return PTR_ERR(dentry);
> 
> +	ret = devm_add_action_or_reset(dev, rzv2h_icu_remove_debugfs, dentry);
> +	if (ret)
> +		return ret;
> +
> +	icu_irq = platform_get_irq_byname(pdev, icu_err);
> +	if (icu_irq < 0)
> +		return dev_err_probe(dev, icu_irq, "Failed to get %s IRQ\n",
> +icu_err);
> +
> +	/* Unmask and clear all IP/CA55 error interrupts */
> +	for (i = 0; i < ICU_NUM_A55ERR; i++) {
> +		writel(0xffffff, base + ICU_ERINTA55CRL(i));
> +		writel(0x0, base + ICU_ERINTA55MSK(i));
> +	}
> +
> +	/* Clear all Bus errors */
> +	for (i = 0; i < ICU_NUM_BE; i++)
> +		writel(0xffffffff, base + ICU_BECLR(i));
> +
> +	/* Clear all ECCRAM errors */
> +	for (i = hw_info->ecc_start; i <= hw_info->ecc_end; i++)
> +		writel(0xffffffff, base + ICU_ERCLR(i));
> +
> +	ret = devm_request_irq(dev, icu_irq, 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);
> +
> +	dentry = debugfs_create_file("swpe", 0200, dir, rzv2h_icu_data, &rzv2h_icu_swpe_fops);
> +	if (IS_ERR(dentry))
> +		return PTR_ERR(dentry);
> +
>  	return devm_add_action_or_reset(dev, rzv2h_icu_remove_debugfs, dentry);  }
> 
> @@ -759,12 +881,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) @@ -772,6
> +906,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); @@ -779,7 +918,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@...esas.com>");
> --
> 2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ