devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sander Vanheule <sander@svanheule.net>
To: Thomas Gleixner <tglx@linutronix.de>,
	Marc Zyngier <maz@kernel.org>, Rob Herring <robh+dt@kernel.org>,
	devicetree@vger.kernel.org
Cc: Birger Koblitz <mail@birger-koblitz.de>,
	Bert Vermeulen <bert@biot.com>, John Crispin <john@phrozen.org>,
	linux-kernel@vger.kernel.org,
	Sander Vanheule <sander@svanheule.net>
Subject: [RFC PATCH v2 5/5] irqchip/realtek-rtl: add explicit output routing
Date: Sun, 26 Dec 2021 20:59:28 +0100	[thread overview]
Message-ID: <5ac543a6b61bbf825519e5cb0e36f8fe218f7054.1640548009.git.sander@svanheule.net> (raw)
In-Reply-To: <cover.1640548009.git.sander@svanheule.net>

Use the list of parent interrupts, and the optional output validity
mask, to build the list of routed output interrupts. This enables us to
remove the assumption that interrupt outputs (1..6) are always connected
to MIPS CPU interrupts (2..7).

Since the use of interrupt-map is non-standard, extra logic is required
to resolve the specified interrupts to one of the parent interrupts.

Signed-off-by: Sander Vanheule <sander@svanheule.net>
---
 drivers/irqchip/irq-realtek-rtl.c | 137 +++++++++++++++++++++++++-----
 1 file changed, 117 insertions(+), 20 deletions(-)

diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c
index 1f8f21a0bd1a..1b9c1108e945 100644
--- a/drivers/irqchip/irq-realtek-rtl.c
+++ b/drivers/irqchip/irq-realtek-rtl.c
@@ -22,6 +22,8 @@
 #define RTL_ICTL_IRR2		0x10
 #define RTL_ICTL_IRR3		0x14
 
+/* Support up to 6 active outputs for now */
+#define RTL_ICTL_OUTPUT_MASK	GENMASK(14, 0)
 #define RTL_ICTL_NUM_OUTPUTS	6
 
 #define REG(x)		(realtek_ictl_base + x)
@@ -31,6 +33,7 @@ static void __iomem *realtek_ictl_base;
 static struct irq_domain *realtek_ictl_domain;
 
 struct realtek_ictl_output {
+	int parent;
 	unsigned int routing_value;
 	u32 child_mask;
 };
@@ -142,10 +145,58 @@ static void __init set_routing(struct realtek_ictl_output *output, unsigned int
 	write_irr(REG(RTL_ICTL_IRR0), soc_int, output->routing_value);
 }
 
+static int __init resolve_parent(struct device_node *node, const __be32 *table,
+	unsigned int table_len, int *parent)
+{
+	struct of_phandle_args parent_irq;
+	struct device_node *parent_ictl;
+	unsigned int parent_cell_count;
+	unsigned int table_len_left;
+	int cell;
+	int ret;
+
+	if (!table_len)
+		return -EINVAL;
+
+	parent_ictl = of_find_node_by_phandle(be32_to_cpup(table++));
+	table_len_left = table_len - 1;
+
+	if (!parent_ictl)
+		return -EINVAL;
+
+	parent_irq.np = parent_ictl;
+
+	parent_cell_count = 0;
+	ret = of_property_read_u32(parent_ictl, "#interrupt-cells", &parent_cell_count);
+	if (ret)
+		goto out;
+
+	if (table_len_left < parent_cell_count) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	parent_irq.args_count = parent_cell_count;
+
+	for (cell = 0; cell < parent_cell_count; cell++)
+		parent_irq.args[cell] = be32_to_cpup(table++);
+
+	table_len_left -= parent_cell_count;
+
+	ret = of_irq_parse_raw(of_get_property(node, "reg", NULL), &parent_irq);
+	if (ret < 0)
+		goto out;
+
+	*parent = irq_create_of_mapping(&parent_irq);
+	ret = table_len - table_len_left;
+out:
+	of_node_put(parent_ictl);
+	return ret;
+}
+
 static int __init map_interrupts(struct device_node *node)
 {
 	struct realtek_ictl_output *output;
-	struct device_node *cpu_ictl;
 	const __be32 *imap;
 	u32 imaplen, soc_int, cpu_int, tmp;
 	int ret, i;
@@ -158,34 +209,76 @@ static int __init map_interrupts(struct device_node *node)
 	if (!imap || imaplen % 3)
 		return -EINVAL;
 
-	for (i = 0; i < imaplen; i += 3 * sizeof(u32)) {
-		soc_int = be32_to_cpup(imap);
-		if (soc_int > 31)
-			return -EINVAL;
+	imaplen /= sizeof(*imap);
+	while (imaplen > 1) {
+		soc_int = be32_to_cpup(imap++);
+		imaplen--;
 
-		cpu_ictl = of_find_node_by_phandle(be32_to_cpup(imap + 1));
-		if (!cpu_ictl)
-			return -EINVAL;
-		ret = of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp);
-		if (ret || tmp != 1)
+		if (soc_int > 31)
 			return -EINVAL;
-		of_node_put(cpu_ictl);
 
-		cpu_int = be32_to_cpup(imap + 2);
-		if (cpu_int > 7 || cpu_int < 2)
-			return -EINVAL;
+		cpu_int = 0;
+		ret = resolve_parent(node, imap, imaplen, &cpu_int);
+		if (ret < 0)
+			return ret;
+		imaplen -= ret;
+		imap += ret;
 
-		output = &realtek_ictl_outputs[cpu_int - 2];
+		i = 0;
+		output = &realtek_ictl_outputs[0];
 
-		if (!output->routing_value) {
-			irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch, output);
-			/* Use routing values (1..6) for CPU interrupts (2..7) */
-			output->routing_value = cpu_int - 1;
+		while (i < RTL_ICTL_NUM_OUTPUTS && output->parent != cpu_int) {
+			output++;
+			i++;
 		}
 
+		if (i == RTL_ICTL_NUM_OUTPUTS)
+			return -EINVAL;
+
 		set_routing(output, soc_int);
+	}
+
+	return 0;
+}
 
