blob: d453cc6930e442390a458e1db58ca9826206c653 [file] [log] [blame]
Claudiu Manoilfc054d52021-01-25 14:23:53 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019-2021 NXP
4 */
5
6#include <net/dsa.h>
7#include <dm/lists.h>
8#include <dm/device_compat.h>
9#include <dm/device-internal.h>
10#include <dm/uclass-internal.h>
11#include <linux/bitmap.h>
12#include <miiphy.h>
13
14#define DSA_PORT_CHILD_DRV_NAME "dsa-port"
15
16/* per-device internal state structure */
17struct dsa_priv {
18 struct phy_device *cpu_port_fixed_phy;
19 struct udevice *master_dev;
20 int num_ports;
21 u32 cpu_port;
22 int headroom;
23 int tailroom;
24};
25
26/* external API */
27int dsa_set_tagging(struct udevice *dev, ushort headroom, ushort tailroom)
28{
29 struct dsa_priv *priv;
30
Michael Walle108157c2021-02-24 17:40:41 +010031 if (!dev)
32 return -EINVAL;
Claudiu Manoilfc054d52021-01-25 14:23:53 +020033
34 if (headroom + tailroom > DSA_MAX_OVR)
35 return -EINVAL;
36
37 priv = dev_get_uclass_priv(dev);
38
39 if (headroom > 0)
40 priv->headroom = headroom;
41 if (tailroom > 0)
42 priv->tailroom = tailroom;
43
44 return 0;
45}
46
47/* returns the DSA master Ethernet device */
48struct udevice *dsa_get_master(struct udevice *dev)
49{
Michael Walle108157c2021-02-24 17:40:41 +010050 struct dsa_priv *priv;
Claudiu Manoilfc054d52021-01-25 14:23:53 +020051
Michael Walle108157c2021-02-24 17:40:41 +010052 if (!dev)
Claudiu Manoilfc054d52021-01-25 14:23:53 +020053 return NULL;
54
Michael Walle108157c2021-02-24 17:40:41 +010055 priv = dev_get_uclass_priv(dev);
56
Claudiu Manoilfc054d52021-01-25 14:23:53 +020057 return priv->master_dev;
58}
59
60/*
61 * Start the desired port, the CPU port and the master Eth interface.
62 * TODO: if cascaded we may need to _start ports in other switches too
63 */
64static int dsa_port_start(struct udevice *pdev)
65{
66 struct udevice *dev = dev_get_parent(pdev);
67 struct dsa_priv *priv = dev_get_uclass_priv(dev);
68 struct udevice *master = dsa_get_master(dev);
69 struct dsa_ops *ops = dsa_get_ops(dev);
70 int err;
71
Claudiu Manoilfc054d52021-01-25 14:23:53 +020072 if (!master) {
73 dev_err(pdev, "DSA master Ethernet device not found!\n");
74 return -EINVAL;
75 }
76
77 if (ops->port_enable) {
78 struct dsa_port_pdata *port_pdata;
79
80 port_pdata = dev_get_parent_plat(pdev);
81 err = ops->port_enable(dev, port_pdata->index,
82 port_pdata->phy);
83 if (err)
84 return err;
85
86 err = ops->port_enable(dev, priv->cpu_port,
87 priv->cpu_port_fixed_phy);
88 if (err)
89 return err;
90 }
91
92 return eth_get_ops(master)->start(master);
93}
94
95/* Stop the desired port, the CPU port and the master Eth interface */
96static void dsa_port_stop(struct udevice *pdev)
97{
98 struct udevice *dev = dev_get_parent(pdev);
99 struct dsa_priv *priv = dev_get_uclass_priv(dev);
100 struct udevice *master = dsa_get_master(dev);
101 struct dsa_ops *ops = dsa_get_ops(dev);
102
Claudiu Manoilfc054d52021-01-25 14:23:53 +0200103 if (ops->port_disable) {
104 struct dsa_port_pdata *port_pdata;
105
106 port_pdata = dev_get_parent_plat(pdev);
107 ops->port_disable(dev, port_pdata->index, port_pdata->phy);
108 ops->port_disable(dev, priv->cpu_port, NULL);
109 }
110
111 /*
112 * stop master only if it's active, don't probe it otherwise.
113 * Under normal usage it would be active because we're using it, but
114 * during tear-down it may have been removed ahead of us.
115 */
116 if (master && device_active(master))
117 eth_get_ops(master)->stop(master);
118}
119
120/*
121 * Insert a DSA tag and call master Ethernet send on the resulting packet
122 * We copy the frame to a stack buffer where we have reserved headroom and
123 * tailroom space. Headroom and tailroom are set to 0.
124 */
125static int dsa_port_send(struct udevice *pdev, void *packet, int length)
126{
127 struct udevice *dev = dev_get_parent(pdev);
128 struct dsa_priv *priv = dev_get_uclass_priv(dev);
129 int head = priv->headroom, tail = priv->tailroom;
130 struct udevice *master = dsa_get_master(dev);
131 struct dsa_ops *ops = dsa_get_ops(dev);
132 uchar dsa_packet_tmp[PKTSIZE_ALIGN];
133 struct dsa_port_pdata *port_pdata;
134 int err;
135
136 if (!master)
137 return -EINVAL;
138
139 if (length + head + tail > PKTSIZE_ALIGN)
140 return -EINVAL;
141
142 memset(dsa_packet_tmp, 0, head);
143 memset(dsa_packet_tmp + head + length, 0, tail);
144 memcpy(dsa_packet_tmp + head, packet, length);
145 length += head + tail;
146 /* copy back to preserve original buffer alignment */
147 memcpy(packet, dsa_packet_tmp, length);
148
149 port_pdata = dev_get_parent_plat(pdev);
150 err = ops->xmit(dev, port_pdata->index, packet, length);
151 if (err)
152 return err;
153
154 return eth_get_ops(master)->send(master, packet, length);
155}
156
157/* Receive a frame from master Ethernet, process it and pass it on */
158static int dsa_port_recv(struct udevice *pdev, int flags, uchar **packetp)
159{
160 struct udevice *dev = dev_get_parent(pdev);
161 struct dsa_priv *priv = dev_get_uclass_priv(dev);
162 int head = priv->headroom, tail = priv->tailroom;
163 struct udevice *master = dsa_get_master(dev);
164 struct dsa_ops *ops = dsa_get_ops(dev);
165 struct dsa_port_pdata *port_pdata;
166 int length, port_index, err;
167
168 if (!master)
169 return -EINVAL;
170
171 length = eth_get_ops(master)->recv(master, flags, packetp);
172 if (length <= 0)
173 return length;
174
175 /*
176 * If we receive frames from a different port or frames that DSA driver
177 * doesn't like we discard them here.
178 * In case of discard we return with no frame and expect to be called
179 * again instead of looping here, so upper layer can deal with timeouts.
180 */
181 port_pdata = dev_get_parent_plat(pdev);
182 err = ops->rcv(dev, &port_index, *packetp, length);
183 if (err || port_index != port_pdata->index || (length <= head + tail)) {
184 if (eth_get_ops(master)->free_pkt)
185 eth_get_ops(master)->free_pkt(master, *packetp, length);
186 return -EAGAIN;
187 }
188
189 /*
190 * We move the pointer over headroom here to avoid a copy. If free_pkt
191 * gets called we move the pointer back before calling master free_pkt.
192 */
193 *packetp += head;
194
195 return length - head - tail;
196}
197
198static int dsa_port_free_pkt(struct udevice *pdev, uchar *packet, int length)
199{
200 struct udevice *dev = dev_get_parent(pdev);
201 struct udevice *master = dsa_get_master(dev);
202 struct dsa_priv *priv;
203
204 if (!master)
205 return -EINVAL;
206
207 priv = dev_get_uclass_priv(dev);
208 if (eth_get_ops(master)->free_pkt) {
209 /* return the original pointer and length to master Eth */
210 packet -= priv->headroom;
211 length += priv->headroom - priv->tailroom;
212
213 return eth_get_ops(master)->free_pkt(master, packet, length);
214 }
215
216 return 0;
217}
218
219static int dsa_port_of_to_pdata(struct udevice *pdev)
220{
221 struct dsa_port_pdata *port_pdata;
222 struct dsa_pdata *dsa_pdata;
223 struct eth_pdata *eth_pdata;
224 struct udevice *dev;
225 const char *label;
226 u32 index;
227 int err;
228
229 if (!pdev)
230 return -ENODEV;
231
232 err = ofnode_read_u32(dev_ofnode(pdev), "reg", &index);
233 if (err)
234 return err;
235
236 dev = dev_get_parent(pdev);
237 dsa_pdata = dev_get_uclass_plat(dev);
238
239 port_pdata = dev_get_parent_plat(pdev);
240 port_pdata->index = index;
241
242 label = ofnode_read_string(dev_ofnode(pdev), "label");
243 if (label)
244 strncpy(port_pdata->name, label, DSA_PORT_NAME_LENGTH);
245
246 eth_pdata = dev_get_plat(pdev);
247 eth_pdata->priv_pdata = port_pdata;
248
249 dev_dbg(pdev, "port %d node %s\n", port_pdata->index,
250 ofnode_get_name(dev_ofnode(pdev)));
251
252 return 0;
253}
254
255static const struct eth_ops dsa_port_ops = {
256 .start = dsa_port_start,
257 .send = dsa_port_send,
258 .recv = dsa_port_recv,
259 .stop = dsa_port_stop,
260 .free_pkt = dsa_port_free_pkt,
261};
262
263static int dsa_port_probe(struct udevice *pdev)
264{
265 struct udevice *dev = dev_get_parent(pdev);
266 struct eth_pdata *eth_pdata, *master_pdata;
267 unsigned char env_enetaddr[ARP_HLEN];
268 struct dsa_port_pdata *port_pdata;
269 struct dsa_priv *dsa_priv;
270 struct udevice *master;
Michael Wallee5d7d112021-02-24 17:40:40 +0100271 int ret;
Claudiu Manoilfc054d52021-01-25 14:23:53 +0200272
273 port_pdata = dev_get_parent_plat(pdev);
274 dsa_priv = dev_get_uclass_priv(dev);
275
276 port_pdata->phy = dm_eth_phy_connect(pdev);
277 if (!port_pdata->phy)
278 return -ENODEV;
279
Michael Wallea02dcbb2021-02-24 17:40:39 +0100280 master = dsa_get_master(dev);
281 if (!master)
282 return -ENODEV;
283
Claudiu Manoilfc054d52021-01-25 14:23:53 +0200284 /*
Michael Wallee5d7d112021-02-24 17:40:40 +0100285 * Probe the master device. We depend on the master device for proper
286 * operation and we also need it for MAC inheritance below.
287 */
288 ret = device_probe(master);
289 if (ret)
290 return ret;
291
292 /*
Claudiu Manoilfc054d52021-01-25 14:23:53 +0200293 * Inherit port's hwaddr from the DSA master, unless the port already
294 * has a unique MAC address specified in the environment.
295 */
296 eth_env_get_enetaddr_by_index("eth", dev_seq(pdev), env_enetaddr);
297 if (!is_zero_ethaddr(env_enetaddr))
298 return 0;
299
Claudiu Manoilfc054d52021-01-25 14:23:53 +0200300 master_pdata = dev_get_plat(master);
301 eth_pdata = dev_get_plat(pdev);
302 memcpy(eth_pdata->enetaddr, master_pdata->enetaddr, ARP_HLEN);
303 eth_env_set_enetaddr_by_index("eth", dev_seq(pdev),
304 master_pdata->enetaddr);
305
306 return 0;
307}
308
309static int dsa_port_remove(struct udevice *pdev)
310{
311 struct udevice *dev = dev_get_parent(pdev);
312 struct dsa_port_pdata *port_pdata;
313 struct dsa_priv *dsa_priv;
314
315 port_pdata = dev_get_parent_plat(pdev);
316 dsa_priv = dev_get_uclass_priv(dev);
317
318 port_pdata->phy = NULL;
319
320 return 0;
321}
322
323U_BOOT_DRIVER(dsa_port) = {
324 .name = DSA_PORT_CHILD_DRV_NAME,
325 .id = UCLASS_ETH,
326 .ops = &dsa_port_ops,
327 .probe = dsa_port_probe,
328 .remove = dsa_port_remove,
329 .of_to_plat = dsa_port_of_to_pdata,
330 .plat_auto = sizeof(struct eth_pdata),
331};
332
333/*
334 * This function mostly deals with pulling information out of the device tree
335 * into the pdata structure.
336 * It goes through the list of switch ports, registers an eth device for each
337 * front panel port and identifies the cpu port connected to master eth device.
338 * TODO: support cascaded switches
339 */
340static int dsa_post_bind(struct udevice *dev)
341{
342 struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
343 ofnode node = dev_ofnode(dev), pnode;
344 int i, err, first_err = 0;
345
Michael Walle108157c2021-02-24 17:40:41 +0100346 if (!ofnode_valid(node))
Claudiu Manoilfc054d52021-01-25 14:23:53 +0200347 return -ENODEV;
348
349 pdata->master_node = ofnode_null();
350
351 node = ofnode_find_subnode(node, "ports");
352 if (!ofnode_valid(node))
353 node = ofnode_find_subnode(node, "ethernet-ports");
354 if (!ofnode_valid(node)) {
355 dev_err(dev, "ports node is missing under DSA device!\n");
356 return -EINVAL;
357 }
358
359 pdata->num_ports = ofnode_get_child_count(node);
360 if (pdata->num_ports <= 0 || pdata->num_ports > DSA_MAX_PORTS) {
361 dev_err(dev, "invalid number of ports (%d)\n",
362 pdata->num_ports);
363 return -EINVAL;
364 }
365
366 /* look for the CPU port */
367 ofnode_for_each_subnode(pnode, node) {
368 u32 ethernet;
369
370 if (ofnode_read_u32(pnode, "ethernet", &ethernet))
371 continue;
372
373 pdata->master_node = ofnode_get_by_phandle(ethernet);
374 pdata->cpu_port_node = pnode;
375 break;
376 }
377
378 if (!ofnode_valid(pdata->master_node)) {
379 dev_err(dev, "master eth node missing!\n");
380 return -EINVAL;
381 }
382
383 if (ofnode_read_u32(pnode, "reg", &pdata->cpu_port)) {
384 dev_err(dev, "CPU port node not valid!\n");
385 return -EINVAL;
386 }
387
388 dev_dbg(dev, "master node %s on port %d\n",
389 ofnode_get_name(pdata->master_node), pdata->cpu_port);
390
391 for (i = 0; i < pdata->num_ports; i++) {
392 char name[DSA_PORT_NAME_LENGTH];
393 struct udevice *pdev;
394
395 /*
396 * If this is the CPU port don't register it as an ETH device,
397 * we skip it on purpose since I/O to/from it from the CPU
398 * isn't useful.
399 */
400 if (i == pdata->cpu_port)
401 continue;
402
403 /*
404 * Set up default port names. If present, DT port labels
405 * will override the default port names.
406 */
407 snprintf(name, DSA_PORT_NAME_LENGTH, "%s@%d", dev->name, i);
408
409 ofnode_for_each_subnode(pnode, node) {
410 u32 reg;
411
412 if (ofnode_read_u32(pnode, "reg", &reg))
413 continue;
414
415 if (reg == i)
416 break;
417 }
418
419 /*
420 * skip registration if port id not found or if the port
421 * is explicitly disabled in DT
422 */
423 if (!ofnode_valid(pnode) || !ofnode_is_available(pnode))
424 continue;
425
426 err = device_bind_driver_to_node(dev, DSA_PORT_CHILD_DRV_NAME,
427 name, pnode, &pdev);
428 if (pdev) {
429 struct dsa_port_pdata *port_pdata;
430
431 port_pdata = dev_get_parent_plat(pdev);
432 strncpy(port_pdata->name, name, DSA_PORT_NAME_LENGTH);
433 pdev->name = port_pdata->name;
434 }
435
436 /* try to bind all ports but keep 1st error */
437 if (err && !first_err)
438 first_err = err;
439 }
440
441 if (first_err)
442 return first_err;
443
444 dev_dbg(dev, "DSA ports successfully bound\n");
445
446 return 0;
447}
448
449/**
450 * Initialize the uclass per device internal state structure (priv).
451 * TODO: pick up references to other switch devices here, if we're cascaded.
452 */
453static int dsa_pre_probe(struct udevice *dev)
454{
455 struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
456 struct dsa_priv *priv = dev_get_uclass_priv(dev);
457
Claudiu Manoilfc054d52021-01-25 14:23:53 +0200458 priv->num_ports = pdata->num_ports;
459 priv->cpu_port = pdata->cpu_port;
460 priv->cpu_port_fixed_phy = fixed_phy_create(pdata->cpu_port_node);
461 if (!priv->cpu_port_fixed_phy) {
462 dev_err(dev, "Failed to register fixed-link for CPU port\n");
463 return -ENODEV;
464 }
465
466 uclass_find_device_by_ofnode(UCLASS_ETH, pdata->master_node,
467 &priv->master_dev);
468 return 0;
469}
470
471UCLASS_DRIVER(dsa) = {
472 .id = UCLASS_DSA,
473 .name = "dsa",
474 .post_bind = dsa_post_bind,
475 .pre_probe = dsa_pre_probe,
476 .per_device_auto = sizeof(struct dsa_priv),
477 .per_device_plat_auto = sizeof(struct dsa_pdata),
478 .per_child_plat_auto = sizeof(struct dsa_port_pdata),
479 .flags = DM_UC_FLAG_SEQ_ALIAS,
480};