[PATCH v2 14/21] sandbox: Add a DSA sandbox driver and unit test

Bin Meng bmeng.cn at gmail.com
Fri Mar 12 14:35:55 CET 2021


From: Claudiu Manoil <claudiu.manoil at nxp.com>

The DSA sandbox driver is used for unit testing the DSA class code.
It implements a simple 2 port switch plus 1 CPU port, and uses a
very simple tag to identify the ports.

The DSA sandbox device is connected via CPU port to a regular Ethernet
sandbox device, called 'dsa-test-eth, managed by the existing eth
sandbox driver.  The 'dsa-test-eth' is not intended for testing the
eth class code however, but it is used to emulate traffic through the
'lan0' and 'lan1' front pannel switch ports.  To achieve this the dsa
sandbox driver registers a tx handler for the 'dsa-test-eth' device.
The switch ports, labeled as 'lan0' and 'lan1', are also registered
as eth devices by the dsa class code this time.  So pinging through
these switch ports is as easy as:

=> setenv ethact lan0
=> ping 1.2.3.5

Unit tests for the dsa class code were also added.  The 'dsa_probe'
test exercises most API functions from dsa.h.  The 'dsa' unit test
simply exercises ARP/ICMP traffic through the two switch ports,
including tag injection and extraction, with the help of the dsa
sandbox driver.

I took care to minimize the impact on the existing eth unit tests,
though some adjustments needed to be made with the addition of
extra eth interfaces used by the dsa unit tests. The additional eth
interfaces also require MAC addresses, these have been added to the
sandbox default environment.

Signed-off-by: Alex Marginean <alexandru.marginean at nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil at nxp.com>
Reviewed-by: Simon Glass <sjg at chromium.org>
Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
Message-Id: <20210216224804.3355044-5-olteanv at gmail.com>
Signed-off-by: Bin Meng <bmeng.cn at gmail.com>
---

(no changes since v1)

 arch/Kconfig              |   2 +
 arch/sandbox/dts/test.dts |  48 ++++++++++
 drivers/net/Kconfig       |   9 ++
 drivers/net/Makefile      |   1 +
 drivers/net/dsa_sandbox.c | 179 ++++++++++++++++++++++++++++++++++++++
 include/configs/sandbox.h |   2 +
 test/dm/Makefile          |   1 +
 test/dm/dsa.c             |  82 +++++++++++++++++
 test/dm/eth.c             |  10 +--
 9 files changed, 329 insertions(+), 5 deletions(-)
 create mode 100644 drivers/net/dsa_sandbox.c
 create mode 100644 test/dm/dsa.c

diff --git a/arch/Kconfig b/arch/Kconfig
index 27843cd79c..5672d1df7e 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -160,6 +160,8 @@ config SANDBOX
 	imply CMD_CLONE
 	imply SILENT_CONSOLE
 	imply BOOTARGS_SUBST
+	imply PHY_FIXED
+	imply DM_DSA
 
 config SH
 	bool "SuperH architecture"
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 995c93c95a..0e3eb63481 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -15,7 +15,9 @@
 	aliases {
 		console = &uart0;
 		eth0 = "/eth at 10002000";
+		eth2 = &swp_0;
 		eth3 = &eth_3;
+		eth4 = &dsa_eth0;
 		eth5 = &eth_5;
 		gpio1 = &gpio_a;
 		gpio2 = &gpio_b;
@@ -478,6 +480,52 @@
 		fake-host-hwaddr = [00 00 66 44 22 22];
 	};
 
