xref: /freebsd/sys/dev/etherswitch/e6000sw/e6060sw.c (revision 95ee2897)
1 /*-
2  * Copyright (c) 2016-2017 Hiroki Mori
3  * Copyright (c) 2013 Luiz Otavio O Souza.
4  * Copyright (c) 2011-2012 Stefan Bethke.
5  * Copyright (c) 2012 Adrian Chadd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * This code is Marvell 88E6060 ethernet switch support code on etherswitch
32  * framework.
33  * 88E6060 support is only port vlan support. Not support ingress/egress
34  * trailer.
35  * 88E6065 support is port and dot1q vlan. Also group base tag support.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/bus.h>
40 #include <sys/errno.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/module.h>
45 #include <sys/mutex.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/sysctl.h>
49 #include <sys/systm.h>
50 
51 #include <net/if.h>
52 #include <net/if_var.h>
53 #include <net/ethernet.h>
54 #include <net/if_media.h>
55 #include <net/if_types.h>
56 
57 #include <machine/bus.h>
58 #include <dev/mii/mii.h>
59 #include <dev/mii/miivar.h>
60 #include <dev/mdio/mdio.h>
61 
62 #include <dev/etherswitch/etherswitch.h>
63 
64 #include "mdio_if.h"
65 #include "miibus_if.h"
66 #include "etherswitch_if.h"
67 
68 #define	CORE_REGISTER	0x8
69 #define	SWITCH_ID	3
70 
71 #define	PORT_CONTROL	4
72 #define	ENGRESSFSHIFT	2
73 #define	ENGRESSFMASK	3
74 #define	ENGRESSTAGSHIFT	12
75 #define	ENGRESSTAGMASK	3
76 
77 #define	PORT_VLAN_MAP	6
78 #define	FORCEMAPSHIFT	8
79 #define	FORCEMAPMASK	1
80 
81 #define	PORT_DEFVLAN	7
82 #define	DEFVIDMASK	0xfff
83 #define	DEFPRIMASK	7
84 
85 #define	PORT_CONTROL2	8
86 #define	DOT1QMODESHIFT	10
87 #define	DOT1QMODEMASK	3
88 #define	DOT1QNONE	0
89 #define	DOT1QFALLBACK	1
90 #define	DOT1QCHECK	2
91 #define	DOT1QSECURE	3
92 
93 #define	GLOBAL_REGISTER	0xf
94 
95 #define	VTU_OPERATION	5
96 #define	VTU_VID_REG	6
97 #define	VTU_DATA1_REG	7
98 #define	VTU_DATA2_REG	8
99 #define	VTU_DATA3_REG	9
100 #define	VTU_BUSY	0x8000
101 #define	VTU_FLASH	1
102 #define	VTU_LOAD_PURGE	3
103 #define	VTU_GET_NEXT	4
104 #define	VTU_VIOLATION	7
105 
106 MALLOC_DECLARE(M_E6060SW);
107 MALLOC_DEFINE(M_E6060SW, "e6060sw", "e6060sw data structures");
108 
109 struct e6060sw_softc {
110 	struct mtx	sc_mtx;		/* serialize access to softc */
111 	device_t	sc_dev;
112 	int		vlan_mode;
113 	int		media;		/* cpu port media */
114 	int		cpuport;	/* which PHY is connected to the CPU */
115 	int		phymask;	/* PHYs we manage */
116 	int		numports;	/* number of ports */
117 	int		ifpport[MII_NPHY];
118 	int		*portphy;
119 	char		**ifname;
120 	device_t	**miibus;
121 	if_t *ifp;
122 	struct callout	callout_tick;
123 	etherswitch_info_t	info;
124 	int		smi_offset;
125 	int		sw_model;
126 };
127 
128 /* Switch Identifier DeviceID */
129 
130 #define	E6060		0x60
131 #define	E6063		0x63
132 #define	E6065		0x65
133 
134 #define	E6060SW_LOCK(_sc)			\
135 	    mtx_lock(&(_sc)->sc_mtx)
136 #define	E6060SW_UNLOCK(_sc)			\
137 	    mtx_unlock(&(_sc)->sc_mtx)
138 #define	E6060SW_LOCK_ASSERT(_sc, _what)	\
139 	    mtx_assert(&(_sc)->sc_mtx, (_what))
140 #define	E6060SW_TRYLOCK(_sc)			\
141 	    mtx_trylock(&(_sc)->sc_mtx)
142 
143 #if defined(DEBUG)
144 #define	DPRINTF(dev, args...) device_printf(dev, args)
145 #else
146 #define	DPRINTF(dev, args...)
147 #endif
148 
149 static inline int e6060sw_portforphy(struct e6060sw_softc *, int);
150 static void e6060sw_tick(void *);
151 static int e6060sw_ifmedia_upd(if_t);
152 static void e6060sw_ifmedia_sts(if_t, struct ifmediareq *);
153 
154 static void e6060sw_setup(device_t dev);
155 static int e6060sw_read_vtu(device_t dev, int num, int *data1, int *data2);
156 static void e6060sw_set_vtu(device_t dev, int num, int data1, int data2);
157 
158 static int
e6060sw_probe(device_t dev)159 e6060sw_probe(device_t dev)
160 {
161 	int data;
162 	struct e6060sw_softc *sc;
163 	int devid, i;
164 	char *devname;
165 	char desc[80];
166 
167 	sc = device_get_softc(dev);
168 	bzero(sc, sizeof(*sc));
169 
170 	devid = 0;
171 	for (i = 0; i < 2; ++i) {
172 		data = MDIO_READREG(device_get_parent(dev),
173 		    CORE_REGISTER + i * 0x10, SWITCH_ID);
174 		if (bootverbose)
175 			device_printf(dev,"Switch Identifier Register %x\n",
176 			    data);
177 
178 		devid = data >> 4;
179 		if (devid == E6060 ||
180 		    devid == E6063 || devid == E6065) {
181 			sc->sw_model = devid;
182 			sc->smi_offset = i * 0x10;
183 			break;
184 		}
185 	}
186 
187 	if (devid == E6060)
188 		devname = "88E6060";
189 	else if (devid == E6063)
190 		devname = "88E6063";
191 	else if (devid == E6065)
192 		devname = "88E6065";
193 	else
194 		return (ENXIO);
195 
196 	sprintf(desc, "Marvell %s MDIO switch driver at 0x%02x",
197 	    devname, sc->smi_offset);
198 	device_set_desc_copy(dev, desc);
199 
200 	return (BUS_PROBE_DEFAULT);
201 }
202 
203 static int
e6060sw_attach_phys(struct e6060sw_softc * sc)204 e6060sw_attach_phys(struct e6060sw_softc *sc)
205 {
206 	int phy, port, err;
207 	char name[IFNAMSIZ];
208 
209 	port = 0;
210 	err = 0;
211 	/* PHYs need an interface, so we generate a dummy one */
212 	snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
213 	for (phy = 0; phy < sc->numports; phy++) {
214 		if (((1 << phy) & sc->phymask) == 0)
215 			continue;
216 		sc->ifpport[phy] = port;
217 		sc->portphy[port] = phy;
218 		sc->ifp[port] = if_alloc(IFT_ETHER);
219 		if (sc->ifp[port] == NULL) {
220 			device_printf(sc->sc_dev, "couldn't allocate ifnet structure\n");
221 			err = ENOMEM;
222 			break;
223 		}
224 
225 		sc->ifp[port]->if_softc = sc;
226 		sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
227 		    IFF_DRV_RUNNING | IFF_SIMPLEX;
228 		if_initname(sc->ifp[port], name, port);
229 		sc->miibus[port] = malloc(sizeof(device_t), M_E6060SW,
230 		    M_WAITOK | M_ZERO);
231 		err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
232 		    e6060sw_ifmedia_upd, e6060sw_ifmedia_sts, \
233 		    BMSR_DEFCAPMASK, phy + sc->smi_offset, MII_OFFSET_ANY, 0);
234 		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
235 		    device_get_nameunit(*sc->miibus[port]),
236 		    sc->ifp[port]->if_xname);
237 		if (err != 0) {
238 			device_printf(sc->sc_dev,
239 			    "attaching PHY %d failed\n",
240 			    phy);
241 			break;
242 		}
243 		++port;
244 	}
245 	sc->info.es_nports = port;
246 	if (sc->cpuport != -1) {
247 		/* assume cpuport is last one */
248 		sc->ifpport[sc->cpuport] = port;
249 		sc->portphy[port] = sc->cpuport;
250 		++sc->info.es_nports;
251 	}
252 	return (err);
253 }
254 
255 static int
e6060sw_attach(device_t dev)256 e6060sw_attach(device_t dev)
257 {
258 	struct e6060sw_softc *sc;
259 	int err;
260 
261 	sc = device_get_softc(dev);
262 	err = 0;
263 
264 	sc->sc_dev = dev;
265 	mtx_init(&sc->sc_mtx, "e6060sw", NULL, MTX_DEF);
266 	strlcpy(sc->info.es_name, device_get_desc(dev),
267 	    sizeof(sc->info.es_name));
268 
269 	/* XXX Defaults */
270 	if (sc->sw_model == E6063) {
271 		sc->numports = 3;
272 		sc->phymask = 0x07;
273 		sc->cpuport = 2;
274 	} else {
275 		sc->numports = 6;
276 		sc->phymask = 0x1f;
277 		sc->cpuport = 5;
278 	}
279 	sc->media = 100;
280 
281 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
282 	    "numports", &sc->numports);
283 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
284 	    "phymask", &sc->phymask);
285 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
286 	    "cpuport", &sc->cpuport);
287 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
288 	    "media", &sc->media);
289 
290 	if (sc->sw_model == E6060) {
291 		sc->info.es_nvlangroups = sc->numports;
292 		sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT;
293 	} else {
294 		sc->info.es_nvlangroups = 64;
295 		sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT |
296 		    ETHERSWITCH_VLAN_DOT1Q;
297 	}
298 
299 	e6060sw_setup(dev);
300 
301 	sc->ifp = malloc(sizeof(if_t) * sc->numports, M_E6060SW,
302 	    M_WAITOK | M_ZERO);
303 	sc->ifname = malloc(sizeof(char *) * sc->numports, M_E6060SW,
304 	    M_WAITOK | M_ZERO);
305 	sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_E6060SW,
306 	    M_WAITOK | M_ZERO);
307 	sc->portphy = malloc(sizeof(int) * sc->numports, M_E6060SW,
308 	    M_WAITOK | M_ZERO);
309 
310 	/*
311 	 * Attach the PHYs and complete the bus enumeration.
312 	 */
313 	err = e6060sw_attach_phys(sc);
314 	if (err != 0)
315 		return (err);
316 
317 	bus_generic_probe(dev);
318 	bus_enumerate_hinted_children(dev);
319 	err = bus_generic_attach(dev);
320 	if (err != 0)
321 		return (err);
322 
323 	callout_init(&sc->callout_tick, 0);
324 
325 	e6060sw_tick(sc);
326 
327 	return (err);
328 }
329 
330 static int
e6060sw_detach(device_t dev)331 e6060sw_detach(device_t dev)
332 {
333 	struct e6060sw_softc *sc;
334 	int i, port;
335 
336 	sc = device_get_softc(dev);
337 
338 	callout_drain(&sc->callout_tick);
339 
340 	for (i = 0; i < MII_NPHY; i++) {
341 		if (((1 << i) & sc->phymask) == 0)
342 			continue;
343 		port = e6060sw_portforphy(sc, i);
344 		if (sc->miibus[port] != NULL)
345 			device_delete_child(dev, (*sc->miibus[port]));
346 		if (sc->ifp[port] != NULL)
347 			if_free(sc->ifp[port]);
348 		free(sc->ifname[port], M_E6060SW);
349 		free(sc->miibus[port], M_E6060SW);
350 	}
351 
352 	free(sc->portphy, M_E6060SW);
353 	free(sc->miibus, M_E6060SW);
354 	free(sc->ifname, M_E6060SW);
355 	free(sc->ifp, M_E6060SW);
356 
357 	bus_generic_detach(dev);
358 	mtx_destroy(&sc->sc_mtx);
359 
360 	return (0);
361 }
362 
363 /*
364  * Convert PHY number to port number.
365  */
366 static inline int
e6060sw_portforphy(struct e6060sw_softc * sc,int phy)367 e6060sw_portforphy(struct e6060sw_softc *sc, int phy)
368 {
369 
370 	return (sc->ifpport[phy]);
371 }
372 
373 static inline struct mii_data *
e6060sw_miiforport(struct e6060sw_softc * sc,int port)374 e6060sw_miiforport(struct e6060sw_softc *sc, int port)
375 {
376 
377 	if (port < 0 || port > sc->numports)
378 		return (NULL);
379 	if (port == sc->cpuport)
380 		return (NULL);
381 	return (device_get_softc(*sc->miibus[port]));
382 }
383 
384 static inline if_t
e6060sw_ifpforport(struct e6060sw_softc * sc,int port)385 e6060sw_ifpforport(struct e6060sw_softc *sc, int port)
386 {
387 
388 	if (port < 0 || port > sc->numports)
389 		return (NULL);
390 	return (sc->ifp[port]);
391 }
392 
393 /*
394  * Poll the status for all PHYs.
395  */
396 static void
e6060sw_miipollstat(struct e6060sw_softc * sc)397 e6060sw_miipollstat(struct e6060sw_softc *sc)
398 {
399 	int i, port;
400 	struct mii_data *mii;
401 	struct mii_softc *miisc;
402 
403 	E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
404 
405 	for (i = 0; i < MII_NPHY; i++) {
406 		if (((1 << i) & sc->phymask) == 0)
407 			continue;
408 		port = e6060sw_portforphy(sc, i);
409 		if ((*sc->miibus[port]) == NULL)
410 			continue;
411 		mii = device_get_softc(*sc->miibus[port]);
412 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
413 			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
414 			    miisc->mii_inst)
415 				continue;
416 			ukphy_status(miisc);
417 			mii_phy_update(miisc, MII_POLLSTAT);
418 		}
419 	}
420 }
421 
422 static void
e6060sw_tick(void * arg)423 e6060sw_tick(void *arg)
424 {
425 	struct e6060sw_softc *sc;
426 
427 	sc = arg;
428 
429 	e6060sw_miipollstat(sc);
430 	callout_reset(&sc->callout_tick, hz, e6060sw_tick, sc);
431 }
432 
433 static void
e6060sw_lock(device_t dev)434 e6060sw_lock(device_t dev)
435 {
436 	struct e6060sw_softc *sc;
437 
438 	sc = device_get_softc(dev);
439 
440 	E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
441 	E6060SW_LOCK(sc);
442 }
443 
444 static void
e6060sw_unlock(device_t dev)445 e6060sw_unlock(device_t dev)
446 {
447 	struct e6060sw_softc *sc;
448 
449 	sc = device_get_softc(dev);
450 
451 	E6060SW_LOCK_ASSERT(sc, MA_OWNED);
452 	E6060SW_UNLOCK(sc);
453 }
454 
455 static etherswitch_info_t *
e6060sw_getinfo(device_t dev)456 e6060sw_getinfo(device_t dev)
457 {
458 	struct e6060sw_softc *sc;
459 
460 	sc = device_get_softc(dev);
461 
462 	return (&sc->info);
463 }
464 
465 static int
e6060sw_getport(device_t dev,etherswitch_port_t * p)466 e6060sw_getport(device_t dev, etherswitch_port_t *p)
467 {
468 	struct e6060sw_softc *sc;
469 	struct mii_data *mii;
470 	struct ifmediareq *ifmr;
471 	int err, phy;
472 
473 	sc = device_get_softc(dev);
474 	ifmr = &p->es_ifmr;
475 
476 	if (p->es_port < 0 || p->es_port >= sc->numports)
477 		return (ENXIO);
478 
479 	p->es_pvid = 0;
480 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
481 		p->es_pvid = MDIO_READREG(device_get_parent(dev),
482 		    CORE_REGISTER + sc->smi_offset + p->es_port,
483 		    PORT_DEFVLAN) & 0xfff;
484 	}
485 
486 	phy = sc->portphy[p->es_port];
487 	mii = e6060sw_miiforport(sc, p->es_port);
488 	if (sc->cpuport != -1 && phy == sc->cpuport) {
489 		/* fill in fixed values for CPU port */
490 		p->es_flags |= ETHERSWITCH_PORT_CPU;
491 		ifmr->ifm_count = 0;
492 		if (sc->media == 100)
493 			ifmr->ifm_current = ifmr->ifm_active =
494 			    IFM_ETHER | IFM_100_TX | IFM_FDX;
495 		else
496 			ifmr->ifm_current = ifmr->ifm_active =
497 			    IFM_ETHER | IFM_1000_T | IFM_FDX;
498 		ifmr->ifm_mask = 0;
499 		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
500 	} else if (mii != NULL) {
501 		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
502 		    &mii->mii_media, SIOCGIFMEDIA);
503 		if (err)
504 			return (err);
505 	} else {
506 		return (ENXIO);
507 	}
508 	return (0);
509 }
510 
511 static int
e6060sw_setport(device_t dev,etherswitch_port_t * p)512 e6060sw_setport(device_t dev, etherswitch_port_t *p)
513 {
514 	struct e6060sw_softc *sc;
515 	struct ifmedia *ifm;
516 	struct mii_data *mii;
517 	if_t ifp;
518 	int err;
519 	int data;
520 
521 	sc = device_get_softc(dev);
522 
523 	if (p->es_port < 0 || p->es_port >= sc->numports)
524 		return (ENXIO);
525 
526 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
527 		data = MDIO_READREG(device_get_parent(dev),
528 		    CORE_REGISTER + sc->smi_offset + p->es_port,
529 		    PORT_DEFVLAN);
530 		data &= ~0xfff;
531 		data |= p->es_pvid;
532 		data |= 1 << 12;
533 		MDIO_WRITEREG(device_get_parent(dev),
534 		    CORE_REGISTER + sc->smi_offset + p->es_port,
535 		    PORT_DEFVLAN, data);
536 	}
537 
538 	if (sc->portphy[p->es_port] == sc->cpuport)
539 		return(0);
540 
541 	mii = e6060sw_miiforport(sc, p->es_port);
542 	if (mii == NULL)
543 		return (ENXIO);
544 
545 	ifp = e6060sw_ifpforport(sc, p->es_port);
546 
547 	ifm = &mii->mii_media;
548 	err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
549 	return (err);
550 }
551 
552 static int
e6060sw_getvgroup(device_t dev,etherswitch_vlangroup_t * vg)553 e6060sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
554 {
555 	struct e6060sw_softc *sc;
556 	int data1, data2;
557 	int vid;
558 	int i, tag;
559 
560 	sc = device_get_softc(dev);
561 
562 	if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
563 		vg->es_vid = ETHERSWITCH_VID_VALID;
564 		vg->es_vid |= vg->es_vlangroup;
565 		data1 = MDIO_READREG(device_get_parent(dev),
566 		    CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
567 		    PORT_VLAN_MAP);
568 		vg->es_member_ports = data1 & 0x3f;
569 		vg->es_untagged_ports = vg->es_member_ports;
570 		vg->es_fid = 0;
571 	} else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
572 		if (vg->es_vlangroup == 0)
573 			return (0);
574 		vid = e6060sw_read_vtu(dev, vg->es_vlangroup, &data1, &data2);
575 		if (vid > 0) {
576 			vg->es_vid = ETHERSWITCH_VID_VALID;
577 			vg->es_vid |= vid;
578 			vg->es_member_ports = 0;
579 			vg->es_untagged_ports = 0;
580 			for (i = 0; i < 4; ++i) {
581 				tag = data1 >> (i * 4) & 3;
582 				if (tag == 0 || tag == 1) {
583 					vg->es_member_ports |= 1 << i;
584 					vg->es_untagged_ports |= 1 << i;
585 				} else if (tag == 2) {
586 					vg->es_member_ports |= 1 << i;
587 				}
588 			}
589 			for (i = 0; i < 2; ++i) {
590 				tag = data2 >> (i * 4) & 3;
591 				if (tag == 0 || tag == 1) {
592 					vg->es_member_ports |= 1 << (i + 4);
593 					vg->es_untagged_ports |= 1 << (i + 4);
594 				} else if (tag == 2) {
595 					vg->es_member_ports |= 1 << (i + 4);
596 				}
597 			}
598 
599 		}
600 	} else {
601 		vg->es_vid = 0;
602 	}
603 	return (0);
604 }
605 
606 static int
e6060sw_setvgroup(device_t dev,etherswitch_vlangroup_t * vg)607 e6060sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
608 {
609 	struct e6060sw_softc *sc;
610 	int data1, data2;
611 	int i;
612 
613 	sc = device_get_softc(dev);
614 
615 	if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
616 		data1 = MDIO_READREG(device_get_parent(dev),
617 		    CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
618 		    PORT_VLAN_MAP);
619 		data1 &= ~0x3f;
620 		data1 |= vg->es_member_ports;
621 		MDIO_WRITEREG(device_get_parent(dev),
622 		    CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
623 		    PORT_VLAN_MAP, data1);
624 	} else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
625 		if (vg->es_vlangroup == 0)
626 			return (0);
627 		data1 = 0;
628 		data2 = 0;
629 		for (i = 0; i < 6; ++i) {
630 			if (vg->es_member_ports &
631 			    vg->es_untagged_ports & (1 << i)) {
632 				if (i < 4) {
633 					data1 |= (0xd << i * 4);
634 				} else {
635 					data2 |= (0xd << (i - 4) * 4);
636 				}
637 			} else if (vg->es_member_ports & (1 << i)) {
638 				if (i < 4) {
639 					data1 |= (0xe << i * 4);
640 				} else {
641 					data2 |= (0xe << (i - 4) * 4);
642 				}
643 			} else {
644 				if (i < 4) {
645 					data1 |= (0x3 << i * 4);
646 				} else {
647 					data2 |= (0x3 << (i - 4) * 4);
648 				}
649 			}
650 		}
651 		e6060sw_set_vtu(dev, vg->es_vlangroup, data1, data2);
652 	}
653 	return (0);
654 }
655 
656 static void
e6060sw_reset_vlans(device_t dev)657 e6060sw_reset_vlans(device_t dev)
658 {
659 	struct e6060sw_softc *sc;
660 	uint32_t ports;
661 	int i;
662 	int data;
663 
664 	sc = device_get_softc(dev);
665 
666 	for (i = 0; i <= sc->numports; i++) {
667 		ports = (1 << (sc->numports + 1)) - 1;
668 		ports &= ~(1 << i);
669 		if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
670 			data = i << 12;
671 		} else if (sc->vlan_mode == 0) {
672 			data = 1 << 8;
673 		} else {
674 			data = 0;
675 		}
676 		data |= ports;
677 		MDIO_WRITEREG(device_get_parent(dev),
678 		    CORE_REGISTER + sc->smi_offset + i, PORT_VLAN_MAP, data);
679 	}
680 }
681 
682 static void
e6060sw_setup(device_t dev)683 e6060sw_setup(device_t dev)
684 {
685 	struct e6060sw_softc *sc;
686 	int i;
687 	int data;
688 
689 	sc = device_get_softc(dev);
690 
691 	for (i = 0; i <= sc->numports; i++) {
692 		if (sc->sw_model == E6063 || sc->sw_model == E6065) {
693 			data = MDIO_READREG(device_get_parent(dev),
694 			    CORE_REGISTER + sc->smi_offset + i, PORT_VLAN_MAP);
695 			data &= ~(FORCEMAPMASK << FORCEMAPSHIFT);
696 			MDIO_WRITEREG(device_get_parent(dev),
697 			    CORE_REGISTER + sc->smi_offset + i,
698 			    PORT_VLAN_MAP, data);
699 
700 			data = MDIO_READREG(device_get_parent(dev),
701 			    CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL);
702 			data |= 3 << ENGRESSFSHIFT;
703 			MDIO_WRITEREG(device_get_parent(dev),
704 			    CORE_REGISTER + sc->smi_offset + i,
705 			    PORT_CONTROL, data);
706 		}
707 	}
708 }
709 
710 static void
e6060sw_dot1q_mode(device_t dev,int mode)711 e6060sw_dot1q_mode(device_t dev, int mode)
712 {
713 	struct e6060sw_softc *sc;
714 	int i;
715 	int data;
716 
717 	sc = device_get_softc(dev);
718 
719 	for (i = 0; i <= sc->numports; i++) {
720 		data = MDIO_READREG(device_get_parent(dev),
721 		    CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL2);
722 		data &= ~(DOT1QMODEMASK << DOT1QMODESHIFT);
723 		data |= mode << DOT1QMODESHIFT;
724 		MDIO_WRITEREG(device_get_parent(dev),
725 		    CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL2, data);
726 
727 		data = MDIO_READREG(device_get_parent(dev),
728 		    CORE_REGISTER + sc->smi_offset + i,
729 		    PORT_DEFVLAN);
730 		data &= ~0xfff;
731 		data |= 1;
732 		MDIO_WRITEREG(device_get_parent(dev),
733 		    CORE_REGISTER + sc->smi_offset + i,
734 		    PORT_DEFVLAN, data);
735 	}
736 }
737 
738 static int
e6060sw_getconf(device_t dev,etherswitch_conf_t * conf)739 e6060sw_getconf(device_t dev, etherswitch_conf_t *conf)
740 {
741 	struct e6060sw_softc *sc;
742 
743 	sc = device_get_softc(dev);
744 
745 	/* Return the VLAN mode. */
746 	conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
747 	conf->vlan_mode = sc->vlan_mode;
748 
749 	return (0);
750 }
751 
752 static void
e6060sw_init_vtu(device_t dev)753 e6060sw_init_vtu(device_t dev)
754 {
755 	struct e6060sw_softc *sc;
756 	int busy;
757 
758 	sc = device_get_softc(dev);
759 
760 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
761 	    VTU_OPERATION, VTU_BUSY | (VTU_FLASH << 12));
762 	while (1) {
763 		busy = MDIO_READREG(device_get_parent(dev),
764 		    GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
765 		if ((busy & VTU_BUSY) == 0)
766 			break;
767 	}
768 
769 	/* initial member set at vlan 1*/
770 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
771 	    VTU_DATA1_REG, 0xcccc);
772 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
773 	    VTU_DATA2_REG, 0x00cc);
774 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
775 	    VTU_VID_REG, 0x1000 | 1);
776 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
777 	    VTU_OPERATION, VTU_BUSY | (VTU_LOAD_PURGE << 12) | 1);
778 	while (1) {
779 		busy = MDIO_READREG(device_get_parent(dev),
780 		    GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
781 		if ((busy & VTU_BUSY) == 0)
782 			break;
783 	}
784 }
785 
786 static void
e6060sw_set_vtu(device_t dev,int num,int data1,int data2)787 e6060sw_set_vtu(device_t dev, int num, int data1, int data2)
788 {
789 	struct e6060sw_softc *sc;
790 	int busy;
791 
792 	sc = device_get_softc(dev);
793 
794 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
795 	    VTU_DATA1_REG, data1);
796 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
797 	    VTU_DATA2_REG, data2);
798 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
799 	    VTU_VID_REG, 0x1000 | num);
800 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
801 	    VTU_OPERATION, VTU_BUSY | (VTU_LOAD_PURGE << 12) | num);
802 	while (1) {
803 		busy = MDIO_READREG(device_get_parent(dev),
804 		    GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
805 		if ((busy & VTU_BUSY) == 0)
806 			break;
807 	}
808 
809 }
810 
811 static int
e6060sw_read_vtu(device_t dev,int num,int * data1,int * data2)812 e6060sw_read_vtu(device_t dev, int num, int *data1, int *data2)
813 {
814 	struct e6060sw_softc *sc;
815 	int busy;
816 
817 	sc = device_get_softc(dev);
818 
819 	num = num - 1;
820 
821 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
822 	    VTU_VID_REG, num & 0xfff);
823 	/* Get Next */
824 	MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
825 	    VTU_OPERATION, VTU_BUSY | (VTU_GET_NEXT << 12));
826 	while (1) {
827 		busy = MDIO_READREG(device_get_parent(dev),
828 		    GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
829 		if ((busy & VTU_BUSY) == 0)
830 			break;
831 	}
832 
833 	int vid = MDIO_READREG(device_get_parent(dev),
834 	    GLOBAL_REGISTER + sc->smi_offset, VTU_VID_REG);
835 	if (vid & 0x1000) {
836 		*data1 = MDIO_READREG(device_get_parent(dev),
837 		    GLOBAL_REGISTER + sc->smi_offset, VTU_DATA1_REG);
838 		*data2 = MDIO_READREG(device_get_parent(dev),
839 		    GLOBAL_REGISTER + sc->smi_offset, VTU_DATA2_REG);
840 
841 		return (vid & 0xfff);
842 	}
843 
844 	return (-1);
845 }
846 
847 static int
e6060sw_setconf(device_t dev,etherswitch_conf_t * conf)848 e6060sw_setconf(device_t dev, etherswitch_conf_t *conf)
849 {
850 	struct e6060sw_softc *sc;
851 
852 	sc = device_get_softc(dev);
853 
854 	/* Set the VLAN mode. */
855 	if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
856 		if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) {
857 			sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
858 			e6060sw_dot1q_mode(dev, DOT1QNONE);
859 			e6060sw_reset_vlans(dev);
860 		} else if ((sc->sw_model == E6063 || sc->sw_model == E6065) &&
861 		    conf->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
862 			sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
863 			e6060sw_dot1q_mode(dev, DOT1QSECURE);
864 			e6060sw_init_vtu(dev);
865 		} else {
866 			sc->vlan_mode = 0;
867 			/* Reset VLANs. */
868 			e6060sw_dot1q_mode(dev, DOT1QNONE);
869 			e6060sw_reset_vlans(dev);
870 		}
871 	}
872 
873 	return (0);
874 }
875 
876 static void
e6060sw_statchg(device_t dev)877 e6060sw_statchg(device_t dev)
878 {
879 
880 	DPRINTF(dev, "%s\n", __func__);
881 }
882 
883 static int
e6060sw_ifmedia_upd(if_t ifp)884 e6060sw_ifmedia_upd(if_t ifp)
885 {
886 	struct e6060sw_softc *sc;
887 	struct mii_data *mii;
888 
889 	sc = if_getsoftc(ifp);
890 	mii = e6060sw_miiforport(sc, if_getdunit(ifp));
891 
892 	DPRINTF(sc->sc_dev, "%s\n", __func__);
893 	if (mii == NULL)
894 		return (ENXIO);
895 	mii_mediachg(mii);
896 	return (0);
897 }
898 
899 static void
e6060sw_ifmedia_sts(if_t ifp,struct ifmediareq * ifmr)900 e6060sw_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
901 {
902 	struct e6060sw_softc *sc;
903 	struct mii_data *mii;
904 
905 	sc = if_getsoftc(ifp);
906 	mii = e6060sw_miiforport(sc, if_getdunit(ifp));
907 
908 	DPRINTF(sc->sc_dev, "%s\n", __func__);
909 
910 	if (mii == NULL)
911 		return;
912 	mii_pollstat(mii);
913 	ifmr->ifm_active = mii->mii_media_active;
914 	ifmr->ifm_status = mii->mii_media_status;
915 }
916 
917 static int
e6060sw_readphy(device_t dev,int phy,int reg)918 e6060sw_readphy(device_t dev, int phy, int reg)
919 {
920 	struct e6060sw_softc *sc;
921 	int data;
922 
923 	sc = device_get_softc(dev);
924 	E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
925 
926 	if (phy < 0 || phy >= 32)
927 		return (ENXIO);
928 	if (reg < 0 || reg >= 32)
929 		return (ENXIO);
930 
931 	E6060SW_LOCK(sc);
932 	data = MDIO_READREG(device_get_parent(dev), phy, reg);
933 	E6060SW_UNLOCK(sc);
934 
935 	return (data);
936 }
937 
938 static int
e6060sw_writephy(device_t dev,int phy,int reg,int data)939 e6060sw_writephy(device_t dev, int phy, int reg, int data)
940 {
941 	struct e6060sw_softc *sc;
942 	int err;
943 
944 	sc = device_get_softc(dev);
945 	E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
946 
947 	if (phy < 0 || phy >= 32)
948 		return (ENXIO);
949 	if (reg < 0 || reg >= 32)
950 		return (ENXIO);
951 
952 	E6060SW_LOCK(sc);
953 	err = MDIO_WRITEREG(device_get_parent(dev), phy, reg, data);
954 	E6060SW_UNLOCK(sc);
955 
956 	return (err);
957 }
958 
959 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */
960 
961 static int
e6060sw_readreg(device_t dev,int addr)962 e6060sw_readreg(device_t dev, int addr)
963 {
964 	int devaddr, regaddr;
965 
966 	devaddr = (addr >> 5) & 0x1f;
967 	regaddr = addr & 0x1f;
968 
969 	return MDIO_READREG(device_get_parent(dev), devaddr, regaddr);
970 }
971 
972 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */
973 
974 static int
e6060sw_writereg(device_t dev,int addr,int value)975 e6060sw_writereg(device_t dev, int addr, int value)
976 {
977 	int devaddr, regaddr;
978 
979 	devaddr = (addr >> 5) & 0x1f;
980 	regaddr = addr & 0x1f;
981 
982 	return (MDIO_WRITEREG(device_get_parent(dev), devaddr, regaddr, value));
983 }
984 
985 static device_method_t e6060sw_methods[] = {
986 	/* Device interface */
987 	DEVMETHOD(device_probe,		e6060sw_probe),
988 	DEVMETHOD(device_attach,	e6060sw_attach),
989 	DEVMETHOD(device_detach,	e6060sw_detach),
990 
991 	/* bus interface */
992 	DEVMETHOD(bus_add_child,	device_add_child_ordered),
993 
994 	/* MII interface */
995 	DEVMETHOD(miibus_readreg,	e6060sw_readphy),
996 	DEVMETHOD(miibus_writereg,	e6060sw_writephy),
997 	DEVMETHOD(miibus_statchg,	e6060sw_statchg),
998 
999 	/* MDIO interface */
1000 	DEVMETHOD(mdio_readreg,		e6060sw_readphy),
1001 	DEVMETHOD(mdio_writereg,	e6060sw_writephy),
1002 
1003 	/* etherswitch interface */
1004 	DEVMETHOD(etherswitch_lock,	e6060sw_lock),
1005 	DEVMETHOD(etherswitch_unlock,	e6060sw_unlock),
1006 	DEVMETHOD(etherswitch_getinfo,	e6060sw_getinfo),
1007 	DEVMETHOD(etherswitch_readreg,	e6060sw_readreg),
1008 	DEVMETHOD(etherswitch_writereg,	e6060sw_writereg),
1009 	DEVMETHOD(etherswitch_readphyreg,	e6060sw_readphy),
1010 	DEVMETHOD(etherswitch_writephyreg,	e6060sw_writephy),
1011 	DEVMETHOD(etherswitch_getport,	e6060sw_getport),
1012 	DEVMETHOD(etherswitch_setport,	e6060sw_setport),
1013 	DEVMETHOD(etherswitch_getvgroup,	e6060sw_getvgroup),
1014 	DEVMETHOD(etherswitch_setvgroup,	e6060sw_setvgroup),
1015 	DEVMETHOD(etherswitch_setconf,	e6060sw_setconf),
1016 	DEVMETHOD(etherswitch_getconf,	e6060sw_getconf),
1017 
1018 	DEVMETHOD_END
1019 };
1020 
1021 DEFINE_CLASS_0(e6060sw, e6060sw_driver, e6060sw_methods,
1022     sizeof(struct e6060sw_softc));
1023 
1024 DRIVER_MODULE(e6060sw, mdio, e6060sw_driver, 0, 0);
1025 DRIVER_MODULE(miibus, e6060sw, miibus_driver, 0, 0);
1026 DRIVER_MODULE(mdio, e6060sw, mdio_driver, 0, 0);
1027 DRIVER_MODULE(etherswitch, e6060sw, etherswitch_driver, 0, 0);
1028 MODULE_VERSION(e6060sw, 1);
1029 MODULE_DEPEND(e6060sw, miibus, 1, 1, 1); /* XXX which versions? */
1030 MODULE_DEPEND(e6060sw, etherswitch, 1, 1, 1); /* XXX which versions? */
1031