eth_nxp_enet_qos_mac: implement the nxp,unique-mac address feature

This implements to generate the MAC address of the device UUID.
The UUID is hashed to reduce the size to 3 bytes.
Ideas taken from eth_nxp_enet.c
Adding dependencies on: HWInfo and CRC

Signed-off-by: Adib Taraben <theadib@gmail.com>
This commit is contained in:
Adib Taraben 2025-01-04 00:58:53 +01:00 committed by Henrik Brix Andersen
parent cf91c1b84f
commit cce082626e
4 changed files with 111 additions and 44 deletions

View file

@ -23,6 +23,17 @@ config ETH_NXP_ENET_QOS_MAC
if ETH_NXP_ENET_QOS_MAC if ETH_NXP_ENET_QOS_MAC
DT_PROP_NXP_ENET_QOS_MAC_UNIQUE_MAC := nxp,unique-mac
config ETH_NXP_ENET_QOS_MAC_UNIQUE_MAC_ADDRESS
bool "Unique MAC address support"
default y if $(dt_compat_any_has_prop,$(DT_COMPAT_NXP_ENET_QOS_MAC),$(DT_PROP_NXP_ENET_QOS_MAC_UNIQUE_MAC),True)
select HWINFO
select CRC
help
Enable Unique MAC address support based on device UUID.
config ETH_NXP_ENET_QOS_TX_BUFFER_DESCRIPTORS config ETH_NXP_ENET_QOS_TX_BUFFER_DESCRIPTORS
int "Number of tx buffer descriptors" int "Number of tx buffer descriptors"
default 4 default 4

View file

