Program net device MAC addresses after initializing
Add a new function to the eth_device struct for programming a network
controller's hardware address.
After all network devices have been initialized and the proper MAC address
for each has been determined, make a device driver call to program the
address into the device. Only device instances with valid unicast addresses
will be programmed.
Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
Acked-by: Detlev Zundel <dzu@denx.de>
Tested-by: Prafulla Wadaskar <prafulla@marvell.com>
Tested-by: Heiko Schocher <hs@denx.de>
Tested-by: Thomas Chou <thomas@wytron.com.tw>
diff --git a/README b/README
index cdd81d4..81692c0 100644
--- a/README
+++ b/README
@@ -3303,6 +3303,11 @@
o If neither SROM nor the environment contain a MAC address, an error
is raised.
+If Ethernet drivers implement the 'write_hwaddr' function, valid MAC addresses
+will be programmed into hardware as part of the initialization process. This
+may be skipped by setting the appropriate 'ethmacskip' environment variable.
+The naming convention is as follows:
+"ethmacskip" (=>eth0), "eth1macskip" (=>eth1) etc.
Image Formats:
==============
diff --git a/doc/README.drivers.eth b/doc/README.drivers.eth
index d0c3571..eb83038 100644
--- a/doc/README.drivers.eth
+++ b/doc/README.drivers.eth
@@ -70,6 +70,7 @@
dev->halt = ape_halt;
dev->send = ape_send;
dev->recv = ape_recv;
+ dev->write_hwaddr = ape_write_hwaddr;
eth_register(dev);
@@ -102,11 +103,12 @@
-----------
Now that we've registered with the ethernet layer, we can start getting some
-real work done. You will need four functions:
+real work done. You will need five functions:
int ape_init(struct eth_device *dev, bd_t *bis);
int ape_send(struct eth_device *dev, volatile void *packet, int length);
int ape_recv(struct eth_device *dev);
int ape_halt(struct eth_device *dev);
+ int ape_write_hwaddr(struct eth_device *dev);
The init function checks the hardware (probing/identifying) and gets it ready
for send/recv operations. You often do things here such as resetting the MAC
@@ -150,6 +152,9 @@
its reset state. It can be called at any time (before any call to the related
init function), so make sure it can handle this sort of thing.
+The write_hwaddr function should program the MAC address stored in dev->enetaddr
+into the Ethernet controller.
+
So the call graph at this stage would look something like:
some net operation (ping / tftp / whatever...)
eth_init()
diff --git a/doc/README.enetaddr b/doc/README.enetaddr
index 94d800a..2d8e24f 100644
--- a/doc/README.enetaddr
+++ b/doc/README.enetaddr
@@ -33,11 +33,13 @@
1. Read from hardware in initialize() function
2. Read from environment in net/eth.c after initialize()
3. Give priority to the value in the environment if a conflict
-4. Program hardware in the device's init() function.
+4. Program the address into hardware if the following conditions are met:
+ a) The relevant driver has a 'write_addr' function
+ b) The user hasn't set an 'ethmacskip' environment variable
+ c) The address is valid (unicast, not all-zeros)
-If somebody wants to subvert the design philosophy, this can be done
-in the board-specific board_eth_init() function by calling eth_init()
-after all the NICs have been registered.
+Previous behavior had the MAC address always being programmed into hardware
+in the device's init() function.
-------
Usage
diff --git a/include/net.h b/include/net.h
index 3f6a5d1..a180881 100644
--- a/include/net.h
+++ b/include/net.h
@@ -105,6 +105,7 @@
#ifdef CONFIG_MCAST_TFTP
int (*mcast) (struct eth_device*, u32 ip, u8 set);
#endif
+ int (*write_hwaddr) (struct eth_device*);
struct eth_device *next;
void *priv;
};
diff --git a/net/eth.c b/net/eth.c
index aff6987..45e4a26 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -60,6 +60,14 @@
return eth_getenv_enetaddr(enetvar, enetaddr);
}
+static int eth_mac_skip(int index)
+{
+ char enetvar[15];
+ char *skip_state;
+ sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
+ return ((skip_state = getenv(enetvar)) != NULL);
+}
+
#ifdef CONFIG_NET_MULTI
/*
@@ -242,6 +250,11 @@
memcpy(dev->enetaddr, env_enetaddr, 6);
}
+ if (dev->write_hwaddr &&
+ !eth_mac_skip(eth_number) &&
+ is_valid_ether_addr(dev->enetaddr)) {
+ dev->write_hwaddr(dev);
+ }
eth_number++;
dev = dev->next;