From: Navid Ghahremani <ghahramani.navid@gmail.com>
To: srini@kernel.org, mathieu.dubois-briand@bootlin.com
Cc: linux-kernel@vger.kernel.org, rafal@milecki.pl,
Navid Ghahremani <ghahramani.navid@gmail.com>
Subject: [PATCH] nvmem: layouts: fixed-layout: Apply mac-base consumer offsets
Date: Sat, 10 Oct 2026 13:59:47 +0100 [thread overview]
Message-ID: <20261010125947.176459-1-ghahramani.navid@gmail.com> (raw)
The fixed-cell binding describes mac-base cells whose consumer argument
is an offset from a stored base address. The fixed-layout driver currently
registers these as ordinary cells, so all consumers receive the unchanged
base address. On the ZTE ZXHN H3600 this gives LAN and WAN the same MAC.
Allow the DT cell parser to call a layout-specific fixup and use it to
attach a read postprocessor for mac-base cells. Support the binding's
six-byte binary and 17-byte colon-separated ASCII formats. Keep the raw
read length while returning a six-byte address, and reject unsupported
sizes and bit-field MAC cells. Legacy cells retain their existing path.
This follows the mac-base support introduced in OpenWrt by Rafal Milecki,
but keeps the postprocessor in the fixed-layout driver introduced in
mainline since then. The ASCII parser receives a terminated local copy.
Link: https://git.openwrt.org/61f674df4f0ce2b1c53b0b7f6b0c1d03d99838c0
Cc: Rafal Milecki <rafal@milecki.pl>
Assisted-by: LLM
Signed-off-by: Navid Ghahremani <ghahramani.navid@gmail.com>
---
drivers/nvmem/core.c | 14 +++++++--
drivers/nvmem/internals.h | 3 +-
drivers/nvmem/layouts/Kconfig | 1 +
drivers/nvmem/layouts/fixed-layout.c | 45 +++++++++++++++++++++++++++-
include/linux/nvmem-provider.h | 3 +-
5 files changed, 61 insertions(+), 5 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 0556d14017..5de82ccdb1 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -789,7 +789,8 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
return 0;
}
-int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
+int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np,
+ int (*fixup)(struct nvmem_cell_info *info))
{
struct device *dev = &nvmem->dev;
const __be32 *addr;
@@ -827,6 +828,15 @@ int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
if (nvmem->fixup_dt_cell_info)
nvmem->fixup_dt_cell_info(nvmem, &info);
+ if (fixup) {
+ ret = fixup(&info);
+ if (ret) {
+ kfree(info.name);
+ of_node_put(info.np);
+ return ret;
+ }
+ }
+
ret = nvmem_add_one_cell(nvmem, &info);
kfree(info.name);
if (ret) {
@@ -841,7 +851,7 @@ EXPORT_SYMBOL_GPL(nvmem_add_cells_from_dt);
static int nvmem_add_cells_from_legacy_of(struct nvmem_device *nvmem)
{
- return nvmem_add_cells_from_dt(nvmem, nvmem->dev.of_node);
+ return nvmem_add_cells_from_dt(nvmem, nvmem->dev.of_node, NULL);
}
int nvmem_layout_register(struct nvmem_layout *layout)
diff --git a/drivers/nvmem/internals.h b/drivers/nvmem/internals.h
index 4e610deeaa..060d41363e 100644
--- a/drivers/nvmem/internals.h
+++ b/drivers/nvmem/internals.h
@@ -39,7 +39,8 @@ struct nvmem_device {
bool sysfs_cells_populated;
};
-int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np);
+int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np,
+ int (*fixup)(struct nvmem_cell_info *info));
#if IS_ENABLED(CONFIG_OF)
int nvmem_layout_bus_register(void);
diff --git a/drivers/nvmem/layouts/Kconfig b/drivers/nvmem/layouts/Kconfig
index 5e586dfebe..66fc5d9e1f 100644
--- a/drivers/nvmem/layouts/Kconfig
+++ b/drivers/nvmem/layouts/Kconfig
@@ -3,6 +3,7 @@
config NVMEM_LAYOUTS
bool
depends on OF
+ select GENERIC_NET_UTILS
if NVMEM_LAYOUTS
diff --git a/drivers/nvmem/layouts/fixed-layout.c b/drivers/nvmem/layouts/fixed-layout.c
index 635d448b3d..33961f23aa 100644
--- a/drivers/nvmem/layouts/fixed-layout.c
+++ b/drivers/nvmem/layouts/fixed-layout.c
@@ -5,11 +5,54 @@
* Authors: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
*/
+#include <linux/etherdevice.h>
+#include <linux/hex.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
#include "../internals.h"
+/* Return the base address plus the offset supplied by the consumer. */
+static int fixed_layout_read_mac_base(void *priv, const char *id, int index,
+ unsigned int offset, void *buf, size_t bytes)
+{
+ u8 mac[ETH_ALEN];
+ char ascii[3 * ETH_ALEN];
+
+ if (bytes == ETH_ALEN) {
+ ether_addr_copy(mac, buf);
+ } else if (bytes == sizeof(ascii) - 1) {
+ memcpy(ascii, buf, bytes);
+ ascii[bytes] = '\0';
+ if (!mac_pton(ascii, mac))
+ return -EINVAL;
+ } else {
+ return -EINVAL;
+ }
+
+ eth_addr_add(mac, index);
+ ether_addr_copy(buf, mac);
+
+ return 0;
+}
+
+static int fixed_layout_fixup_cell(struct nvmem_cell_info *info)
+{
+ if (!of_device_is_compatible(info->np, "mac-base"))
+ return 0;
+
+ /* The binding permits binary or colon-separated ASCII MAC addresses. */
+ if ((info->bytes != ETH_ALEN && info->bytes != 3 * ETH_ALEN - 1) ||
+ info->nbits)
+ return -EINVAL;
+
+ info->raw_len = info->bytes;
+ info->bytes = ETH_ALEN;
+ info->read_post_process = fixed_layout_read_mac_base;
+
+ return 0;
+}
+
static int fixed_layout_add_cells(struct nvmem_layout *layout)
{
struct device_node *np;
@@ -19,7 +62,7 @@ static int fixed_layout_add_cells(struct nvmem_layout *layout)
if (!np)
return -ENOENT;
- ret = nvmem_add_cells_from_dt(layout->nvmem, np);
+ ret = nvmem_add_cells_from_dt(layout->nvmem, np, fixed_layout_fixup_cell);
of_node_put(np);
return ret;
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 6063fe5b77..1e31101201 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -215,7 +215,8 @@ static inline int nvmem_layout_register(struct nvmem_layout *layout)
static inline void nvmem_layout_unregister(struct nvmem_layout *layout) {}
static inline int nvmem_add_cells_from_dt(struct nvmem_device *nvmem,
- struct device_node *np)
+ struct device_node *np,
+ int (*fixup)(struct nvmem_cell_info *info))
{
return -EOPNOTSUPP;
}
--
2.55.0
reply other threads:[~2026-10-10 12:59 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261010125947.176459-1-ghahramani.navid@gmail.com \
--to=ghahramani.navid@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mathieu.dubois-briand@bootlin.com \
--cc=rafal@milecki.pl \
--cc=srini@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®