-From 995a6e0d3fdd1e4fb38465f224db8a4c7b1e279d Mon Sep 17 00:00:00 2001
+From fd0e523037439520813db7c57df5bd37cdf40f7e Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Mon, 3 Feb 2025 00:10:18 +0100
Subject: [PATCH 1/2] nvmem: core: generalize "mac-base" cells handling
Such helper will change the nvmem_info_cell and apply the correct post
process function to correctly parse the mac address.
+Since the API requires OF and is only related to layout, move the
+function in layouts.c to correctly handle non-OF NVMEM.
+
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
- drivers/nvmem/core.c | 41 +++++++++++++++++++---------------
- include/linux/nvmem-provider.h | 4 ++++
- 2 files changed, 27 insertions(+), 18 deletions(-)
+ drivers/nvmem/core.c | 79 +--------------------------------
+ drivers/nvmem/layouts.c | 80 ++++++++++++++++++++++++++++++++++
+ include/linux/nvmem-provider.h | 4 ++
+ 3 files changed, 86 insertions(+), 77 deletions(-)
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
-@@ -855,6 +855,27 @@ static int nvmem_mac_base_hex_read(void
+@@ -7,12 +7,9 @@
+ */
+
+ #include <linux/device.h>
+-#include <linux/ctype.h>
+-#include <linux/etherdevice.h>
+ #include <linux/export.h>
+ #include <linux/fs.h>
+ #include <linux/idr.h>
+-#include <linux/if_ether.h>
+ #include <linux/init.h>
+ #include <linux/kref.h>
+ #include <linux/module.h>
+@@ -799,62 +796,6 @@ static int nvmem_validate_keepouts(struc
return 0;
}
-+void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info)
-+{
-+ if (!of_device_is_compatible(info->np, "mac-base"))
-+ return;
-+
-+ if (info->bytes == ETH_ALEN) {
-+ info->raw_len = info->bytes;
-+ info->bytes = ETH_ALEN;
-+ info->read_post_process = nvmem_mac_base_raw_read;
-+ } else if (info->bytes == 2 * ETH_ALEN) {
-+ info->raw_len = info->bytes;
-+ info->bytes = ETH_ALEN;
-+ info->read_post_process = nvmem_mac_base_hex_read;
-+ } else if (info->bytes == 3 * ETH_ALEN - 1) {
-+ info->raw_len = info->bytes;
-+ info->bytes = ETH_ALEN;
-+ info->read_post_process = nvmem_mac_base_ascii_read;
-+ }
-+}
-+EXPORT_SYMBOL_GPL(nvmem_layout_parse_mac_base);
-+
+-static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset,
+- void *buf, size_t bytes)
+-{
+- if (WARN_ON(bytes != ETH_ALEN))
+- return -EINVAL;
+-
+- if (index)
+- eth_addr_add(buf, index);
+-
+- return 0;
+-}
+-
+-static int nvmem_mac_base_ascii_read(void *context, 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 nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset,
+- void *buf, size_t bytes)
+-{
+- u8 mac[ETH_ALEN], *hexstr;
+- int i;
+-
+- if (WARN_ON(bytes != 2 * ETH_ALEN))
+- return -EINVAL;
+-
+- hexstr = (u8 *)buf;
+- for (i = 0; i < ETH_ALEN; i++) {
+- if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1]))
+- return -EINVAL;
+-
+- mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]);
+- }
+-
+- if (index)
+- eth_addr_add(mac, index);
+-
+- ether_addr_copy(buf, mac);
+-
+- return 0;
+-}
+-
static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
{
struct device *dev = &nvmem->dev;
-@@ -894,24 +915,8 @@ static int nvmem_add_cells_from_dt(struc
+@@ -894,24 +835,8 @@ static int nvmem_add_cells_from_dt(struc
if (nvmem->fixup_dt_cell_info)
nvmem->fixup_dt_cell_info(nvmem, &info);
ret = nvmem_add_one_cell(nvmem, &info);
kfree(info.name);
+--- a/drivers/nvmem/layouts.c
++++ b/drivers/nvmem/layouts.c
+@@ -6,8 +6,11 @@
+ * Author: Miquel Raynal <miquel.raynal@bootlin.com
+ */
+
++#include <linux/ctype.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
++#include <linux/etherdevice.h>
++#include <linux/if_ether.h>
+ #include <linux/nvmem-consumer.h>
+ #include <linux/nvmem-provider.h>
+ #include <linux/of.h>
+@@ -21,6 +24,83 @@
+ #define to_nvmem_layout_device(_dev) \
+ container_of((_dev), struct nvmem_layout, dev)
+
++static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset,
++ void *buf, size_t bytes)
++{
++ if (WARN_ON(bytes != ETH_ALEN))
++ return -EINVAL;
++
++ if (index)
++ eth_addr_add(buf, index);
++
++ return 0;
++}
++
++static int nvmem_mac_base_ascii_read(void *context, 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 nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset,
++ void *buf, size_t bytes)
++{
++ u8 mac[ETH_ALEN], *hexstr;
++ int i;
++
++ if (WARN_ON(bytes != 2 * ETH_ALEN))
++ return -EINVAL;
++
++ hexstr = (u8 *)buf;
++ for (i = 0; i < ETH_ALEN; i++) {
++ if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1]))
++ return -EINVAL;
++
++ mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]);
++ }
++
++ if (index)
++ eth_addr_add(mac, index);
++
++ ether_addr_copy(buf, mac);
++
++ return 0;
++}
++
++void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info)
++{
++ if (!of_device_is_compatible(info->np, "mac-base"))
++ return;
++
++ if (info->bytes == ETH_ALEN) {
++ info->raw_len = info->bytes;
++ info->bytes = ETH_ALEN;
++ info->read_post_process = nvmem_mac_base_raw_read;
++ } else if (info->bytes == 2 * ETH_ALEN) {
++ info->raw_len = info->bytes;
++ info->bytes = ETH_ALEN;
++ info->read_post_process = nvmem_mac_base_hex_read;
++ } else if (info->bytes == 3 * ETH_ALEN - 1) {
++ info->raw_len = info->bytes;
++ info->bytes = ETH_ALEN;
++ info->read_post_process = nvmem_mac_base_ascii_read;
++ }
++}
++EXPORT_SYMBOL_GPL(nvmem_layout_parse_mac_base);
++
+ static int nvmem_layout_bus_match(struct device *dev, struct device_driver *drv)
+ {
+ return of_driver_match_device(dev, drv);
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -242,6 +242,8 @@ static inline void nvmem_layout_unregist
#else /* CONFIG_NVMEM && CONFIG_OF */
-+static inline void nvmem_layout_parse_mac_base(void) {}
++static inline void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) {}
+
static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
{
---
drivers/nvmem/layouts/Kconfig | 13 +++
drivers/nvmem/layouts/Makefile | 1 +
- drivers/nvmem/layouts/ascii-env.c | 131 ++++++++++++++++++++++++++++++
- 3 files changed, 145 insertions(+)
+ drivers/nvmem/layouts/ascii-env.c | 140 ++++++++++++++++++++++++++++++
+ 3 files changed, 154 insertions(+)
create mode 100644 drivers/nvmem/layouts/ascii-env.c
--- a/drivers/nvmem/layouts/Kconfig
+obj-$(CONFIG_NVMEM_LAYOUT_ASCII_ENV) += ascii-env.o
--- /dev/null
+++ b/drivers/nvmem/layouts/ascii-env.c
-@@ -0,0 +1,131 @@
+@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 Christian Marangi <ansuelsmth@gmail.com>
+#include <linux/of.h>
+#include <linux/slab.h>
+
++struct ascii_env_match_data {
++ const char delim;
++};
++
+/*
+ * Parse a buffer as an ASCII text with name delimiter value and each pattern separated
+ * with a new line char '\n'
+ */
+ for (var = data; var < data + data_len && *var;
+ var = value + strlen(value) + 1) {
-+ struct nvmem_cell_info info = {};
++ struct nvmem_cell_info info = {};
++ struct device_node *child;
++ const char *label;
+
+ eq = strchr(var, delim);
+ if (!eq)
+ info.offset = value - data;
+ info.bytes = strlen(value);
+ info.np = of_get_child_by_name(dev->of_node, info.name);
++ for_each_child_of_node(dev->of_node, child) {
++ if (!of_property_read_string(child, "label", &label) &&
++ !strncmp(info.name, label, info.bytes))
++ info.np = child;
++ else if (of_node_name_eq(child, info.name))
++ info.np = child;
++ }
+
+ nvmem_layout_parse_mac_base(&info);
+
+static int ascii_env_add_cells(struct nvmem_layout *layout)
+{
+ struct nvmem_device *nvmem = layout->nvmem;
++ const struct ascii_env_match_data *data;
+ struct device *dev = &layout->dev;
+ size_t dev_size;
+ uint8_t *buf;
-+ char delim;
+ int bytes;
+ int ret;
+
+ /* Get the delimiter for name value pattern */
-+ delim = device_get_match_data(dev);
++ data = device_get_match_data(dev);
+
+ dev_size = nvmem_dev_size(nvmem);
+
+ }
+
+ buf[dev_size - 1] = '\0';
-+ ret = ascii_env_parse_cells(dev, nvmem, buf, dev_size, delim);
++ ret = ascii_env_parse_cells(dev, nvmem, buf, dev_size, data->delim);
+
+err_kfree:
+ kfree(buf);
+ nvmem_layout_unregister(layout);
+}
+
++static const struct ascii_env_match_data ascii_env_eq = {
++ .delim = '=',
++};
++
+static const struct of_device_id ascii_env_of_match_table[] = {
-+ { .compatible = "ascii-eq-delim-env", .data = (void *)'=', },
++ { .compatible = "ascii-eq-delim-env", .data = &ascii_env_eq, },
+ {},
+};
+