Commit dfbc0f6ed175457625dfcc46af527b7bd10ed025

Authored by Alex Marginean
Committed by Priyanka Jain
1 parent dd38c33361

drivers: net: add a DSA sandbox driver

The DSA sandbox driver is used for DSA unit testing.  It implements a
simple 4 port switch that uses a very simple tag to identify the ports.
The DSA driver comes paired with an Ethernet driver that loops packets
back and can selectively filter traffic on DSA switch ports.

Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>

Showing 3 changed files with 281 additions and 0 deletions Side-by-side Diff

... ... @@ -70,6 +70,14 @@
70 70  
71 71 This driver is used for testing in test/dm/mdio.c
72 72  
  73 +config DSA_SANDBOX
  74 + depends on DM_DSA && SANDBOX
  75 + default y
  76 + bool "Sandbox: Mocked DSA driver"
  77 + help
  78 + This driver implements a dummy switch and a dummy Ethernet device used
  79 + to test DSA class code.
  80 +
73 81 menuconfig NETDEVICES
74 82 bool "Network device support"
75 83 depends on NET
drivers/net/Makefile
... ... @@ -83,4 +83,5 @@
83 83 obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
84 84 obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
85 85 obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
  86 +obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
drivers/net/dsa_sandbox.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Copyright 2019-2020 NXP
  4 + */
  5 +
  6 +#include <net/dsa.h>
  7 +
  8 +#define DSA_SANDBOX_MAGIC 0x00415344
  9 +#define DSA_SANDBOX_TAG_LEN sizeof(struct dsa_sandbox_tag)
  10 +/*
  11 + * This global flag is used to enable DSA just for DSA test so it doesn't affect
  12 + * the existing eth unit test.
  13 + */
  14 +int dsa_sandbox_port_mask;
  15 +
  16 +struct dsa_sandbox_priv {
  17 + int enabled;
  18 + int port_enabled;
  19 +};
  20 +
  21 +struct dsa_sandbox_tag {
  22 + u32 magic;
  23 + u32 port;
  24 +};
  25 +
  26 +static int dsa_sandbox_port_enable(struct udevice *dev, int port,
  27 + struct phy_device *phy)
  28 +{
  29 + struct dsa_sandbox_priv *priv = dev->priv;
  30 +
  31 + if (!priv->enabled)
  32 + return -EFAULT;
  33 +
  34 + priv->port_enabled |= BIT(port);
  35 +
  36 + return 0;
  37 +}
  38 +
  39 +static void dsa_sandbox_port_disable(struct udevice *dev, int port,
  40 + struct phy_device *phy)
  41 +{
  42 + struct dsa_sandbox_priv *priv = dev->priv;
  43 +
  44 + if (!priv->enabled)
  45 + return;
  46 +
  47 + priv->port_enabled &= ~BIT(port);
  48 +}
  49 +
  50 +static int dsa_sandbox_xmit(struct udevice *dev, int port, void *packet,
  51 + int length)
  52 +{
  53 + struct dsa_sandbox_priv *priv = dev->priv;
  54 + struct dsa_sandbox_tag *tag = packet;
  55 +
  56 + if (!priv->enabled)
  57 + return -EFAULT;
  58 +
  59 + if (!(priv->port_enabled & BIT(port)))
  60 + return -EFAULT;
  61 +
  62 + tag->magic = DSA_SANDBOX_MAGIC;
  63 + tag->port = port;
  64 +
  65 + return 0;
  66 +}
  67 +
  68 +static int dsa_sandbox_rcv(struct udevice *dev, int *port, void *packet,
  69 + int length)
  70 +{
  71 + struct dsa_sandbox_priv *priv = dev->priv;
  72 + struct dsa_sandbox_tag *tag = packet;
  73 +
  74 + if (!priv->enabled)
  75 + return -EFAULT;
  76 +
  77 + if (tag->magic != DSA_SANDBOX_MAGIC)
  78 + return -EFAULT;
  79 +
  80 + *port = tag->port;
  81 + if (!(priv->port_enabled & BIT(*port)))
  82 + return -EFAULT;
  83 +
  84 + return 0;
  85 +}
  86 +
  87 +static const struct dsa_ops dsa_sandbox_ops = {
  88 + .port_enable = dsa_sandbox_port_enable,
  89 + .port_disable = dsa_sandbox_port_disable,
  90 + .xmit = dsa_sandbox_xmit,
  91 + .rcv = dsa_sandbox_rcv,
  92 +};
  93 +
  94 +static int dsa_sandbox_bind(struct udevice *dev)
  95 +{
  96 + struct dsa_perdev_platdata *pdata = dev->platdata;
  97 +
  98 + /* must be at least 4 to match sandbox test DT */
  99 + pdata->num_ports = 4;
  100 + pdata->headroom = DSA_SANDBOX_TAG_LEN;
  101 +
  102 + return 0;
  103 +}
  104 +
  105 +static int dsa_sandbox_probe(struct udevice *dev)
  106 +{
  107 + struct dsa_sandbox_priv *priv = dev_get_priv(dev);
  108 +
  109 + /*
  110 + * return error if DSA is not being tested so we don't break existing
  111 + * eth test.
  112 + */
  113 + if (!dsa_sandbox_port_mask)
  114 + return -EINVAL;
  115 +
  116 + priv->enabled = 1;
  117 +
  118 + return 0;
  119 +}
  120 +
  121 +static int dsa_sandbox_remove(struct udevice *dev)
  122 +{
  123 + struct dsa_sandbox_priv *priv = dev_get_priv(dev);
  124 +
  125 + priv->enabled = 0;
  126 +
  127 + return 0;
  128 +}
  129 +
  130 +static const struct udevice_id dsa_sandbox_ids[] = {
  131 + { .compatible = "sandbox,dsa" },
  132 + { }
  133 +};
  134 +
  135 +U_BOOT_DRIVER(dsa_sandbox) = {
  136 + .name = "dsa_sandbox",
  137 + .id = UCLASS_DSA,
  138 + .of_match = dsa_sandbox_ids,
  139 + .bind = dsa_sandbox_bind,
  140 + .probe = dsa_sandbox_probe,
  141 + .remove = dsa_sandbox_remove,
  142 + .ops = &dsa_sandbox_ops,
  143 + .priv_auto_alloc_size = sizeof(struct dsa_sandbox_priv),
  144 + .platdata_auto_alloc_size = sizeof(struct dsa_perdev_platdata),
  145 +};
  146 +
  147 +struct dsa_sandbox_eth_priv {
  148 + int enabled;
  149 + int started;
  150 + int packet_length;
  151 + uchar packet[PKTSIZE_ALIGN];
  152 +};
  153 +
  154 +static int dsa_eth_sandbox_start(struct udevice *dev)
  155 +{
  156 + struct dsa_sandbox_eth_priv *priv = dev->priv;
  157 +
  158 + if (!priv->enabled)
  159 + return -EFAULT;
  160 +
  161 + priv->started = 1;
  162 +
  163 + return 0;
  164 +}
  165 +
  166 +static void dsa_eth_sandbox_stop(struct udevice *dev)
  167 +{
  168 + struct dsa_sandbox_eth_priv *priv = dev->priv;
  169 +
  170 + if (!priv->enabled)
  171 + return;
  172 +
  173 + priv->started = 0;
  174 +}
  175 +
  176 +static int dsa_eth_sandbox_send(struct udevice *dev, void *packet, int length)
  177 +{
  178 + struct dsa_sandbox_eth_priv *priv = dev->priv;
  179 + struct dsa_sandbox_tag *tag = packet;
  180 +
  181 + if (!priv->enabled || !priv->started)
  182 + return -EFAULT;
  183 +
  184 + memcpy(priv->packet, packet, length);
  185 + priv->packet_length = length;
  186 +
  187 + /*
  188 + * for DSA test frames we only respond if the associated port is enabled
  189 + * in the dsa test port mask
  190 + */
  191 +
  192 + if (tag->magic == DSA_SANDBOX_MAGIC) {
  193 + int port = tag->port;
  194 +
  195 + if (!(dsa_sandbox_port_mask & BIT(port)))
  196 + /* drop the frame, port is not enabled */
  197 + priv->packet_length = 0;
  198 + }
  199 +
  200 + return 0;
  201 +}
  202 +
  203 +static int dsa_eth_sandbox_recv(struct udevice *dev, int flags, uchar **packetp)
  204 +{
  205 + struct dsa_sandbox_eth_priv *priv = dev->priv;
  206 + int length = priv->packet_length;
  207 +
  208 + if (!priv->enabled || !priv->started)
  209 + return -EFAULT;
  210 +
  211 + if (!length) {
  212 + /* no frames pending, force a time-out */
  213 + timer_test_add_offset(100);
  214 + return -EAGAIN;
  215 + }
  216 +
  217 + *packetp = priv->packet;
  218 + priv->packet_length = 0;
  219 +
  220 + return length;
  221 +}
  222 +
  223 +static const struct eth_ops dsa_eth_sandbox_ops = {
  224 + .start = dsa_eth_sandbox_start,
  225 + .send = dsa_eth_sandbox_send,
  226 + .recv = dsa_eth_sandbox_recv,
  227 + .stop = dsa_eth_sandbox_stop,
  228 +};
  229 +
  230 +static int dsa_eth_sandbox_bind(struct udevice *dev)
  231 +{
  232 + return 0;
  233 +}
  234 +
  235 +static int dsa_eth_sandbox_probe(struct udevice *dev)
  236 +{
  237 + struct dsa_sandbox_eth_priv *priv = dev->priv;
  238 +
  239 + priv->enabled = 1;
  240 +
  241 + /*
  242 + * return error if DSA is not being tested do we don't break existing
  243 + * eth test.
  244 + */
  245 + return dsa_sandbox_port_mask ? 0 : -EINVAL;
  246 +}
  247 +
  248 +static int dsa_eth_sandbox_remove(struct udevice *dev)
  249 +{
  250 + struct dsa_sandbox_eth_priv *priv = dev->priv;
  251 +
  252 + priv->enabled = 0;
  253 +
  254 + return 0;
  255 +}
  256 +
  257 +static const struct udevice_id dsa_eth_sandbox_ids[] = {
  258 + { .compatible = "sandbox,dsa-eth" },
  259 + { }
  260 +};
  261 +
  262 +U_BOOT_DRIVER(dsa_eth_sandbox) = {
  263 + .name = "dsa_eth_sandbox",
  264 + .id = UCLASS_ETH,
  265 + .of_match = dsa_eth_sandbox_ids,
  266 + .bind = dsa_eth_sandbox_bind,
  267 + .probe = dsa_eth_sandbox_probe,
  268 + .remove = dsa_eth_sandbox_remove,
  269 + .ops = &dsa_eth_sandbox_ops,
  270 + .platdata_auto_alloc_size = sizeof(struct eth_pdata),
  271 + .priv_auto_alloc_size = sizeof(struct dsa_sandbox_eth_priv),
  272 +};