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: <20260121150137.3364865-5-prabhakar.mahadev-lad.rj@bp.renesas.com>
Date: Wed, 21 Jan 2026 15:01:35 +0000
From: Prabhakar <prabhakar.csengg@...il.com>
To: 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-renesas-soc@...r.kernel.org,
	Prabhakar <prabhakar.csengg@...il.com>,
	Biju Das <biju.das.jz@...renesas.com>,
	Fabrizio Castro <fabrizio.castro.jz@...esas.com>,
	Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
Subject: [PATCH 4/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support

From: Lad Prabhakar <prabhakar.mahadev-lad.rj@...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.

Introduce a debug mechanism to trigger software interrupts on individual
Cortex-A55 cores via the RZ/V2H ICU. The interface is gated behind
CONFIG_DEBUG_FS and a module parameter to ensure it only exists when
explicitly enabled.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
---
 drivers/irqchip/irq-renesas-rzv2h.c | 111 ++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index 4aa772ba1a1f..7d3ce1d762f0 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -11,16 +11,23 @@
 
 #include <linux/bitfield.h>
 #include <linux/cleanup.h>
+#include <linux/cpu.h>
+#include <linux/debugfs.h>
 #include <linux/err.h>
+#include <linux/fs.h>
 #include <linux/io.h>
 #include <linux/irqchip.h>
 #include <linux/irqchip/irq-renesas-rzv2h.h>
 #include <linux/irqdomain.h>
+#include <linux/kconfig.h>
+#include <linux/kstrtox.h>
+#include <linux/moduleparam.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
 #include <linux/spinlock.h>
 #include <linux/syscore_ops.h>
+#include <linux/uaccess.h>
 
 /* DT "interrupts" indexes */
 #define ICU_IRQ_START				1
@@ -40,6 +47,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)
 
@@ -90,6 +98,13 @@
 #define ICU_RZG3E_TSSEL_MAX_VAL			0x8c
 #define ICU_RZV2H_TSSEL_MAX_VAL			0x55
 
+#define ICU_SWINT_NUM				4
+
+static bool enable_icu_debug;
+module_param_named(debug, enable_icu_debug, bool, 0644);
+MODULE_PARM_DESC(debug,
+		 "Enable RZ/V2H ICU debug/diagnostic interrupts (default: false)");
+
 /**
  * struct rzv2h_irqc_reg_cache - registers cache (necessary for suspend/resume)
  * @nitsr: ICU_NITSR register
@@ -550,6 +565,98 @@ 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_debug("SWINT interrupt for CA55 core %u\n", cpu);
+	return IRQ_HANDLED;
+}
+
+static void rzv2h_icu_remove_debugfs(void *file)
+{
+	debugfs_remove(file);
+}
+
+static ssize_t rzv2h_icu_swint_write(struct file *file, const char __user *ubuf,
+				     size_t len, loff_t *ppos)
+{
+	struct rzv2h_icu_priv *priv = file->private_data;
+	unsigned long cpu;
+	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, &cpu);
+	if (ret)
+		return ret;
+
+	if (cpu >= ICU_SWINT_NUM || cpu >= nr_cpu_ids)
+		return -EINVAL;
+
+	if (!cpu_online(cpu))
+		return -ENODEV;
+
+	writel(BIT(cpu), priv->base + ICU_SWINT);
+	return len;
+}
+
+static const struct file_operations rzv2h_icu_swint_fops = {
+	.open	= simple_open,
+	.write	= rzv2h_icu_swint_write,
+	.llseek	= noop_llseek,
+};
+
+static int rzv2h_icu_setup_debug_irqs(struct platform_device *pdev)
+{
+	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",
+	};
+	struct device *dev = &pdev->dev;
+	struct dentry *dentry;
+	struct dentry *dir;
+	unsigned int i;
+	int icu_irq;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_DEBUG_FS) || !enable_icu_debug)
+		return 0;
+
+	dev_info(dev, "RZ/V2H ICU debug interrupts enabled\n");
+
+	for (i = 0; i < ICU_SWINT_NUM; i++) {
+		icu_irq = platform_get_irq_byname(pdev, rzv2h_swint_names[i]);
+		if (icu_irq < 0)
+			return dev_err_probe(dev, icu_irq,
+					     "Failed to get %s IRQ\n", rzv2h_swint_names[i]);
+		ret = devm_request_irq(dev, icu_irq, rzv2h_icu_swint_irq, 0, dev_name(dev),
+				       (void *)&swint_idx[i]);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to request SWINT IRQ: %s\n",
+					     rzv2h_swint_names[i]);
+	}
+
+	dir = debugfs_create_dir("rzv2h_icu", NULL);
+	if (IS_ERR(dir))
+		return PTR_ERR(dir);
+
+	ret = devm_add_action_or_reset(dev, rzv2h_icu_remove_debugfs, dir);
+	if (ret)
+		return ret;
+
+	dentry = debugfs_create_file("swint", 0200, dir, rzv2h_icu_data, &rzv2h_icu_swint_fops);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+
+	return devm_add_action_or_reset(dev, rzv2h_icu_remove_debugfs, dentry);
+}
+
 static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_node *parent,
 				  const struct rzv2h_hw_info *hw_info)
 {
@@ -605,6 +712,10 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 
 	register_syscore(&rzv2h_irqc_syscore);
 
+	ret = rzv2h_icu_setup_debug_irqs(pdev);
+	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


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