Skip to content

Introduce new DSA switch framework #87045

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions boards/nxp/mimxrt1180_evk/mimxrt1180_evk.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
};

&switch_port0 {
local-mac-address = [00 00 00 01 04 00];
zephyr,random-mac-address;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This board has Ethernet sockets that have factory MAC address marked to them. Why can't we use the factory set MAC addresses here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may need to have some investigation on how to do that in both zephyr and platform.
Not sure if any fuse related driver needed?
Could you share any factory set MAC address case support in zephyr?
I'd like to support that seperately for NETC and RT1180 platform in another PR if it's okay.
Thank you very much.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example NXP frdm_rw612 board has both Wi-Fi and Ethernet. The Wi-Fi is properly using factory set MAC address, but the Ethernet is not. I created an issue for it #88336

I have STM nucleo_f767zi board which uses device id by default a mac address.

hwinfo_get_device_id(unique_device_ID_12_bytes, 12);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a separate PR for setting MAC address to fixed value is ok. I was just wondering why NXP is using random MAC address for several boards I have been using.

Copy link
Contributor Author

@yangbolu1991 yangbolu1991 Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have had some investigation but I have no idea on the reason:(
It looks like the way getting the factory mac address varied from soc/board.
I think for i.MXRT it's from fuse which may read via hal/nxp/mcux/mcux-sdk-ng/drivers/ocotp driver.
For some i.MX8 and i.MX9, it's from fuse too, but it's more complicated to read. As the reading must be via talking with EdgeLock Enclave. I can see below drivers in u-boot for that.

drivers/misc/imx_ele/fuse.c
drivers/misc/imx_ele/ele_api.c

Not sure about other series SoC. I am not sure if all boards are assigned mac addresses either.
Anyway, I will take some time to make this clear, and try to support to use in zephyr if has.
Thanks.

pinctrl-0 = <&eth0_default>;
pinctrl-names = "default";
phy-handle = <&phy0>;
Expand All @@ -104,7 +104,7 @@
};

&switch_port1 {
local-mac-address = [00 00 00 01 05 00];
zephyr,random-mac-address;
pinctrl-0 = <&eth1_default>;
pinctrl-names = "default";
phy-handle = <&phy1>;
Expand All @@ -113,7 +113,7 @@
};

&switch_port2 {
local-mac-address = [00 00 00 01 06 00];
zephyr,random-mac-address;
pinctrl-0 = <&eth2_default>;
pinctrl-names = "default";
phy-handle = <&phy2>;
Expand All @@ -122,7 +122,7 @@
};

&switch_port3 {
local-mac-address = [00 00 00 01 07 00];
zephyr,random-mac-address;
pinctrl-0 = <&eth3_default>;
pinctrl-names = "default";
phy-handle = <&phy3>;
Expand All @@ -132,7 +132,7 @@

/* Internal port */
&switch_port4 {
local-mac-address = [00 00 00 01 06 00];
zephyr,random-mac-address;
status = "okay";
};

Expand Down
129 changes: 129 additions & 0 deletions doc/connectivity/networking/dsa.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
.. _dsa:

Distributed Switch Architecture (DSA)
#####################################

.. contents::
:local:
:depth: 2

Distributed Switch Architecture (DSA) is not something new. It has been a mature
subsystem in Linux for many years. This document just skips the background,
terms and any knowledge related description, as user may find all of these in
`Linux DSA documentation`_.


DSA switch TX/RX process
************************

The DSA switch TX/RX process is as below.

.. image:: dsa_txrx_process.svg

Host interface
**************

Host interface network devices use regular and unmodified ethernet driver working
as DSA conduit port, which manages the switch through processor.

Switch interface
****************

The switch interfaces are also exposed as standard ethernet interfaces in zephyr.
The one connected to conduit port work as CPU port, and the others for user purpose
work as user ports.

Switch tagging protocols
************************

Generally, switch tagging protocols are vendor specific. They all contain something which:

- identifies which port the Ethernet frame came from/should be sent to
- provides a reason why this frame was forwarded to the management interface

And tag on the packets to give them a switch frame header. But there are also tag-less case.
It depends on the vendor.

Networking stack process
************************

In order to have the DSA subsystem process the Ethernet switch specific tagging protocol
via conduit port.

For RX path, put ``dsa_recv()`` at beginning of ``net_recv_data()`` in ``subsys/net/ip/net_core.c``
to handle first for untagging and re-directing interface.

For TX path, the switch interfaces register as standard ethernet devices with ``dsa_xmit()``
as ``ethernet_api->send``. The ``dsa_xmit()`` processes the tagging and re-directing to conduit
port work.

DSA device driver support
*************************

As the DSA core driver interacts with subsystems/drivers including MDIO, PHY and device tree to
to support the common DSA setup and working process. The device driver support is much easy.

For device tree, the switch description should be following the ``dts/bindings/dsa/dsa.yaml``.

For device driver, all needed to prepare are :c:struct:`dsa_api`, private data if has, and
:c:struct:`dsa_port_config`. The macro functions could be utilized. And below is an example
of i.MX NETC.

- :c:macro:`DSA_SWITCH_INST_INIT`
- :c:macro:`DSA_PORT_INST_INIT`

.. code-block:: c

#define DSA_NETC_PORT_INST_INIT(port, n) \
COND_CODE_1(DT_NUM_PINCTRL_STATES(port), \
(PINCTRL_DT_DEFINE(port);), (EMPTY)) \
struct dsa_netc_port_config dsa_netc_##n##_##port##_config = { \
.pincfg = COND_CODE_1(DT_NUM_PINCTRL_STATES(port), \
(PINCTRL_DT_DEV_CONFIG_GET(port)), NULL), \
.phy_mode = NETC_PHY_MODE(port), \
}; \
struct dsa_port_config dsa_##n##_##port##_config = { \
.use_random_mac_addr = DT_NODE_HAS_PROP(port, zephyr_random_mac_address), \
.mac_addr = DT_PROP_OR(port, local_mac_address, {0}), \
.port_idx = DT_REG_ADDR(port), \
.phy_dev = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(port, phy_handle)), \
.phy_mode = DT_PROP_OR(port, phy_connection_type, ""), \
.ethernet_connection = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(port, ethernet)), \
.prv_config = &dsa_netc_##n##_##port##_config, \
}; \
DSA_PORT_INST_INIT(port, n, &dsa_##n##_##port##_config)

#define DSA_NETC_DEVICE(n) \
AT_NONCACHEABLE_SECTION_ALIGN(static netc_cmd_bd_t dsa_netc_##n##_cmd_bd[8], \
NETC_BD_ALIGN); \
static struct dsa_netc_data dsa_netc_data_##n = { \
.cmd_bd = dsa_netc_##n##_cmd_bd, \
}; \
DSA_SWITCH_INST_INIT(n, &dsa_netc_api, &dsa_netc_data_##n, DSA_NETC_PORT_INST_INIT);

Common pitfalls using DSA setups
********************************

This is copied from Linux DSA documentation. It applies to zephyr too. Although conduit port and
cpu port exposed as ethernet device in zephyr, they are not able to be used.

.. note::

Once a conduit network device is configured to use DSA (dev->dsa_ptr becomes non-NULL), and
the switch behind it expects a tagging protocol, this network interface can only exclusively
be used as a conduit interface. Sending packets directly through this interface (e.g.: opening
a socket using this interface) will not make us go through the switch tagging protocol transmit
function, so the Ethernet switch on the other end, expecting a tag will typically drop this frame.

TODO work
*********

Comparing to Linux, there are too much features to support in/based on zephyr DSA. But basically
bridge layer should be supported. Then DSA could provide two options for users to use switch ports.

- Standalone mode: all user ports work as regular ethernet devices. No switching.
- Bridge mode: switch mode enabled with adding user ports into virtual bridge device. IP address could
be assigned to the bridge.

.. _Linux DSA documentation:
https://www.kernel.org/doc/html/latest/networking/dsa/dsa.html
1 change: 1 addition & 0 deletions doc/connectivity/networking/dsa_txrx_process.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions doc/connectivity/networking/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ operation of the stacks and how they were implemented.
network_tracing.rst
api/index.rst
conn_mgr/index.rst
dsa.rst
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The image is nice and it is ok to have it in png format. But if we ever needs to adjust the image in the future, could you also provide the original file in svg format?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Will provide svg.

4 changes: 4 additions & 0 deletions doc/releases/migration-guide-4.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ Ethernet
* NuMaker Ethernet driver ``eth_numaker.c`` now supports ``gen_random_mac``,
and the EMAC data flash feature has been removed (:github:`87953`).

* The enum ``ETHERNET_DSA_MASTER_PORT`` and ``ETHERNET_DSA_SLAVE_PORT`` in
:zephyr_file:`include/zephyr/net/ethernet.h` have been renamed
to ``ETHERNET_DSA_CONDUIT_PORT`` and ``ETHERNET_DSA_USER_PORT``.

Enhanced Serial Peripheral Interface (eSPI)
===========================================

Expand Down
2 changes: 1 addition & 1 deletion drivers/ethernet/Kconfig.nxp_enet
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ config ETH_NXP_ENET
select ARM_MPU if CPU_CORTEX_M7
select MDIO if DT_HAS_NXP_ENET_MDIO_ENABLED
select NET_POWER_MANAGEMENT if (PM_DEVICE && SOC_FAMILY_KINETIS)
select ETH_DSA_SUPPORT
select ETH_DSA_SUPPORT_DEPRECATED
select PINCTRL
help
Enable NXP ENET Ethernet driver.
Expand Down
2 changes: 1 addition & 1 deletion drivers/ethernet/Kconfig.sam_gmac
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ menuconfig ETH_SAM_GMAC
DT_HAS_ATMEL_SAM0_GMAC_ENABLED
select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT
select MDIO
select ETH_DSA_SUPPORT
select ETH_DSA_SUPPORT_DEPRECATED
select PINCTRL
help
Enable Atmel SAM MCU Family Ethernet driver.
Expand Down
2 changes: 1 addition & 1 deletion drivers/ethernet/Kconfig.stm32_hal
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ menuconfig ETH_STM32_HAL
select USE_STM32_HAL_RIF if SOC_SERIES_STM32N6X
select NOCACHE_MEMORY if (SOC_SERIES_STM32H7X && CPU_CORTEX_M7) || SOC_SERIES_STM32N6X
select HWINFO
select ETH_DSA_SUPPORT
select ETH_DSA_SUPPORT_DEPRECATED
select PINCTRL
select MDIO if DT_HAS_ST_STM32_MDIO_ENABLED
imply CRC
Expand Down
22 changes: 17 additions & 5 deletions drivers/ethernet/dsa/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,32 @@
# Lukasz Majewski <[email protected]>
# SPDX-License-Identifier: Apache-2.0

config ETH_DSA_SUPPORT
config ETH_DSA_SUPPORT_DEPRECATED
bool
help
Set by an ethernet driver that supports DSA.
Set by an ethernet driver that supports DSA. This is obsolete,
and only used for legacy dsa device.

menuconfig NET_DSA
bool "Distributed Switch Architecture support"
depends on ETH_DSA_SUPPORT
help
Enable Distributed Switch Architecture support. For now it
only supports Kinetics and STM32 ENET drivers.
Enable Distributed Switch Architecture support.

if NET_DSA

config NET_DSA_DEPRECATED
bool "Distributed Switch Architecture support for legacy device"
select DEPRECATED
depends on ETH_DSA_SUPPORT_DEPRECATED
help
This is obsolete, and only used for legacy dsa device.

config DSA_PORT_MAX_COUNT
int "DSA port max count"
default 8
help
Set DSA port max count.

config DSA_KSZ8XXX
bool

Expand Down
4 changes: 2 additions & 2 deletions drivers/ethernet/dsa/dsa_ksz8xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,7 @@ static struct net_if *dsa_ksz8xxx_get_iface(struct net_if *iface,
uint8_t pnum;

if (!(net_eth_get_hw_capabilities(iface) &
(ETHERNET_DSA_SLAVE_PORT | ETHERNET_DSA_MASTER_PORT))) {
(ETHERNET_DSA_USER_PORT | ETHERNET_DSA_CONDUIT_PORT))) {
return iface;
}

Expand Down Expand Up @@ -1114,7 +1114,7 @@ static enum ethernet_hw_caps dsa_port_get_capabilities(const struct device *dev)
{
ARG_UNUSED(dev);

return ETHERNET_DSA_SLAVE_PORT | ETHERNET_LINK_10BASE_T |
return ETHERNET_DSA_USER_PORT | ETHERNET_LINK_10BASE_T |
ETHERNET_LINK_100BASE_T;
}

Expand Down
14 changes: 7 additions & 7 deletions drivers/ethernet/eth_nxp_enet.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <zephyr/drivers/ptp_clock.h>
#endif

#ifdef CONFIG_NET_DSA
#ifdef CONFIG_NET_DSA_DEPRECATED
#include <zephyr/net/dsa.h>
#endif

Expand Down Expand Up @@ -260,8 +260,8 @@ static enum ethernet_hw_caps eth_nxp_enet_get_capabilities(const struct device *
#if defined(CONFIG_PTP_CLOCK_NXP_ENET)
ETHERNET_PTP |
#endif
#if defined(CONFIG_NET_DSA)
ETHERNET_DSA_MASTER_PORT |
#if defined(CONFIG_NET_DSA_DEPRECATED)
ETHERNET_DSA_CONDUIT_PORT |
#endif
#if defined(CONFIG_ETH_NXP_ENET_HW_ACCELERATION)
ETHERNET_HW_TX_CHKSUM_OFFLOAD |
Expand Down Expand Up @@ -415,7 +415,7 @@ static int eth_nxp_enet_rx(const struct device *dev)
#endif /* CONFIG_PTP_CLOCK_NXP_ENET */

iface = get_iface(data);
#if defined(CONFIG_NET_DSA)
#if defined(CONFIG_NET_DSA_DEPRECATED)
iface = dsa_net_recv(iface, &pkt);
#endif
if (net_recv_data(iface, pkt) < 0) {
Expand Down Expand Up @@ -555,7 +555,7 @@ static void eth_nxp_enet_iface_init(struct net_if *iface)
data->iface = iface;
}

#if defined(CONFIG_NET_DSA)
#if defined(CONFIG_NET_DSA_DEPRECATED)
dsa_register_master_tx(iface, &eth_nxp_enet_tx);
#endif

Expand Down Expand Up @@ -876,11 +876,11 @@ static int eth_nxp_enet_device_pm_action(const struct device *dev, enum pm_devic
#define ETH_NXP_ENET_PM_DEVICE_GET(n) NULL
#endif /* CONFIG_NET_POWER_MANAGEMENT */

#ifdef CONFIG_NET_DSA
#ifdef CONFIG_NET_DSA_DEPRECATED
#define NXP_ENET_SEND_FUNC dsa_tx
#else
#define NXP_ENET_SEND_FUNC eth_nxp_enet_tx
#endif /* CONFIG_NET_DSA */
#endif /* CONFIG_NET_DSA_DEPRECATED */

static const struct ethernet_api api_funcs = {
.iface_api.init = eth_nxp_enet_iface_init,
Expand Down
12 changes: 6 additions & 6 deletions drivers/ethernet/eth_stm32_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <zephyr/net/lldp.h>
#include <zephyr/drivers/hwinfo.h>

#if defined(CONFIG_NET_DSA)
#if defined(CONFIG_NET_DSA_DEPRECATED)
#include <zephyr/net/dsa.h>
#endif

Expand Down Expand Up @@ -682,7 +682,7 @@ static void rx_thread(void *arg1, void *unused1, void *unused2)
/* semaphore taken and receive packets */
while ((pkt = eth_rx(dev)) != NULL) {
iface = net_pkt_iface(pkt);
#if defined(CONFIG_NET_DSA)
#if defined(CONFIG_NET_DSA_DEPRECATED)
iface = dsa_net_recv(iface, &pkt);
#endif
res = net_recv_data(iface, pkt);
Expand Down Expand Up @@ -1215,7 +1215,7 @@ static void eth_iface_init(struct net_if *iface)
sizeof(dev_data->mac_addr),
NET_LINK_ETHERNET);

#if defined(CONFIG_NET_DSA)
#if defined(CONFIG_NET_DSA_DEPRECATED)
dsa_register_master_tx(iface, &eth_tx);
#endif

Expand Down Expand Up @@ -1281,8 +1281,8 @@ static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(const struct device
| ETHERNET_HW_RX_CHKSUM_OFFLOAD
| ETHERNET_HW_TX_CHKSUM_OFFLOAD
#endif
#if defined(CONFIG_NET_DSA)
| ETHERNET_DSA_MASTER_PORT
#if defined(CONFIG_NET_DSA_DEPRECATED)
| ETHERNET_DSA_CONDUIT_PORT
#endif
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
| ETHERNET_HW_FILTERING
Expand Down Expand Up @@ -1419,7 +1419,7 @@ static const struct ethernet_api eth_api = {
.set_config = eth_stm32_hal_set_config,
.get_phy = eth_stm32_hal_get_phy,
.get_config = eth_stm32_hal_get_config,
#if defined(CONFIG_NET_DSA)
#if defined(CONFIG_NET_DSA_DEPRECATED)
.send = dsa_tx,
#else
.send = eth_tx,
Expand Down
1 change: 0 additions & 1 deletion drivers/ethernet/nxp_imx_netc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ menuconfig ETH_NXP_IMX_NETC
depends on DT_HAS_NXP_IMX_NETC_PSI_ENABLED
select MDIO
select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT
select ETH_DSA_SUPPORT
help
Enable Ethernet and Network Controller (NETC) driver for NXP IMX SoCs.

Expand Down
Loading