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 for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220708165225.269192-1-ben.dooks@sifive.com>
Date:   Fri,  8 Jul 2022 17:52:25 +0100
From:   Ben Dooks <ben.dooks@...ive.com>
To:     devicetree@...r.kernel.org, frowand.list@...il.com
Cc:     linux-kernel@...r.kernel.org, robh+dt@...nel.org,
        Sudip Mukherjee <sudip.mukherjee@...ive.com>,
        Jude Onyenegecha <jude.onyenegecha@...ive.com>,
        Ben Dooks <ben.dooks@...ive.com>
Subject: [PATCH] of/irq: parse interrupts-extended during irq init heirarchy calculation

When the irq controler code works out the heirarchy for initialialisation
it only looks at interrupt-parent properties, but controllers such as the
RISC-V PLIC use a extended-interrupt property and therefore do not get
properly considered during initialisation.

This means that if anything changes in the driver initialisation order
then the PLIC can get called before the CLINT nodes, and thus interrupts
do not get configured properly and the init continues without noticing
the error until drivers fail due to having no interrupts delivered.

Add code to the of_irq_init that checks for the extended-interrupt
property and adds these parent nodes so that they can be considered
during the calculations of whether an irq controller node can be
initialised.

Signed-off-by: Ben Dooks <ben.dooks@...ive.com>
---
 drivers/of/irq.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)

diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index d22f605fa7ee..abfee1fb8717 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -507,11 +507,32 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
 
 struct of_intc_desc {
 	struct list_head	list;
+	struct list_head	parents;
 	of_irq_init_cb_t	irq_init_cb;
 	struct device_node	*dev;
 	struct device_node	*interrupt_parent;
 };
 
+static bool of_irq_init_check_parents(struct of_intc_desc *desc,
+				      struct device_node *parent)
+{
+	struct of_intc_desc *search, *temp_desc;
+
+	if (list_empty(&desc->parents))
+		return desc->interrupt_parent == parent;
+
+	list_for_each_entry_safe(search, temp_desc, &desc->parents, list) {
+		if (search->interrupt_parent == parent) {
+			pr_debug("%s: %pOF removing %pOF\n",
+				__func__, desc->dev, search->interrupt_parent);
+			list_del(&search->list);
+			kfree(search);
+		}
+	}
+
+	return list_empty(&desc->parents);
+}
+
 /**
  * of_irq_init - Scan and init matching interrupt controllers in DT
  * @matches: 0 terminated array of nodes to match and init function to call
@@ -548,6 +569,7 @@ void __init of_irq_init(const struct of_device_id *matches)
 			goto err;
 		}
 
+		INIT_LIST_HEAD(&desc->parents);
 		desc->irq_init_cb = match->data;
 		desc->dev = of_node_get(np);
 		/*
@@ -563,6 +585,40 @@ void __init of_irq_init(const struct of_device_id *matches)
 			desc->interrupt_parent = NULL;
 		}
 		list_add_tail(&desc->list, &intc_desc_list);
+
+		/*
+		 * If the irq controller has an interrupts-extended
+		 * property then go through it to find out if there
+		 * are any parents in there to consider.
+		 */
+		if (!desc->interrupt_parent &&
+		    of_find_property(np, "interrupts-extended", NULL)) {
+			struct of_phandle_args irq;
+			int nr_irqs = of_irq_count(np);
+			int index, res;
+
+			pr_debug("%s: %pOF interrupts-extended, %d irqs\n",
+				__func__, np, nr_irqs);
+
+			for (index = 0; index < nr_irqs; index++) {
+				res = of_parse_phandle_with_args(np, "interrupts-extended",
+								 "#interrupt-cells", index, &irq);
+				if (res) {
+					goto err;
+				}
+
+				pr_debug("%s: %pOF parent %pOF\n", __func__, np, irq.np);
+				if (irq.np == np)
+					continue;
+
+				temp_desc = kzalloc(sizeof(*temp_desc), GFP_KERNEL);
+				if (!temp_desc)
+					goto err;
+
+				temp_desc->interrupt_parent = irq.np;
+				list_add_tail(&temp_desc->list, &desc->parents);
+			}
+		}
 	}
 
 	/*
@@ -579,14 +635,14 @@ void __init of_irq_init(const struct of_device_id *matches)
 		list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
 			int ret;
 
-			if (desc->interrupt_parent != parent)
+			if (!of_irq_init_check_parents(desc, parent))
 				continue;
 
 			list_del(&desc->list);
 
 			of_node_set_flag(desc->dev, OF_POPULATED);
 
-			pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
+			pr_debug("of_irq_init: init %pOF (%px), parent %px\n",
 				 desc->dev,
 				 desc->dev, desc->interrupt_parent);
 			ret = desc->irq_init_cb(desc->dev,
-- 
2.35.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