From nobody Tue Dec 2 02:05:23 2025 Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6519519992C for ; Thu, 20 Nov 2025 00:41:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763599286; cv=none; b=fN9COVkp6WHefv4pzMyNRSaH+L00aiagVZDbwj2Mna+fufBb/92vBb7lEm28+DjXzm82UhtZItS+c3hBpZyaPZguC28dTnuUAepUeHsocNfRHUDJho9UlHk9Qj1REV0/xdkij6abYq3rScYOeJvSRvHlsuXb+BuDi5VkDyDv6pw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763599286; c=relaxed/simple; bh=cbxLhEu1L4Kb81XXH31TPTxLcK20qAwRmZjrdrLLan0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=GcyBkMkrhFnpuOu6JktLA84e6vQOe8JQSqnCY58VWYADSKXO0Xs+b+mZ2JcByaNjauhk0RqQvXRnLDF9F3YpU20j8qmHPKfL2omFwQcSqBmcc5gULFdAUEzkYwQxABMZTPQD5AOIePLztw2VVbmNtxXwH1rKbgyJhPm1qDGlhwg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=EqFnDsby; arc=none smtp.client-ip=209.85.214.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="EqFnDsby" Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-297e264528aso3665595ad.2 for ; Wed, 19 Nov 2025 16:41:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1763599283; x=1764204083; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=5RlDJuQZd0htln5phgfffcajqnUqhntFkkh1llCg7yY=; b=EqFnDsbyBRzwqoYFPTkhcuvfm6iI2NeorDCnnUdGOjiIxEEl95nEZQXICIP+wd1M0O l68BoIveoi5+Qb9LeBFWFWryhl6aJK0fUiUYSCoxVi0+ymoBc1f2afCYtSjEXs5zjeH9 9LiJ6NNzKJTPqHbAHVW57bgZEu8p+1CcFA2+tI6HUJKObAQ4zl2U3kckhL4RmRXCmG7t eWxCiZDWZprZQPNpkeJE0S2YjeUMWzwTRNAakifWgYRWY4/SjnpFL0BGTbyCynE1hPlv pTfIwKGnEBdYr9VWdyfqlg5Gf0wXK0swsdvkcIhimmGQyGtIbG73x21E4e0jPrv6n52b DPPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763599283; x=1764204083; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=5RlDJuQZd0htln5phgfffcajqnUqhntFkkh1llCg7yY=; b=v1t20lBDtaiu6fImMS6wlmkSbap5bm6l2Isnh0nrDKKoPkh/D0vDh4KHnjaXI4tZMM wgPOYG92J/VBZhWFhU3xczJk1RPh+BCnHGgMxeMEDSf5XM+p6EuV3glnAbuBTSvAn6d+ 4nk+qojAIsUnny1r97Ylqha/uZmiE7mtgj5R6jbbf1LklSTDti3WBvXrItqPeIAVXjlR vVqPAdkkIbd+Li8Yk1f3E89aLzPwJDO2tR32ogpn9GTFGlUXwkDv3f42VZB0I9jnRowU pnrE07NfnMZJoM3iVaJtFieMABO930LVbT3SBniSpGL8ul++QKJHaLTIWHPdChJ464dq HNkA== X-Forwarded-Encrypted: i=1; AJvYcCUktqH6UGpYWqjkV0PblmZugzOH2qA3wC7LCCvIjy093oULkB4AXEu3knjrWPHdChGhoZoJ1aQxrfu16m4=@vger.kernel.org X-Gm-Message-State: AOJu0YyPxSZhDGS+Di/kxwd53WHOYPMoo/r6cXKaJoF465Qup0ZZ6S8N x0+S3oDaz0e91RvQjUZtoJX9FDknMUIGuvLBNzYXNQjwVna+xuWN/8OpLXK73fKjR9k= X-Gm-Gg: ASbGncu4tLKKm4eSjA95AZjfp/gL4u0jgprIDPfox2E3+MP6A1mbMvYWQbA2oZL2FGa /du/6NQyFPjiNrrYZo5+iQgRpCOh4K0+8NDQnJmYL8auXZyTiBku+XcvbHmFRDXvvAzgVfLpedw TKmn/V2PMEtiSvYuw5OKy9Y1fGcgjYZoMN4pa+IbuQldM4gG38wZblJ3eVZCvb8bVHzHHT7IIdb o4va7KsGhIy3OAbCbMWFXABXP9Iq8LdIKCvwYq2WRE40j+3DHbPK5HHisnRav6SaTfwrBXTMqBQ oeZPL2T9hoMlY7rlXTHc1rqk6Tj968J7oK+bEEKmugx8TpqLqczgLzeu12VDKOKec6Usr0apcUX zZcyPH0Evi3tIWQbo8Okk4aeIXd+sHZ7wtt6SYissM+ObgFHEfWLJ+akPoua6/iQSsruz43z08S wBdO8DwQBW X-Google-Smtp-Source: AGHT+IEpm/8NtbsUYzJgPetyOChIIrYY2ppow/LPXleN+nBLnvVuN5z3sf8IX+Vk/KabuyPrsWcW8Q== X-Received: by 2002:a17:903:1b05:b0:297:e575:cc5d with SMTP id d9443c01a7336-29b5b0d5d22mr15249425ad.35.1763599282597; Wed, 19 Nov 2025 16:41:22 -0800 (PST) Received: from localhost ([71.212.208.158]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-29b5b2a7ad6sm6252645ad.87.2025.11.19.16.41.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Nov 2025 16:41:22 -0800 (PST) From: "Kevin Hilman (TI.com)" Date: Wed, 19 Nov 2025 16:41:07 -0800 Subject: [PATCH RFC] of: Add of_parse_map_iter() helper for nexus node map iteration 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: <20251119-topic-lpm-of-map-iterator-v6-18-v1-1-1f0075d771a3@baylibre.com> X-B4-Tracking: v=1; b=H4sIAKJjHmkC/x3NPQrDMAxA4asEzRVUrpv+rIEeoGvIIBylFTSxk U0ohNy9puO3vLdBFlPJcG82MFk1a1wq6NBAePPyEtSxGtzRnYnohiUmDfhJM8YJZ06oRYxLNFx bpCtyS95fvDvxGKBWksmk3/+hh+ejg2Hffzkfx992AAAA X-Change-ID: 20251119-topic-lpm-of-map-iterator-v6-18-a61447423adc To: Ulf Hansson , Rob Herring , Krzysztof Kozlowski Cc: devicetree@vger.kernel.org, linux-pm@vger.kernel.org, arm-scmi@vger.kernel.org, linux-kernel@vger.kernel.org, "Kevin Hilman (TI.com)" X-Mailer: b4 0.15-dev-a6db3 X-Developer-Signature: v=1; a=openpgp-sha256; l=8588; i=khilman@baylibre.com; h=from:subject:message-id; bh=cbxLhEu1L4Kb81XXH31TPTxLcK20qAwRmZjrdrLLan0=; b=owEBbQKS/ZANAwAIAVk3GJrT+8ZlAcsmYgBpHmOx/aOxo/I0ZUbmjbJ/adMveX3iGQ/4/28/Y xnYNDy7hlaJAjMEAAEIAB0WIQR7h0YOFpJ/qfW/8QxZNxia0/vGZQUCaR5jsQAKCRBZNxia0/vG ZU3iD/9pILnfJNIMRZZzU54QAQpXl5pW5xHZk4kgKkVRHRXTVCYCOhdWwak5zxBzLp5RMl5EBV0 oJXEq2jF7jdXkU1LPYfkK7PoiWk4Gyb8Ol1Wd54DaCXdAUWDz5fPZMq8Vlrz+dohPkhpKhUDZCi R5PxCyY3M7QLJwpFZBdIWUWHoXe6xcWLnfScMO/HrlNIv0PqS0euXZ2rxTs5ZpMmYMyLsmtnOyK lECRVcWnY0I0UrqhdjJmupZarcaJV8lca/XlReCgjh9X80V0mvYtwxKiCbC9xGIJV4bigHVvnv5 scemgoDCptyYgsK69cXwoaRw3FmIlIvGwLKfOUbuGDc5zMfMJgoxHi9/1oLSSgwrH9Td67T+BH0 gzNBrm8xLViRgevbtHzt0l2Ewuxxgeb2z2gvOQfi78Gw/iyi4VeQ7gw/CUsw5IB5cnrtRXQz/H4 MbYvjRgWSH3mUB2NBqQv5dyOpYpMyGO/f/BWVUzH9Dx7TlRe48mq9OFqc/bxnq/jBfLXbOUp3Wx Nf0DQid7xHefE0CtA13VuT05nCXae3DEkbvPcsRQ3J0//fgM+ViyYs4AyAm452vhVvY7RjGvPN6 6Bw8+La6lRnbB/VZuL/bfnyWzzZNYdYnOFmteVd0WtZeLtKVLvR7b4sqQXh3kkbMw+WFaqcyX9C 7h/2WVLEUtnJw6w== X-Developer-Key: i=khilman@baylibre.com; a=openpgp; fpr=7B87460E16927FA9F5BFF10C5937189AD3FBC665 Add a new helper function of_parse_map_iter() to iterate over nexus node maps (c.f. DT spec, section 2.5.1.) This function provides an iterator interface for traversing map entries, handling the complexity of variable-sized entries based on -cells properties, as well as handling the -skip and -pass-thru properties. RFC: There's a lot of overlap between this function and of_parse_phandle_with_args_map(). However the key differences are: - of_parse_phandle_with_args_map() does matching it searches for an entry that matches specific child args - of_parse_map_iter() does iteration it simply walks through all entries sequentially There are likely ways to extract some shared code between these two functions into some shared helpers, but I'm hoping someone more familiar with this OF code can help here. However, before refactoring the shared code, it would be good to have some feedback on this approach. Signed-off-by: Kevin Hilman (TI.com) --- drivers/of/base.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++= +++ include/linux/of.h | 13 ++++ 2 files changed, 180 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 7043acd971a0..bdb4fde1bfa9 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1594,6 +1594,173 @@ int of_parse_phandle_with_args_map(const struct dev= ice_node *np, } EXPORT_SYMBOL(of_parse_phandle_with_args_map); =20 +/** + * of_parse_map_iter() - Iterate through entries in a nexus node map + * @np: pointer to a device tree node containing the map + * @stem_name: stem of property names (e.g., "power-domain" for "power-do= main-map") + * @index: pointer to iteration index (set to 0 for first call) + * @child_args: pointer to structure to fill with child specifier (can be= NULL) + * @parent_args: pointer to structure to fill with parent phandle and spec= ifier + * + * This function iterates through a nexus node map property as defined in = DT spec 2.5.1. + * Each map entry has the format: + * + * On each call, it extracts one map entry and fills child_args (if provid= ed) with the + * child specifier and parent_args with the parent phandle and specifier. + * The index pointer is updated to point to the next entry for the followi= ng call. + * + * Example usage:: + * + * int index =3D 0; + * struct of_phandle_args child_args, parent_args; + * + * while (!of_parse_map_iter(np, "power-domain", &index, &child_args, &pa= rent_args)) { + * // Process child_args and parent_args + * of_node_put(parent_args.np); + * } + * + * Caller is responsible for calling of_node_put() on parent_args.np. + * + * Return: 0 on success, -ENOENT when iteration is complete, or negative e= rror code on failure. + */ +int of_parse_map_iter(const struct device_node *np, + const char *stem_name, + int *index, + struct of_phandle_args *child_args, + struct of_phandle_args *parent_args) +{ + char *cells_name __free(kfree) =3D kasprintf(GFP_KERNEL, "#%s-cells", ste= m_name); + char *map_name __free(kfree) =3D kasprintf(GFP_KERNEL, "%s-map", stem_nam= e); + char *mask_name __free(kfree) =3D kasprintf(GFP_KERNEL, "%s-map-mask", st= em_name); + char *pass_name __free(kfree) =3D kasprintf(GFP_KERNEL, "%s-map-pass-thru= ", stem_name); + static const __be32 dummy_mask[] =3D { [0 ... MAX_PHANDLE_ARGS] =3D cpu_t= o_be32(~0) }; + static const __be32 dummy_pass[] =3D { [0 ... MAX_PHANDLE_ARGS] =3D cpu_t= o_be32(0) }; + const __be32 *map, *mask, *pass; + __be32 child_spec[MAX_PHANDLE_ARGS]; + u32 child_cells, parent_cells; + int map_len, i, entry_idx; + + if (!np || !stem_name || !index || !parent_args) + return -EINVAL; + + if (!cells_name || !map_name || !mask_name || !pass_name) + return -ENOMEM; + + /* Get the map property */ + map =3D of_get_property(np, map_name, &map_len); + if (!map) + return -ENOENT; + + map_len /=3D sizeof(u32); + + /* Get child #cells */ + if (of_property_read_u32(np, cells_name, &child_cells)) + return -EINVAL; + + /* Get the mask property (optional) */ + mask =3D of_get_property(np, mask_name, NULL); + if (!mask) + mask =3D dummy_mask; + + /* Get the pass-thru property (optional) */ + pass =3D of_get_property(np, pass_name, NULL); + if (!pass) + pass =3D dummy_pass; + + /* Iterate through map to find the entry at the requested index */ + entry_idx =3D 0; + while (map_len > child_cells + 1) { + /* If this is the entry we're looking for, extract it */ + if (entry_idx =3D=3D *index) { + /* Save masked child specifier for pass-thru processing */ + for (i =3D 0; i < child_cells && i < MAX_PHANDLE_ARGS; i++) + child_spec[i] =3D map[i] & mask[i]; + + /* Extract child specifier if requested */ + if (child_args) { + child_args->np =3D (struct device_node *)np; + child_args->args_count =3D child_cells; + for (i =3D 0; i < child_cells && i < MAX_PHANDLE_ARGS; i++) + child_args->args[i] =3D be32_to_cpu(map[i]); + } + + /* Move past child specifier */ + map +=3D child_cells; + map_len -=3D child_cells; + + /* Extract parent phandle */ + parent_args->np =3D of_find_node_by_phandle(be32_to_cpup(map)); + map++; + map_len--; + + if (!parent_args->np) + return -EINVAL; + + /* Get parent #cells */ + if (of_property_read_u32(parent_args->np, cells_name, &parent_cells)) + parent_cells =3D 0; + + /* Check for malformed properties */ + if (WARN_ON(parent_cells > MAX_PHANDLE_ARGS) || + map_len < parent_cells) { + of_node_put(parent_args->np); + return -EINVAL; + } + + /* + * Copy parent specifier into the out_args structure, keeping + * the bits specified in -map-pass-thru per DT spec 2.5.1 + */ + parent_args->args_count =3D parent_cells; + for (i =3D 0; i < parent_cells; i++) { + __be32 val =3D map[i]; + + if (i < child_cells) { + val &=3D ~pass[i]; + val |=3D child_spec[i] & pass[i]; + } + + parent_args->args[i] =3D be32_to_cpu(val); + } + + /* Advance index for next iteration */ + (*index)++; + return 0; + } + + /* Skip this entry: child_cells + phandle + parent_cells */ + map +=3D child_cells; + map_len -=3D child_cells; + + /* Get parent node to determine parent_cells */ + parent_args->np =3D of_find_node_by_phandle(be32_to_cpup(map)); + map++; + map_len--; + + if (!parent_args->np) + return -EINVAL; + + if (of_property_read_u32(parent_args->np, cells_name, &parent_cells)) + parent_cells =3D 0; + + of_node_put(parent_args->np); + + /* Check for malformed properties */ + if (map_len < parent_cells) + return -EINVAL; + + /* Move forward by parent node's #-cells amount */ + map +=3D parent_cells; + map_len -=3D parent_cells; + + entry_idx++; + } + + /* Reached end of map without finding the requested index */ + return -ENOENT; +} +EXPORT_SYMBOL(of_parse_map_iter); + /** * of_count_phandle_with_args() - Find the number of phandles references i= n a property * @np: pointer to a device tree node containing a list diff --git a/include/linux/of.h b/include/linux/of.h index 121a288ca92d..79470218089c 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -384,6 +384,10 @@ extern int __of_parse_phandle_with_args(const struct d= evice_node *np, extern int of_parse_phandle_with_args_map(const struct device_node *np, const char *list_name, const char *stem_name, int index, struct of_phandle_args *out_args); +extern int of_parse_map_iter(const struct device_node *np, + const char *stem_name, int *index, + struct of_phandle_args *child_args, + struct of_phandle_args *parent_args); extern int of_count_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name); =20 @@ -786,6 +790,15 @@ static inline int of_parse_phandle_with_args_map(const= struct device_node *np, return -ENOSYS; } =20 +static inline int of_parse_map_iter(const struct device_node *np, + const char *stem_name, + int *index, + struct of_phandle_args *child_args, + struct of_phandle_args *parent_args) +{ + return -ENOSYS; +} + static inline int of_count_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name) --- base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787 change-id: 20251119-topic-lpm-of-map-iterator-v6-18-a61447423adc Best regards, -- =20 Kevin Hilman (TI.com)