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