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