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