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