From nobody Mon Feb 9 04:56:41 2026 Received: from mail-pl1-f169.google.com (mail-pl1-f169.google.com [209.85.214.169]) (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 89B1043CEC1 for ; Wed, 21 Jan 2026 23:55:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769039739; cv=none; b=kv6SWHJSFFctaKeAPNdDWuXaWPkkyTvehBBrNYXrqqDH4nfPydQYwPQ1RgMiUKDk1puE6cmjhpSpjNT7HAWQhbBKcPwFXht3O4G2ziMAiEjruUxJ3UdSEjT3LeRe6hrjooJoTAG6xAd0zVfDdPuCJu9D2n3Nm/hePIkrzbxkLYE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769039739; c=relaxed/simple; bh=wqs3ot1lzYp1uxjm9+RCV8ylRHq0mF6h93+LA8PtmTw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=il3WadsuXFpYfdpppZKilk1oCRA+XZY51g8SsSiMEksdeF61/J4+1i8OxNSoCoSdu2g8JOJvoIYWFaob7B8/Y2HqdAsC16Sga/4/zs2Ha8gJjCH7Dy4hH3MIhuxRk57WBhvvPq0t74Yc3iMzXJYy4uYX8xO5GHLg9TLtX3EL4Ns= 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=UqAc/n8A; arc=none smtp.client-ip=209.85.214.169 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="UqAc/n8A" Received: by mail-pl1-f169.google.com with SMTP id d9443c01a7336-29efd139227so2877055ad.1 for ; Wed, 21 Jan 2026 15:55:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1769039735; x=1769644535; 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=PjllSAPGQe9z4wytVvsWXJp6Q+2QEqXJfq4b/O+DazI=; b=UqAc/n8AoHRDmZF/KIIQqbnV6wOhlWf7BQky21fuHrQMoa8G0mPnIrEk2sYfuu8jxf vHqcOxiI8Px4E/2qkzkkokAyAWq8W9EpNQ9+Gg+Vp9H6wsV+Q+36GCVyQpoS4yUaUkzb 8oBmRVFwnVGQ+ZA0xrZg1Kx9mt5UoEZ1H2/NTIw5vP9gebjbSAvkEEcMXwLu/vcDub4O ZDhdCbTQOWOAv8lA4UOtxINXrQGyQ7IWl5lYpRerROsWu2ENHnfZ3auhxd9zzZ+ucZ9Q K+bmdkI1O2nIZPxitYlNWUyFYF0+B6Mfg97OKCrajV8zgq/6MKCCoWBW/oJlQErMkl8Q bZ0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769039735; x=1769644535; 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=PjllSAPGQe9z4wytVvsWXJp6Q+2QEqXJfq4b/O+DazI=; b=kRWL590jBlfHynJN9sxiLKGdY0ONvlJbES2f1NhtS4GsGUdO4r9mPG99NNZMYbuvq7 YSnIND0L62u/qIaA7sJYZcZ61OcG/M1JBLc8R1dVGxI0Ll5/gh3SpNxiSoWgcgtjKf7s SGFYeGhMB5KNqvdYYl1Dnnms2lln+SBs/le4KYFOOTz3LeMptwi6/d8+/XXejyd5REs8 mOuYPJEGW43GwSiVeSrSEnE6S/TKDKfetJM6xPJWZVKqnELuYRa5sXKhy3p71AlEOjWB XR28j3nNxVsxsGKlI45Zjxkl4QD3KkxENlw6Y8bEzDjIJejLjIVLfHAucarS/NrjeaoJ f1Jg== X-Forwarded-Encrypted: i=1; AJvYcCX6LC6UV09rtR8xbBIku7KOaoGpJNGcgMoXbRc4TW2SW0FTWpz7Wic9BkNRsBcqbVI4r93pdANTDnhJX+4=@vger.kernel.org X-Gm-Message-State: AOJu0Ywrj8COfgRUfILKXGom7TBDlsaaRk5kv+jmnuxDtm+ni/2Pknwt glLko3r4msa8chqBCZeZMnE9awgxOPpaRrne0mA11h27TnT36rAz6AGs5ET8lkucMJI= X-Gm-Gg: AZuq6aK1QTZfgVgkPmxfMTiRfg2cQgcHGKCPH1kZWMQbhWnhOQnFbpyZ4eIGep92Zch qpmcpvXFuS0HdI001Tgq+5+m1Oe2L+HMFJfp+aLUv0KeQtNdmWc8iKyk09jQffsbONWKXhH2Unv VDewEtooh2Wcf0yOD9QjoOB1LG3XXYijb257U99+dYCJ3kNimHU08t4xbBUP6jJ385v1D/w6PD8 UO+qAuOLs6vgWPAFcIfNPTP37oCmEonhzqYEnqJb+s4dWqjboZa326w+hyovDF7uOD3XEE5krrA A9AWYJDqRoYBFP8VNbnk34N2hTXs2HXG3tsmrMrVWtlDxNTFRYROyzv/QrIG5GHdR2U0ZZf9d8y +93ArjwlomvCcWMnEH4UCtfaECAgU7p6rnpiRk1NJuIRivdH3oNadaJxdapoBbWjj4qN4Y9RFBm Ue6g6EyAEa X-Received: by 2002:a17:902:e750:b0:2a7:7872:8f52 with SMTP id d9443c01a7336-2a77872a27bmr53983595ad.26.1769039734673; Wed, 21 Jan 2026 15:55:34 -0800 (PST) Received: from localhost ([71.212.200.220]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a7190d16a8sm165990235ad.39.2026.01.21.15.55.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Jan 2026 15:55:33 -0800 (PST) From: "Kevin Hilman (TI)" Date: Wed, 21 Jan 2026 15:55:33 -0800 Subject: [PATCH RFC v2] 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: <20260121-topic-lpm-of-map-iterator-v6-18-v2-1-a40bf8e91045@baylibre.com> X-B4-Tracking: v=1; b=H4sIAHRncWkC/42PQQrCQAxFr1KyNtLU2qorQfAAbsXFdJpqoHXqz Dgo4t0N1QNIVj8//z/ygsBeOMAme4HnJEHcVUUxy8BezPXMKK1qKPJiSURrjG4Ui/04oOtwMCN KZG+i85gqpBWaisqyLouFaS1oy+i5k8dEOMJhv4OTLi8SNPGcqIkm629AItTp8rxetnVNZrFtz LOXxvPcugFO7y/U8+2u38QfuTGBUf1B4iZL1VxB3pJevz9Yh9CQAwEAAA== X-Change-ID: 20251119-topic-lpm-of-map-iterator-v6-18-a61447423adc To: Rob Herring , Krzysztof Kozlowski , devicetree@vger.kernel.org Cc: Ulf Hansson , linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-47773 X-Developer-Signature: v=1; a=openpgp-sha256; l=8833; i=khilman@baylibre.com; h=from:subject:message-id; bh=wqs3ot1lzYp1uxjm9+RCV8ylRHq0mF6h93+LA8PtmTw=; b=owEBbQKS/ZANAwAIAVk3GJrT+8ZlAcsmYgBpcWd1WL993O8PYDXTzo62Wq4RlUwG0W/MaQPWh eF9IsQAKHmJAjMEAAEIAB0WIQR7h0YOFpJ/qfW/8QxZNxia0/vGZQUCaXFndQAKCRBZNxia0/vG ZXicD/9NPuh6q7O6rUhTKer/d8KxiaMnleU+oRey6slWvjYWEV5yzUH1zc+Gho2G6bmwjz7vjMH OQvvJS/D4Fz3JGhdiOF0jaiSV6NmAq8WE2qqGHG7ar/rWgaOSUTl7YfUjkVyLtaVMO5Z6nlocTO jvQXEINNDxPvGtv6zX9heQ2h3E9Rk9Dnaxh2YIfntzvl/YApQzB5Jgts6N4FB+AI7W0Et7zDoSU W1k/I5wWJMk804zV27QNX2IhnNxZM0P9mW3DR24GVI4c+lpJ8lR3Oe5HncwjFWqWemdJnXhhq8Z Ck2WPFjm1AfrozOYp6U630WWR3RVeDCVUO9o8JqvjmNbL+BsALf85TBQBhBTBG4HZ/XgeqNVZaR NUmaz5UWmba2eco9kplFLd10gkGJhxfs7eTxP8JllHsnv+fssQV/LXK5JRXgy7BOrV4l1/qWaH7 X/Xmd/+GyLCszXKAGmA7vFWLdJsiRZFeXKM12iERrujgi9pmfsyw5aY+FlofXPe7Fq46Y280pJ8 g3BrAvqwJvnaE9lqgyTSAHKLAoFhvN5UgbSxhc6NoeidfLbO0WMmB/Jxw4oEru/XGSPSSx8A+5j s0FI974Yuhr28Lxp8RLfO0ez8NLnNoANEbvJnsAVm/450uvr2phJsunjHwp1ArmPjelJXb/CJIl kTUtz6pYUY3pfrg== X-Developer-Key: i=khilman@baylibre.com; a=openpgp; fpr=7B87460E16927FA9F5BFF10C5937189AD3FBC665 Add a new helper function of_parse_map_iter() to simplify parsing of nexus node maps as defined in the 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. Each map entry follows the format: The iterator extracts both the child specifier and parent phandle+args for each entry, managing all the details of: - Reading #-cells from both child and parent nodes - Calculating variable entry sizes - Resolving phandles - Proper node reference management This eliminates the need for subsystems to manually parse map properties, reducing code duplication and potential bugs. This code was developed in collaboration with Claude Code (model: Sonnet 4.5), which needed some guidance to use existing OF helpers, iterators etc. Signed-off-by: Kevin Hilman (TI) --- Changes in v2: - Use helpers of_phandle_iterator_init() and of_phandle_iterator_next() - add missing of_node_put() pointed out in v1 - Link to v1: https://patch.msgid.link/20251119-topic-lpm-of-map-iterator-v= 6-18-v1-1-1f0075d771a3@baylibre.com --- drivers/of/base.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++ include/linux/of.h | 13 +++++++++++++ 2 files changed, 176 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 0b65039ece53..8392fe54cf60 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1641,6 +1641,169 @@ 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) }; + struct of_phandle_iterator it; + const __be32 *map, *mask, *pass; + __be32 child_spec[MAX_PHANDLE_ARGS]; + u32 child_cells, parent_cells; + int i, entry_idx, ret; + + if (!np || !stem_name || !index || !parent_args) + return -EINVAL; + + if (!cells_name || !map_name || !mask_name || !pass_name) + return -ENOMEM; + + /* Initialize iterator to get the map property */ + ret =3D of_phandle_iterator_init(&it, np, map_name, cells_name, -1); + if (ret) + return ret; + + map =3D it.cur; + + /* 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 (it.cur + child_cells + 1 < it.list_end) { + /* 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 */ + it.cur +=3D child_cells; + + /* Use iterator to read phandle and get parent node/cells */ + it.phandle_end =3D it.cur; + ret =3D of_phandle_iterator_next(&it); + if (ret) { + if (it.node) + of_node_put(it.node); + return ret; + } + + parent_args->np =3D it.node; + it.node =3D NULL; /* Ownership transferred to parent_args */ + parent_cells =3D it.cur_count; + map =3D it.cur; + + /* Check for malformed properties */ + if (WARN_ON(parent_cells > MAX_PHANDLE_ARGS)) { + 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 */ + it.cur +=3D child_cells; + + /* Use iterator to read phandle and skip parent cells */ + it.phandle_end =3D it.cur; + ret =3D of_phandle_iterator_next(&it); + if (ret) { + if (it.node) + of_node_put(it.node); + return ret; + } + + /* Move forward to next entry and clean up node reference */ + it.cur =3D it.phandle_end; + map =3D it.cur; + of_node_put(it.node); + it.node =3D NULL; + + entry_idx++; + } + + /* Reached end of map without finding the requested index */ + if (it.node) + of_node_put(it.node); + 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 9bbdcf25a2b4..4908b78ac3e1 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -387,6 +387,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 @@ -797,6 +801,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: 3e7f562e20ee87a25e104ef4fce557d39d62fa85 change-id: 20251119-topic-lpm-of-map-iterator-v6-18-a61447423adc Best regards, -- =20 Kevin Hilman (TI)