[U-Boot] [PATCH 09/14] net: Add ability to set MAC address via EEPROM

Olliver Schinagl oliver at schinagl.nl
Tue Nov 29 17:45:21 CET 2016


Hey Michal,


On 28-11-16 09:21, Michal Simek wrote:
> On 25.11.2016 16:30, Olliver Schinagl wrote:
>> This patch allows Kconfig to enable and set parameters to make it
>> possible to read the MAC address from an EEPROM. The net core layer then
>> uses this information to read MAC addresses from this EEPROM.
>>
>> Besides the various tuneables as to how to access the eeprom (bus,
>> address, addressing mode/length, 2 configurable that are EEPROM generic
>> (e.g. SPI or some other form of access) which are:
>>
>> NET_ETHADDR_EEPROM_OFFSET, indicating where in the EEPROM the start of
>> the MAC address is. The default is 8 allowing for 8 bytes before the MAC
>> for other purposes (header MAGIC for example).
>>
>> NET_ETHADDR_EEPROM_CRC8, indicating the MAC is appended with a CRC8-CCIT
>> checksum that should be verified.
>>
>> Currently only I2C eeproms have been tested and thus only those options
>> are available, but shouldn't be a limit. NET_ETHADDR_EEPROM_SPI can be
>> just as created and added.
>>
>> The code currently first checks if there is a non-zero MAC address in
>> the eeprom. If that fails to be the case, the read_rom_hwaddr can be
>> used by a board to supply the MAC in other ways.
>>
>> If both these fails, the other code is still in place to query the
>> environent, which then can be used to override the hardware supplied
>> data.
>>
>> Signed-off-by: Olliver Schinagl <oliver at schinagl.nl>
>> ---
>>   doc/README.enetaddr | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   include/net.h       | 14 ++++++++
>>   net/Kconfig         | 59 +++++++++++++++++++++++++++++++
>>   net/eth-uclass.c    |  9 +++--
>>   net/eth_common.c    | 34 ++++++++++++++++++
>>   net/eth_legacy.c    |  2 ++
>>   6 files changed, 214 insertions(+), 3 deletions(-)
>>
>> diff --git a/doc/README.enetaddr b/doc/README.enetaddr
>> index 50e4899..89c1f7d 100644
>> --- a/doc/README.enetaddr
>> +++ b/doc/README.enetaddr
>> @@ -47,6 +47,105 @@ Correct flow of setting up the MAC address (summarized):
>>   Previous behavior had the MAC address always being programmed into hardware
>>   in the device's init() function.
>>   
>> +--------
>> + EEPROM
>> +--------
>> +
>> +Boards may come with an EEPROM specifically to store configuration bits, such
>> +as a MAC address. Using CONFIG_NET_ETHADDR_EEPROM enables this feature.
>> +Depending on the board, the EEPROM may be connected on various methods, but
>> +currently, only the I2C bus can be used via CONFIG_NET_ETHADDR_EEPROM_I2C.
>> +
>> +The following config options are available,
>> +CONFIG_NET_ETHADDR_EEPROM_I2C_BUS is the I2C bus on which the eeprom is present.
>> +CONFIG_NET_ETHADDR_EEPROM_I2C_ADDR sets the address of the EEPROM, which
>> +defaults to the very common 0x50. Small size EEPROM's generally use single byte
>> +addressing but larger EEPROM's may use double byte addressing, which can be
>> +configured using CONFIG_NET_ETHADDR_EEPROM_ADDRLEN.
>> +
>> +Within the EEPROM, the MAC address can be stored on any arbitrary offset,
>> +CONFIG_NET_ETHADDR_EEPROM_OFFSET sets this to 8 as a default however, allowing
>> +the first 8 bytes to be used for an optional data, for example a configuration
>> +struct where the mac address is part of.
>> +
>> +Appending the 6 (ARP_HLEN) bytes is a CRC8 byte over the previous ARP_HLEN
>> +bytes. Whether to check this CRC8 or not is dependent on
>> +CONFIG_NET_ETHADDR_EEPROM_CRC8.
>> +
>> +To keep things nicely aligned, a final 'reserved' byte is added to the mac
>> +address + crc8 combo.
>> +
>> +A board may want to store more information in its eeprom, using the following
>> +example layout, this can be achieved.
>> +
>> +struct mac_addr {
>> +	uint8_t mac[ARP_HLEN];
>> +	uint8_t crc8;
>> +	uint8_t reserved;
>> +};
>> +
>> +struct config_eeprom {
>> +	uint32_t magic;
>> +	uint8_t version;
>> +	uint8_t reserved[2];
>> +	uint8_t mac_cnt;
>> +	struct mac_addr[mac_cnt];
>> +};
>> +
>> +Filling this in:
>> +struct config_eeprom eeprom = {
>> +	.magic = { 'M', 'g', 'i', 'c' },
>> +	.reserved = { 0x00, 0x00 },
>> +	.mac_cnt = 2,
>> +	.mac_addr = {
>> +		{
>> +			.mac = {
>> +				0x01, 0x23, 0x45,
>> +				0x67, 0x89, 0xab,
>> +			},
>> +			.crc8 = 0xbe,
>> +			.reserved = 0x00,
>> +		}, {
>> +			.mac = {
>> +				0xba, 0x98, 0x76,
>> +				0x54, 0x32, 0x10,
>> +			},
>> +			.crc8 = 0x82,
>> +			.reserved = 0x00,
>> +		},
>> +	},
>> +};
>> +
>> +The eeprom content would look like this.
>> +
>> +00000000  4d 67 69 63 01 00 00 02  01 23 45 67 89 ab be 00 |Mgic.....#Eg....|
>> +00000010  ba 98 76 54 32 10 82 00                          |..vT2...|
>> +
>> +This can be done from linux using the i2c-tools:
>> +
>> +i2cset I2CBUS 0x50 0x08 0x01
>> +i2cset I2CBUS 0x50 0x09 0x23
>> +i2cset I2CBUS 0x50 0x0a 0x45
>> +i2cset I2CBUS 0x50 0x0b 0x67
>> +i2cset I2CBUS 0x50 0x0c 0x89
>> +i2cset I2CBUS 0x50 0x0d 0xab
>> +i2cset I2CBUS 0x50 0x0e 0xbe
>> +
>> +Alternativly this can be done from the u-boot console as:
>> +
>> +u-boot> mm.b 0
>> +00000000: 00 ? 01
>> +00000001: 23 ? 23
>> +00000002: 45 ? 45
>> +00000003: 67 ? 67
>> +00000004: 89 ? 89
>> +00000005: ab ? ab
>> +00000006: be ? be
>> +00000007: 00 ? q
>> +i2c dev I2CBUS
>> +i2c write 0 50 8 7
>> +i2c md 50 8
>> +
>>   -------
>>    Usage
>>   -------
>> diff --git a/include/net.h b/include/net.h
>> index 08f8af8..e50ab5d 100644
>> --- a/include/net.h
>> +++ b/include/net.h
>> @@ -248,6 +248,20 @@ int eth_getenv_enetaddr(const char *name, uchar *enetaddr);
>>   int eth_setenv_enetaddr(const char *name, const uchar *enetaddr);
>>   
>>   /**
>> + * eeprom_read_enetaddr() - Read the hardware address from an eeprom
>> + *
>> + * This function tries to read the MAC address from an eeprom as can be read
>> + * in docs/README.enetaddr.
>> + *
>> + * @index:	index of the interface to get the hwaddr for
>> + * @enetaddr:	pointer for the found hwaddr. Needs to be atleast ARP_HLEN
>> + * @return:	0 on success, non-zero is error status. Additionally hwaddr
>> + *		is set to 00:00:00:00:00. This is also the case if
>> + *		CONFIG_NET_ETHADDR_EEPROM is not set.
>> + */
>> +int eeprom_read_enetaddr(const int index, unsigned char *enetaddr);
>> +
>> +/**
>>    * eth_setenv_enetaddr_by_index() - set the MAC address environment variable
>>    *
>>    * This sets up an environment variable with the given MAC address (@enetaddr).
>> diff --git a/net/Kconfig b/net/Kconfig
>> index 414c549..f699e1c 100644
>> --- a/net/Kconfig
>> +++ b/net/Kconfig
>> @@ -7,6 +7,65 @@ menuconfig NET
>>   
>>   if NET
>>   
>> +config NET_ETHADDR_EEPROM
>> +	bool "Get ethaddr from eeprom"
>> +	help
>> +	  Selecting this will try to get the Ethernet address from an onboard
>> +	  EEPROM and set into the environment if and only if the environment
>> +	  does currently not already hold a MAC address. For more information
>> +	  see doc/README.enetaddr.
>> +
>> +config NET_ETHADDR_EEPROM_I2C
>> +	depends on NET_ETHADDR_EEPROM
>> +	bool "EEPROM on I2C bus"
>> +	help
>> +	  This switch enables checks for an EEPROM on the I2C bus. Naturally
>> +	  this will only work if there is an actual EEPROM connected on the
>> +	  I2C bus and the bus and device are properly configured via the
>> +	  options below.
>> +
>> +config NET_ETHADDR_EEPROM_I2C_BUS
>> +	depends on NET_ETHADDR_EEPROM_I2C
>> +	int "I2C bus"
>> +	default 0
>> +	help
>> +	  Select the bus on which the EEPROM is present, defaults to bus 0.
>> +	  Remember to also make the selected bus available via I2Cn_ENABLE.
>> +
>> +config NET_ETHADDR_EEPROM_I2C_ADDR
>> +	depends on NET_ETHADDR_EEPROM_I2C
>> +	hex "EEPROM address"
>> +	default 0x50
>> +	help
>> +	  Select the address of the EEPROM, defaults to address 0x50.
>> +
>> +config NET_ETHADDR_EEPROM_I2C_ADDRLEN
>> +	depends on NET_ETHADDR_EEPROM_I2C
>> +	int "EEPROM address length"
>> +	default 1
>> +	help
>> +	  Number of bytes to be used for the I2C address length. Typically 1,
>> +	  2 for large memories, 0 for register type devices with only one
>> +	  register.
>> +
>> +config NET_ETHADDR_EEPROM_OFFSET
>> +	depends on NET_ETHADDR_EEPROM
>> +	int "EEPROM offset"
>> +	default 8
>> +	help
>> +	  Select the byte offset of the MAC address within the page,
>> +	  defaults to byte 8.
> I would prefer to all these values to be in hex because i2c commands are
> also taking values in hex.
You are completly right and this is indeed my mistake. I will fix it for v2.

Incidently I put them on 0x50 in my own config files for this exact 
reason. I probably did not realise I could make it default to hex :)
>
>> +
>> +config NET_ETHADDR_EEPROM_CRC8
>> +	depends on NET_ETHADDR_EEPROM
>> +	bool "Check CRC8 of MAC"
>> +	default y
>> +	help
>> +	  Optionally, it is possible to run a CRC-8-CCITT check on the MAC
>> +	  address. To do so, the MAC address is stored with a CRC8 byte append.
>> +	  This option enables the CRC check of the MAC address against the CRC
>> +	  byte.
>> +
> Would it be possible to have default n here?
> I would guess that more boards don't have this CRC8 sums.
I agree, but most boards will not use this by default yet. If you enable 
this feature for your board, I strongly strongly recommend enabeling 
this feature as well. Thus disable it by user request.

Reason why I strongly recommend to enable it: If i have an unprogrammed 
eeprom, it comes filled with 0xffffffff. Which is interpreted as a 
correct mac address. What if i have random garbage in the eeprom (or a 
user change one bit by accident). I still have a valid mac address. 
Using the crc8 to validate the mac address makes this a lot more safe.

Olliver
>
> Thanks,
> Michal
>
>
>



More information about the U-Boot mailing list