[PATCH 11/13] of: of_net: sync of_get_mac_address with Linux for NVMEM support

Ahmad Fatoum a.fatoum at pengutronix.de
Fri Jun 18 20:45:14 PDT 2021


We don't use of_get_mac_address anywhere, but it can come in handy as a
last resort before barebox generates a random MAC address. With the
existing implementation, that MAC address is written literally into the
DT, so it's mainly useful when barebox is booted with an external device
tree. The kernel implementation adds support for parsing the MAC address
out of a revered mac-address nvmem cell, which is much more prevalent.

Sync the implementation with Linux v5.13 in preparation for using it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/of/of_net.c | 78 +++++++++++++++++++++++++++++++++++++--------
 include/of_net.h    | 21 +++++++++++-
 2 files changed, 84 insertions(+), 15 deletions(-)

diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
index cee45971950b..67015160e230 100644
--- a/drivers/of/of_net.c
+++ b/drivers/of/of_net.c
@@ -9,6 +9,7 @@
 #include <net.h>
 #include <of_net.h>
 #include <linux/phy.h>
+#include <linux/nvmem-consumer.h>
 
 /**
  * It maps 'enum phy_interface_t' found in include/linux/phy.h
@@ -67,12 +68,55 @@ int of_get_phy_mode(struct device_node *np)
 }
 EXPORT_SYMBOL_GPL(of_get_phy_mode);
 
+static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr)
+{
+	struct property *pp = of_find_property(np, name, NULL);
+
+	if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value)) {
+		memcpy(addr, pp->value, ETH_ALEN);
+		return 0;
+	}
+	return -ENODEV;
+}
+
+int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr)
+{
+	struct nvmem_cell *cell;
+	const void *mac;
+	size_t len;
+
+	if (!IS_ENABLED(CONFIG_NVMEM))
+		return -ENODEV;
+
+	cell = of_nvmem_cell_get(np, "mac-address");
+	if (IS_ERR(cell))
+		return PTR_ERR(cell);
+
+	mac = nvmem_cell_read(cell, &len);
+	nvmem_cell_put(cell);
+
+	if (IS_ERR(mac))
+		return PTR_ERR(mac);
+
+	if (len != ETH_ALEN || !is_valid_ether_addr(mac)) {
+		kfree(mac);
+		return -EINVAL;
+	}
+
+	memcpy(addr, mac, ETH_ALEN);
+	kfree(mac);
+
+	return 0;
+}
+
 /**
  * Search the device tree for the best MAC address to use.  'mac-address' is
  * checked first, because that is supposed to contain to "most recent" MAC
  * address. If that isn't set, then 'local-mac-address' is checked next,
- * because that is the default address.  If that isn't set, then the obsolete
- * 'address' is checked, just in case we're using an old device tree.
+ * because that is the default address. If that isn't set, then the obsolete
+ * 'address' is checked, just in case we're using an old device tree. If any
+ * of the above isn't set, then try to get MAC address from nvmem cell named
+ * 'mac-address'.
  *
  * Note that the 'address' property is supposed to contain a virtual address of
  * the register set, but some DTS files have redefined that property to be the
@@ -85,18 +129,24 @@ EXPORT_SYMBOL_GPL(of_get_phy_mode);
  * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
  * but is all zeros.
 */
-const void *of_get_mac_address(struct device_node *np)
+int of_get_mac_address(struct device_node *np, u8 *addr)
 {
-	const void *p;
-	int len, i;
-	const char *str[] = { "mac-address", "local-mac-address", "address" };
-
-	for (i = 0; i < ARRAY_SIZE(str); i++) {
-		p = of_get_property(np, str[i], &len);
-		if (p && (len == 6) && is_valid_ether_addr(p))
-			return p;
-	}
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	ret = of_get_mac_addr(np, "mac-address", addr);
+	if (!ret)
+		return 0;
+
+	ret = of_get_mac_addr(np, "local-mac-address", addr);
+	if (!ret)
+		return 0;
+
+	ret = of_get_mac_addr(np, "address", addr);
+	if (!ret)
+		return 0;
 
-	return NULL;
+	return of_get_mac_addr_nvmem(np, addr);
 }
-EXPORT_SYMBOL(of_get_mac_address);
diff --git a/include/of_net.h b/include/of_net.h
index f37af58303a5..36f1058cbae8 100644
--- a/include/of_net.h
+++ b/include/of_net.h
@@ -6,8 +6,27 @@
 #ifndef __LINUX_OF_NET_H
 #define __LINUX_OF_NET_H
 
+#include <linux/types.h>
 #include <of.h>
+
+#ifdef CONFIG_OFDEVICE
+int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr);
+int of_get_mac_address(struct device_node *np, u8 *addr);
 int of_get_phy_mode(struct device_node *np);
-const void *of_get_mac_address(struct device_node *np);
+#else
+static inline int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr)
+{
+	return -ENOSYS;
+}
+static inline int of_get_mac_address(struct device_node *np, u8 *addr)
+{
+	return -ENOSYS;
+}
+
+static inline int of_get_phy_mode(struct device_node *np)
+{
+	return -ENOSYS;
+}
+#endif
 
 #endif /* __LINUX_OF_NET_H */
-- 
2.29.2




More information about the barebox mailing list