From f7d3f7790b75b098e1c92530dc3d28ba3b40b5a4 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Sat, 10 Aug 2013 12:48:51 +0200 Subject: [PATCH 28/29] of: add support for parsing mac addresses from mtd Signed-off-by: Jonas Gorski --- drivers/of/of_net.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) --- a/drivers/of/of_net.c +++ b/drivers/of/of_net.c @@ -10,6 +10,7 @@ #include #include #include +#include /** * It maps 'enum phy_interface_t' found in include/linux/phy.h @@ -55,6 +56,103 @@ const int of_get_phy_mode(struct device_ } EXPORT_SYMBOL_GPL(of_get_phy_mode); +static const void *of_get_mac_address_mtd(struct device_node *np) +{ + const __be32 *list; + int size, ret; + size_t ret_len; + phandle phandle; + struct device_node *part_node; + struct mtd_info *mtd; + const char *part; + u8 mac[ETH_ALEN]; + u64 offset; + bool parse_mac = false; + + if (!IS_ENABLED(CONFIG_MTD)) + return NULL; + + list = of_get_property(np, "mtd-mac-address", &size); + + if (!list) { + list = of_get_property(np, "mtd-mac-address-string", &size); + parse_mac = true; + } + + if (!list) + return NULL; + + if (size != sizeof(*list) * 2) + return NULL; + + phandle = be32_to_cpup(list++); + if (!phandle) + return NULL; + + part_node = of_find_node_by_phandle(phandle); + if (!part_node) + return NULL; + + offset = be32_to_cpup(list++); + + part = of_get_property(part_node, "label", NULL); + if (!part) + part = part_node->name; + + mtd = get_mtd_device_nm(part); + + of_node_put(part_node); + + if (IS_ERR(mtd)) + return NULL; + + if (parse_mac) { + u8 mac_str[18]; + + ret = mtd_read(mtd, offset, 18, &ret_len, (u_char *)&mac_str); + if (!ret && ret_len != 18) + ret = -EIO; + + if (!ret) + ret_len = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + mac, mac + 1, mac + 2, mac + 3, + mac + 4, mac + 5); + + } else { + ret = mtd_read(mtd, offset, ETH_ALEN, &ret_len, (u_char *)&mac); + } + + put_mtd_device(mtd); + + if (!ret && ret_len == ETH_ALEN && is_valid_ether_addr(mac)) { + struct property *pp = kzalloc(sizeof(*pp), GFP_KERNEL); + + if (!pp) + return NULL; + + pp->name = kstrdup("mac-address", GFP_KERNEL); + pp->value = kzalloc(ETH_ALEN, GFP_KERNEL); + + if (!pp->name || !pp->value) { + kfree(pp->name); + kfree(pp); + return NULL; + } + + memcpy(pp->value, mac, ETH_ALEN); + pp->length = ETH_ALEN; + + if (of_find_property(np, "mac-address", NULL)) + of_update_property(np, pp); + else + of_add_property(np, pp); + + return pp->value; + } + + return NULL; +} + /** * 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 @@ -89,6 +187,6 @@ const void *of_get_mac_address(struct de if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) return pp->value; - return NULL; + return of_get_mac_address_mtd(np); } EXPORT_SYMBOL(of_get_mac_address);