All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: "Rob Herring (Arm)" <robh@kernel.org>,
	Marc Zyngier <maz@kernel.org>,
	Anup Patel <apatel@ventanamicro.com>,
	Sasha Levin <sashal@kernel.org>,
	saravanak@google.com, devicetree@vger.kernel.org
Subject: [PATCH AUTOSEL 6.6 25/35] of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw()
Date: Mon, 17 Jun 2024 09:22:23 -0400	[thread overview]
Message-ID: <20240617132309.2588101-25-sashal@kernel.org> (raw)
In-Reply-To: <20240617132309.2588101-1-sashal@kernel.org>

From: "Rob Herring (Arm)" <robh@kernel.org>

[ Upstream commit 935df1bd40d43c4ee91838c42a20e9af751885cc ]

Factor out the parsing of interrupt-map interrupt parent phandle and its
arg cells to a separate function, of_irq_parse_imap_parent(), so that it
can be used in other parsing scenarios (e.g. fw_devlink).

There was a refcount leak on non-matching entries when iterating thru
"interrupt-map" which is fixed.

Tested-by: Marc Zyngier <maz@kernel.org>
Tested-by: Anup Patel <apatel@ventanamicro.com>
Link: https://lore.kernel.org/r/20240529-dt-interrupt-map-fix-v2-1-ef86dc5bcd2a@kernel.org
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/of/irq.c        | 125 ++++++++++++++++++++++++----------------
 drivers/of/of_private.h |   3 +
 2 files changed, 77 insertions(+), 51 deletions(-)

diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 174900072c18c..462375b293e47 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -25,6 +25,8 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 
+#include "of_private.h"
+
 /**
  * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
  * @dev: Device node of the device whose interrupt is to be mapped
@@ -96,6 +98,57 @@ static const char * const of_irq_imap_abusers[] = {
 	NULL,
 };
 
+const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len, struct of_phandle_args *out_irq)
+{
+	u32 intsize, addrsize;
+	struct device_node *np;
+
+	/* Get the interrupt parent */
+	if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
+		np = of_node_get(of_irq_dflt_pic);
+	else
+		np = of_find_node_by_phandle(be32_to_cpup(imap));
+	imap++;
+
+	/* Check if not found */
+	if (!np) {
+		pr_debug(" -> imap parent not found !\n");
+		return NULL;
+	}
+
+	/* Get #interrupt-cells and #address-cells of new parent */
+	if (of_property_read_u32(np, "#interrupt-cells",
+					&intsize)) {
+		pr_debug(" -> parent lacks #interrupt-cells!\n");
+		of_node_put(np);
+		return NULL;
+	}
+	if (of_property_read_u32(np, "#address-cells",
+					&addrsize))
+		addrsize = 0;
+
+	pr_debug(" -> intsize=%d, addrsize=%d\n",
+		intsize, addrsize);
+
+	/* Check for malformed properties */
+	if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)
+		|| (len < (addrsize + intsize))) {
+		of_node_put(np);
+		return NULL;
+	}
+
+	pr_debug(" -> imaplen=%d\n", len);
+
+	imap += addrsize + intsize;
+
+	out_irq->np = np;
+	for (int i = 0; i < intsize; i++)
+		out_irq->args[i] = be32_to_cpup(imap - intsize + i);
+	out_irq->args_count = intsize;
+
+	return imap;
+}
+
 /**
  * of_irq_parse_raw - Low level interrupt tree parsing
  * @addr:	address specifier (start of "reg" property of the device) in be32 format
@@ -112,12 +165,12 @@ static const char * const of_irq_imap_abusers[] = {
  */
 int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 {
-	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
+	struct device_node *ipar, *tnode, *old = NULL;
 	__be32 initial_match_array[MAX_PHANDLE_ARGS];
 	const __be32 *match_array = initial_match_array;
-	const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
-	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
-	int imaplen, match, i, rc = -EINVAL;
+	const __be32 *tmp, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
+	u32 intsize = 1, addrsize;
+	int i, rc = -EINVAL;
 
 #ifdef DEBUG
 	of_print_phandle_args("of_irq_parse_raw: ", out_irq);
@@ -176,6 +229,9 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 
 	/* Now start the actual "proper" walk of the interrupt tree */
 	while (ipar != NULL) {
+		int imaplen, match;
+		const __be32 *imap, *oldimap, *imask;
+		struct device_node *newpar;
 		/*
 		 * Now check if cursor is an interrupt-controller and
 		 * if it is then we are done, unless there is an
@@ -216,7 +272,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 
 		/* Parse interrupt-map */
 		match = 0;
-		while (imaplen > (addrsize + intsize + 1) && !match) {
+		while (imaplen > (addrsize + intsize + 1)) {
 			/* Compare specifiers */
 			match = 1;
 			for (i = 0; i < (addrsize + intsize); i++, imaplen--)
@@ -224,48 +280,17 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 
 			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
 
-			/* Get the interrupt parent */
-			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
-				newpar = of_node_get(of_irq_dflt_pic);
-			else
-				newpar = of_find_node_by_phandle(be32_to_cpup(imap));
-			imap++;
-			--imaplen;
-
-			/* Check if not found */
-			if (newpar == NULL) {
-				pr_debug(" -> imap parent not found !\n");
-				goto fail;
-			}
-
-			if (!of_device_is_available(newpar))
-				match = 0;
-
-			/* Get #interrupt-cells and #address-cells of new
-			 * parent
-			 */
-			if (of_property_read_u32(newpar, "#interrupt-cells",
-						 &newintsize)) {
-				pr_debug(" -> parent lacks #interrupt-cells!\n");
-				goto fail;
-			}
-			if (of_property_read_u32(newpar, "#address-cells",
-						 &newaddrsize))
-				newaddrsize = 0;
-
-			pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
-			    newintsize, newaddrsize);
-
-			/* Check for malformed properties */
-			if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)
-			    || (imaplen < (newaddrsize + newintsize))) {
-				rc = -EFAULT;
+			oldimap = imap;
+			imap = of_irq_parse_imap_parent(oldimap, imaplen, out_irq);
+			if (!imap)
 				goto fail;
-			}
 
-			imap += newaddrsize + newintsize;
-			imaplen -= newaddrsize + newintsize;
+			match &= of_device_is_available(out_irq->np);
+			if (match)
+				break;
 
+			of_node_put(out_irq->np);
+			imaplen -= imap - oldimap;
 			pr_debug(" -> imaplen=%d\n", imaplen);
 		}
 		if (!match) {
@@ -287,11 +312,11 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 		 * Successfully parsed an interrupt-map translation; copy new
 		 * interrupt specifier into the out_irq structure
 		 */
-		match_array = imap - newaddrsize - newintsize;
-		for (i = 0; i < newintsize; i++)
-			out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
-		out_irq->args_count = intsize = newintsize;
-		addrsize = newaddrsize;
+		match_array = oldimap + 1;
+
+		newpar = out_irq->np;
+		intsize = out_irq->args_count;
+		addrsize = (imap - match_array) - intsize;
 
 		if (ipar == newpar) {
 			pr_debug("%pOF interrupt-map entry to self\n", ipar);
@@ -300,7 +325,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 
 	skiplevel:
 		/* Iterate again with new parent */
-		out_irq->np = newpar;
 		pr_debug(" -> new parent: %pOF\n", newpar);
 		of_node_put(ipar);
 		ipar = newpar;
@@ -310,7 +334,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 
  fail:
 	of_node_put(ipar);
-	of_node_put(newpar);
 
 	return rc;
 }
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index f38397c7b5824..21f8f5e80917d 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -158,6 +158,9 @@ extern void __of_sysfs_remove_bin_file(struct device_node *np,
 extern int of_bus_n_addr_cells(struct device_node *np);
 extern int of_bus_n_size_cells(struct device_node *np);
 
+const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len,
+				       struct of_phandle_args *out_irq);
+
 struct bus_dma_region;
 #if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_HAS_DMA)
 int of_dma_get_range(struct device_node *np,
-- 
2.43.0


  parent reply	other threads:[~2024-06-17 13:24 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-17 13:21 [PATCH AUTOSEL 6.6 01/35] scsi: core: alua: I/O errors for ALUA state transitions Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 02/35] scsi: sr: Fix unintentional arithmetic wraparound Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 03/35] scsi: qedf: Don't process stag work during unload and recovery Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 04/35] scsi: qedf: Wait for stag work during unload Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 05/35] scsi: qedf: Set qed_slowpath_params to zero before use Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 06/35] efi/libstub: zboot.lds: Discard .discard sections Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 07/35] efi: pstore: Return proper errors on UEFI failures Sasha Levin
2024-06-17 13:24   ` Ard Biesheuvel
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 08/35] ACPI: EC: Abort address space access upon error Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 09/35] ACPI: EC: Avoid returning AE_OK on errors in address space handler Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 10/35] tools/power/cpupower: Fix Pstate frequency reporting on AMD Family 1Ah CPUs Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 11/35] wifi: mac80211: mesh: init nonpeer_pm to active by default in mesh sdata Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 12/35] wifi: mac80211: apply mcast rate only if interface is up Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 13/35] wifi: mac80211: handle tasklet frames before stopping Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 14/35] wifi: cfg80211: fix 6 GHz scan request building Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 15/35] wifi: iwlwifi: mvm: d3: fix WoWLAN command version lookup Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 16/35] wifi: iwlwifi: mvm: remove stale STA link data during restart Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 17/35] wifi: iwlwifi: mvm: Handle BIGTK cipher in kek_kck cmd Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 18/35] wifi: iwlwifi: mvm: handle BA session teardown in RF-kill Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 19/35] wifi: iwlwifi: mvm: properly set 6 GHz channel direct probe option Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 20/35] wifi: iwlwifi: mvm: Fix scan abort handling with HW rfkill Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 21/35] wifi: mac80211: fix UBSAN noise in ieee80211_prep_hw_scan() Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 22/35] selftests: cachestat: Fix build warnings on ppc64 Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 23/35] selftests/openat2: " Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 24/35] selftests/futex: pass _GNU_SOURCE without a value to the compiler Sasha Levin
2024-06-17 13:22 ` Sasha Levin [this message]
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 26/35] Input: silead - Always support 10 fingers Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 27/35] net: ipv6: rpl_iptunnel: block BH in rpl_output() and rpl_input() Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 28/35] ila: block BH in ila_output() Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 29/35] arm64: armv8_deprecated: Fix warning in isndep cpuhp starting process Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 30/35] null_blk: fix validation of block size Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 31/35] kconfig: gconf: give a proper initial state to the Save button Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 32/35] kconfig: remove wrong expr_trans_bool() Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 33/35] input: Add event code for accessibility key Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 34/35] input: Add support for "Do Not Disturb" Sasha Levin
2024-06-17 13:22 ` [PATCH AUTOSEL 6.6 35/35] HID: Ignore battery for ELAN touchscreens 2F2C and 4116 Sasha Levin
  -- strict thread matches above, loose matches on Subject: below --
2024-06-18 12:37 [PATCH AUTOSEL 6.6 01/35] scsi: core: alua: I/O errors for ALUA state transitions Sasha Levin
2024-06-18 12:37 ` [PATCH AUTOSEL 6.6 25/35] of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw() Sasha Levin

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=20240617132309.2588101-25-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=apatel@ventanamicro.com \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maz@kernel.org \
    --cc=robh@kernel.org \
    --cc=saravanak@google.com \
    --cc=stable@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.