Received: by 2002:a05:6500:1b8f:b0:1fa:5c73:8e2d with SMTP id df15csp866326lqb; Wed, 29 May 2024 12:59:56 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCWgFesSv67MD8crW1MmQ3ZiIBit2sM6kPs24nVofOWwcMIpIqVeix/LvqU15FqDVQKqFmpaqZ1CMPFWl/PlvDJYQ3aig4/mGFN5jnPSjQ== X-Google-Smtp-Source: AGHT+IHVe4GAYugsuiFHsmL68Ww36HO0MqOrRh0BcuFYvLBkGB/1ZpA5hEYkZXoJJHxnI4Q1/pYR X-Received: by 2002:a05:6a00:4214:b0:6ed:60a4:6d9c with SMTP id d2e1a72fcca58-702310e53cdmr51810b3a.4.1717012796429; Wed, 29 May 2024 12:59:56 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1717012796; cv=pass; d=google.com; s=arc-20160816; b=Gt6zMXy4F+Q43gfwFahJj96LRGYwR+MAh2PYEuPefWbYqOqvkvlrG2V5YLYCIxbi3h /Etd9vRkd8rmpD0vAwFxxW7DUyaVDbpj5T295WV5jipS5o7ck3iyrnkxIELYHWMTfWqY xfrFUhyq9/eg9EFTO41wDHhW4ew9YqizySm65XjqHHGtz8yYEbdS3dXRpzIO2b7s0dVu v/RuYqh06B+Mo9nqOFSwRF8emkoGO4IYWyaxfc+LMb954ZqyorpRLWY2nP7aVzx5v8QV T0ruhZRK/d06NebmHlXXk6r5VtlqQoiPzJNvkPHd7Ue7WAB7dMRhq4wWeXHegEbOGaD9 uSGw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :subject:date:from:dkim-signature; bh=xO85bJQiObZAdvYOll9GPvgl3F824rtq8Qetjn37g7Y=; fh=e+vXXKYvG0Xid1LrmpDmPKIE50d+k+jNOteszH/kJXA=; b=fkacuEBROThtDhmtvfpEBUqERfzDPdzAqsyDQmtZsjd4F4ggeI0zfzO8ESi0DNbla+ JnzTqrB865SYCWWdgbtLYEj8Jgbd6+8jkdFpUyp0+1FKjfhFkxG8Ujv11NDID4a6kW6j IpyY20EVDGFcGZYZsPc/k0ZjGlqjrVGpMzJgE5YHhH7j1L+e6xT8lm/uCKxbYgaMWsYC w8raV7FALpLzHNpHgKc5sxJTo5KStZ0XkgRruWOJHXgdjvG27uvIdghWuE6Fo5bg3E3N b1rgJDWwSK7GGBf7CKPRV/aKqAFd3841V+IThov3rttlY0lWsuo5mvmgOfXaxHBVqh/y iQ3g==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=SWbyT8ZK; arc=pass (i=1 dkim=pass dkdomain=kernel.org); spf=pass (google.com: domain of linux-kernel+bounces-194630-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-194630-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [2604:1380:45e3:2400::1]) by mx.google.com with ESMTPS id d2e1a72fcca58-6f8fc046e03si11075036b3a.29.2024.05.29.12.59.56 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 May 2024 12:59:56 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-194630-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) client-ip=2604:1380:45e3:2400::1; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=SWbyT8ZK; arc=pass (i=1 dkim=pass dkdomain=kernel.org); spf=pass (google.com: domain of linux-kernel+bounces-194630-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-194630-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id 109E4287FAF for ; Wed, 29 May 2024 19:59:56 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 109731C68B6; Wed, 29 May 2024 19:59:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SWbyT8ZK" 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 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: 7bit 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 +#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[] = { 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 +167,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 +231,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 +274,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 +282,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 +314,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 +327,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 +336,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 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_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