-		imap += 3;
+static int __init route_parent_interrupts(struct device_node *node)
+{
+	struct realtek_ictl_output *output;
+	unsigned int current_output;
+	unsigned int num_parents;
+	unsigned int parent;
+	u32 output_mask;
+	int parent_irq;
+
+	output_mask = RTL_ICTL_OUTPUT_MASK;
+	of_property_read_u32(node, "realtek,output-valid-mask", &output_mask);
+	if (output_mask & ~RTL_ICTL_OUTPUT_MASK) {
+		pr_warn("realtek,output-valid-mask contains unsupported outputs\n");
+		output_mask &= RTL_ICTL_OUTPUT_MASK;
+	}
+
+	num_parents = of_irq_count(node);
+	if (num_parents > RTL_ICTL_NUM_OUTPUTS) {
+		pr_err("too many parent interrupts\n");
+		return -EINVAL;
+	}
+
+	for (parent = 0; output_mask && parent < num_parents; parent++) {
+		current_output = __ffs(output_mask);
+
+		parent_irq = of_irq_get(node, parent);
+		if (parent_irq < 0)
+			return parent_irq;
+		else if (!parent_irq)
+			return -ENODEV;
+
+		output = &realtek_ictl_outputs[parent];
+		output->parent = parent_irq;
+		output->routing_value = current_output + 1;
+
+		irq_set_chained_handler_and_data(parent_irq, realtek_irq_dispatch, output);
+
+		output_mask &= ~BIT(current_output);
 	}
 
 	return 0;
@@ -209,6 +302,10 @@ static int __init realtek_rtl_of_init(struct device_node *node, struct device_no
 
 	realtek_ictl_domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL);
 
+	ret = route_parent_interrupts(node);
+	if (ret)
+		return ret;
+
 	ret = map_interrupts(node);
 	if (ret) {
 		pr_err("invalid interrupt map\n");
-- 
2.33.1


  parent reply	other threads:[~2021-12-26 20:02 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-26 19:59 [RFC PATCH v2 0/5] Rework realtek-rtl IRQ driver Sander Vanheule
2021-12-26 19:59 ` [RFC PATCH v2 1/5] irqchip/realtek-rtl: map control data to virq Sander Vanheule
2021-12-26 19:59 ` [RFC PATCH v2 2/5] irqchip/realtek-rtl: fix off-by-one in routing Sander Vanheule
2021-12-27 10:16   ` Marc Zyngier
2021-12-28 10:13     ` Sander Vanheule
2021-12-28 10:59       ` Marc Zyngier
2021-12-28 16:21         ` Sander Vanheule
2021-12-26 19:59 ` [RFC PATCH v2 3/5] irqchip/realtek-rtl: use per-parent irq handling Sander Vanheule
2021-12-27 10:38   ` Marc Zyngier
2021-12-26 19:59 ` [RFC PATCH v2 4/5] dt-bindings: interrupt-controller: realtek,rtl-intc: map output lines Sander Vanheule
2021-12-27 11:17   ` Marc Zyngier
2021-12-28 16:21     ` Sander Vanheule
2021-12-28 16:53       ` Birger Koblitz
2021-12-29 19:32         ` Sander Vanheule
2021-12-26 19:59 ` Sander Vanheule [this message]
2021-12-27  9:06 ` [RFC PATCH v2 0/5] Rework realtek-rtl IRQ driver Birger Koblitz
2021-12-27 10:39   ` Sander Vanheule
2021-12-28  8:09     ` Birger Koblitz
2021-12-29 20:03       ` Sander Vanheule

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=5ac543a6b61bbf825519e5cb0e36f8fe218f7054.1640548009.git.sander@svanheule.net \
    --to=sander@svanheule.net \
    --cc=bert@biot.com \
    --cc=devicetree@vger.kernel.org \
    --cc=john@phrozen.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mail@birger-koblitz.de \
    --cc=maz@kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=tglx@linutronix.de \
    /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;
as well as URLs for NNTP newsgroup(s).