mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-30 06:53:09 +00:00
fb8977c5be
Part of the env cleanup moved this out of the environment code and into the net code. However, this helper is sometimes needed even when the net stack isn't included. Move the helper to lib/net_utils.c like it's similarly-purposed string_to_ip(). Also rename the moved function to similar naming. Signed-off-by: Joe Hershberger <joe.hershberger@ni.com> Reported-by: Ondrej Jirman <megous@megous.com>
118 lines
4.8 KiB
Text
118 lines
4.8 KiB
Text
---------------------------------
|
|
Ethernet Address (MAC) Handling
|
|
---------------------------------
|
|
|
|
There are a variety of places in U-Boot where the MAC address is used, parsed,
|
|
and stored. This document covers proper usage of each location and the moving
|
|
of data between them.
|
|
|
|
-----------
|
|
Locations
|
|
-----------
|
|
|
|
Here are the places where MAC addresses might be stored:
|
|
|
|
- board-specific location (eeprom, dedicated flash, ...)
|
|
Note: only used when mandatory due to hardware design etc...
|
|
|
|
- environment ("ethaddr", "eth1addr", ...)
|
|
Note: this is the preferred way to permanently store MAC addresses
|
|
|
|
- ethernet data (struct eth_device -> enetaddr)
|
|
Note: these are temporary copies of the MAC address which exist only
|
|
after the respective init steps have run and only to make usage
|
|
in other places easier (to avoid constant env lookup/parsing)
|
|
|
|
- struct bd_info and/or device tree
|
|
Note: these are temporary copies of the MAC address only for the
|
|
purpose of passing this information to an OS kernel we are about
|
|
to boot
|
|
|
|
Correct flow of setting up the MAC address (summarized):
|
|
|
|
1. Read from hardware in initialize() function
|
|
2. Read from environment in net/eth.c after initialize()
|
|
3. The environment variable will be compared to the driver initialized
|
|
struct eth_device->enetaddr. If they differ, a warning is printed, and the
|
|
environment variable will be used unchanged.
|
|
If the environment variable is not set, it will be initialized from
|
|
eth_device->enetaddr, and a warning will be printed.
|
|
If both are invalid and CONFIG_NET_RANDOM_ETHADDR is defined, a random,
|
|
locally-assigned MAC is written to eth_device->enetaddr.
|
|
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)
|
|
|
|
Previous behavior had the MAC address always being programmed into hardware
|
|
in the device's init() function.
|
|
|
|
-------
|
|
Usage
|
|
-------
|
|
|
|
If the hardware design mandates that the MAC address is stored in some special
|
|
place (like EEPROM etc...), then the board specific init code (such as the
|
|
board-specific misc_init_r() function) is responsible for locating the MAC
|
|
address(es) and initializing the respective environment variable(s) from it.
|
|
Note that this shall be done if, and only if, the environment does not already
|
|
contain these environment variables, i.e. existing variable definitions must
|
|
not be overwritten.
|
|
|
|
During runtime, the ethernet layer will use the environment variables to sync
|
|
the MAC addresses to the ethernet structures. All ethernet driver code should
|
|
then only use the enetaddr member of the eth_device structure. This is done
|
|
on every network command, so the ethernet copies will stay in sync.
|
|
|
|
Any other code that wishes to access the MAC address should query the
|
|
environment directly. The helper functions documented below should make
|
|
working with this storage much smoother.
|
|
|
|
---------
|
|
Helpers
|
|
---------
|
|
|
|
To assist in the management of these layers, a few helper functions exist. You
|
|
should use these rather than attempt to do any kind of parsing/manipulation
|
|
yourself as many common errors have arisen in the past.
|
|
|
|
* void string_to_enetaddr(const char *addr, uchar *enetaddr);
|
|
|
|
Convert a string representation of a MAC address to the binary version.
|
|
char *addr = "00:11:22:33:44:55";
|
|
uchar enetaddr[6];
|
|
string_to_enetaddr(addr, enetaddr);
|
|
/* enetaddr now equals { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } */
|
|
|
|
* int eth_env_get_enetaddr(char *name, uchar *enetaddr);
|
|
|
|
Look up an environment variable and convert the stored address. If the address
|
|
is valid, then the function returns 1. Otherwise, the function returns 0. In
|
|
all cases, the enetaddr memory is initialized. If the env var is not found,
|
|
then it is set to all zeros. The common function is_valid_ethaddr() is used
|
|
to determine address validity.
|
|
uchar enetaddr[6];
|
|
if (!eth_env_get_enetaddr("ethaddr", enetaddr)) {
|
|
/* "ethaddr" is not set in the environment */
|
|
... try and setup "ethaddr" in the env ...
|
|
}
|
|
/* enetaddr is now set to the value stored in the ethaddr env var */
|
|
|
|
* int eth_env_set_enetaddr(char *name, const uchar *enetaddr);
|
|
|
|
Store the MAC address into the named environment variable. The return value is
|
|
the same as the env_set() function.
|
|
uchar enetaddr[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
|
|
eth_env_set_enetaddr("ethaddr", enetaddr);
|
|
/* the "ethaddr" env var should now be set to "00:11:22:33:44:55" */
|
|
|
|
* the %pM format modifier
|
|
|
|
The %pM format modifier can be used with any standard printf function to format
|
|
the binary 6 byte array representation of a MAC address.
|
|
uchar enetaddr[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
|
|
printf("The MAC is %pM\n", enetaddr);
|
|
|
|
char buf[20];
|
|
sprintf(buf, "%pM", enetaddr);
|
|
/* the buf variable is now set to "00:11:22:33:44:55" */
|