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