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