@ -12,6 +12,10 @@ LOG_MODULE_REGISTER(eth_nxp_enet_qos_mac, CONFIG_ETHERNET_LOG_LEVEL);
#include <zephyr/net/phy.h> #include <zephyr/net/phy.h>
#include <zephyr/kernel/thread_stack.h> #include <zephyr/kernel/thread_stack.h>
#include <zephyr/sys_clock.h> #include <zephyr/sys_clock.h>
#if defined(CONFIG_ETH_NXP_ENET_QOS_MAC_UNIQUE_MAC_ADDRESS)
#include <zephyr/sys/crc.h>
#include <zephyr/drivers/hwinfo.h>
#endif
#include <ethernet/eth_stats.h> #include <ethernet/eth_stats.h>
#include "../eth.h" #include "../eth.h"
#include "nxp_enet_qos_priv.h" #include "nxp_enet_qos_priv.h"
@ -480,6 +484,33 @@ static inline int enet_qos_rx_desc_init(enet_qos_t *base, struct nxp_enet_qos_rx
return 0; return 0;
} }
#if defined(CONFIG_ETH_NXP_ENET_QOS_MAC_UNIQUE_MAC_ADDRESS)
/* Note this is not universally unique, it just is probably unique on a network */
static inline void nxp_enet_unique_mac(uint8_t *mac_addr)
{
uint8_t unique_device_ID_16_bytes[16] = {0};
ssize_t uuid_length =
hwinfo_get_device_id(unique_device_ID_16_bytes, sizeof(unique_device_ID_16_bytes));
uint32_t hash = 0;
if (uuid_length > 0) {
hash = crc24_pgp((uint8_t *)unique_device_ID_16_bytes, uuid_length);
} else {
LOG_ERR("No unique MAC can be provided in this platform");
}
/* Setting LAA bit because it is not guaranteed universally unique */
mac_addr[0] = NXP_OUI_BYTE_0 | 0x02;
mac_addr[1] = NXP_OUI_BYTE_1;
mac_addr[2] = NXP_OUI_BYTE_2;
mac_addr[3] = FIELD_GET(0xFF0000, hash);
mac_addr[4] = FIELD_GET(0x00FF00, hash);
mac_addr[5] = FIELD_GET(0x0000FF, hash);
}
#else
#define nxp_enet_unique_mac(arg)
#endif
static int eth_nxp_enet_qos_mac_init(const struct device *dev) static int eth_nxp_enet_qos_mac_init(const struct device *dev)
{ {
const struct nxp_enet_qos_mac_config *config = dev->config; const struct nxp_enet_qos_mac_config *config = dev->config;
@ -501,8 +532,11 @@ static int eth_nxp_enet_qos_mac_init(const struct device *dev)
return ret; return ret;
} }
/* Random mac therefore overrides local mac that may have been initialized */ if (config->mac_addr_source == NXP_ENET_QOS_MAC_ADDR_SOURCE_LOCAL) {
if (config->random_mac) { /* Use the mac address provided in the devicetree */
} else if (config->mac_addr_source == NXP_ENET_QOS_MAC_ADDR_SOURCE_UNIQUE) {
nxp_enet_unique_mac(data->mac_addr.addr);
} else {
gen_random_mac(data->mac_addr.addr, gen_random_mac(data->mac_addr.addr,
NXP_OUI_BYTE_0, NXP_OUI_BYTE_1, NXP_OUI_BYTE_2); NXP_OUI_BYTE_0, NXP_OUI_BYTE_1, NXP_OUI_BYTE_2);
} }
@ -626,56 +660,59 @@ static const struct ethernet_api api_funcs = {
.set_config = eth_nxp_enet_qos_set_config, .set_config = eth_nxp_enet_qos_set_config,
}; };
#define NXP_ENET_QOS_NODE_HAS_MAC_ADDR_CHECK(n) \ #define NXP_ENET_QOS_NODE_HAS_MAC_ADDR_CHECK(n) \
BUILD_ASSERT(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)) || \ BUILD_ASSERT(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)) || \
DT_INST_PROP(n, zephyr_random_mac_address), \ DT_INST_PROP(n, zephyr_random_mac_address) || \
"MAC address not specified on ENET QOS DT node"); DT_INST_PROP(n, nxp_unique_mac), \
"MAC address not specified on ENET QOS DT node");
#define NXP_ENET_QOS_CONNECT_IRQS(node_id, prop, idx) \ #define NXP_ENET_QOS_MAC_ADDR_SOURCE(n) \
do { \ COND_CODE_1(DT_NODE_HAS_PROP(DT_DRV_INST(n), local_mac_address), \
IRQ_CONNECT(DT_IRQN_BY_IDX(node_id, idx), \ (NXP_ENET_QOS_MAC_ADDR_SOURCE_LOCAL), \
DT_IRQ_BY_IDX(node_id, idx, priority), \ (COND_CODE_1(DT_INST_PROP(n, zephyr_random_mac_address), \
eth_nxp_enet_qos_mac_isr, \ (NXP_ENET_QOS_MAC_ADDR_SOURCE_RANDOM), \
DEVICE_DT_GET(node_id), \ (COND_CODE_1(DT_INST_PROP(n, nxp_unique_mac), \
0); \ (NXP_ENET_QOS_MAC_ADDR_SOURCE_UNIQUE), \
irq_enable(DT_IRQN_BY_IDX(node_id, idx)); \ (NXP_ENET_QOS_MAC_ADDR_SOURCE_INVALID))))))
#define NXP_ENET_QOS_CONNECT_IRQS(node_id, prop, idx) \
do { \
IRQ_CONNECT(DT_IRQN_BY_IDX(node_id, idx), DT_IRQ_BY_IDX(node_id, idx, priority), \
eth_nxp_enet_qos_mac_isr, DEVICE_DT_GET(node_id), 0); \
irq_enable(DT_IRQN_BY_IDX(node_id, idx)); \
} while (false); } while (false);
#define NXP_ENET_QOS_IRQ_CONFIG_FUNC(n) \ #define NXP_ENET_QOS_IRQ_CONFIG_FUNC(n) \
static void nxp_enet_qos_##n##_irq_config_func(void) \ static void nxp_enet_qos_##n##_irq_config_func(void) \
{ \ { \
DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), \ DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), interrupt_names, NXP_ENET_QOS_CONNECT_IRQS) \
interrupt_names, \
NXP_ENET_QOS_CONNECT_IRQS) \
} }
#define NXP_ENET_QOS_DRIVER_STRUCTS_INIT(n) \
#define NXP_ENET_QOS_DRIVER_STRUCTS_INIT(n) \ static const struct nxp_enet_qos_mac_config enet_qos_##n##_mac_config = { \
static const struct nxp_enet_qos_mac_config enet_qos_##n##_mac_config = { \ .enet_dev = DEVICE_DT_GET(DT_INST_PARENT(n)), \
.enet_dev = DEVICE_DT_GET(DT_INST_PARENT(n)), \ .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \
.phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \ .base = (enet_qos_t *)DT_REG_ADDR(DT_INST_PARENT(n)), \
.base = (enet_qos_t *)DT_REG_ADDR(DT_INST_PARENT(n)), \ .hw_info = \
.hw_info = { \ { \
.max_frame_len = ENET_QOS_MAX_NORMAL_FRAME_LEN, \ .max_frame_len = ENET_QOS_MAX_NORMAL_FRAME_LEN, \
}, \ }, \
.irq_config_func = nxp_enet_qos_##n##_irq_config_func, \ .irq_config_func = nxp_enet_qos_##n##_irq_config_func, \
.random_mac = DT_INST_PROP(n, zephyr_random_mac_address), \ .mac_addr_source = NXP_ENET_QOS_MAC_ADDR_SOURCE(n), \
}; \ }; \
\ static struct nxp_enet_qos_mac_data enet_qos_##n##_mac_data = { \
static struct nxp_enet_qos_mac_data enet_qos_##n##_mac_data = \ .mac_addr.addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \
{ \
.mac_addr.addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \
}; };
#define NXP_ENET_QOS_DRIVER_INIT(n) \ #define NXP_ENET_QOS_DRIVER_INIT(n) \
NXP_ENET_QOS_NODE_HAS_MAC_ADDR_CHECK(n) \ NXP_ENET_QOS_NODE_HAS_MAC_ADDR_CHECK(n) \
NXP_ENET_QOS_IRQ_CONFIG_FUNC(n) \ NXP_ENET_QOS_IRQ_CONFIG_FUNC(n) \
NXP_ENET_QOS_DRIVER_STRUCTS_INIT(n) NXP_ENET_QOS_DRIVER_STRUCTS_INIT(n)
DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_QOS_DRIVER_INIT) DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_QOS_DRIVER_INIT)
#define NXP_ENET_QOS_MAC_DEVICE_DEFINE(n) \ #define NXP_ENET_QOS_MAC_DEVICE_DEFINE(n) \
ETH_NET_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_qos_mac_init, NULL, \ ETH_NET_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_qos_mac_init, NULL, \
&enet_qos_##n##_mac_data, &enet_qos_##n##_mac_config, \ &enet_qos_##n##_mac_data, &enet_qos_##n##_mac_config, \
CONFIG_ETH_INIT_PRIORITY, &api_funcs, NET_ETH_MTU); CONFIG_ETH_INIT_PRIORITY, &api_funcs, NET_ETH_MTU);
DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_QOS_MAC_DEVICE_DEFINE) DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_QOS_MAC_DEVICE_DEFINE)

