Add Barebox specific device tree provisions to allow specifying MAC addresses for network interfaces via device tree. Signed-off-by: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> --- .../bindings/barebox/barebox,mac-address-map.rst | 27 ++++ drivers/misc/Makefile | 1 + drivers/misc/mac-address-map.c | 142 +++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 Documentation/devicetree/bindings/barebox/barebox,mac-address-map.rst create mode 100644 drivers/misc/mac-address-map.c diff --git a/Documentation/devicetree/bindings/barebox/barebox,mac-address-map.rst b/Documentation/devicetree/bindings/barebox/barebox,mac-address-map.rst new file mode 100644 index 0000000..1ac3062 --- /dev/null +++ b/Documentation/devicetree/bindings/barebox/barebox,mac-address-map.rst @@ -0,0 +1,27 @@ +barebox MAC address map +======================= + +This driver allows to specify each network adapter's source of MAC address from the devicetree. + +Required properties: + +* ``compatible``: should be ``barebox,mac-address-map`` + +Besides ``compatible`` property the node is expected to contain a +number of children nodes each specifing a single "MAC source -> +interface" mapping. + +Child node's required properties: +* ``network-interface``: phandle corresponding to network interface +* ``mac-location``: a pair of phandle to 'cdev' containing MAC address + and offset withing that 'cdev' + +Example:: + + mac-address-map { + compatible = "barebox,mac-address-map"; + nic@0 { + network-interface = <&fec>; + mac-location = <&ocotp 0x88>; + }; + }; diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 487e4b8..94d2a4f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_JTAG) += jtag.o obj-$(CONFIG_SRAM) += sram.o obj-$(CONFIG_STATE_DRV) += state.o +obj-y += mac-address-map.o diff --git a/drivers/misc/mac-address-map.c b/drivers/misc/mac-address-map.c new file mode 100644 index 0000000..2161dc3 --- /dev/null +++ b/drivers/misc/mac-address-map.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2016 Zodiac Inflight Innovation + * Author: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <malloc.h> +#include <of.h> +#include <state.h> +#include <io.h> +#include <fcntl.h> +#include <net.h> + +#include <linux/err.h> + +/* + * a single MAC address reference has the form + * <&phandle regoffset> + */ +#define MAC_ADDRESS_PROPLEN (2 * sizeof(__be32)) +#define MAC_ADDRESS_SIZE 8 /* FIXME ocotp driver is broken and + * can't read non multiple of 4 + * quantities of data */ + +static int mac_address_map_read_cdev(struct device_d *dev, + struct cdev *cdev, + size_t offset, + uint8_t *addr) +{ + int ret; + + ret = cdev_do_open(cdev, O_RDONLY); + if (ret < 0) { + dev_err(dev, "Failed to open %s\n", cdev->name); + return ret; + } + + ret = cdev_read(cdev, addr, MAC_ADDRESS_SIZE, offset, 0); + cdev_close(cdev); + + if (ret != MAC_ADDRESS_SIZE) { + dev_err(dev, "Failed to read MAC address\n"); + return (ret < 0) ? ret : -EIO; + } + + return 0; +} + +static int mac_address_map_probe(struct device_d *dev) +{ + int ret; + struct device_node *np = dev->device_node; + struct device_node *child; + + if (!np || !of_get_next_child(np, NULL)) + return -EINVAL; + + for_each_child_of_node(np, child) { + uint8_t addr[MAC_ADDRESS_SIZE]; + + struct { + const __be32 *prop; + int plen; + uint32_t phandle; + size_t offset; + struct cdev *cdev; + struct device_node *node; + } nvm; + + struct device_node *nic_node; + + nvm.prop = of_get_property(child, "mac-location", &nvm.plen); + + if (!nvm.prop || nvm.plen != MAC_ADDRESS_PROPLEN) { + dev_err(dev, "'mac-location' lookup failed\n"); + return -EINVAL; + } + + nvm.phandle = be32_to_cpup(nvm.prop); + nvm.offset = be32_to_cpup(++nvm.prop); + + nvm.node = of_find_node_by_phandle(nvm.phandle); + if (!nvm.node) { + dev_err(dev, "'mac-location' lookup failed\n"); + return -EINVAL; + } + + nvm.cdev = cdev_by_device_node(nvm.node); + if (!nvm.cdev) { + dev_err(dev, "no OCOTP character device\n"); + return -ENODEV; + } + + nic_node = of_parse_phandle(child, "network-interface", 0); + if (!nic_node) { + dev_err(dev, "'network-interface' lookup failed\n"); + return -EINVAL; + } + + ret = mac_address_map_read_cdev(dev, + nvm.cdev, nvm.offset, + addr); + if (ret < 0) + return ret; + + if (is_valid_ether_addr(addr)) + of_eth_register_ethaddr(nic_node, addr); + else + dev_warn(dev, + "%s @ 0x%x does not contain a vaild MAC address\n", + nvm.node->name, nvm.offset); + } + + return 0; +} + +static __maybe_unused struct of_device_id mac_address_map_ids[] = { + { + .compatible = "barebox,mac-address-map", + }, { + /* sentinel */ + } +}; + +static struct driver_d mac_address_map_driver = { + .name = "mac-address-map", + .probe = mac_address_map_probe, + .of_compatible = DRV_OF_COMPAT(mac_address_map_ids), +}; +device_platform_driver(mac_address_map_driver); -- 2.5.0 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox