192 lines
4.9 KiB
Diff
192 lines
4.9 KiB
Diff
From c22bc82183c2dea64919f975473ec518738baa3e Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Wed, 12 Jul 2023 13:38:35 +0100
|
|
Subject: [PATCH] nvmem: add layout for Adtran devices
|
|
|
|
Adtran stores unique factory data on GPT partitions on the eMMC.
|
|
Using blk-nvmem the 'mfginfo' partition gets exposes as NVMEM provider.
|
|
|
|
Add layout driver to parse mfginfo, mainly to provide MAC addresses to
|
|
Ethernet and wireless interfaces.
|
|
|
|
Variable names are converted to lower-case and '_' is replaced with '-'
|
|
in order to comply with the device tree node naming convention.
|
|
The main MAC address always ends on a 0 and up to 16 addresses are
|
|
alocated for each device to use for various interfaces.
|
|
|
|
Implement post-processing function for 'MFG_MAC' variable ('mfg-mac'
|
|
node name in device tree) adding the nvmem cell index to the least
|
|
significant digit of the MAC address.
|
|
|
|
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|
---
|
|
drivers/nvmem/layouts/Kconfig | 9 +++
|
|
drivers/nvmem/layouts/Makefile | 1 +
|
|
drivers/nvmem/layouts/adtran.c | 135 +++++++++++++++++++++++++++++++++
|
|
3 files changed, 145 insertions(+)
|
|
create mode 100644 drivers/nvmem/layouts/adtran.c
|
|
|
|
--- a/drivers/nvmem/layouts/Kconfig
|
|
+++ b/drivers/nvmem/layouts/Kconfig
|
|
@@ -8,6 +8,15 @@ if NVMEM_LAYOUTS
|
|
|
|
menu "Layout Types"
|
|
|
|
+config NVMEM_LAYOUT_ADTRAN
|
|
+ tristate "Adtran mfginfo layout support"
|
|
+ select GENERIC_NET_UTILS
|
|
+ help
|
|
+ Say Y here if you want to support the layout used by Adtran for
|
|
+ mfginfo.
|
|
+
|
|
+ If unsure, say N.
|
|
+
|
|
config NVMEM_LAYOUT_SL28_VPD
|
|
tristate "Kontron sl28 VPD layout support"
|
|
select CRC8
|
|
--- a/drivers/nvmem/layouts/Makefile
|
|
+++ b/drivers/nvmem/layouts/Makefile
|
|
@@ -6,3 +6,4 @@
|
|
obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o
|
|
obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o
|
|
obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o
|
|
+obj-$(CONFIG_NVMEM_LAYOUT_ADTRAN) += adtran.o
|
|
--- /dev/null
|
|
+++ b/drivers/nvmem/layouts/adtran.c
|
|
@@ -0,0 +1,135 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+#include <linux/ctype.h>
|
|
+#include <linux/etherdevice.h>
|
|
+#include <linux/nvmem-consumer.h>
|
|
+#include <linux/nvmem-provider.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+/*
|
|
+ * Adtran devices usually come with a main MAC address ending on 0 and
|
|
+ * hence may have up to 16 MAC addresses per device.
|
|
+ * The main MAC address is stored as variable MFG_MAC in ASCII format.
|
|
+ */
|
|
+static int adtran_mac_address_pp(void *priv, const char *id, int index,
|
|
+ unsigned int offset, void *buf,
|
|
+ size_t bytes)
|
|
+{
|
|
+ u8 mac[ETH_ALEN];
|
|
+
|
|
+ if (WARN_ON(bytes != 3 * ETH_ALEN - 1))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!mac_pton(buf, mac))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (index)
|
|
+ eth_addr_add(mac, index);
|
|
+
|
|
+ ether_addr_copy(buf, mac);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int adtran_add_cells(struct nvmem_layout *layout)
|
|
+{
|
|
+ struct nvmem_device *nvmem = layout->nvmem;
|
|
+ struct nvmem_cell_info info;
|
|
+ struct device_node *layout_np;
|
|
+ char mfginfo[1024], *c, *t, *p;
|
|
+ int ret = -EINVAL;
|
|
+
|
|
+ ret = nvmem_device_read(nvmem, 0, sizeof(mfginfo), mfginfo);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ else if (ret != sizeof(mfginfo))
|
|
+ return -EIO;
|
|
+
|
|
+ layout_np = of_nvmem_layout_get_container(nvmem);
|
|
+ if (!layout_np)
|
|
+ return -ENOENT;
|
|
+
|
|
+ c = mfginfo;
|
|
+ while (*c != 0xff) {
|
|
+ memset(&info, 0, sizeof(info));
|
|
+ if (*c == '#')
|
|
+ goto nextline;
|
|
+
|
|
+ t = strchr(c, '=');
|
|
+ if (!t)
|
|
+ goto nextline;
|
|
+
|
|
+ *t = '\0';
|
|
+ ++t;
|
|
+ info.offset = t - mfginfo;
|
|
+ /* process variable name: convert to lower-case, '_' -> '-' */
|
|
+ p = c;
|
|
+ do {
|
|
+ *p = tolower(*p);
|
|
+ if (*p == '_')
|
|
+ *p = '-';
|
|
+ } while (*++p);
|
|
+ info.name = c;
|
|
+ c = strchr(t, 0xa); /* find newline */
|
|
+ if (!c)
|
|
+ break;
|
|
+
|
|
+ info.bytes = c - t;
|
|
+ if (!strcmp(info.name, "mfg-mac")) {
|
|
+ info.raw_len = info.bytes;
|
|
+ info.bytes = ETH_ALEN;
|
|
+ info.read_post_process = adtran_mac_address_pp;
|
|
+ }
|
|
+
|
|
+ info.np = of_get_child_by_name(layout_np, info.name);
|
|
+ ret = nvmem_add_one_cell(nvmem, &info);
|
|
+ if (ret)
|
|
+ break;
|
|
+
|
|
+ ++c;
|
|
+ continue;
|
|
+
|
|
+nextline:
|
|
+ c = strchr(c, 0xa); /* find newline */
|
|
+ if (!c)
|
|
+ break;
|
|
+ ++c;
|
|
+ }
|
|
+
|
|
+ of_node_put(layout_np);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int adtran_probe(struct nvmem_layout *layout)
|
|
+{
|
|
+ layout->add_cells = adtran_add_cells;
|
|
+
|
|
+ return nvmem_layout_register(layout);
|
|
+}
|
|
+
|
|
+static void adtran_remove(struct nvmem_layout *layout)
|
|
+{
|
|
+ nvmem_layout_unregister(layout);
|
|
+}
|
|
+
|
|
+static const struct of_device_id adtran_of_match_table[] = {
|
|
+ { .compatible = "adtran,mfginfo" },
|
|
+ {},
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, adtran_of_match_table);
|
|
+
|
|
+static struct nvmem_layout_driver adtran_layout = {
|
|
+ .driver = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .name = "adtran-layout",
|
|
+ .of_match_table = adtran_of_match_table,
|
|
+ },
|
|
+ .probe = adtran_probe,
|
|
+ .remove = adtran_remove,
|
|
+};
|
|
+module_nvmem_layout_driver(adtran_layout);
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
|
|
+MODULE_DESCRIPTION("NVMEM layout driver for Adtran mfginfo");
|