Skip to content

Commit

Permalink
eth_nxp_enet_qos_mac: implement the nxp,unique-mac address feature
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
theadib authored and henrikbrixandersen committed Jan 8, 2025
1 parent cf91c1b commit cce0826
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 45 deletions.
11 changes: 11 additions & 0 deletions drivers/ethernet/eth_nxp_enet_qos/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ config 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
int "Number of tx buffer descriptors"
default 4
Expand Down
125 changes: 81 additions & 44 deletions drivers/ethernet/eth_nxp_enet_qos/eth_nxp_enet_qos_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ LOG_MODULE_REGISTER(eth_nxp_enet_qos_mac, CONFIG_ETHERNET_LOG_LEVEL);
#include <zephyr/net/phy.h>
#include <zephyr/kernel/thread_stack.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 "../eth.h"
#include "nxp_enet_qos_priv.h"
Expand Down Expand Up @@ -480,6 +484,33 @@ static inline int enet_qos_rx_desc_init(enet_qos_t *base, struct nxp_enet_qos_rx
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)
{
const struct nxp_enet_qos_mac_config *config = dev->config;
Expand All @@ -501,8 +532,11 @@ static int eth_nxp_enet_qos_mac_init(const struct device *dev)
return ret;
}

/* Random mac therefore overrides local mac that may have been initialized */
if (config->random_mac) {
if (config->mac_addr_source == NXP_ENET_QOS_MAC_ADDR_SOURCE_LOCAL) {
/* 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,
NXP_OUI_BYTE_0, NXP_OUI_BYTE_1, NXP_OUI_BYTE_2);
}
Expand Down Expand Up @@ -626,56 +660,59 @@ static const struct ethernet_api api_funcs = {
.set_config = eth_nxp_enet_qos_set_config,
};

#define NXP_ENET_QOS_NODE_HAS_MAC_ADDR_CHECK(n) \
BUILD_ASSERT(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)) || \
DT_INST_PROP(n, zephyr_random_mac_address), \
"MAC address not specified on ENET QOS DT node");

#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)); \
#define NXP_ENET_QOS_NODE_HAS_MAC_ADDR_CHECK(n) \
BUILD_ASSERT(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)) || \
DT_INST_PROP(n, zephyr_random_mac_address) || \
DT_INST_PROP(n, nxp_unique_mac), \
"MAC address not specified on ENET QOS DT node");

#define NXP_ENET_QOS_MAC_ADDR_SOURCE(n) \
COND_CODE_1(DT_NODE_HAS_PROP(DT_DRV_INST(n), local_mac_address), \
(NXP_ENET_QOS_MAC_ADDR_SOURCE_LOCAL), \
(COND_CODE_1(DT_INST_PROP(n, zephyr_random_mac_address), \
(NXP_ENET_QOS_MAC_ADDR_SOURCE_RANDOM), \
(COND_CODE_1(DT_INST_PROP(n, nxp_unique_mac), \
(NXP_ENET_QOS_MAC_ADDR_SOURCE_UNIQUE), \
(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);

#define NXP_ENET_QOS_IRQ_CONFIG_FUNC(n) \
static void nxp_enet_qos_##n##_irq_config_func(void) \
{ \
DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), \
interrupt_names, \
NXP_ENET_QOS_CONNECT_IRQS) \
#define NXP_ENET_QOS_IRQ_CONFIG_FUNC(n) \
static void nxp_enet_qos_##n##_irq_config_func(void) \
{ \
DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), interrupt_names, NXP_ENET_QOS_CONNECT_IRQS) \
}

#define NXP_ENET_QOS_DRIVER_STRUCTS_INIT(n) \
static const struct nxp_enet_qos_mac_config enet_qos_##n##_mac_config = { \
.enet_dev = DEVICE_DT_GET(DT_INST_PARENT(n)), \
.phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \
.base = (enet_qos_t *)DT_REG_ADDR(DT_INST_PARENT(n)), \
.hw_info = { \
.max_frame_len = ENET_QOS_MAX_NORMAL_FRAME_LEN, \
}, \
.irq_config_func = nxp_enet_qos_##n##_irq_config_func, \
.random_mac = DT_INST_PROP(n, zephyr_random_mac_address), \
}; \
\
static struct nxp_enet_qos_mac_data enet_qos_##n##_mac_data = \
{ \
.mac_addr.addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \
#define NXP_ENET_QOS_DRIVER_STRUCTS_INIT(n) \
static const struct nxp_enet_qos_mac_config enet_qos_##n##_mac_config = { \
.enet_dev = DEVICE_DT_GET(DT_INST_PARENT(n)), \
.phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \
.base = (enet_qos_t *)DT_REG_ADDR(DT_INST_PARENT(n)), \
.hw_info = \
{ \
.max_frame_len = ENET_QOS_MAX_NORMAL_FRAME_LEN, \
}, \
.irq_config_func = nxp_enet_qos_##n##_irq_config_func, \
.mac_addr_source = NXP_ENET_QOS_MAC_ADDR_SOURCE(n), \
}; \
static struct nxp_enet_qos_mac_data enet_qos_##n##_mac_data = { \
.mac_addr.addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \
};

#define NXP_ENET_QOS_DRIVER_INIT(n) \
NXP_ENET_QOS_NODE_HAS_MAC_ADDR_CHECK(n) \
NXP_ENET_QOS_IRQ_CONFIG_FUNC(n) \
#define NXP_ENET_QOS_DRIVER_INIT(n) \
NXP_ENET_QOS_NODE_HAS_MAC_ADDR_CHECK(n) \
NXP_ENET_QOS_IRQ_CONFIG_FUNC(n) \
NXP_ENET_QOS_DRIVER_STRUCTS_INIT(n)

DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_QOS_DRIVER_INIT)

#define NXP_ENET_QOS_MAC_DEVICE_DEFINE(n) \
ETH_NET_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_qos_mac_init, NULL, \
&enet_qos_##n##_mac_data, &enet_qos_##n##_mac_config, \
CONFIG_ETH_INIT_PRIORITY, &api_funcs, NET_ETH_MTU);
#define NXP_ENET_QOS_MAC_DEVICE_DEFINE(n) \
ETH_NET_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_qos_mac_init, NULL, \
&enet_qos_##n##_mac_data, &enet_qos_##n##_mac_config, \
CONFIG_ETH_INIT_PRIORITY, &api_funcs, NET_ETH_MTU);

DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_QOS_MAC_DEVICE_DEFINE)
9 changes: 8 additions & 1 deletion drivers/ethernet/eth_nxp_enet_qos/nxp_enet_qos_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,20 @@ struct nxp_enet_qos_hw_info {
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 {
const struct device *enet_dev;
const struct device *phy_dev;
enet_qos_t *base;
struct nxp_enet_qos_hw_info hw_info;
void (*irq_config_func)(void);
bool random_mac;
enum mac_address_source mac_addr_source;
};

struct nxp_enet_qos_tx_data {
Expand Down
12 changes: 12 additions & 0 deletions dts/bindings/ethernet/nxp,enet-qos-mac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ properties:

interrupt-names:
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.

0 comments on commit cce0826

Please sign in to comment.