1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2021 Alstom Group.
5 * Copyright (c) 2021 Semihalf.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/bus.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/socket.h>
34 #include <sys/sockio.h>
35 #include <sys/sysctl.h>
36 #include <sys/rman.h>
37
38 #include <machine/bus.h>
39 #include <machine/resource.h>
40
41 #include <net/if.h>
42 #include <net/if_media.h>
43 #include <net/if_types.h>
44
45 #include <dev/enetc/enetc_mdio.h>
46
47 #include <dev/etherswitch/etherswitch.h>
48 #include <dev/mii/mii.h>
49 #include <dev/mii/miivar.h>
50 #include <dev/pci/pcireg.h>
51 #include <dev/pci/pcivar.h>
52
53 #include <dev/ofw/ofw_bus.h>
54 #include <dev/ofw/ofw_bus_subr.h>
55
56 #include <dev/etherswitch/felix/felix_var.h>
57 #include <dev/etherswitch/felix/felix_reg.h>
58
59 #include "etherswitch_if.h"
60 #include "miibus_if.h"
61
62 MALLOC_DECLARE(M_FELIX);
63 MALLOC_DEFINE(M_FELIX, "felix", "felix switch");
64
65 static device_probe_t felix_probe;
66 static device_attach_t felix_attach;
67 static device_detach_t felix_detach;
68
69 static etherswitch_info_t* felix_getinfo(device_t);
70 static int felix_getconf(device_t, etherswitch_conf_t *);
71 static int felix_setconf(device_t, etherswitch_conf_t *);
72 static void felix_lock(device_t);
73 static void felix_unlock(device_t);
74 static int felix_getport(device_t, etherswitch_port_t *);
75 static int felix_setport(device_t, etherswitch_port_t *);
76 static int felix_readreg_wrapper(device_t, int);
77 static int felix_writereg_wrapper(device_t, int, int);
78 static int felix_readphy(device_t, int, int);
79 static int felix_writephy(device_t, int, int, int);
80 static int felix_setvgroup(device_t, etherswitch_vlangroup_t *);
81 static int felix_getvgroup(device_t, etherswitch_vlangroup_t *);
82
83 static int felix_parse_port_fdt(felix_softc_t, phandle_t, int *);
84 static int felix_setup(felix_softc_t);
85 static void felix_setup_port(felix_softc_t, int);
86
87 static void felix_tick(void *);
88 static int felix_ifmedia_upd(if_t);
89 static void felix_ifmedia_sts(if_t, struct ifmediareq *);
90
91 static void felix_get_port_cfg(felix_softc_t, etherswitch_port_t *);
92 static void felix_set_port_cfg(felix_softc_t, etherswitch_port_t *);
93
94 static bool felix_is_phyport(felix_softc_t, int);
95 static struct mii_data *felix_miiforport(felix_softc_t, unsigned int);
96
97 static struct felix_pci_id felix_pci_ids[] = {
98 {PCI_VENDOR_FREESCALE, FELIX_DEV_ID, FELIX_DEV_NAME},
99 {0, 0, NULL}
100 };
101
102 static device_method_t felix_methods[] = {
103 /* device interface */
104 DEVMETHOD(device_probe, felix_probe),
105 DEVMETHOD(device_attach, felix_attach),
106 DEVMETHOD(device_detach, felix_detach),
107
108 /* bus interface */
109 DEVMETHOD(bus_add_child, device_add_child_ordered),
110 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
111 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
112 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
113 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
114 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
115 DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
116 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
117
118 /* etherswitch interface */
119 DEVMETHOD(etherswitch_getinfo, felix_getinfo),
120 DEVMETHOD(etherswitch_getconf, felix_getconf),
121 DEVMETHOD(etherswitch_setconf, felix_setconf),
122 DEVMETHOD(etherswitch_lock, felix_lock),
123 DEVMETHOD(etherswitch_unlock, felix_unlock),
124 DEVMETHOD(etherswitch_getport, felix_getport),
125 DEVMETHOD(etherswitch_setport, felix_setport),
126 DEVMETHOD(etherswitch_readreg, felix_readreg_wrapper),
127 DEVMETHOD(etherswitch_writereg, felix_writereg_wrapper),
128 DEVMETHOD(etherswitch_readphyreg, felix_readphy),
129 DEVMETHOD(etherswitch_writephyreg, felix_writephy),
130 DEVMETHOD(etherswitch_setvgroup, felix_setvgroup),
131 DEVMETHOD(etherswitch_getvgroup, felix_getvgroup),
132
133 /* miibus interface */
134 DEVMETHOD(miibus_readreg, felix_readphy),
135 DEVMETHOD(miibus_writereg, felix_writephy),
136
137 DEVMETHOD_END
138 };
139
140 DEFINE_CLASS_0(felix, felix_driver, felix_methods,
141 sizeof(struct felix_softc));
142
143 DRIVER_MODULE_ORDERED(felix, pci, felix_driver, NULL, NULL, SI_ORDER_ANY);
144 DRIVER_MODULE(miibus, felix, miibus_fdt_driver, NULL, NULL);
145 DRIVER_MODULE(etherswitch, felix, etherswitch_driver, NULL, NULL);
146 MODULE_VERSION(felix, 1);
147 MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, felix,
148 felix_pci_ids, nitems(felix_pci_ids) - 1);
149
150 static int
felix_probe(device_t dev)151 felix_probe(device_t dev)
152 {
153 struct felix_pci_id *id;
154 felix_softc_t sc;
155
156 sc = device_get_softc(dev);
157 sc->dev = dev;
158
159 for (id = felix_pci_ids; id->vendor != 0; ++id) {
160 if (pci_get_device(dev) != id->device ||
161 pci_get_vendor(dev) != id->vendor)
162 continue;
163
164 device_set_desc(dev, id->desc);
165
166 return (BUS_PROBE_DEFAULT);
167 }
168
169 return (ENXIO);
170 }
171
172 static int
felix_parse_port_fdt(felix_softc_t sc,phandle_t child,int * pport)173 felix_parse_port_fdt(felix_softc_t sc, phandle_t child, int *pport)
174 {
175 uint32_t port, status;
176 phandle_t node;
177
178 if (OF_getencprop(child, "reg", (void *)&port, sizeof(port)) < 0) {
179 device_printf(sc->dev, "Port node doesn't have reg property\n");
180 return (ENXIO);
181 }
182
183 *pport = port;
184
185 node = OF_getproplen(child, "ethernet");
186 if (node <= 0)
187 sc->ports[port].cpu_port = false;
188 else
189 sc->ports[port].cpu_port = true;
190
191 node = ofw_bus_find_child(child, "fixed-link");
192 if (node <= 0) {
193 sc->ports[port].fixed_port = false;
194 return (0);
195 }
196
197 sc->ports[port].fixed_port = true;
198
199 if (OF_getencprop(node, "speed", &status, sizeof(status)) <= 0) {
200 device_printf(sc->dev,
201 "Port has fixed-link node without link speed specified\n");
202 return (ENXIO);
203 }
204
205 switch (status) {
206 case 2500:
207 status = IFM_2500_T;
208 break;
209 case 1000:
210 status = IFM_1000_T;
211 break;
212 case 100:
213 status = IFM_100_T;
214 break;
215 case 10:
216 status = IFM_10_T;
217 break;
218 default:
219 device_printf(sc->dev,
220 "Unsupported link speed value of %d\n",
221 status);
222 return (ENXIO);
223 }
224
225 if (OF_hasprop(node, "full-duplex"))
226 status |= IFM_FDX;
227 else
228 status |= IFM_HDX;
229
230 status |= IFM_ETHER;
231 sc->ports[port].fixed_link_status = status;
232 return (0);
233 }
234
235 static int
felix_init_interface(felix_softc_t sc,int port)236 felix_init_interface(felix_softc_t sc, int port)
237 {
238 char name[IFNAMSIZ];
239
240 snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->dev));
241
242 sc->ports[port].ifp = if_alloc(IFT_ETHER);
243 if (sc->ports[port].ifp == NULL)
244 return (ENOMEM);
245
246 if_setsoftc(sc->ports[port].ifp, sc);
247 if_setflags(sc->ports[port].ifp, IFF_UP | IFF_BROADCAST | IFF_MULTICAST |
248 IFF_DRV_RUNNING | IFF_SIMPLEX);
249 sc->ports[port].ifname = malloc(strlen(name) + 1, M_FELIX, M_NOWAIT);
250 if (sc->ports[port].ifname == NULL) {
251 if_free(sc->ports[port].ifp);
252 return (ENOMEM);
253 }
254
255 memcpy(sc->ports[port].ifname, name, strlen(name) + 1);
256 if_initname(sc->ports[port].ifp, sc->ports[port].ifname, port);
257 return (0);
258 }
259
260 static void
felix_setup_port(felix_softc_t sc,int port)261 felix_setup_port(felix_softc_t sc, int port)
262 {
263
264 /* Link speed has to be always set to 1000 in the clock register. */
265 FELIX_DEVGMII_PORT_WR4(sc, port, FELIX_DEVGMII_CLK_CFG,
266 FELIX_DEVGMII_CLK_CFG_SPEED_1000);
267 FELIX_DEVGMII_PORT_WR4(sc, port, FELIX_DEVGMII_MAC_CFG,
268 FELIX_DEVGMII_MAC_CFG_TX_ENA | FELIX_DEVGMII_MAC_CFG_RX_ENA);
269 FELIX_WR4(sc, FELIX_QSYS_PORT_MODE(port),
270 FELIX_QSYS_PORT_MODE_PORT_ENA);
271
272 /*
273 * Enable "VLANMTU". Each port has a configurable MTU.
274 * Accept frames that are 8 and 4 bytes longer than it
275 * for double and single tagged frames respectively.
276 * Since etherswitch API doesn't provide an option to change
277 * MTU don't touch it for now.
278 */
279 FELIX_DEVGMII_PORT_WR4(sc, port, FELIX_DEVGMII_VLAN_CFG,
280 FELIX_DEVGMII_VLAN_CFG_ENA |
281 FELIX_DEVGMII_VLAN_CFG_LEN_ENA |
282 FELIX_DEVGMII_VLAN_CFG_DOUBLE_ENA);
283 }
284
285 static int
felix_setup(felix_softc_t sc)286 felix_setup(felix_softc_t sc)
287 {
288 int timeout, i;
289 uint32_t reg;
290
291 /* Trigger soft reset, bit is self-clearing, with 5s timeout. */
292 FELIX_WR4(sc, FELIX_DEVCPU_GCB_RST, FELIX_DEVCPU_GCB_RST_EN);
293 timeout = FELIX_INIT_TIMEOUT;
294 do {
295 DELAY(1000);
296 reg = FELIX_RD4(sc, FELIX_DEVCPU_GCB_RST);
297 if ((reg & FELIX_DEVCPU_GCB_RST_EN) == 0)
298 break;
299 } while (timeout-- > 0);
300 if (timeout == 0) {
301 device_printf(sc->dev,
302 "Timeout while waiting for switch to reset\n");
303 return (ETIMEDOUT);
304 }
305
306 FELIX_WR4(sc, FELIX_SYS_RAM_CTRL, FELIX_SYS_RAM_CTRL_INIT);
307 timeout = FELIX_INIT_TIMEOUT;
308 do {
309 DELAY(1000);
310 reg = FELIX_RD4(sc, FELIX_SYS_RAM_CTRL);
311 if ((reg & FELIX_SYS_RAM_CTRL_INIT) == 0)
312 break;
313 } while (timeout-- > 0);
314 if (timeout == 0) {
315 device_printf(sc->dev,
316 "Timeout while waiting for switch RAM init.\n");
317 return (ETIMEDOUT);
318 }
319
320 FELIX_WR4(sc, FELIX_SYS_CFG, FELIX_SYS_CFG_CORE_EN);
321
322 for (i = 0; i < sc->info.es_nports; i++)
323 felix_setup_port(sc, i);
324
325 return (0);
326 }
327
328 static int
felix_timer_rate(SYSCTL_HANDLER_ARGS)329 felix_timer_rate(SYSCTL_HANDLER_ARGS)
330 {
331 felix_softc_t sc;
332 int error, value, old;
333
334 sc = arg1;
335
336 old = value = sc->timer_ticks;
337 error = sysctl_handle_int(oidp, &value, 0, req);
338 if (error != 0 || req->newptr == NULL)
339 return (error);
340
341 if (value < 0)
342 return (EINVAL);
343
344 if (value == old)
345 return (0);
346
347 FELIX_LOCK(sc);
348 sc->timer_ticks = value;
349 callout_reset(&sc->tick_callout, sc->timer_ticks, felix_tick, sc);
350 FELIX_UNLOCK(sc);
351
352 return (0);
353 }
354
355 static int
felix_attach(device_t dev)356 felix_attach(device_t dev)
357 {
358 phandle_t child, ports, node;
359 int error, port, rid;
360 felix_softc_t sc;
361 uint32_t phy_addr;
362 ssize_t size;
363
364 sc = device_get_softc(dev);
365 sc->info.es_nports = 0;
366 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q;
367 strlcpy(sc->info.es_name, "Felix TSN Switch", sizeof(sc->info.es_name));
368
369 rid = PCIR_BAR(FELIX_BAR_MDIO);
370 sc->mdio = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
371 RF_ACTIVE);
372 if (sc->mdio == NULL) {
373 device_printf(dev, "Failed to allocate MDIO registers.\n");
374 return (ENXIO);
375 }
376
377 rid = PCIR_BAR(FELIX_BAR_REGS);
378 sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
379 RF_ACTIVE);
380 if (sc->regs == NULL) {
381 device_printf(dev, "Failed to allocate registers BAR.\n");
382 error = ENXIO;
383 goto out_fail;
384 }
385
386 mtx_init(&sc->mtx, "felix lock", NULL, MTX_DEF);
387 callout_init_mtx(&sc->tick_callout, &sc->mtx, 0);
388
389 node = ofw_bus_get_node(dev);
390 if (node <= 0) {
391 error = ENXIO;
392 goto out_fail;
393 }
394
395 ports = ofw_bus_find_child(node, "ports");
396 if (ports == 0) {
397 device_printf(dev,
398 "Failed to find \"ports\" property in DTS.\n");
399 error = ENXIO;
400 goto out_fail;
401 }
402
403 for (child = OF_child(ports); child != 0; child = OF_peer(child)) {
404 /* Do not parse disabled ports. */
405 if (ofw_bus_node_status_okay(child) == 0)
406 continue;
407
408 error = felix_parse_port_fdt(sc, child, &port);
409 if (error != 0)
410 goto out_fail;
411
412 error = felix_init_interface(sc, port);
413 if (error != 0) {
414 device_printf(sc->dev,
415 "Failed to initialize interface.\n");
416 goto out_fail;
417 }
418
419 if (sc->ports[port].fixed_port) {
420 sc->info.es_nports++;
421 continue;
422 }
423
424 size = OF_getencprop(child, "phy-handle", &node, sizeof(node));
425 if (size <= 0) {
426 device_printf(sc->dev,
427 "Failed to acquire PHY handle from FDT.\n");
428 error = ENXIO;
429 goto out_fail;
430 }
431
432 node = OF_node_from_xref(node);
433 size = OF_getencprop(node, "reg", &phy_addr, sizeof(phy_addr));
434 if (size <= 0) {
435 device_printf(sc->dev,
436 "Failed to obtain PHY address.\n");
437 error = ENXIO;
438 goto out_fail;
439 }
440
441 sc->ports[port].phyaddr = phy_addr;
442 sc->ports[port].miibus = NULL;
443 error = mii_attach(dev, &sc->ports[port].miibus, sc->ports[port].ifp,
444 felix_ifmedia_upd, felix_ifmedia_sts, BMSR_DEFCAPMASK,
445 phy_addr, MII_OFFSET_ANY, 0);
446 if (error != 0)
447 goto out_fail;
448
449 sc->info.es_nports++;
450 }
451
452 error = felix_setup(sc);
453 if (error != 0)
454 goto out_fail;
455
456 sc->timer_ticks = hz; /* Default to 1s. */
457 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
458 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
459 OID_AUTO, "timer_ticks", CTLTYPE_INT | CTLFLAG_RW,
460 sc, 0, felix_timer_rate, "I",
461 "Number of ticks between timer invocations");
462
463 /* The tick routine has to be called with the lock held. */
464 FELIX_LOCK(sc);
465 felix_tick(sc);
466 FELIX_UNLOCK(sc);
467
468 /* Allow etherswitch to attach as our child. */
469 bus_generic_probe(dev);
470 bus_generic_attach(dev);
471
472 return (0);
473
474 out_fail:
475 felix_detach(dev);
476 return (error);
477 }
478
479 static int
felix_detach(device_t dev)480 felix_detach(device_t dev)
481 {
482 felix_softc_t sc;
483 int error;
484 int i;
485
486 error = 0;
487 sc = device_get_softc(dev);
488 bus_generic_detach(dev);
489
490 mtx_lock(&sc->mtx);
491 callout_stop(&sc->tick_callout);
492 mtx_unlock(&sc->mtx);
493 mtx_destroy(&sc->mtx);
494
495 /*
496 * If we have been fully attached do a soft reset.
497 * This way after when driver is unloaded switch is left in unmanaged mode.
498 */
499 if (device_is_attached(dev))
500 felix_setup(sc);
501
502 for (i = 0; i < sc->info.es_nports; i++) {
503 if (sc->ports[i].miibus != NULL)
504 device_delete_child(dev, sc->ports[i].miibus);
505 if (sc->ports[i].ifp != NULL)
506 if_free(sc->ports[i].ifp);
507 if (sc->ports[i].ifname != NULL)
508 free(sc->ports[i].ifname, M_FELIX);
509 }
510
511 if (sc->regs != NULL)
512 error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
513 rman_get_rid(sc->regs), sc->regs);
514
515 if (sc->mdio != NULL)
516 error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
517 rman_get_rid(sc->mdio), sc->mdio);
518
519 return (error);
520 }
521
522 static etherswitch_info_t*
felix_getinfo(device_t dev)523 felix_getinfo(device_t dev)
524 {
525 felix_softc_t sc;
526
527 sc = device_get_softc(dev);
528 return (&sc->info);
529 }
530
531 static int
felix_getconf(device_t dev,etherswitch_conf_t * conf)532 felix_getconf(device_t dev, etherswitch_conf_t *conf)
533 {
534 felix_softc_t sc;
535
536 sc = device_get_softc(dev);
537
538 /* Return the VLAN mode. */
539 conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
540 conf->vlan_mode = sc->vlan_mode;
541 return (0);
542 }
543
544 static int
felix_init_vlan(felix_softc_t sc)545 felix_init_vlan(felix_softc_t sc)
546 {
547 int timeout = FELIX_INIT_TIMEOUT;
548 uint32_t reg;
549 int i;
550
551 /* Flush VLAN table in hardware. */
552 FELIX_WR4(sc, FELIX_ANA_VT, FELIX_ANA_VT_RESET);
553 do {
554 DELAY(1000);
555 reg = FELIX_RD4(sc, FELIX_ANA_VT);
556 if ((reg & FELIX_ANA_VT_STS) == FELIX_ANA_VT_IDLE)
557 break;
558 } while (timeout-- > 0);
559 if (timeout == 0) {
560 device_printf(sc->dev,
561 "Timeout during VLAN table reset.\n");
562 return (ETIMEDOUT);
563 }
564
565 /* Flush VLAN table in sc. */
566 for (i = 0; i < sc->info.es_nvlangroups; i++)
567 sc->vlans[i] = 0;
568
569 /*
570 * Make all ports VLAN aware.
571 * Read VID from incoming frames and use it for port grouping
572 * purposes.
573 * Don't set this if pvid is set.
574 */
575 for (i = 0; i < sc->info.es_nports; i++) {
576 reg = FELIX_ANA_PORT_RD4(sc, i, FELIX_ANA_PORT_VLAN_CFG);
577 if ((reg & FELIX_ANA_PORT_VLAN_CFG_VID_MASK) != 0)
578 continue;
579
580 reg |= FELIX_ANA_PORT_VLAN_CFG_VID_AWARE;
581 FELIX_ANA_PORT_WR4(sc, i, FELIX_ANA_PORT_VLAN_CFG, reg);
582 }
583 return (0);
584 }
585
586 static int
felix_setconf(device_t dev,etherswitch_conf_t * conf)587 felix_setconf(device_t dev, etherswitch_conf_t *conf)
588 {
589 felix_softc_t sc;
590 int error;
591
592 error = 0;
593 /* Set the VLAN mode. */
594 sc = device_get_softc(dev);
595 FELIX_LOCK(sc);
596 if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
597 switch (conf->vlan_mode) {
598 case ETHERSWITCH_VLAN_DOT1Q:
599 sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
600 sc->info.es_nvlangroups = FELIX_NUM_VLANS;
601 error = felix_init_vlan(sc);
602 break;
603 default:
604 error = EINVAL;
605 }
606 }
607 FELIX_UNLOCK(sc);
608 return (error);
609 }
610
611 static void
felix_lock(device_t dev)612 felix_lock(device_t dev)
613 {
614 felix_softc_t sc;
615
616 sc = device_get_softc(dev);
617 FELIX_LOCK_ASSERT(sc, MA_NOTOWNED);
618 FELIX_LOCK(sc);
619 }
620
621 static void
felix_unlock(device_t dev)622 felix_unlock(device_t dev)
623 {
624 felix_softc_t sc;
625
626 sc = device_get_softc(dev);
627 FELIX_LOCK_ASSERT(sc, MA_OWNED);
628 FELIX_UNLOCK(sc);
629 }
630
631 static void
felix_get_port_cfg(felix_softc_t sc,etherswitch_port_t * p)632 felix_get_port_cfg(felix_softc_t sc, etherswitch_port_t *p)
633 {
634 uint32_t reg;
635
636 p->es_flags = 0;
637
638 reg = FELIX_ANA_PORT_RD4(sc, p->es_port, FELIX_ANA_PORT_DROP_CFG);
639 if (reg & FELIX_ANA_PORT_DROP_CFG_TAGGED)
640 p->es_flags |= ETHERSWITCH_PORT_DROPTAGGED;
641
642 if (reg & FELIX_ANA_PORT_DROP_CFG_UNTAGGED)
643 p->es_flags |= ETHERSWITCH_PORT_DROPUNTAGGED;
644
645 reg = FELIX_DEVGMII_PORT_RD4(sc, p->es_port, FELIX_DEVGMII_VLAN_CFG);
646 if (reg & FELIX_DEVGMII_VLAN_CFG_DOUBLE_ENA)
647 p->es_flags |= ETHERSWITCH_PORT_DOUBLE_TAG;
648
649 reg = FELIX_REW_PORT_RD4(sc, p->es_port, FELIX_REW_PORT_TAG_CFG);
650 if (reg & FELIX_REW_PORT_TAG_CFG_ALL)
651 p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
652
653 reg = FELIX_ANA_PORT_RD4(sc, p->es_port, FELIX_ANA_PORT_VLAN_CFG);
654 if (reg & FELIX_ANA_PORT_VLAN_CFG_POP)
655 p->es_flags |= ETHERSWITCH_PORT_STRIPTAGINGRESS;
656
657 p->es_pvid = reg & FELIX_ANA_PORT_VLAN_CFG_VID_MASK;
658 }
659
660 static int
felix_getport(device_t dev,etherswitch_port_t * p)661 felix_getport(device_t dev, etherswitch_port_t *p)
662 {
663 struct ifmediareq *ifmr;
664 struct mii_data *mii;
665 felix_softc_t sc;
666 int error;
667
668 error = 0;
669 sc = device_get_softc(dev);
670 FELIX_LOCK_ASSERT(sc, MA_NOTOWNED);
671
672 if (p->es_port >= sc->info.es_nports || p->es_port < 0)
673 return (EINVAL);
674
675 FELIX_LOCK(sc);
676 felix_get_port_cfg(sc, p);
677 if (sc->ports[p->es_port].fixed_port) {
678 ifmr = &p->es_ifmr;
679 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
680 ifmr->ifm_count = 0;
681 ifmr->ifm_active = sc->ports[p->es_port].fixed_link_status;
682 ifmr->ifm_current = ifmr->ifm_active;
683 ifmr->ifm_mask = 0;
684 } else {
685 mii = felix_miiforport(sc, p->es_port);
686 error = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
687 &mii->mii_media, SIOCGIFMEDIA);
688 }
689 FELIX_UNLOCK(sc);
690 return (error);
691 }
692
693 static void
felix_set_port_cfg(felix_softc_t sc,etherswitch_port_t * p)694 felix_set_port_cfg(felix_softc_t sc, etherswitch_port_t *p)
695 {
696 uint32_t reg;
697
698 reg = FELIX_ANA_PORT_RD4(sc, p->es_port, FELIX_ANA_PORT_DROP_CFG);
699 if (p->es_flags & ETHERSWITCH_PORT_DROPTAGGED)
700 reg |= FELIX_ANA_PORT_DROP_CFG_TAGGED;
701 else
702 reg &= ~FELIX_ANA_PORT_DROP_CFG_TAGGED;
703
704 if (p->es_flags & ETHERSWITCH_PORT_DROPUNTAGGED)
705 reg |= FELIX_ANA_PORT_DROP_CFG_UNTAGGED;
706 else
707 reg &= ~FELIX_ANA_PORT_DROP_CFG_UNTAGGED;
708
709 FELIX_ANA_PORT_WR4(sc, p->es_port, FELIX_ANA_PORT_DROP_CFG, reg);
710
711 reg = FELIX_REW_PORT_RD4(sc, p->es_port, FELIX_REW_PORT_TAG_CFG);
712 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
713 reg |= FELIX_REW_PORT_TAG_CFG_ALL;
714 else
715 reg &= ~FELIX_REW_PORT_TAG_CFG_ALL;
716
717 FELIX_REW_PORT_WR4(sc, p->es_port, FELIX_REW_PORT_TAG_CFG, reg);
718
719 reg = FELIX_ANA_PORT_RD4(sc, p->es_port, FELIX_ANA_PORT_VLAN_CFG);
720 if (p->es_flags & ETHERSWITCH_PORT_STRIPTAGINGRESS)
721 reg |= FELIX_ANA_PORT_VLAN_CFG_POP;
722 else
723 reg &= ~FELIX_ANA_PORT_VLAN_CFG_POP;
724
725 reg &= ~FELIX_ANA_PORT_VLAN_CFG_VID_MASK;
726 reg |= p->es_pvid & FELIX_ANA_PORT_VLAN_CFG_VID_MASK;
727 /*
728 * If port VID is set use it for VLAN classification,
729 * instead of frame VID.
730 * By default the frame tag takes precedence.
731 * Force the switch to ignore it.
732 */
733 if (p->es_pvid != 0)
734 reg &= ~FELIX_ANA_PORT_VLAN_CFG_VID_AWARE;
735 else
736 reg |= FELIX_ANA_PORT_VLAN_CFG_VID_AWARE;
737
738 FELIX_ANA_PORT_WR4(sc, p->es_port, FELIX_ANA_PORT_VLAN_CFG, reg);
739 }
740
741 static int
felix_setport(device_t dev,etherswitch_port_t * p)742 felix_setport(device_t dev, etherswitch_port_t *p)
743 {
744 felix_softc_t sc;
745 struct mii_data *mii;
746 int error;
747
748 error = 0;
749 sc = device_get_softc(dev);
750 FELIX_LOCK_ASSERT(sc, MA_NOTOWNED);
751
752 if (p->es_port >= sc->info.es_nports || p->es_port < 0)
753 return (EINVAL);
754
755 FELIX_LOCK(sc);
756 felix_set_port_cfg(sc, p);
757 if (felix_is_phyport(sc, p->es_port)) {
758 mii = felix_miiforport(sc, p->es_port);
759 error = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media,
760 SIOCSIFMEDIA);
761 }
762 FELIX_UNLOCK(sc);
763
764 return (error);
765 }
766
767 static int
felix_readreg_wrapper(device_t dev,int addr_reg)768 felix_readreg_wrapper(device_t dev, int addr_reg)
769 {
770 felix_softc_t sc;
771
772 sc = device_get_softc(dev);
773 if (addr_reg > rman_get_size(sc->regs))
774 return (UINT32_MAX); /* Can't return errors here. */
775
776 return (FELIX_RD4(sc, addr_reg));
777 }
778
779 static int
felix_writereg_wrapper(device_t dev,int addr_reg,int val)780 felix_writereg_wrapper(device_t dev, int addr_reg, int val)
781 {
782 felix_softc_t sc;
783
784 sc = device_get_softc(dev);
785 if (addr_reg > rman_get_size(sc->regs))
786 return (EINVAL);
787
788 FELIX_WR4(sc, addr_reg, val);
789 return (0);
790 }
791
792 static int
felix_readphy(device_t dev,int phy,int reg)793 felix_readphy(device_t dev, int phy, int reg)
794 {
795 felix_softc_t sc;
796
797 sc = device_get_softc(dev);
798
799 return (enetc_mdio_read(sc->mdio, FELIX_MDIO_BASE, phy, reg));
800 }
801
802 static int
felix_writephy(device_t dev,int phy,int reg,int data)803 felix_writephy(device_t dev, int phy, int reg, int data)
804 {
805 felix_softc_t sc;
806
807 sc = device_get_softc(dev);
808
809 return (enetc_mdio_write(sc->mdio, FELIX_MDIO_BASE, phy, reg, data));
810 }
811
812 static int
felix_set_dot1q_vlan(felix_softc_t sc,etherswitch_vlangroup_t * vg)813 felix_set_dot1q_vlan(felix_softc_t sc, etherswitch_vlangroup_t *vg)
814 {
815 uint32_t reg;
816 int i, vid;
817
818 vid = vg->es_vid & ETHERSWITCH_VID_MASK;
819
820 /* Tagged mode is not supported. */
821 if (vg->es_member_ports != vg->es_untagged_ports)
822 return (EINVAL);
823
824 /*
825 * Hardware support 4096 groups, but we can't do group_id == vid.
826 * Note that hw_group_id == vid.
827 */
828 if (vid == 0) {
829 /* Clear VLAN table entry using old VID. */
830 FELIX_WR4(sc, FELIX_ANA_VTIDX, sc->vlans[vg->es_vlangroup]);
831 FELIX_WR4(sc, FELIX_ANA_VT, FELIX_ANA_VT_WRITE);
832 sc->vlans[vg->es_vlangroup] = 0;
833 return (0);
834 }
835
836 /* The VID is already used in a different group. */
837 for (i = 0; i < sc->info.es_nvlangroups; i++)
838 if (i != vg->es_vlangroup && vid == sc->vlans[i])
839 return (EINVAL);
840
841 /* This group already uses a different VID. */
842 if (sc->vlans[vg->es_vlangroup] != 0 &&
843 sc->vlans[vg->es_vlangroup] != vid)
844 return (EINVAL);
845
846 sc->vlans[vg->es_vlangroup] = vid;
847
848 /* Assign members to the given group. */
849 reg = vg->es_member_ports & FELIX_ANA_VT_PORTMASK_MASK;
850 reg <<= FELIX_ANA_VT_PORTMASK_SHIFT;
851 reg |= FELIX_ANA_VT_WRITE;
852
853 FELIX_WR4(sc, FELIX_ANA_VTIDX, vid);
854 FELIX_WR4(sc, FELIX_ANA_VT, reg);
855
856 /*
857 * According to documentation read and write commands
858 * are instant.
859 * Add a small delay just to be safe.
860 */
861 mb();
862 DELAY(100);
863 reg = FELIX_RD4(sc, FELIX_ANA_VT);
864 if ((reg & FELIX_ANA_VT_STS) != FELIX_ANA_VT_IDLE)
865 return (ENXIO);
866
867 return (0);
868 }
869
870 static int
felix_setvgroup(device_t dev,etherswitch_vlangroup_t * vg)871 felix_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
872 {
873 felix_softc_t sc;
874 int error;
875
876 sc = device_get_softc(dev);
877
878 FELIX_LOCK(sc);
879 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
880 error = felix_set_dot1q_vlan(sc, vg);
881 else
882 error = EINVAL;
883
884 FELIX_UNLOCK(sc);
885 return (error);
886 }
887
888 static int
felix_get_dot1q_vlan(felix_softc_t sc,etherswitch_vlangroup_t * vg)889 felix_get_dot1q_vlan(felix_softc_t sc, etherswitch_vlangroup_t *vg)
890 {
891 uint32_t reg;
892 int vid;
893
894 vid = sc->vlans[vg->es_vlangroup];
895
896 if (vid == 0)
897 return (0);
898
899 FELIX_WR4(sc, FELIX_ANA_VTIDX, vid);
900 FELIX_WR4(sc, FELIX_ANA_VT, FELIX_ANA_VT_READ);
901
902 /*
903 * According to documentation read and write commands
904 * are instant.
905 * Add a small delay just to be safe.
906 */
907 mb();
908 DELAY(100);
909 reg = FELIX_RD4(sc, FELIX_ANA_VT);
910 if ((reg & FELIX_ANA_VT_STS) != FELIX_ANA_VT_IDLE)
911 return (ENXIO);
912
913 reg >>= FELIX_ANA_VT_PORTMASK_SHIFT;
914 reg &= FELIX_ANA_VT_PORTMASK_MASK;
915
916 vg->es_untagged_ports = vg->es_member_ports = reg;
917 vg->es_fid = 0;
918 vg->es_vid = vid | ETHERSWITCH_VID_VALID;
919 return (0);
920 }
921
922 static int
felix_getvgroup(device_t dev,etherswitch_vlangroup_t * vg)923 felix_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
924 {
925 felix_softc_t sc;
926 int error;
927
928 sc = device_get_softc(dev);
929
930 FELIX_LOCK(sc);
931 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
932 error = felix_get_dot1q_vlan(sc, vg);
933 else
934 error = EINVAL;
935
936 FELIX_UNLOCK(sc);
937 return (error);
938 }
939
940 static void
felix_tick(void * arg)941 felix_tick(void *arg)
942 {
943 struct mii_data *mii;
944 felix_softc_t sc;
945 int port;
946
947 sc = arg;
948
949 FELIX_LOCK_ASSERT(sc, MA_OWNED);
950
951 for (port = 0; port < sc->info.es_nports; port++) {
952 if (!felix_is_phyport(sc, port))
953 continue;
954
955 mii = felix_miiforport(sc, port);
956 MPASS(mii != NULL);
957 mii_tick(mii);
958 }
959 if (sc->timer_ticks != 0)
960 callout_reset(&sc->tick_callout, sc->timer_ticks, felix_tick, sc);
961 }
962
963 static int
felix_ifmedia_upd(if_t ifp)964 felix_ifmedia_upd(if_t ifp)
965 {
966 struct mii_data *mii;
967 felix_softc_t sc;
968
969 sc = if_getsoftc(ifp);
970 mii = felix_miiforport(sc, if_getdunit(ifp));
971 if (mii == NULL)
972 return (ENXIO);
973
974 mii_mediachg(mii);
975 return (0);
976 }
977
978 static void
felix_ifmedia_sts(if_t ifp,struct ifmediareq * ifmr)979 felix_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
980 {
981 felix_softc_t sc;
982 struct mii_data *mii;
983
984 sc = if_getsoftc(ifp);
985 mii = felix_miiforport(sc, if_getdunit(ifp));
986 if (mii == NULL)
987 return;
988
989 mii_pollstat(mii);
990 ifmr->ifm_active = mii->mii_media_active;
991 ifmr->ifm_status = mii->mii_media_status;
992 }
993
994 static bool
felix_is_phyport(felix_softc_t sc,int port)995 felix_is_phyport(felix_softc_t sc, int port)
996 {
997
998 return (!sc->ports[port].fixed_port);
999 }
1000
1001 static struct mii_data*
felix_miiforport(felix_softc_t sc,unsigned int port)1002 felix_miiforport(felix_softc_t sc, unsigned int port)
1003 {
1004
1005 if (!felix_is_phyport(sc, port))
1006 return (NULL);
1007
1008 return (device_get_softc(sc->ports[port].miibus));
1009 }
1010