Commit dfbc0f6ed175457625dfcc46af527b7bd10ed025
Committed by
Priyanka Jain
1 parent
dd38c33361
Exists in
smarc_8mq_lf_v2020.04
and in
4 other branches
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
drivers/net/Kconfig
... | ... | @@ -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
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 | +}; |