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