xref: /freebsd/sys/dev/etherswitch/e6000sw/e6060sw.c (revision 642870485c089b57000fe538d3485e272b038d59)
1 /*-
2  * Copyright (c) 2016 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  * Current code is only support port base vlan. Not support ingress/egress
36  * trailer. This switch chip can't work vlan(4) support.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/errno.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/module.h>
46 #include <sys/mutex.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/sysctl.h>
50 #include <sys/systm.h>
51 
52 #include <net/if.h>
53 #include <net/if_var.h>
54 #include <net/ethernet.h>
55 #include <net/if_media.h>
56 #include <net/if_types.h>
57 
58 #include <machine/bus.h>
59 #include <dev/mii/mii.h>
60 #include <dev/mii/miivar.h>
61 #include <dev/mdio/mdio.h>
62 
63 #include <dev/etherswitch/etherswitch.h>
64 
65 #include "mdio_if.h"
66 #include "miibus_if.h"
67 #include "etherswitch_if.h"
68 
69 #define	SMI_OFFSET	0x10
70 #define	CORE_REGISTER	(SMI_OFFSET + 8)
71 
72 #define	SWITCH_ID	3
73 #define	PORT_VLAN_MAP	6
74 
75 MALLOC_DECLARE(M_E6060SW);
76 MALLOC_DEFINE(M_E6060SW, "e6060sw", "e6060sw data structures");
77 
78 struct e6060sw_softc {
79 	struct mtx	sc_mtx;		/* serialize access to softc */
80 	device_t	sc_dev;
81 	int		vlan_mode;
82 	int		media;		/* cpu port media */
83 	int		cpuport;	/* which PHY is connected to the CPU */
84 	int		phymask;	/* PHYs we manage */
85 	int		numports;	/* number of ports */
86 	int		ifpport[MII_NPHY];
87 	int		*portphy;
88 	char		**ifname;
89 	device_t	**miibus;
90 	struct ifnet	**ifp;
91 	struct callout	callout_tick;
92 	etherswitch_info_t	info;
93 };
94 
95 #define	E6060SW_LOCK(_sc)			\
96 	    mtx_lock(&(_sc)->sc_mtx)
97 #define	E6060SW_UNLOCK(_sc)			\
98 	    mtx_unlock(&(_sc)->sc_mtx)
99 #define	E6060SW_LOCK_ASSERT(_sc, _what)	\
100 	    mtx_assert(&(_sc)->sc_mtx, (_what))
101 #define	E6060SW_TRYLOCK(_sc)			\
102 	    mtx_trylock(&(_sc)->sc_mtx)
103 
104 #if defined(DEBUG)
105 #define	DPRINTF(dev, args...) device_printf(dev, args)
106 #else
107 #define	DPRINTF(dev, args...)
108 #endif
109 
110 static inline int e6060sw_portforphy(struct e6060sw_softc *, int);
111 static void e6060sw_tick(void *);
112 static int e6060sw_ifmedia_upd(struct ifnet *);
113 static void e6060sw_ifmedia_sts(struct ifnet *, struct ifmediareq *);
114 
115 static int
116 e6060sw_probe(device_t dev)
117 {
118 	int data;
119 	struct e6060sw_softc *sc;
120 
121 	sc = device_get_softc(dev);
122 	bzero(sc, sizeof(*sc));
123 
124 	data = MDIO_READREG(device_get_parent(dev), CORE_REGISTER, SWITCH_ID);
125 	if (bootverbose)
126 		device_printf(dev,"Switch Identifier Register %x\n", data);
127 
128 	if ((data >> 4) != 0x060) {
129 		return (ENXIO);
130 	}
131 
132 	device_set_desc_copy(dev, "Marvell 88E6060 MDIO switch driver");
133 	return (BUS_PROBE_DEFAULT);
134 }
135 
136 static int
137 e6060sw_attach_phys(struct e6060sw_softc *sc)
138 {
139 	int phy, port, err;
140 	char name[IFNAMSIZ];
141 
142 	port = 0;
143 	err = 0;
144 	/* PHYs need an interface, so we generate a dummy one */
145 	snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
146 	for (phy = 0; phy < sc->numports; phy++) {
147 		if (((1 << phy) & sc->phymask) == 0)
148 			continue;
149 		sc->ifpport[phy] = port;
150 		sc->portphy[port] = phy;
151 		sc->ifp[port] = if_alloc(IFT_ETHER);
152 		sc->ifp[port]->if_softc = sc;
153 		sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
154 		    IFF_DRV_RUNNING | IFF_SIMPLEX;
155 		if_initname(sc->ifp[port], name, port);
156 		sc->miibus[port] = malloc(sizeof(device_t), M_E6060SW,
157 		    M_WAITOK | M_ZERO);
158 		err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
159 		    e6060sw_ifmedia_upd, e6060sw_ifmedia_sts, \
160 		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
161 		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
162 		    device_get_nameunit(*sc->miibus[port]),
163 		    sc->ifp[port]->if_xname);
164 		if (err != 0) {
165 			device_printf(sc->sc_dev,
166 			    "attaching PHY %d failed\n",
167 			    phy);
168 			break;
169 		}
170 		++port;
171 	}
172 	sc->info.es_nports = port;
173 	if (sc->cpuport != -1) {
174 		/* assume cpuport is last one */
175 		sc->ifpport[sc->cpuport] = port;
176 		sc->portphy[port] = sc->cpuport;
177 		++sc->info.es_nports;
178 	}
179 	return (err);
180 }
181 
182 static int
183 e6060sw_attach(device_t dev)
184 {
185 	struct e6060sw_softc *sc;
186 	int err;
187 
188 	sc = device_get_softc(dev);
189 	err = 0;
190 
191 	sc->sc_dev = dev;
192 	mtx_init(&sc->sc_mtx, "e6060sw", NULL, MTX_DEF);
193 	strlcpy(sc->info.es_name, device_get_desc(dev),
194 	    sizeof(sc->info.es_name));
195 
196 	/* XXX Defaults */
197 	sc->numports = 6;
198 	sc->phymask = 0x1f;
199 	sc->cpuport = 5;
200 	sc->media = 100;
201 
202 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
203 	    "numports", &sc->numports);
204 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
205 	    "phymask", &sc->phymask);
206 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
207 	    "cpuport", &sc->cpuport);
208 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
209 	    "media", &sc->media);
210 
211 	sc->info.es_nvlangroups = sc->numports;
212 	sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT;
213 
214 	sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_E6060SW,
215 	    M_WAITOK | M_ZERO);
216 	sc->ifname = malloc(sizeof(char *) * sc->numports, M_E6060SW,
217 	    M_WAITOK | M_ZERO);
218 	sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_E6060SW,
219 	    M_WAITOK | M_ZERO);
220 	sc->portphy = malloc(sizeof(int) * sc->numports, M_E6060SW,
221 	    M_WAITOK | M_ZERO);
222 
223 	/*
224 	 * Attach the PHYs and complete the bus enumeration.
225 	 */
226 	err = e6060sw_attach_phys(sc);
227 	if (err != 0)
228 		return (err);
229 
230 	bus_generic_probe(dev);
231 	bus_enumerate_hinted_children(dev);
232 	err = bus_generic_attach(dev);
233 	if (err != 0)
234 		return (err);
235 
236 	callout_init(&sc->callout_tick, 0);
237 
238 	e6060sw_tick(sc);
239 
240 	return (err);
241 }
242 
243 static int
244 e6060sw_detach(device_t dev)
245 {
246 	struct e6060sw_softc *sc;
247 	int i, port;
248 
249 	sc = device_get_softc(dev);
250 
251 	callout_drain(&sc->callout_tick);
252 
253 	for (i = 0; i < MII_NPHY; i++) {
254 		if (((1 << i) & sc->phymask) == 0)
255 			continue;
256 		port = e6060sw_portforphy(sc, i);
257 		if (sc->miibus[port] != NULL)
258 			device_delete_child(dev, (*sc->miibus[port]));
259 		if (sc->ifp[port] != NULL)
260 			if_free(sc->ifp[port]);
261 		free(sc->ifname[port], M_E6060SW);
262 		free(sc->miibus[port], M_E6060SW);
263 	}
264 
265 	free(sc->portphy, M_E6060SW);
266 	free(sc->miibus, M_E6060SW);
267 	free(sc->ifname, M_E6060SW);
268 	free(sc->ifp, M_E6060SW);
269 
270 	bus_generic_detach(dev);
271 	mtx_destroy(&sc->sc_mtx);
272 
273 	return (0);
274 }
275 
276 /*
277  * Convert PHY number to port number.
278  */
279 static inline int
280 e6060sw_portforphy(struct e6060sw_softc *sc, int phy)
281 {
282 
283 	return (sc->ifpport[phy]);
284 }
285 
286 static inline struct mii_data *
287 e6060sw_miiforport(struct e6060sw_softc *sc, int port)
288 {
289 
290 	if (port < 0 || port > sc->numports)
291 		return (NULL);
292 	if (port == sc->cpuport)
293 		return (NULL);
294 	return (device_get_softc(*sc->miibus[port]));
295 }
296 
297 static inline struct ifnet *
298 e6060sw_ifpforport(struct e6060sw_softc *sc, int port)
299 {
300 
301 	if (port < 0 || port > sc->numports)
302 		return (NULL);
303 	return (sc->ifp[port]);
304 }
305 
306 /*
307  * Poll the status for all PHYs.
308  */
309 static void
310 e6060sw_miipollstat(struct e6060sw_softc *sc)
311 {
312 	int i, port;
313 	struct mii_data *mii;
314 	struct mii_softc *miisc;
315 
316 	E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
317 
318 	for (i = 0; i < MII_NPHY; i++) {
319 		if (((1 << i) & sc->phymask) == 0)
320 			continue;
321 		port = e6060sw_portforphy(sc, i);
322 		if ((*sc->miibus[port]) == NULL)
323 			continue;
324 		mii = device_get_softc(*sc->miibus[port]);
325 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
326 			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
327 			    miisc->mii_inst)
328 				continue;
329 			ukphy_status(miisc);
330 			mii_phy_update(miisc, MII_POLLSTAT);
331 		}
332 	}
333 }
334 
335 static void
336 e6060sw_tick(void *arg)
337 {
338 	struct e6060sw_softc *sc;
339 
340 	sc = arg;
341 
342 	e6060sw_miipollstat(sc);
343 	callout_reset(&sc->callout_tick, hz, e6060sw_tick, sc);
344 }
345 
346 static void
347 e6060sw_lock(device_t dev)
348 {
349 	struct e6060sw_softc *sc;
350 
351 	sc = device_get_softc(dev);
352 
353 	E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
354 	E6060SW_LOCK(sc);
355 }
356 
357 static void
358 e6060sw_unlock(device_t dev)
359 {
360 	struct e6060sw_softc *sc;
361 
362 	sc = device_get_softc(dev);
363 
364 	E6060SW_LOCK_ASSERT(sc, MA_OWNED);
365 	E6060SW_UNLOCK(sc);
366 }
367 
368 static etherswitch_info_t *
369 e6060sw_getinfo(device_t dev)
370 {
371 	struct e6060sw_softc *sc;
372 
373 	sc = device_get_softc(dev);
374 
375 	return (&sc->info);
376 }
377 
378 static int
379 e6060sw_getport(device_t dev, etherswitch_port_t *p)
380 {
381 	struct e6060sw_softc *sc;
382 	struct mii_data *mii;
383 	struct ifmediareq *ifmr;
384 	int err, phy;
385 
386 	sc = device_get_softc(dev);
387 	ifmr = &p->es_ifmr;
388 
389 	if (p->es_port < 0 || p->es_port >= sc->numports)
390 		return (ENXIO);
391 	p->es_pvid = 0;
392 
393 	phy = sc->portphy[p->es_port];
394 	mii = e6060sw_miiforport(sc, p->es_port);
395 	if (sc->cpuport != -1 && phy == sc->cpuport) {
396 		/* fill in fixed values for CPU port */
397 		p->es_flags |= ETHERSWITCH_PORT_CPU;
398 		ifmr->ifm_count = 0;
399 		if (sc->media == 100)
400 			ifmr->ifm_current = ifmr->ifm_active =
401 			    IFM_ETHER | IFM_100_TX | IFM_FDX;
402 		else
403 			ifmr->ifm_current = ifmr->ifm_active =
404 			    IFM_ETHER | IFM_1000_T | IFM_FDX;
405 		ifmr->ifm_mask = 0;
406 		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
407 	} else if (mii != NULL) {
408 		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
409 		    &mii->mii_media, SIOCGIFMEDIA);
410 		if (err)
411 			return (err);
412 	} else {
413 		return (ENXIO);
414 	}
415 	return (0);
416 }
417 
418 static int
419 e6060sw_setport(device_t dev, etherswitch_port_t *p)
420 {
421 	struct e6060sw_softc *sc;
422 	struct ifmedia *ifm;
423 	struct mii_data *mii;
424 	struct ifnet *ifp;
425 	int err;
426 
427 	sc = device_get_softc(dev);
428 
429 	if (p->es_port < 0 || p->es_port >= sc->numports)
430 		return (ENXIO);
431 
432 	if (sc->portphy[p->es_port] == sc->cpuport)
433 		return (ENXIO);
434 
435 	mii = e6060sw_miiforport(sc, p->es_port);
436 	if (mii == NULL)
437 		return (ENXIO);
438 
439 	ifp = e6060sw_ifpforport(sc, p->es_port);
440 
441 	ifm = &mii->mii_media;
442 	err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
443 	return (err);
444 }
445 
446 static int
447 e6060sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
448 {
449 	struct e6060sw_softc *sc;
450 	int data;
451 
452 	sc = device_get_softc(dev);
453 
454 	if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
455 		vg->es_vid = ETHERSWITCH_VID_VALID;
456 		vg->es_vid |= vg->es_vlangroup;
457 		data = MDIO_READREG(device_get_parent(dev), CORE_REGISTER + vg->es_vlangroup, PORT_VLAN_MAP);
458 		vg->es_member_ports = data & 0x3f;
459 		vg->es_untagged_ports = vg->es_member_ports;
460 		vg->es_fid = 0;
461 	} else {
462 		vg->es_vid = 0;
463 	}
464 	return (0);
465 }
466 
467 static int
468 e6060sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
469 {
470 	struct e6060sw_softc *sc;
471 	int data;
472 
473 	sc = device_get_softc(dev);
474 
475 	if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
476 		data = MDIO_READREG(device_get_parent(dev), CORE_REGISTER + vg->es_vlangroup, PORT_VLAN_MAP);
477 		data &= ~0x3f;
478 		data |= vg->es_member_ports;
479 		MDIO_WRITEREG(device_get_parent(dev), CORE_REGISTER + vg->es_vlangroup, PORT_VLAN_MAP, data);
480 	}
481 
482 	return (0);
483 }
484 
485 static void
486 e6060sw_reset_vlans(device_t dev)
487 {
488 	struct e6060sw_softc *sc;
489 	uint32_t ports;
490 	int i;
491 	int data;
492 
493 	sc = device_get_softc(dev);
494 
495 	for (i = 0; i <= sc->numports; i++) {
496 		ports = (1 << (sc->numports + 1)) - 1;
497 		ports &= ~(1 << i);
498 		if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
499 			data = i << 12;
500 		} else {
501 			data = 0;
502 		}
503 		data |= ports;
504 		MDIO_WRITEREG(device_get_parent(dev), CORE_REGISTER + i, PORT_VLAN_MAP, data);
505 	}
506 }
507 
508 static int
509 e6060sw_getconf(device_t dev, etherswitch_conf_t *conf)
510 {
511 	struct e6060sw_softc *sc;
512 
513 	sc = device_get_softc(dev);
514 
515 	/* Return the VLAN mode. */
516 	conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
517 	conf->vlan_mode = sc->vlan_mode;
518 
519 	return (0);
520 }
521 
522 static int
523 e6060sw_setconf(device_t dev, etherswitch_conf_t *conf)
524 {
525 	struct e6060sw_softc *sc;
526 
527 	sc = device_get_softc(dev);
528 
529 	/* Set the VLAN mode. */
530 	if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
531 		if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) {
532 			sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
533 		} else {
534 			sc->vlan_mode = 0;
535 		}
536 
537 		/* Reset VLANs. */
538 		e6060sw_reset_vlans(dev);
539 	}
540 
541 	return (0);
542 }
543 
544 static void
545 e6060sw_statchg(device_t dev)
546 {
547 
548 	DPRINTF(dev, "%s\n", __func__);
549 }
550 
551 static int
552 e6060sw_ifmedia_upd(struct ifnet *ifp)
553 {
554 	struct e6060sw_softc *sc;
555 	struct mii_data *mii;
556 
557 	sc = ifp->if_softc;
558 	mii = e6060sw_miiforport(sc, ifp->if_dunit);
559 
560 	DPRINTF(sc->sc_dev, "%s\n", __func__);
561 	if (mii == NULL)
562 		return (ENXIO);
563 	mii_mediachg(mii);
564 	return (0);
565 }
566 
567 static void
568 e6060sw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
569 {
570 	struct e6060sw_softc *sc;
571 	struct mii_data *mii;
572 
573 	sc = ifp->if_softc;
574 	mii = e6060sw_miiforport(sc, ifp->if_dunit);
575 
576 	DPRINTF(sc->sc_dev, "%s\n", __func__);
577 
578 	if (mii == NULL)
579 		return;
580 	mii_pollstat(mii);
581 	ifmr->ifm_active = mii->mii_media_active;
582 	ifmr->ifm_status = mii->mii_media_status;
583 }
584 
585 static int
586 e6060sw_readphy(device_t dev, int phy, int reg)
587 {
588 	struct e6060sw_softc *sc;
589 	int data;
590 
591 	phy += SMI_OFFSET;
592 
593 	sc = device_get_softc(dev);
594 	E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
595 
596 	if (phy < 0 || phy >= 32)
597 		return (ENXIO);
598 	if (reg < 0 || reg >= 32)
599 		return (ENXIO);
600 
601 	E6060SW_LOCK(sc);
602 	data = MDIO_READREG(device_get_parent(dev), phy, reg);
603 	E6060SW_UNLOCK(sc);
604 
605 	return (data);
606 }
607 
608 static int
609 e6060sw_writephy(device_t dev, int phy, int reg, int data)
610 {
611 	struct e6060sw_softc *sc;
612 	int err;
613 
614 	phy += SMI_OFFSET;
615 
616 	sc = device_get_softc(dev);
617 	E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
618 
619 	if (phy < 0 || phy >= 32)
620 		return (ENXIO);
621 	if (reg < 0 || reg >= 32)
622 		return (ENXIO);
623 
624 	E6060SW_LOCK(sc);
625 	err = MDIO_WRITEREG(device_get_parent(dev), phy, reg, data);
626 	E6060SW_UNLOCK(sc);
627 
628 	return (err);
629 }
630 
631 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */
632 
633 static int
634 e6060sw_readreg(device_t dev, int addr)
635 {
636 	int devaddr, regaddr;
637 
638 	devaddr = (addr >> 5) & 0xf;
639 	regaddr = addr & 0x1f;
640 
641 	return MDIO_READREG(device_get_parent(dev), devaddr+SMI_OFFSET, regaddr);
642 }
643 
644 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */
645 
646 static int
647 e6060sw_writereg(device_t dev, int addr, int value)
648 {
649 	int devaddr, regaddr;
650 
651 	devaddr = (addr >> 5) & 0xf;
652 	regaddr = addr & 0x1f;
653 
654 	return (MDIO_WRITEREG(device_get_parent(dev), devaddr+SMI_OFFSET, regaddr, value));
655 }
656 
657 static device_method_t e6060sw_methods[] = {
658 	/* Device interface */
659 	DEVMETHOD(device_probe,		e6060sw_probe),
660 	DEVMETHOD(device_attach,	e6060sw_attach),
661 	DEVMETHOD(device_detach,	e6060sw_detach),
662 
663 	/* bus interface */
664 	DEVMETHOD(bus_add_child,	device_add_child_ordered),
665 
666 	/* MII interface */
667 	DEVMETHOD(miibus_readreg,	e6060sw_readphy),
668 	DEVMETHOD(miibus_writereg,	e6060sw_writephy),
669 	DEVMETHOD(miibus_statchg,	e6060sw_statchg),
670 
671 	/* MDIO interface */
672 	DEVMETHOD(mdio_readreg,		e6060sw_readphy),
673 	DEVMETHOD(mdio_writereg,	e6060sw_writephy),
674 
675 	/* etherswitch interface */
676 	DEVMETHOD(etherswitch_lock,	e6060sw_lock),
677 	DEVMETHOD(etherswitch_unlock,	e6060sw_unlock),
678 	DEVMETHOD(etherswitch_getinfo,	e6060sw_getinfo),
679 	DEVMETHOD(etherswitch_readreg,	e6060sw_readreg),
680 	DEVMETHOD(etherswitch_writereg,	e6060sw_writereg),
681 	DEVMETHOD(etherswitch_readphyreg,	e6060sw_readphy),
682 	DEVMETHOD(etherswitch_writephyreg,	e6060sw_writephy),
683 	DEVMETHOD(etherswitch_getport,	e6060sw_getport),
684 	DEVMETHOD(etherswitch_setport,	e6060sw_setport),
685 	DEVMETHOD(etherswitch_getvgroup,	e6060sw_getvgroup),
686 	DEVMETHOD(etherswitch_setvgroup,	e6060sw_setvgroup),
687 	DEVMETHOD(etherswitch_setconf,	e6060sw_setconf),
688 	DEVMETHOD(etherswitch_getconf,	e6060sw_getconf),
689 
690 	DEVMETHOD_END
691 };
692 
693 DEFINE_CLASS_0(e6060sw, e6060sw_driver, e6060sw_methods,
694     sizeof(struct e6060sw_softc));
695 static devclass_t e6060sw_devclass;
696 
697 DRIVER_MODULE(e6060sw, mdio, e6060sw_driver, e6060sw_devclass, 0, 0);
698 DRIVER_MODULE(miibus, e6060sw, miibus_driver, miibus_devclass, 0, 0);
699 DRIVER_MODULE(mdio, e6060sw, mdio_driver, mdio_devclass, 0, 0);
700 DRIVER_MODULE(etherswitch, e6060sw, etherswitch_driver, etherswitch_devclass, 0, 0);
701 MODULE_VERSION(e6060sw, 1);
702 MODULE_DEPEND(e6060sw, miibus, 1, 1, 1); /* XXX which versions? */
703 MODULE_DEPEND(e6060sw, etherswitch, 1, 1, 1); /* XXX which versions? */
704