+	dsa_eth0: dsa-test-eth {
+		compatible = "sandbox,eth";
+		reg = <0x10006000 0x1000>;
+		fake-host-hwaddr = [00 00 66 44 22 66];
+	};
+
+	dsa-test {
+		compatible = "sandbox,dsa";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			swp_0: port at 0 {
+				reg = <0>;
+				label = "lan0";
+				phy-mode = "rgmii-rxid";
+
+				fixed-link {
+					speed = <100>;
+					full-duplex;
+				};
+			};
+
+			swp_1: port at 1 {
+				reg = <1>;
+				label = "lan1";
+				phy-mode = "rgmii-txid";
+
+				fixed-link {
+					speed = <100>;
+					full-duplex;
+				};
+			};
+
+			port at 2 {
+				reg = <2>;
+				ethernet = <&dsa_eth0>;
+
+				fixed-link {
+					speed = <1000>;
+					full-duplex;
+				};
+			};
+		};
+	};
+
 	fixed-link-test1 {
 		fixed-link {
 			speed = <1000>;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0e84c22b50..f96ee64249 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -78,6 +78,15 @@ config DM_ETH_PHY
 	help
 	  Enable driver model for Ethernet Generic PHY .
 
+config DSA_SANDBOX
+	depends on DM_DSA && SANDBOX
+	default y
+	bool "Sandbox: Mocked DSA driver"
+	help
+	  This driver implements a dummy DSA switch connected to a dummy sandbox
+	  Ethernet device used as DSA master, to test DSA class code, including
+	  exported DSA API and datapath processing of Ethernet traffic.
+
 menuconfig NETDEVICES
 	bool "Network device support"
 	depends on NET
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a19511aaa7..108138fdb9 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o
 obj-$(CONFIG_ETH_DESIGNWARE_S700) += dwmac_s700.o
 obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
 obj-$(CONFIG_DNET) += dnet.o
+obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
 obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o
 obj-$(CONFIG_E1000) += e1000.o
 obj-$(CONFIG_E1000_SPI) += e1000_spi.o
diff --git a/drivers/net/dsa_sandbox.c b/drivers/net/dsa_sandbox.c
new file mode 100644
index 0000000000..4b62670e5d
--- /dev/null
+++ b/drivers/net/dsa_sandbox.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019-2021 NXP Semiconductors
+ */
+
+#include <asm/eth.h>
+#include <net/dsa.h>
+#include <net.h>
+
+#define DSA_SANDBOX_MAGIC	0x00415344
+#define DSA_SANDBOX_TAG_LEN	sizeof(struct dsa_sandbox_tag)
+
+struct dsa_sandbox_priv {
+	struct eth_sandbox_priv *master_priv;
+	int port_en_mask;
+};
+
+struct dsa_sandbox_tag {
+	u32 magic;
+	u32 port;
+};
+
+static bool sb_dsa_port_enabled(struct udevice *dev, int port)
+{
+	struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+
+	return priv->port_en_mask & BIT(port);
+}
+
+static bool sb_dsa_master_enabled(struct udevice *dev)
+{
+	struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+
+	return !priv->master_priv->disabled;
+}
+
+static int dsa_sandbox_port_enable(struct udevice *dev, int port,
+				   struct phy_device *phy)
+{
+	struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+
+	if (!sb_dsa_master_enabled(dev))
+		return -EFAULT;
+
+	priv->port_en_mask |= BIT(port);
+
+	return 0;
+}
+
+static void dsa_sandbox_port_disable(struct udevice *dev, int port,
+				     struct phy_device *phy)
+{
+	struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+
+	priv->port_en_mask &= ~BIT(port);
+}
+
+static int dsa_sandbox_xmit(struct udevice *dev, int port, void *packet,
+			    int length)
+{
+	struct dsa_sandbox_tag *tag = packet;
+
+	if (!sb_dsa_master_enabled(dev))
+		return -EFAULT;
+
+	if (!sb_dsa_port_enabled(dev, port))
+		return -EFAULT;
+
+	tag->magic = DSA_SANDBOX_MAGIC;
+	tag->port = port;
+
+	return 0;
+}
+
+static int dsa_sandbox_rcv(struct udevice *dev, int *port, void *packet,
+			   int length)
+{
+	struct dsa_sandbox_tag *tag = packet;
+
+	if (!sb_dsa_master_enabled(dev))
+		return -EFAULT;
+
+	if (tag->magic != DSA_SANDBOX_MAGIC)
+		return -EFAULT;
+
+	*port = tag->port;
+	if (!sb_dsa_port_enabled(dev, tag->port))
+		return -EFAULT;
+
+	return 0;
+}
+
+static const struct dsa_ops dsa_sandbox_ops = {
+	.port_enable = dsa_sandbox_port_enable,
+	.port_disable = dsa_sandbox_port_disable,
+	.xmit = dsa_sandbox_xmit,
+	.rcv = dsa_sandbox_rcv,
+};
+
+static int sb_dsa_handler(struct udevice *dev, void *packet,
+			  unsigned int len)
+{
+	struct eth_sandbox_priv *master_priv;
+	struct dsa_sandbox_tag *tag = packet;
+	struct udevice *dsa_dev;
+	u32 port_index;
+	void *rx_buf;
+	int i;
+
+	/* this emulates the switch hw and the network side */
+	if (tag->magic != DSA_SANDBOX_MAGIC)
+		return -EFAULT;
+
+	port_index = tag->port;
+	master_priv = dev_get_priv(dev);
+	dsa_dev = master_priv->priv;
+	if (!sb_dsa_port_enabled(dsa_dev, port_index))
+		return -EFAULT;
+
+	packet += DSA_SANDBOX_TAG_LEN;
+	len -= DSA_SANDBOX_TAG_LEN;
+
+	if (!sandbox_eth_arp_req_to_reply(dev, packet, len))
+		goto dsa_tagging;
+	if (!sandbox_eth_ping_req_to_reply(dev, packet, len))
+		goto dsa_tagging;
+
+	return 0;
+
+dsa_tagging:
+	master_priv->recv_packets--;
+	i = master_priv->recv_packets;
+	rx_buf = master_priv->recv_packet_buffer[i];
+	len = master_priv->recv_packet_length[i];
+	memmove(rx_buf + DSA_SANDBOX_TAG_LEN, rx_buf, len);
+
+	tag = rx_buf;
+	tag->magic = DSA_SANDBOX_MAGIC;
+	tag->port = port_index;
+	len += DSA_SANDBOX_TAG_LEN;
+	master_priv->recv_packet_length[i] = len;
+	master_priv->recv_packets++;
+
+	return 0;
+}
+
+static int dsa_sandbox_probe(struct udevice *dev)
+{
+	struct dsa_sandbox_priv *priv = dev_get_priv(dev);
+	struct udevice *master = dsa_get_master(dev);
+	struct eth_sandbox_priv *master_priv;
+
+	if (!master)
+		return -ENODEV;
+
+	dsa_set_tagging(dev, DSA_SANDBOX_TAG_LEN, 0);
+
+	master_priv = dev_get_priv(master);
+	master_priv->priv = dev;
+	master_priv->tx_handler = sb_dsa_handler;
+
+	priv->master_priv = master_priv;
+
+	return 0;
+}
+
+static const struct udevice_id dsa_sandbox_ids[] = {
+	{ .compatible = "sandbox,dsa" },
+	{ }
+};
+
+U_BOOT_DRIVER(dsa_sandbox) = {
+	.name		= "dsa_sandbox",
+	.id		= UCLASS_DSA,
+	.of_match	= dsa_sandbox_ids,
+	.probe		= dsa_sandbox_probe,
+	.ops		= &dsa_sandbox_ops,
+	.priv_auto	= sizeof(struct dsa_sandbox_priv),
+};
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index e0708fe573..91f636b2c1 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -93,7 +93,9 @@
 #endif
 
 #define SANDBOX_ETH_SETTINGS		"ethaddr=00:00:11:22:33:44\0" \
+					"eth2addr=00:00:11:22:33:48\0" \
 					"eth3addr=00:00:11:22:33:45\0" \
+					"eth4addr=00:00:11:22:33:48\0" \
 					"eth5addr=00:00:11:22:33:46\0" \
 					"eth6addr=00:00:11:22:33:47\0" \
 					"ipaddr=1.2.3.4\0"
diff --git a/test/dm/Makefile b/test/dm/Makefile
index fd1455109d..1c2fa95f4a 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_CLK) += clk.o clk_ccf.o
 obj-$(CONFIG_CROS_EC) += cros_ec.o
 obj-$(CONFIG_DEVRES) += devres.o
 obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o
+obj-$(CONFIG_DM_DSA) += dsa.o
 obj-$(CONFIG_DM_ETH) += eth.o
 obj-$(CONFIG_FIRMWARE) += firmware.o
 obj-$(CONFIG_DM_GPIO) += gpio.o
diff --git a/test/dm/dsa.c b/test/dm/dsa.c
new file mode 100644
index 0000000000..18c1776460
--- /dev/null
+++ b/test/dm/dsa.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020-2021 NXP Semiconductors
+ */
+
+#include <net/dsa.h>
+#include <dm/test.h>
+#include <test/ut.h>
+#include <net.h>
+#include <dm/uclass-internal.h>
+#include <dm/device-internal.h>
+
+/* This test exercises the major dsa.h API functions, after making sure
+ * that the DSA ports and the master Eth are correctly probed.
+ */
+static int dm_test_dsa_probe(struct unit_test_state *uts)
+{
+	struct udevice *dev_dsa, *dev_port, *dev_master;
+	struct dsa_pdata *dsa_pdata;
+	enum uclass_id id;
+
+	id = uclass_get_by_name("dsa");
+	ut_assert(id == UCLASS_DSA);
+
+	ut_assertok(uclass_find_device_by_name(UCLASS_DSA, "dsa-test",
+					       &dev_dsa));
+	ut_assertok(uclass_find_device_by_name(UCLASS_ETH, "dsa-test-eth",
+					       &dev_master));
+	ut_assertok(device_probe(dev_master));
+
+	ut_assertok(uclass_find_device_by_name(UCLASS_ETH, "dsa-test at 0",
+					       &dev_port));
+	ut_assertok(device_probe(dev_port));
+
+	ut_assertok(uclass_find_device_by_name(UCLASS_ETH, "dsa-test at 1",
+					       &dev_port));
+	ut_assertok(device_probe(dev_port));
+
+	/* exercise DSA API */
+	dsa_pdata = dev_get_uclass_plat(dev_dsa);
+	ut_assertnonnull(dsa_pdata);
+	/* includes CPU port */
+	ut_assert(dsa_pdata->num_ports == 3);
+
+	ut_assertok(uclass_find_device_by_name(UCLASS_ETH, "lan0",
+					       &dev_port));
+	ut_assertok(device_probe(dev_port));
+
+	ut_assertok(uclass_find_device_by_name(UCLASS_ETH, "lan1",
+					       &dev_port));
+	ut_assertok(device_probe(dev_port));
+
+	dev_master = dsa_get_master(dev_dsa);
+	ut_assertnonnull(dev_master);
+	ut_asserteq_str("dsa-test-eth", dev_master->name);
+
+	return 0;
+}
+
+DM_TEST(dm_test_dsa_probe, UT_TESTF_SCAN_FDT);
+
+/* This test sends ping requests with the local address through each DSA port
+ * via the sandbox DSA master Eth.
+ */
+static int dm_test_dsa(struct unit_test_state *uts)
+{
+	net_ping_ip = string_to_ip("1.2.3.5");
+
+	env_set("ethact", "eth2");
+	ut_assertok(net_loop(PING));
+
+	env_set("ethact", "lan0");
+	ut_assertok(net_loop(PING));
+	env_set("ethact", "lan1");
+	ut_assertok(net_loop(PING));
+
+	env_set("ethact", "");
+
+	return 0;
+}
+
+DM_TEST(dm_test_dsa, UT_TESTF_SCAN_FDT);
diff --git a/test/dm/eth.c b/test/dm/eth.c
index fa8a69da70..e4ee695610 100644
--- a/test/dm/eth.c
+++ b/test/dm/eth.c
@@ -53,8 +53,8 @@ static int dm_test_eth_alias(struct unit_test_state *uts)
 	ut_assertok(net_loop(PING));
 	ut_asserteq_str("eth at 10004000", env_get("ethact"));
 
-	/* Expected to fail since eth2 is not defined in the device tree */
-	env_set("ethact", "eth2");
+	/* Expected to fail since eth1 is not defined in the device tree */
+	env_set("ethact", "eth1");
 	ut_assertok(net_loop(PING));
 	ut_asserteq_str("eth at 10002000", env_get("ethact"));
 
@@ -227,7 +227,7 @@ static int _dm_test_net_retry(struct unit_test_state *uts)
 	 * the active device should be eth0
 	 */
 	sandbox_eth_disable_response(1, true);
-	env_set("ethact", "eth at 10004000");
+	env_set("ethact", "lan1");
 	env_set("netretry", "yes");
 	sandbox_eth_skip_timeout();
 	ut_assertok(net_loop(PING));
@@ -237,11 +237,11 @@ static int _dm_test_net_retry(struct unit_test_state *uts)
 	 * eth1 is disabled and netretry is no, so the ping should fail and the
 	 * active device should be eth1
 	 */
-	env_set("ethact", "eth at 10004000");
+	env_set("ethact", "lan1");
 	env_set("netretry", "no");
 	sandbox_eth_skip_timeout();
 	ut_asserteq(-ENONET, net_loop(PING));
-	ut_asserteq_str("eth at 10004000", env_get("ethact"));
+	ut_asserteq_str("lan1", env_get("ethact"));
 
 	return 0;
 }
-- 
2.25.1



More information about the U-Boot mailing list