From nobody Tue Dec 16 22:10:48 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 09AC11C689B; Wed, 29 May 2024 19:59:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717012777; cv=none; b=nl8L4znp1+M+IxSsgDdJjPCQ+/p3jWypFHG/L/0PLTB4Re8MXoXnThHKyDFdFFwklsKgGU/roeHY+IyKO5BGLiVeTWQq5/yvTQyd87Wc4jMW5yqEohodMZgnoQ2sblRE2rkAuT4s9tv3kCXtJeI9WDTevAN1XLA0pae0jjsRae4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717012777; c=relaxed/simple; bh=Myy67zQc7yPP4+bflABBuXvp0h9t/IzFdbDgUN/BEa0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pOVtPuhIx1Ij2iyrPCBPM9rNx0S0l6T7RVE6ajdpkHMy18eRciswQmUw2zxKk0HyH0Yl0yhixmky6hhaCOLPwTja/soaZsOivNN7ZQJIjQlT188woWQXH1yZ2UMXcDtVBykzv/pg7gkybOedA2HufSkZOSNS6hLKAqK1JQRPopE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SWbyT8ZK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SWbyT8ZK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3875EC32781; Wed, 29 May 2024 19:59:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1717012776; bh=Myy67zQc7yPP4+bflABBuXvp0h9t/IzFdbDgUN/BEa0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=SWbyT8ZKutysBAIRtYQdzCfC7xxK8EFxD7aWsugjHhCKykE9F5UE2iSv5RWpha/x8 msD1LccMJLbfEHVKsQ5wvsvjzFOKQY2+EwD4J9an3VBEoPsw5fLJXvjvUnkgKH7MXF 9WvAPCuLChjnG3Boe03qjlxZw3VGq70P63QgWeIRkBCojphS8k+wvmGs3bfQ1NOzzd Ophx343l7mF98JPAI/q+G/wlZjgCOHbGR5FpZacARi3TzhOQdT3pHw8andNJnQ6LZ1 RcBfBLa1pfIqF4ALhSRuK2c0Vp2VSskbwRHHQFtk9qYmJRsz3BpV8B6kQHyW0+OYfZ 8FkqLfgcv4HTw== From: "Rob Herring (Arm)" Date: Wed, 29 May 2024 14:59:20 -0500 Subject: [PATCH v2 1/2] of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20240529-dt-interrupt-map-fix-v2-1-ef86dc5bcd2a@kernel.org> References: <20240529-dt-interrupt-map-fix-v2-0-ef86dc5bcd2a@kernel.org> In-Reply-To: <20240529-dt-interrupt-map-fix-v2-0-ef86dc5bcd2a@kernel.org> To: Saravana Kannan , Anup Patel , Marc Zyngier Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-riscv@lists.infradead.org X-Mailer: b4 0.14-dev 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. Signed-off-by: Rob Herring (Arm) --- drivers/of/irq.c | 127 +++++++++++++++++++++++++++++---------------= ---- drivers/of/of_private.h | 3 ++ 2 files changed, 79 insertions(+), 51 deletions(-) diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 174900072c18..a7cdb892991e 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -25,6 +25,8 @@ #include #include =20 +#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,59 @@ static const char * const of_irq_imap_abusers[] =3D { NULL, }; =20 +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 =3D of_node_get(of_irq_dflt_pic); + else + np =3D 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 =3D 0; + + pr_debug(" -> intsize=3D%d, addrsize=3D%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=3D%d\n", len); + + imap +=3D addrsize + intsize; + + out_irq->np =3D np; + for (int i =3D 0; i < intsize; i++) + out_irq->args[i] =3D be32_to_cpup(imap - intsize + i); + out_irq->args_count =3D intsize; + + return imap; +} + /** * of_irq_parse_raw - Low level interrupt tree parsing * @addr: address specifier (start of "reg" property of the device) in be3= 2 format @@ -112,12 +167,12 @@ static const char * const of_irq_imap_abusers[] =3D { */ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) { - struct device_node *ipar, *tnode, *old =3D NULL, *newpar =3D NULL; + struct device_node *ipar, *tnode, *old =3D NULL; __be32 initial_match_array[MAX_PHANDLE_ARGS]; const __be32 *match_array =3D initial_match_array; - const __be32 *tmp, *imap, *imask, dummy_imask[] =3D { [0 ... MAX_PHANDLE_= ARGS] =3D cpu_to_be32(~0) }; - u32 intsize =3D 1, addrsize, newintsize =3D 0, newaddrsize =3D 0; - int imaplen, match, i, rc =3D -EINVAL; + const __be32 *tmp, dummy_imask[] =3D { [0 ... MAX_PHANDLE_ARGS] =3D cpu_t= o_be32(~0) }; + u32 intsize =3D 1, addrsize; + int i, rc =3D -EINVAL; =20 #ifdef DEBUG of_print_phandle_args("of_irq_parse_raw: ", out_irq); @@ -176,6 +231,9 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phan= dle_args *out_irq) =20 /* Now start the actual "proper" walk of the interrupt tree */ while (ipar !=3D 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 +274,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phan= dle_args *out_irq) =20 /* Parse interrupt-map */ match =3D 0; - while (imaplen > (addrsize + intsize + 1) && !match) { + while (imaplen > (addrsize + intsize + 1)) { /* Compare specifiers */ match =3D 1; for (i =3D 0; i < (addrsize + intsize); i++, imaplen--) @@ -224,48 +282,17 @@ int of_irq_parse_raw(const __be32 *addr, struct of_ph= andle_args *out_irq) =20 pr_debug(" -> match=3D%d (imaplen=3D%d)\n", match, imaplen); =20 - /* Get the interrupt parent */ - if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) - newpar =3D of_node_get(of_irq_dflt_pic); - else - newpar =3D of_find_node_by_phandle(be32_to_cpup(imap)); - imap++; - --imaplen; - - /* Check if not found */ - if (newpar =3D=3D NULL) { - pr_debug(" -> imap parent not found !\n"); - goto fail; - } - - if (!of_device_is_available(newpar)) - match =3D 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 =3D 0; - - pr_debug(" -> newintsize=3D%d, newaddrsize=3D%d\n", - newintsize, newaddrsize); - - /* Check for malformed properties */ - if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS) - || (imaplen < (newaddrsize + newintsize))) { - rc =3D -EFAULT; + oldimap =3D imap; + imap =3D of_irq_parse_imap_parent(oldimap, imaplen, out_irq); + if (!imap) goto fail; - } =20 - imap +=3D newaddrsize + newintsize; - imaplen -=3D newaddrsize + newintsize; + match &=3D of_device_is_available(out_irq->np); + if (match) + break; =20 + of_node_put(out_irq->np); + imaplen -=3D imap - oldimap; pr_debug(" -> imaplen=3D%d\n", imaplen); } if (!match) { @@ -287,11 +314,11 @@ int of_irq_parse_raw(const __be32 *addr, struct of_ph= andle_args *out_irq) * Successfully parsed an interrupt-map translation; copy new * interrupt specifier into the out_irq structure */ - match_array =3D imap - newaddrsize - newintsize; - for (i =3D 0; i < newintsize; i++) - out_irq->args[i] =3D be32_to_cpup(imap - newintsize + i); - out_irq->args_count =3D intsize =3D newintsize; - addrsize =3D newaddrsize; + match_array =3D oldimap + 1; + + newpar =3D out_irq->np; + intsize =3D out_irq->args_count; + addrsize =3D (imap - match_array) - intsize; =20 if (ipar =3D=3D newpar) { pr_debug("%pOF interrupt-map entry to self\n", ipar); @@ -300,7 +327,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phan= dle_args *out_irq) =20 skiplevel: /* Iterate again with new parent */ - out_irq->np =3D newpar; pr_debug(" -> new parent: %pOF\n", newpar); of_node_put(ipar); ipar =3D newpar; @@ -310,7 +336,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phan= dle_args *out_irq) =20 fail: of_node_put(ipar); - of_node_put(newpar); =20 return rc; } diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 94fc0aa07af9..04aa2a91f851 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -159,6 +159,9 @@ extern void __of_sysfs_remove_bin_file(struct device_no= de *np, extern int of_bus_n_addr_cells(struct device_node *np); extern int of_bus_n_size_cells(struct device_node *np); =20 +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, --=20 2.43.0