View file

@ -85,13 +85,20 @@ struct nxp_enet_qos_hw_info {
uint16_t max_frame_len; uint16_t max_frame_len;
}; };
enum mac_address_source {
NXP_ENET_QOS_MAC_ADDR_SOURCE_LOCAL,
NXP_ENET_QOS_MAC_ADDR_SOURCE_RANDOM,
NXP_ENET_QOS_MAC_ADDR_SOURCE_UNIQUE,
NXP_ENET_QOS_MAC_ADDR_SOURCE_INVALID,
};
struct nxp_enet_qos_mac_config { struct nxp_enet_qos_mac_config {
const struct device *enet_dev; const struct device *enet_dev;
const struct device *phy_dev; const struct device *phy_dev;
enet_qos_t *base; enet_qos_t *base;
struct nxp_enet_qos_hw_info hw_info; struct nxp_enet_qos_hw_info hw_info;
void (*irq_config_func)(void); void (*irq_config_func)(void);
bool random_mac; enum mac_address_source mac_addr_source;
}; };
struct nxp_enet_qos_tx_data { struct nxp_enet_qos_tx_data {

View file

@ -13,3 +13,15 @@ properties:
interrupt-names: interrupt-names:
required: true required: true
nxp,unique-mac:
type: boolean
description: |
Use part of the unique silicon ID to generate the MAC.
This property will be overridden if the node has
zephyr,random-mac-address or local-mac-address also.
This option is intended for cases where a very low likelihood
that the mac address is the same as another on the network
is sufficient, such as, testing, bringup, demos, etc.
The first 3 bytes will be the freescale OUI and the next
3 bytes will come from the chip's unique ID.