xref: /freebsd/sys/dev/etherswitch/ip17x/ip17x.c (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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(struct ifnet *);
83 static void ip17x_ifmedia_sts(struct ifnet *, 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 		sc->ifp[port]->if_softc = sc;
178 		sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
179 		    IFF_DRV_RUNNING | IFF_SIMPLEX;
180 		if_initname(sc->ifp[port], name, port);
181 		sc->miibus[port] = malloc(sizeof(device_t), M_IP17X,
182 		    M_WAITOK | M_ZERO);
183 		err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
184 		    ip17x_ifmedia_upd, ip17x_ifmedia_sts, \
185 		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
186 		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
187 		    device_get_nameunit(*sc->miibus[port]),
188 		    sc->ifp[port]->if_xname);
189 		if (err != 0) {
190 			device_printf(sc->sc_dev,
191 			    "attaching PHY %d failed\n",
192 			    phy);
193 			break;
194 		}
195 		sc->info.es_nports = port + 1;
196 		if (++port >= sc->numports)
197 			break;
198 	}
199 	return (err);
200 }
201 
202 static int
203 ip17x_attach(device_t dev)
204 {
205 	struct ip17x_softc *sc;
206 	int err;
207 
208 	sc = device_get_softc(dev);
209 
210 	sc->sc_dev = dev;
211 	mtx_init(&sc->sc_mtx, "ip17x", NULL, MTX_DEF);
212 	strlcpy(sc->info.es_name, device_get_desc(dev),
213 	    sizeof(sc->info.es_name));
214 
215 	/* XXX Defaults */
216 	sc->phymask = 0x0f;
217 	sc->media = 100;
218 
219 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
220 	    "phymask", &sc->phymask);
221 
222 	/* Number of vlans supported by the switch. */
223 	sc->info.es_nvlangroups = IP17X_MAX_VLANS;
224 
225 	/* Attach the switch related functions. */
226 	if (IP17X_IS_SWITCH(sc, IP175C))
227 		ip175c_attach(sc);
228 	else if (IP17X_IS_SWITCH(sc, IP175D))
229 		ip175d_attach(sc);
230 	else
231 		/* We don't have support to all the models yet :-/ */
232 		return (ENXIO);
233 
234 	/* Always attach the cpu port. */
235 	sc->phymask |= (1 << sc->cpuport);
236 
237 	sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_IP17X,
238 	    M_WAITOK | M_ZERO);
239 	sc->pvid = malloc(sizeof(uint32_t) * sc->numports, M_IP17X,
240 	    M_WAITOK | M_ZERO);
241 	sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_IP17X,
242 	    M_WAITOK | M_ZERO);
243 	sc->portphy = malloc(sizeof(int) * sc->numports, M_IP17X,
244 	    M_WAITOK | M_ZERO);
245 
246 	/* Initialize the switch. */
247 	sc->hal.ip17x_reset(sc);
248 
249 	/*
250 	 * Attach the PHYs and complete the bus enumeration.
251 	 */
252 	err = ip17x_attach_phys(sc);
253 	if (err != 0)
254 		return (err);
255 
256 	/*
257 	 * Set the switch to port based vlans or disabled (if not supported
258 	 * on this model).
259 	 */
260 	sc->hal.ip17x_set_vlan_mode(sc, ETHERSWITCH_VLAN_PORT);
261 
262 	bus_generic_probe(dev);
263 	bus_enumerate_hinted_children(dev);
264 	err = bus_generic_attach(dev);
265 	if (err != 0)
266 		return (err);
267 
268 	if (sc->miipoll) {
269 		callout_init(&sc->callout_tick, 0);
270 
271 		ip17x_tick(sc);
272 	}
273 
274 	return (0);
275 }
276 
277 static int
278 ip17x_detach(device_t dev)
279 {
280 	struct ip17x_softc *sc;
281 	int i, port;
282 
283 	sc = device_get_softc(dev);
284 	if (sc->miipoll)
285 		callout_drain(&sc->callout_tick);
286 
287 	for (i=0; i < MII_NPHY; i++) {
288 		if (((1 << i) & sc->phymask) == 0)
289 			continue;
290 		port = sc->phyport[i];
291 		if (sc->miibus[port] != NULL)
292 			device_delete_child(dev, (*sc->miibus[port]));
293 		if (sc->ifp[port] != NULL)
294 			if_free(sc->ifp[port]);
295 		free(sc->miibus[port], M_IP17X);
296 	}
297 
298 	free(sc->portphy, M_IP17X);
299 	free(sc->miibus, M_IP17X);
300 	free(sc->pvid, M_IP17X);
301 	free(sc->ifp, M_IP17X);
302 
303 	/* Reset the switch. */
304 	sc->hal.ip17x_reset(sc);
305 
306 	bus_generic_detach(dev);
307 	mtx_destroy(&sc->sc_mtx);
308 
309 	return (0);
310 }
311 
312 static inline struct mii_data *
313 ip17x_miiforport(struct ip17x_softc *sc, int port)
314 {
315 
316 	if (port < 0 || port > sc->numports)
317 		return (NULL);
318 	return (device_get_softc(*sc->miibus[port]));
319 }
320 
321 static inline struct ifnet *
322 ip17x_ifpforport(struct ip17x_softc *sc, int port)
323 {
324 
325 	if (port < 0 || port > sc->numports)
326 		return (NULL);
327 	return (sc->ifp[port]);
328 }
329 
330 /*
331  * Poll the status for all PHYs.
332  */
333 static void
334 ip17x_miipollstat(struct ip17x_softc *sc)
335 {
336 	struct mii_softc *miisc;
337 	struct mii_data *mii;
338 	int i, port;
339 
340 	IP17X_LOCK_ASSERT(sc, MA_NOTOWNED);
341 
342 	for (i = 0; i < MII_NPHY; i++) {
343 		if (((1 << i) & sc->phymask) == 0)
344 			continue;
345 		port = sc->phyport[i];
346 		if ((*sc->miibus[port]) == NULL)
347 			continue;
348 		mii = device_get_softc(*sc->miibus[port]);
349 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
350 			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
351 			    miisc->mii_inst)
352 				continue;
353 			ukphy_status(miisc);
354 			mii_phy_update(miisc, MII_POLLSTAT);
355 		}
356 	}
357 }
358 
359 static void
360 ip17x_tick(void *arg)
361 {
362 	struct ip17x_softc *sc;
363 
364 	sc = arg;
365 	ip17x_miipollstat(sc);
366 	callout_reset(&sc->callout_tick, hz, ip17x_tick, sc);
367 }
368 
369 static void
370 ip17x_lock(device_t dev)
371 {
372 	struct ip17x_softc *sc;
373 
374 	sc = device_get_softc(dev);
375 	IP17X_LOCK_ASSERT(sc, MA_NOTOWNED);
376 	IP17X_LOCK(sc);
377 }
378 
379 static void
380 ip17x_unlock(device_t dev)
381 {
382 	struct ip17x_softc *sc;
383 
384 	sc = device_get_softc(dev);
385 	IP17X_LOCK_ASSERT(sc, MA_OWNED);
386 	IP17X_UNLOCK(sc);
387 }
388 
389 static etherswitch_info_t *
390 ip17x_getinfo(device_t dev)
391 {
392 	struct ip17x_softc *sc;
393 
394 	sc = device_get_softc(dev);
395 	return (&sc->info);
396 }
397 
398 static int
399 ip17x_getport(device_t dev, etherswitch_port_t *p)
400 {
401 	struct ip17x_softc *sc;
402 	struct ifmediareq *ifmr;
403 	struct mii_data *mii;
404 	int err, phy;
405 
406 	sc = device_get_softc(dev);
407 	if (p->es_port < 0 || p->es_port >= sc->numports)
408 		return (ENXIO);
409 
410 	phy = sc->portphy[p->es_port];
411 
412 	/* Retrieve the PVID. */
413 	p->es_pvid = sc->pvid[phy];
414 
415 	/* Port flags. */
416 	if (sc->addtag & (1 << phy))
417 		p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
418 	if (sc->striptag & (1 << phy))
419 		p->es_flags |= ETHERSWITCH_PORT_STRIPTAG;
420 
421 	ifmr = &p->es_ifmr;
422 
423 	/* No media settings ? */
424 	if (p->es_ifmr.ifm_count == 0)
425 		return (0);
426 
427 	mii = ip17x_miiforport(sc, p->es_port);
428 	if (mii == NULL)
429 		return (ENXIO);
430 	if (phy == sc->cpuport) {
431 		/* fill in fixed values for CPU port */
432 		p->es_flags |= ETHERSWITCH_PORT_CPU;
433 		ifmr->ifm_count = 0;
434 		if (sc->media == 100)
435 			ifmr->ifm_current = ifmr->ifm_active =
436 			    IFM_ETHER | IFM_100_TX | IFM_FDX;
437 		else
438 			ifmr->ifm_current = ifmr->ifm_active =
439 			    IFM_ETHER | IFM_1000_T | IFM_FDX;
440 		ifmr->ifm_mask = 0;
441 		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
442 	} else {
443 		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
444 		    &mii->mii_media, SIOCGIFMEDIA);
445 		if (err)
446 			return (err);
447 	}
448 	return (0);
449 }
450 
451 static int
452 ip17x_setport(device_t dev, etherswitch_port_t *p)
453 {
454 	struct ip17x_softc *sc;
455 	struct ifmedia *ifm;
456 	struct ifnet *ifp;
457 	struct mii_data *mii;
458 	int phy;
459 
460  	sc = device_get_softc(dev);
461 	if (p->es_port < 0 || p->es_port >= sc->numports)
462 		return (ENXIO);
463 
464 	phy = sc->portphy[p->es_port];
465 	ifp = ip17x_ifpforport(sc, p->es_port);
466 	mii = ip17x_miiforport(sc, p->es_port);
467 	if (ifp == NULL || mii == NULL)
468 		return (ENXIO);
469 
470 	/* Port flags. */
471 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
472 
473 		/* Set the PVID. */
474 		if (p->es_pvid != 0) {
475 			if (IP17X_IS_SWITCH(sc, IP175C) &&
476 			    p->es_pvid > IP175C_LAST_VLAN)
477 				return (ENXIO);
478 			sc->pvid[phy] = p->es_pvid;
479 		}
480 
481 		/* Mutually exclusive. */
482 		if (p->es_flags & ETHERSWITCH_PORT_ADDTAG &&
483 		    p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
484 			return (EINVAL);
485 
486 		/* Reset the settings for this port. */
487 		sc->addtag &= ~(1 << phy);
488 		sc->striptag &= ~(1 << phy);
489 
490 		/* And then set it to the new value. */
491 		if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
492 			sc->addtag |= (1 << phy);
493 		if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
494 			sc->striptag |= (1 << phy);
495 	}
496 
497 	/* Update the switch configuration. */
498 	if (sc->hal.ip17x_hw_setup(sc))
499 		return (ENXIO);
500 
501 	/* Do not allow media changes on CPU port. */
502 	if (phy == sc->cpuport)
503 		return (0);
504 
505 	/* No media settings ? */
506 	if (p->es_ifmr.ifm_count == 0)
507 		return (0);
508 
509 	ifm = &mii->mii_media;
510 	return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA));
511 }
512 
513 static void
514 ip17x_statchg(device_t dev)
515 {
516 
517 	DPRINTF(dev, "%s\n", __func__);
518 }
519 
520 static int
521 ip17x_ifmedia_upd(struct ifnet *ifp)
522 {
523 	struct ip17x_softc *sc;
524 	struct mii_data *mii;
525 
526  	sc = ifp->if_softc;
527 	DPRINTF(sc->sc_dev, "%s\n", __func__);
528  	mii = ip17x_miiforport(sc, ifp->if_dunit);
529 	if (mii == NULL)
530 		return (ENXIO);
531 	mii_mediachg(mii);
532 
533 	return (0);
534 }
535 
536 static void
537 ip17x_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
538 {
539 	struct ip17x_softc *sc;
540 	struct mii_data *mii;
541 
542  	sc = ifp->if_softc;
543 	DPRINTF(sc->sc_dev, "%s\n", __func__);
544 	mii = ip17x_miiforport(sc, ifp->if_dunit);
545 	if (mii == NULL)
546 		return;
547 	mii_pollstat(mii);
548 	ifmr->ifm_active = mii->mii_media_active;
549 	ifmr->ifm_status = mii->mii_media_status;
550 }
551 
552 static int
553 ip17x_readreg(device_t dev, int addr)
554 {
555 	struct ip17x_softc *sc;
556 
557 	sc = device_get_softc(dev);
558 	IP17X_LOCK_ASSERT(sc, MA_OWNED);
559 
560 	/* Not supported. */
561 	return (0);
562 }
563 
564 static int
565 ip17x_writereg(device_t dev, int addr, int value)
566 {
567 	struct ip17x_softc *sc;
568 
569 	sc = device_get_softc(dev);
570 	IP17X_LOCK_ASSERT(sc, MA_OWNED);
571 
572 	/* Not supported. */
573 	return (0);
574 }
575 
576 static int
577 ip17x_getconf(device_t dev, etherswitch_conf_t *conf)
578 {
579 	struct ip17x_softc *sc;
580 
581 	sc = device_get_softc(dev);
582 
583 	/* Return the VLAN mode. */
584 	conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
585 	conf->vlan_mode = sc->hal.ip17x_get_vlan_mode(sc);
586 
587 	return (0);
588 }
589 
590 static int
591 ip17x_setconf(device_t dev, etherswitch_conf_t *conf)
592 {
593 	struct ip17x_softc *sc;
594 
595 	sc = device_get_softc(dev);
596 
597 	/* Set the VLAN mode. */
598 	if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE)
599 		sc->hal.ip17x_set_vlan_mode(sc, conf->vlan_mode);
600 
601 	return (0);
602 }
603 
604 static device_method_t ip17x_methods[] = {
605 	/* Device interface */
606 	DEVMETHOD(device_identify,	ip17x_identify),
607 	DEVMETHOD(device_probe,		ip17x_probe),
608 	DEVMETHOD(device_attach,	ip17x_attach),
609 	DEVMETHOD(device_detach,	ip17x_detach),
610 
611 	/* bus interface */
612 	DEVMETHOD(bus_add_child,	device_add_child_ordered),
613 
614 	/* MII interface */
615 	DEVMETHOD(miibus_readreg,	ip17x_readphy),
616 	DEVMETHOD(miibus_writereg,	ip17x_writephy),
617 	DEVMETHOD(miibus_statchg,	ip17x_statchg),
618 
619 	/* MDIO interface */
620 	DEVMETHOD(mdio_readreg,		ip17x_readphy),
621 	DEVMETHOD(mdio_writereg,	ip17x_writephy),
622 
623 	/* etherswitch interface */
624 	DEVMETHOD(etherswitch_lock,	ip17x_lock),
625 	DEVMETHOD(etherswitch_unlock,	ip17x_unlock),
626 	DEVMETHOD(etherswitch_getinfo,	ip17x_getinfo),
627 	DEVMETHOD(etherswitch_readreg,	ip17x_readreg),
628 	DEVMETHOD(etherswitch_writereg,	ip17x_writereg),
629 	DEVMETHOD(etherswitch_readphyreg,	ip17x_readphy),
630 	DEVMETHOD(etherswitch_writephyreg,	ip17x_writephy),
631 	DEVMETHOD(etherswitch_getport,	ip17x_getport),
632 	DEVMETHOD(etherswitch_setport,	ip17x_setport),
633 	DEVMETHOD(etherswitch_getvgroup,	ip17x_getvgroup),
634 	DEVMETHOD(etherswitch_setvgroup,	ip17x_setvgroup),
635 	DEVMETHOD(etherswitch_getconf,	ip17x_getconf),
636 	DEVMETHOD(etherswitch_setconf,	ip17x_setconf),
637 
638 	DEVMETHOD_END
639 };
640 
641 DEFINE_CLASS_0(ip17x, ip17x_driver, ip17x_methods,
642     sizeof(struct ip17x_softc));
643 static devclass_t ip17x_devclass;
644 
645 DRIVER_MODULE(ip17x, mdio, ip17x_driver, ip17x_devclass, 0, 0);
646 DRIVER_MODULE(miibus, ip17x, miibus_driver, miibus_devclass, 0, 0);
647 DRIVER_MODULE(etherswitch, ip17x, etherswitch_driver, etherswitch_devclass, 0, 0);
648 MODULE_VERSION(ip17x, 1);
649 
650 #ifdef FDT
651 MODULE_DEPEND(ip17x, mdio, 1, 1, 1); /* XXX which versions? */
652 #else
653 DRIVER_MODULE(mdio, ip17x, mdio_driver, mdio_devclass, 0, 0);
654 MODULE_DEPEND(ip17x, miibus, 1, 1, 1); /* XXX which versions? */
655 MODULE_DEPEND(ip17x, etherswitch, 1, 1, 1); /* XXX which versions? */
656 #endif
657