xref: /freebsd/sys/dev/etherswitch/ip17x/ip17x.c (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 Luiz Otavio O Souza.
5  * Copyright (c) 2011-2012 Stefan Bethke.
6  * Copyright (c) 2012 Adrian Chadd.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32 
33 #include "opt_platform.h"
34 
35 #include <sys/param.h>
36 #include <sys/bus.h>
37 #include <sys/errno.h>
38 #include <sys/kernel.h>
39 #include <sys/lock.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42 #include <sys/mutex.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/sysctl.h>
46 #include <sys/systm.h>
47 #include <sys/types.h>
48 
49 #include <net/if.h>
50 #include <net/ethernet.h>
51 #include <net/if_media.h>
52 #include <net/if_types.h>
53 #include <net/if_var.h>
54 
55 #include <machine/bus.h>
56 #include <dev/mii/mii.h>
57 #include <dev/mii/miivar.h>
58 #include <dev/mdio/mdio.h>
59 
60 #include <dev/etherswitch/etherswitch.h>
61 #include <dev/etherswitch/ip17x/ip17x_phy.h>
62 #include <dev/etherswitch/ip17x/ip17x_reg.h>
63 #include <dev/etherswitch/ip17x/ip17x_var.h>
64 #include <dev/etherswitch/ip17x/ip17x_vlans.h>
65 #include <dev/etherswitch/ip17x/ip175c.h>
66 #include <dev/etherswitch/ip17x/ip175d.h>
67 
68 #ifdef FDT
69 #include <dev/fdt/fdt_common.h>
70 #include <dev/ofw/ofw_bus.h>
71 #include <dev/ofw/ofw_bus_subr.h>
72 #endif
73 
74 #include "mdio_if.h"
75 #include "miibus_if.h"
76 #include "etherswitch_if.h"
77 
78 MALLOC_DECLARE(M_IP17X);
79 MALLOC_DEFINE(M_IP17X, "ip17x", "ip17x data structures");
80 
81 static void ip17x_tick(void *);
82 static int ip17x_ifmedia_upd(if_t);
83 static void ip17x_ifmedia_sts(if_t, struct ifmediareq *);
84 
85 static void
86 ip17x_identify(driver_t *driver, device_t parent)
87 {
88 	if (device_find_child(parent, "ip17x", -1) == NULL)
89 	    BUS_ADD_CHILD(parent, 0, "ip17x", -1);
90 }
91 
92 static int
93 ip17x_probe(device_t dev)
94 {
95 	struct ip17x_softc *sc;
96 	uint32_t oui, model, phy_id1, phy_id2;
97 #ifdef FDT
98 	phandle_t ip17x_node;
99 	pcell_t cell;
100 
101 	ip17x_node = fdt_find_compatible(OF_finddevice("/"),
102 	    "icplus,ip17x", 0);
103 
104 	if (ip17x_node == 0)
105 		return (ENXIO);
106 #endif
107 
108 	sc = device_get_softc(dev);
109 
110 	/* Read ID from PHY 0. */
111 	phy_id1 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR1);
112 	phy_id2 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR2);
113 
114 	oui = MII_OUI(phy_id1, phy_id2);
115 	model = MII_MODEL(phy_id2);
116 	/* We only care about IC+ devices. */
117 	if (oui != IP17X_OUI) {
118 		device_printf(dev,
119 		    "Unsupported IC+ switch. Unknown OUI: %#x\n", oui);
120 		return (ENXIO);
121 	}
122 
123 	switch (model) {
124 	case IP17X_IP175A:
125 		sc->sc_switchtype = IP17X_SWITCH_IP175A;
126 		break;
127 	case IP17X_IP175C:
128 		sc->sc_switchtype = IP17X_SWITCH_IP175C;
129 		break;
130 	default:
131 		device_printf(dev, "Unsupported IC+ switch model: %#x\n",
132 		    model);
133 		return (ENXIO);
134 	}
135 
136 	/* IP175D has a specific ID register. */
137 	model = MDIO_READREG(device_get_parent(dev), IP175D_ID_PHY,
138 	    IP175D_ID_REG);
139 	if (model == 0x175d)
140 		sc->sc_switchtype = IP17X_SWITCH_IP175D;
141 	else {
142 		/* IP178 has more PHYs.  Try it. */
143 		model = MDIO_READREG(device_get_parent(dev), 5, MII_PHYIDR1);
144 		if (phy_id1 == model)
145 			sc->sc_switchtype = IP17X_SWITCH_IP178C;
146 	}
147 
148 	sc->miipoll = 1;
149 #ifdef FDT
150 	if ((OF_getencprop(ip17x_node, "mii-poll",
151 	    &cell, sizeof(cell))) > 0)
152 		sc->miipoll = cell ? 1 : 0;
153 #else
154 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
155 	    "mii-poll", &sc->miipoll);
156 #endif
157 	device_set_desc_copy(dev, "IC+ IP17x switch driver");
158 	return (BUS_PROBE_DEFAULT);
159 }
160 
161 static int
162 ip17x_attach_phys(struct ip17x_softc *sc)
163 {
164 	int err, phy, port;
165 	char name[IFNAMSIZ];
166 
167 	port = err = 0;
168 
169 	/* PHYs need an interface, so we generate a dummy one */
170 	snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
171 	for (phy = 0; phy < MII_NPHY; phy++) {
172 		if (((1 << phy) & sc->phymask) == 0)
173 			continue;
174 		sc->phyport[phy] = port;
175 		sc->portphy[port] = phy;
176 		sc->ifp[port] = if_alloc(IFT_ETHER);
177 		if (sc->ifp[port] == NULL) {
178 			device_printf(sc->sc_dev, "couldn't allocate ifnet structure\n");
179 			err = ENOMEM;
180 			break;
181 		}
182 
183 		if_setsoftc(sc->ifp[port], sc);
184 		if_setflags(sc->ifp[port], IFF_UP | IFF_BROADCAST |
185 		    IFF_DRV_RUNNING | IFF_SIMPLEX);
186 		if_initname(sc->ifp[port], name, port);
187 		sc->miibus[port] = malloc(sizeof(device_t), M_IP17X,
188 		    M_WAITOK | M_ZERO);
189 		err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
190 		    ip17x_ifmedia_upd, ip17x_ifmedia_sts, \
191 		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
192 		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
193 		    device_get_nameunit(*sc->miibus[port]),
194 		    if_name(sc->ifp[port]));
195 		if (err != 0) {
196 			device_printf(sc->sc_dev,
197 			    "attaching PHY %d failed\n",
198 			    phy);
199 			break;
200 		}
201 		sc->info.es_nports = port + 1;
202 		if (++port >= sc->numports)
203 			break;
204 	}
205 	return (err);
206 }
207 
208 static int
209 ip17x_attach(device_t dev)
210 {
211 	struct ip17x_softc *sc;
212 	int err;
213 
214 	sc = device_get_softc(dev);
215 
216 	sc->sc_dev = dev;
217 	mtx_init(&sc->sc_mtx, "ip17x", NULL, MTX_DEF);
218 	strlcpy(sc->info.es_name, device_get_desc(dev),
219 	    sizeof(sc->info.es_name));
220 
221 	/* XXX Defaults */
222 	sc->phymask = 0x0f;
223 	sc->media = 100;
224 
225 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
226 	    "phymask", &sc->phymask);
227 
228 	/* Number of vlans supported by the switch. */
229 	sc->info.es_nvlangroups = IP17X_MAX_VLANS;
230 
231 	/* Attach the switch related functions. */
232 	if (IP17X_IS_SWITCH(sc, IP175C))
233 		ip175c_attach(sc);
234 	else if (IP17X_IS_SWITCH(sc, IP175D))
235 		ip175d_attach(sc);
236 	else
237 		/* We don't have support to all the models yet :-/ */
238 		return (ENXIO);
239 
240 	/* Always attach the cpu port. */
241 	sc->phymask |= (1 << sc->cpuport);
242 
243 	sc->ifp = malloc(sizeof(if_t) * sc->numports, M_IP17X,
244 	    M_WAITOK | M_ZERO);
245 	sc->pvid = malloc(sizeof(uint32_t) * sc->numports, M_IP17X,
246 	    M_WAITOK | M_ZERO);
247 	sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_IP17X,
248 	    M_WAITOK | M_ZERO);
249 	sc->portphy = malloc(sizeof(int) * sc->numports, M_IP17X,
250 	    M_WAITOK | M_ZERO);
251 
252 	/* Initialize the switch. */
253 	sc->hal.ip17x_reset(sc);
254 
255 	/*
256 	 * Attach the PHYs and complete the bus enumeration.
257 	 */
258 	err = ip17x_attach_phys(sc);
259 	if (err != 0)
260 		return (err);
261 
262 	/*
263 	 * Set the switch to port based vlans or disabled (if not supported
264 	 * on this model).
265 	 */
266 	sc->hal.ip17x_set_vlan_mode(sc, ETHERSWITCH_VLAN_PORT);
267 
268 	bus_generic_probe(dev);
269 	bus_enumerate_hinted_children(dev);
270 	err = bus_generic_attach(dev);
271 	if (err != 0)
272 		return (err);
273 
274 	if (sc->miipoll) {
275 		callout_init(&sc->callout_tick, 0);
276 
277 		ip17x_tick(sc);
278 	}
279 
280 	return (0);
281 }
282 
283 static int
284 ip17x_detach(device_t dev)
285 {
286 	struct ip17x_softc *sc;
287 	int i, port;
288 
289 	sc = device_get_softc(dev);
290 	if (sc->miipoll)
291 		callout_drain(&sc->callout_tick);
292 
293 	for (i=0; i < MII_NPHY; i++) {
294 		if (((1 << i) & sc->phymask) == 0)
295 			continue;
296 		port = sc->phyport[i];
297 		if (sc->miibus[port] != NULL)
298 			device_delete_child(dev, (*sc->miibus[port]));
299 		if (sc->ifp[port] != NULL)
300 			if_free(sc->ifp[port]);
301 		free(sc->miibus[port], M_IP17X);
302 	}
303 
304 	free(sc->portphy, M_IP17X);
305 	free(sc->miibus, M_IP17X);
306 	free(sc->pvid, M_IP17X);
307 	free(sc->ifp, M_IP17X);
308 
309 	/* Reset the switch. */
310 	sc->hal.ip17x_reset(sc);
311 
312 	bus_generic_detach(dev);
313 	mtx_destroy(&sc->sc_mtx);
314 
315 	return (0);
316 }
317 
318 static inline struct mii_data *
319 ip17x_miiforport(struct ip17x_softc *sc, int port)
320 {
321 
322 	if (port < 0 || port > sc->numports)
323 		return (NULL);
324 	return (device_get_softc(*sc->miibus[port]));
325 }
326 
327 static inline if_t
328 ip17x_ifpforport(struct ip17x_softc *sc, int port)
329 {
330 
331 	if (port < 0 || port > sc->numports)
332 		return (NULL);
333 	return (sc->ifp[port]);
334 }
335 
336 /*
337  * Poll the status for all PHYs.
338  */
339 static void
340 ip17x_miipollstat(struct ip17x_softc *sc)
341 {
342 	struct mii_softc *miisc;
343 	struct mii_data *mii;
344 	int i, port;
345 
346 	IP17X_LOCK_ASSERT(sc, MA_NOTOWNED);
347 
348 	for (i = 0; i < MII_NPHY; i++) {
349 		if (((1 << i) & sc->phymask) == 0)
350 			continue;
351 		port = sc->phyport[i];
352 		if ((*sc->miibus[port]) == NULL)
353 			continue;
354 		mii = device_get_softc(*sc->miibus[port]);
355 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
356 			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
357 			    miisc->mii_inst)
358 				continue;
359 			ukphy_status(miisc);
360 			mii_phy_update(miisc, MII_POLLSTAT);
361 		}
362 	}
363 }
364 
365 static void
366 ip17x_tick(void *arg)
367 {
368 	struct ip17x_softc *sc;
369 
370 	sc = arg;
371 	ip17x_miipollstat(sc);
372 	callout_reset(&sc->callout_tick, hz, ip17x_tick, sc);
373 }
374 
375 static void
376 ip17x_lock(device_t dev)
377 {
378 	struct ip17x_softc *sc;
379 
380 	sc = device_get_softc(dev);
381 	IP17X_LOCK_ASSERT(sc, MA_NOTOWNED);
382 	IP17X_LOCK(sc);
383 }
384 
385 static void
386 ip17x_unlock(device_t dev)
387 {
388 	struct ip17x_softc *sc;
389 
390 	sc = device_get_softc(dev);
391 	IP17X_LOCK_ASSERT(sc, MA_OWNED);
392 	IP17X_UNLOCK(sc);
393 }
394 
395 static etherswitch_info_t *
396 ip17x_getinfo(device_t dev)
397 {
398 	struct ip17x_softc *sc;
399 
400 	sc = device_get_softc(dev);
401 	return (&sc->info);
402 }
403 
404 static int
405 ip17x_getport(device_t dev, etherswitch_port_t *p)
406 {
407 	struct ip17x_softc *sc;
408 	struct ifmediareq *ifmr;
409 	struct mii_data *mii;
410 	int err, phy;
411 
412 	sc = device_get_softc(dev);
413 	if (p->es_port < 0 || p->es_port >= sc->numports)
414 		return (ENXIO);
415 
416 	phy = sc->portphy[p->es_port];
417 
418 	/* Retrieve the PVID. */
419 	p->es_pvid = sc->pvid[phy];
420 
421 	/* Port flags. */
422 	if (sc->addtag & (1 << phy))
423 		p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
424 	if (sc->striptag & (1 << phy))
425 		p->es_flags |= ETHERSWITCH_PORT_STRIPTAG;
426 
427 	ifmr = &p->es_ifmr;
428 
429 	/* No media settings ? */
430 	if (p->es_ifmr.ifm_count == 0)
431 		return (0);
432 
433 	mii = ip17x_miiforport(sc, p->es_port);
434 	if (mii == NULL)
435 		return (ENXIO);
436 	if (phy == sc->cpuport) {
437 		/* fill in fixed values for CPU port */
438 		p->es_flags |= ETHERSWITCH_PORT_CPU;
439 		ifmr->ifm_count = 0;
440 		if (sc->media == 100)
441 			ifmr->ifm_current = ifmr->ifm_active =
442 			    IFM_ETHER | IFM_100_TX | IFM_FDX;
443 		else
444 			ifmr->ifm_current = ifmr->ifm_active =
445 			    IFM_ETHER | IFM_1000_T | IFM_FDX;
446 		ifmr->ifm_mask = 0;
447 		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
448 	} else {
449 		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
450 		    &mii->mii_media, SIOCGIFMEDIA);
451 		if (err)
452 			return (err);
453 	}
454 	return (0);
455 }
456 
457 static int
458 ip17x_setport(device_t dev, etherswitch_port_t *p)
459 {
460 	struct ip17x_softc *sc;
461 	struct ifmedia *ifm;
462 	if_t ifp;
463 	struct mii_data *mii;
464 	int phy;
465 
466  	sc = device_get_softc(dev);
467 	if (p->es_port < 0 || p->es_port >= sc->numports)
468 		return (ENXIO);
469 
470 	phy = sc->portphy[p->es_port];
471 	ifp = ip17x_ifpforport(sc, p->es_port);
472 	mii = ip17x_miiforport(sc, p->es_port);
473 	if (ifp == NULL || mii == NULL)
474 		return (ENXIO);
475 
476 	/* Port flags. */
477 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
478 
479 		/* Set the PVID. */
480 		if (p->es_pvid != 0) {
481 			if (IP17X_IS_SWITCH(sc, IP175C) &&
482 			    p->es_pvid > IP175C_LAST_VLAN)
483 				return (ENXIO);
484 			sc->pvid[phy] = p->es_pvid;
485 		}
486 
487 		/* Mutually exclusive. */
488 		if (p->es_flags & ETHERSWITCH_PORT_ADDTAG &&
489 		    p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
490 			return (EINVAL);
491 
492 		/* Reset the settings for this port. */
493 		sc->addtag &= ~(1 << phy);
494 		sc->striptag &= ~(1 << phy);
495 
496 		/* And then set it to the new value. */
497 		if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
498 			sc->addtag |= (1 << phy);
499 		if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
500 			sc->striptag |= (1 << phy);
501 	}
502 
503 	/* Update the switch configuration. */
504 	if (sc->hal.ip17x_hw_setup(sc))
505 		return (ENXIO);
506 
507 	/* Do not allow media changes on CPU port. */
508 	if (phy == sc->cpuport)
509 		return (0);
510 
511 	/* No media settings ? */
512 	if (p->es_ifmr.ifm_count == 0)
513 		return (0);
514 
515 	ifm = &mii->mii_media;
516 	return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA));
517 }
518 
519 static void
520 ip17x_statchg(device_t dev)
521 {
522 
523 	DPRINTF(dev, "%s\n", __func__);
524 }
525 
526 static int
527 ip17x_ifmedia_upd(if_t ifp)
528 {
529 	struct ip17x_softc *sc;
530 	struct mii_data *mii;
531 
532  	sc = if_getsoftc(ifp);
533 	DPRINTF(sc->sc_dev, "%s\n", __func__);
534  	mii = ip17x_miiforport(sc, if_getdunit(ifp));
535 	if (mii == NULL)
536 		return (ENXIO);
537 	mii_mediachg(mii);
538 
539 	return (0);
540 }
541 
542 static void
543 ip17x_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
544 {
545 	struct ip17x_softc *sc;
546 	struct mii_data *mii;
547 
548  	sc = if_getsoftc(ifp);
549 	DPRINTF(sc->sc_dev, "%s\n", __func__);
550 	mii = ip17x_miiforport(sc, if_getdunit(ifp));
551 	if (mii == NULL)
552 		return;
553 	mii_pollstat(mii);
554 	ifmr->ifm_active = mii->mii_media_active;
555 	ifmr->ifm_status = mii->mii_media_status;
556 }
557 
558 static int
559 ip17x_readreg(device_t dev, int addr)
560 {
561 	struct ip17x_softc *sc;
562 
563 	sc = device_get_softc(dev);
564 	IP17X_LOCK_ASSERT(sc, MA_OWNED);
565 
566 	/* Not supported. */
567 	return (0);
568 }
569 
570 static int
571 ip17x_writereg(device_t dev, int addr, int value)
572 {
573 	struct ip17x_softc *sc;
574 
575 	sc = device_get_softc(dev);
576 	IP17X_LOCK_ASSERT(sc, MA_OWNED);
577 
578 	/* Not supported. */
579 	return (0);
580 }
581 
582 static int
583 ip17x_getconf(device_t dev, etherswitch_conf_t *conf)
584 {
585 	struct ip17x_softc *sc;
586 
587 	sc = device_get_softc(dev);
588 
589 	/* Return the VLAN mode. */
590 	conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
591 	conf->vlan_mode = sc->hal.ip17x_get_vlan_mode(sc);
592 
593 	return (0);
594 }
595 
596 static int
597 ip17x_setconf(device_t dev, etherswitch_conf_t *conf)
598 {
599 	struct ip17x_softc *sc;
600 
601 	sc = device_get_softc(dev);
602 
603 	/* Set the VLAN mode. */
604 	if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE)
605 		sc->hal.ip17x_set_vlan_mode(sc, conf->vlan_mode);
606 
607 	return (0);
608 }
609 
610 static device_method_t ip17x_methods[] = {
611 	/* Device interface */
612 	DEVMETHOD(device_identify,	ip17x_identify),
613 	DEVMETHOD(device_probe,		ip17x_probe),
614 	DEVMETHOD(device_attach,	ip17x_attach),
615 	DEVMETHOD(device_detach,	ip17x_detach),
616 
617 	/* bus interface */
618 	DEVMETHOD(bus_add_child,	device_add_child_ordered),
619 
620 	/* MII interface */
621 	DEVMETHOD(miibus_readreg,	ip17x_readphy),
622 	DEVMETHOD(miibus_writereg,	ip17x_writephy),
623 	DEVMETHOD(miibus_statchg,	ip17x_statchg),
624 
625 	/* MDIO interface */
626 	DEVMETHOD(mdio_readreg,		ip17x_readphy),
627 	DEVMETHOD(mdio_writereg,	ip17x_writephy),
628 
629 	/* etherswitch interface */
630 	DEVMETHOD(etherswitch_lock,	ip17x_lock),
631 	DEVMETHOD(etherswitch_unlock,	ip17x_unlock),
632 	DEVMETHOD(etherswitch_getinfo,	ip17x_getinfo),
633 	DEVMETHOD(etherswitch_readreg,	ip17x_readreg),
634 	DEVMETHOD(etherswitch_writereg,	ip17x_writereg),
635 	DEVMETHOD(etherswitch_readphyreg,	ip17x_readphy),
636 	DEVMETHOD(etherswitch_writephyreg,	ip17x_writephy),
637 	DEVMETHOD(etherswitch_getport,	ip17x_getport),
638 	DEVMETHOD(etherswitch_setport,	ip17x_setport),
639 	DEVMETHOD(etherswitch_getvgroup,	ip17x_getvgroup),
640 	DEVMETHOD(etherswitch_setvgroup,	ip17x_setvgroup),
641 	DEVMETHOD(etherswitch_getconf,	ip17x_getconf),
642 	DEVMETHOD(etherswitch_setconf,	ip17x_setconf),
643 
644 	DEVMETHOD_END
645 };
646 
647 DEFINE_CLASS_0(ip17x, ip17x_driver, ip17x_methods,
648     sizeof(struct ip17x_softc));
649 
650 DRIVER_MODULE(ip17x, mdio, ip17x_driver, 0, 0);
651 DRIVER_MODULE(miibus, ip17x, miibus_driver, 0, 0);
652 DRIVER_MODULE(etherswitch, ip17x, etherswitch_driver, 0, 0);
653 MODULE_VERSION(ip17x, 1);
654 
655 #ifdef FDT
656 MODULE_DEPEND(ip17x, mdio, 1, 1, 1); /* XXX which versions? */
657 #else
658 DRIVER_MODULE(mdio, ip17x, mdio_driver, 0, 0);
659 MODULE_DEPEND(ip17x, miibus, 1, 1, 1); /* XXX which versions? */
660 MODULE_DEPEND(ip17x, etherswitch, 1, 1, 1); /* XXX which versions? */
661 #endif
662