[RFC 1/2] misc: Add MAC address mapper "driver"
Andrey Smirnov
andrew.smirnov at gmail.com
Sun Jan 31 21:57:13 PST 2016
Add Barebox specific device tree provisions to allow specifying MAC
addresses for network interfaces via device tree.
Signed-off-by: Andrey Smirnov <andrew.smirnov at gmail.com>
---
.../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 at 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 at gmail.com>
+ *
+ * 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
More information about the barebox
mailing list