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