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