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