arswitch.c revision 235288
1235288Sadrian/*-
2235288Sadrian * Copyright (c) 2011-2012 Stefan Bethke.
3235288Sadrian * Copyright (c) 2012 Adrian Chadd.
4235288Sadrian * All rights reserved.
5235288Sadrian *
6235288Sadrian * Redistribution and use in source and binary forms, with or without
7235288Sadrian * modification, are permitted provided that the following conditions
8235288Sadrian * are met:
9235288Sadrian * 1. Redistributions of source code must retain the above copyright
10235288Sadrian *    notice, this list of conditions and the following disclaimer.
11235288Sadrian * 2. Redistributions in binary form must reproduce the above copyright
12235288Sadrian *    notice, this list of conditions and the following disclaimer in the
13235288Sadrian *    documentation and/or other materials provided with the distribution.
14235288Sadrian *
15235288Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16235288Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17235288Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18235288Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19235288Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20235288Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21235288Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22235288Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23235288Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24235288Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25235288Sadrian * SUCH DAMAGE.
26235288Sadrian *
27235288Sadrian * $FreeBSD: head/sys/dev/etherswitch/arswitch/arswitch.c 235288 2012-05-11 20:53:20Z adrian $
28235288Sadrian */
29235288Sadrian
30235288Sadrian#include <sys/param.h>
31235288Sadrian#include <sys/bus.h>
32235288Sadrian#include <sys/errno.h>
33235288Sadrian#include <sys/kernel.h>
34235288Sadrian#include <sys/module.h>
35235288Sadrian#include <sys/socket.h>
36235288Sadrian#include <sys/sockio.h>
37235288Sadrian#include <sys/sysctl.h>
38235288Sadrian#include <sys/systm.h>
39235288Sadrian
40235288Sadrian#include <net/if.h>
41235288Sadrian#include <net/if_arp.h>
42235288Sadrian#include <net/ethernet.h>
43235288Sadrian#include <net/if_dl.h>
44235288Sadrian#include <net/if_media.h>
45235288Sadrian#include <net/if_types.h>
46235288Sadrian
47235288Sadrian#include <machine/bus.h>
48235288Sadrian#include <dev/iicbus/iic.h>
49235288Sadrian#include <dev/iicbus/iiconf.h>
50235288Sadrian#include <dev/iicbus/iicbus.h>
51235288Sadrian#include <dev/mii/mii.h>
52235288Sadrian#include <dev/mii/miivar.h>
53235288Sadrian#include <dev/etherswitch/mdio.h>
54235288Sadrian
55235288Sadrian#include <dev/etherswitch/etherswitch.h>
56235288Sadrian
57235288Sadrian#include <dev/etherswitch/arswitch/arswitchreg.h>
58235288Sadrian#include <dev/etherswitch/arswitch/arswitchvar.h>
59235288Sadrian#include <dev/etherswitch/arswitch/arswitch_reg.h>
60235288Sadrian#include <dev/etherswitch/arswitch/arswitch_phy.h>
61235288Sadrian
62235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8216.h>
63235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8226.h>
64235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8316.h>
65235288Sadrian
66235288Sadrian#include "mdio_if.h"
67235288Sadrian#include "miibus_if.h"
68235288Sadrian#include "etherswitch_if.h"
69235288Sadrian
70235288Sadrian#if	defined(DEBUG)
71235288Sadrianstatic SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch");
72235288Sadrian#endif
73235288Sadrian
74235288Sadrianstatic inline int arswitch_portforphy(int phy);
75235288Sadrianstatic void arswitch_tick(void *arg);
76235288Sadrianstatic int arswitch_ifmedia_upd(struct ifnet *);
77235288Sadrianstatic void arswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *);
78235288Sadrian
79235288Sadrianstatic void
80235288Sadrianarswitch_identify(driver_t *driver, device_t parent)
81235288Sadrian{
82235288Sadrian	device_t child;
83235288Sadrian
84235288Sadrian	if (device_find_child(parent, driver->name, -1) == NULL) {
85235288Sadrian		child = BUS_ADD_CHILD(parent, 0, driver->name, -1);
86235288Sadrian	}
87235288Sadrian}
88235288Sadrian
89235288Sadrianstatic int
90235288Sadrianarswitch_probe(device_t dev)
91235288Sadrian{
92235288Sadrian	struct arswitch_softc *sc;
93235288Sadrian	uint32_t id;
94235288Sadrian	char *chipname, desc[256];
95235288Sadrian
96235288Sadrian	sc = device_get_softc(dev);
97235288Sadrian	bzero(sc, sizeof(*sc));
98235288Sadrian	sc->page = -1;
99235288Sadrian	id = arswitch_readreg(dev, AR8X16_REG_MASK_CTRL);
100235288Sadrian	switch ((id & AR8X16_MASK_CTRL_VER_MASK) >>
101235288Sadrian	    AR8X16_MASK_CTRL_VER_SHIFT) {
102235288Sadrian	case 1:
103235288Sadrian		chipname = "AR8216";
104235288Sadrian		sc->sc_switchtype = AR8X16_SWITCH_AR8216;
105235288Sadrian		break;
106235288Sadrian	case 2:
107235288Sadrian		chipname = "AR8226";
108235288Sadrian		sc->sc_switchtype = AR8X16_SWITCH_AR8226;
109235288Sadrian		break;
110235288Sadrian	case 16:
111235288Sadrian		chipname = "AR8316";
112235288Sadrian		sc->sc_switchtype = AR8X16_SWITCH_AR8316;
113235288Sadrian		break;
114235288Sadrian	default:
115235288Sadrian		chipname = NULL;
116235288Sadrian	}
117235288Sadrian	DPRINTF(dev, "chipname=%s, rev=%02x\n", chipname,
118235288Sadrian	    id & AR8X16_MASK_CTRL_REV_MASK);
119235288Sadrian	if (chipname != NULL) {
120235288Sadrian		snprintf(desc, sizeof(desc),
121235288Sadrian		    "Atheros %s Ethernet Switch",
122235288Sadrian		    chipname);
123235288Sadrian		device_set_desc_copy(dev, desc);
124235288Sadrian		return (BUS_PROBE_DEFAULT);
125235288Sadrian	}
126235288Sadrian	return (ENXIO);
127235288Sadrian}
128235288Sadrian
129235288Sadrianstatic int
130235288Sadrianarswitch_attach_phys(struct arswitch_softc *sc)
131235288Sadrian{
132235288Sadrian	int phy, err = 0;
133235288Sadrian	char name[IFNAMSIZ];
134235288Sadrian
135235288Sadrian	/* PHYs need an interface, so we generate a dummy one */
136235288Sadrian	snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
137235288Sadrian	for (phy = 0; phy < sc->numphys; phy++) {
138235288Sadrian		sc->ifp[phy] = if_alloc(IFT_ETHER);
139235288Sadrian		sc->ifp[phy]->if_softc = sc;
140235288Sadrian		sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST |
141235288Sadrian		    IFF_DRV_RUNNING | IFF_SIMPLEX;
142235288Sadrian		sc->ifname[phy] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK);
143235288Sadrian		bcopy(name, sc->ifname[phy], strlen(name)+1);
144235288Sadrian		if_initname(sc->ifp[phy], sc->ifname[phy],
145235288Sadrian		    arswitch_portforphy(phy));
146235288Sadrian		err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy],
147235288Sadrian		    arswitch_ifmedia_upd, arswitch_ifmedia_sts, \
148235288Sadrian		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
149235288Sadrian		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
150235288Sadrian		    device_get_nameunit(sc->miibus[phy]),
151235288Sadrian		    sc->ifp[phy]->if_xname);
152235288Sadrian		if (err != 0) {
153235288Sadrian			device_printf(sc->sc_dev,
154235288Sadrian			    "attaching PHY %d failed\n",
155235288Sadrian			    phy);
156235288Sadrian		}
157235288Sadrian	}
158235288Sadrian	return (err);
159235288Sadrian}
160235288Sadrian
161235288Sadrianstatic int
162235288Sadrianarswitch_attach(device_t dev)
163235288Sadrian{
164235288Sadrian	struct arswitch_softc *sc;
165235288Sadrian	int err = 0;
166235288Sadrian
167235288Sadrian	sc = device_get_softc(dev);
168235288Sadrian
169235288Sadrian	/* sc->sc_switchtype is already decided in arswitch_probe() */
170235288Sadrian	sc->sc_dev = dev;
171235288Sadrian	mtx_init(&sc->sc_mtx, "arswitch", NULL, MTX_DEF);
172235288Sadrian	sc->page = -1;
173235288Sadrian	strlcpy(sc->info.es_name, device_get_desc(dev),
174235288Sadrian	    sizeof(sc->info.es_name));
175235288Sadrian
176235288Sadrian	/*
177235288Sadrian	 * Attach switch related functions
178235288Sadrian	 */
179235288Sadrian	if (AR8X16_IS_SWITCH(sc, AR8216))
180235288Sadrian		ar8216_attach(sc);
181235288Sadrian	else if (AR8X16_IS_SWITCH(sc, AR8226))
182235288Sadrian		ar8226_attach(sc);
183235288Sadrian	else if (AR8X16_IS_SWITCH(sc, AR8316))
184235288Sadrian		ar8316_attach(sc);
185235288Sadrian	else
186235288Sadrian		return (ENXIO);
187235288Sadrian
188235288Sadrian	/*
189235288Sadrian	 * XXX these two should be part of the switch attach function
190235288Sadrian	 */
191235288Sadrian	sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */
192235288Sadrian	sc->info.es_nvlangroups = 16;
193235288Sadrian
194235288Sadrian	/* XXX Defaults for externally connected AR8316 */
195235288Sadrian	sc->numphys = 4;
196235288Sadrian	sc->phy4cpu = 1;
197235288Sadrian	sc->is_rgmii = 1;
198235288Sadrian	sc->is_gmii = 0;
199235288Sadrian
200235288Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
201235288Sadrian	    "numphys", &sc->numphys);
202235288Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
203235288Sadrian	    "phy4cpu", &sc->phy4cpu);
204235288Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
205235288Sadrian	    "is_rgmii", &sc->is_rgmii);
206235288Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
207235288Sadrian	    "is_gmii", &sc->is_gmii);
208235288Sadrian
209235288Sadrian#ifdef NOTYET
210235288Sadrian	arswitch_writereg(dev, AR8X16_REG_MASK_CTRL,
211235288Sadrian	    AR8X16_MASK_CTRL_SOFT_RESET);
212235288Sadrian	DELAY(1000);
213235288Sadrian	if (arswitch_readreg(dev, AR8X16_REG_MASK_CTRL) &
214235288Sadrian	    AR8X16_MASK_CTRL_SOFT_RESET) {
215235288Sadrian		device_printf(dev, "unable to reset switch\n");
216235288Sadrian		return (ENXIO);
217235288Sadrian	}
218235288Sadrian	arswitch_modifyreg(dev, AR8X16_REG_GLOBAL_CTRL,
219235288Sadrian	    AR8X16_FLOOD_MASK_BCAST_TO_CPU,
220235288Sadrian	    AR8X16_FLOOD_MASK_BCAST_TO_CPU);
221235288Sadrian#endif
222235288Sadrian
223235288Sadrian	err = sc->hal.arswitch_hw_setup(sc);
224235288Sadrian	if (err != 0)
225235288Sadrian		return (err);
226235288Sadrian
227235288Sadrian	err = sc->hal.arswitch_hw_global_setup(sc);
228235288Sadrian	if (err != 0)
229235288Sadrian		return (err);
230235288Sadrian
231235288Sadrian	/*
232235288Sadrian	 * Attach the PHYs and complete the bus enumeration.
233235288Sadrian	 */
234235288Sadrian	err = arswitch_attach_phys(sc);
235235288Sadrian	if (err != 0)
236235288Sadrian		return (err);
237235288Sadrian
238235288Sadrian	bus_generic_probe(dev);
239235288Sadrian	bus_enumerate_hinted_children(dev);
240235288Sadrian	err = bus_generic_attach(dev);
241235288Sadrian	if (err != 0)
242235288Sadrian		return (err);
243235288Sadrian
244235288Sadrian	callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0);
245235288Sadrian	arswitch_tick(sc);
246235288Sadrian
247235288Sadrian	return (err);
248235288Sadrian}
249235288Sadrian
250235288Sadrianstatic int
251235288Sadrianarswitch_detach(device_t dev)
252235288Sadrian{
253235288Sadrian	struct arswitch_softc *sc = device_get_softc(dev);
254235288Sadrian	int i;
255235288Sadrian
256235288Sadrian	callout_drain(&sc->callout_tick);
257235288Sadrian
258235288Sadrian	for (i=0; i < sc->numphys; i++) {
259235288Sadrian		if (sc->miibus[i] != NULL)
260235288Sadrian			device_delete_child(dev, sc->miibus[i]);
261235288Sadrian		if (sc->ifp[i] != NULL)
262235288Sadrian			if_free(sc->ifp[i]);
263235288Sadrian		free(sc->ifname[i], M_DEVBUF);
264235288Sadrian	}
265235288Sadrian
266235288Sadrian	bus_generic_detach(dev);
267235288Sadrian	mtx_destroy(&sc->sc_mtx);
268235288Sadrian
269235288Sadrian	return (0);
270235288Sadrian}
271235288Sadrian
272235288Sadrian/*
273235288Sadrian * Convert PHY number to port number. PHY0 is connected to port 1, PHY1 to
274235288Sadrian * port 2, etc.
275235288Sadrian */
276235288Sadrianstatic inline int
277235288Sadrianarswitch_portforphy(int phy)
278235288Sadrian{
279235288Sadrian	return (phy+1);
280235288Sadrian}
281235288Sadrian
282235288Sadrianstatic inline struct mii_data *
283235288Sadrianarswitch_miiforport(struct arswitch_softc *sc, int port)
284235288Sadrian{
285235288Sadrian	int phy = port-1;
286235288Sadrian
287235288Sadrian	if (phy < 0 || phy >= sc->numphys)
288235288Sadrian		return (NULL);
289235288Sadrian	return (device_get_softc(sc->miibus[phy]));
290235288Sadrian}
291235288Sadrian
292235288Sadrianstatic inline struct ifnet *
293235288Sadrianarswitch_ifpforport(struct arswitch_softc *sc, int port)
294235288Sadrian{
295235288Sadrian	int phy = port-1;
296235288Sadrian
297235288Sadrian	if (phy < 0 || phy >= sc->numphys)
298235288Sadrian		return (NULL);
299235288Sadrian	return (sc->ifp[phy]);
300235288Sadrian}
301235288Sadrian
302235288Sadrian/*
303235288Sadrian * Convert port status to ifmedia.
304235288Sadrian */
305235288Sadrianstatic void
306235288Sadrianarswitch_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active)
307235288Sadrian{
308235288Sadrian	*media_active = IFM_ETHER;
309235288Sadrian	*media_status = IFM_AVALID;
310235288Sadrian
311235288Sadrian	if ((portstatus & AR8X16_PORT_STS_LINK_UP) != 0)
312235288Sadrian		*media_status |= IFM_ACTIVE;
313235288Sadrian	else {
314235288Sadrian		*media_active |= IFM_NONE;
315235288Sadrian		return;
316235288Sadrian	}
317235288Sadrian	switch (portstatus & AR8X16_PORT_STS_SPEED_MASK) {
318235288Sadrian	case AR8X16_PORT_STS_SPEED_10:
319235288Sadrian		*media_active |= IFM_10_T;
320235288Sadrian		break;
321235288Sadrian	case AR8X16_PORT_STS_SPEED_100:
322235288Sadrian		*media_active |= IFM_100_TX;
323235288Sadrian		break;
324235288Sadrian	case AR8X16_PORT_STS_SPEED_1000:
325235288Sadrian		*media_active |= IFM_1000_T;
326235288Sadrian		break;
327235288Sadrian	}
328235288Sadrian	if ((portstatus & AR8X16_PORT_STS_DUPLEX) == 0)
329235288Sadrian		*media_active |= IFM_FDX;
330235288Sadrian	else
331235288Sadrian		*media_active |= IFM_HDX;
332235288Sadrian	if ((portstatus & AR8X16_PORT_STS_TXFLOW) != 0)
333235288Sadrian		*media_active |= IFM_ETH_TXPAUSE;
334235288Sadrian	if ((portstatus & AR8X16_PORT_STS_RXFLOW) != 0)
335235288Sadrian		*media_active |= IFM_ETH_RXPAUSE;
336235288Sadrian}
337235288Sadrian
338235288Sadrian/*
339235288Sadrian * Poll the status for all PHYs.  We're using the switch port status because
340235288Sadrian * thats a lot quicker to read than talking to all the PHYs.  Care must be
341235288Sadrian * taken that the resulting ifmedia_active is identical to what the PHY will
342235288Sadrian * compute, or gratuitous link status changes will occur whenever the PHYs
343235288Sadrian * update function is called.
344235288Sadrian */
345235288Sadrianstatic void
346235288Sadrianarswitch_miipollstat(struct arswitch_softc *sc)
347235288Sadrian{
348235288Sadrian	int i;
349235288Sadrian	struct mii_data *mii;
350235288Sadrian	struct mii_softc *miisc;
351235288Sadrian	int portstatus;
352235288Sadrian
353235288Sadrian	for (i = 0; i < sc->numphys; i++) {
354235288Sadrian		if (sc->miibus[i] == NULL)
355235288Sadrian			continue;
356235288Sadrian		mii = device_get_softc(sc->miibus[i]);
357235288Sadrian		portstatus = arswitch_readreg(sc->sc_dev,
358235288Sadrian		    AR8X16_REG_PORT_STS(arswitch_portforphy(i)));
359235288Sadrian#if 0
360235288Sadrian		DPRINTF(sc->sc_dev, "p[%d]=%b\n",
361235288Sadrian		    arge_portforphy(i),
362235288Sadrian		    portstatus,
363235288Sadrian		    "\20\3TXMAC\4RXMAC\5TXFLOW\6RXFLOW\7"
364235288Sadrian		    "DUPLEX\11LINK_UP\12LINK_AUTO\13LINK_PAUSE");
365235288Sadrian#endif
366235288Sadrian		arswitch_update_ifmedia(portstatus, &mii->mii_media_status,
367235288Sadrian		    &mii->mii_media_active);
368235288Sadrian		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
369235288Sadrian			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
370235288Sadrian			    miisc->mii_inst)
371235288Sadrian				continue;
372235288Sadrian			mii_phy_update(miisc, MII_POLLSTAT);
373235288Sadrian		}
374235288Sadrian	}
375235288Sadrian}
376235288Sadrian
377235288Sadrianstatic void
378235288Sadrianarswitch_tick(void *arg)
379235288Sadrian{
380235288Sadrian	struct arswitch_softc *sc = arg;
381235288Sadrian
382235288Sadrian	arswitch_miipollstat(sc);
383235288Sadrian	callout_reset(&sc->callout_tick, hz, arswitch_tick, sc);
384235288Sadrian}
385235288Sadrian
386235288Sadrianstatic etherswitch_info_t *
387235288Sadrianarswitch_getinfo(device_t dev)
388235288Sadrian{
389235288Sadrian	struct arswitch_softc *sc = device_get_softc(dev);
390235288Sadrian
391235288Sadrian	return (&sc->info);
392235288Sadrian}
393235288Sadrian
394235288Sadrianstatic int
395235288Sadrianarswitch_getport(device_t dev, etherswitch_port_t *p)
396235288Sadrian{
397235288Sadrian	struct arswitch_softc *sc = device_get_softc(dev);
398235288Sadrian	struct mii_data *mii;
399235288Sadrian	struct ifmediareq *ifmr = &p->es_ifmr;
400235288Sadrian	int err;
401235288Sadrian
402235288Sadrian	if (p->es_port < 0 || p->es_port >= AR8X16_NUM_PORTS)
403235288Sadrian		return (ENXIO);
404235288Sadrian	p->es_vlangroup = 0;
405235288Sadrian
406235288Sadrian	mii = arswitch_miiforport(sc, p->es_port);
407235288Sadrian	if (p->es_port == 0) {
408235288Sadrian		/* fill in fixed values for CPU port */
409235288Sadrian		ifmr->ifm_count = 0;
410235288Sadrian		ifmr->ifm_current = ifmr->ifm_active =
411235288Sadrian		    IFM_ETHER | IFM_1000_T | IFM_FDX;
412235288Sadrian		ifmr->ifm_mask = 0;
413235288Sadrian		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
414235288Sadrian	} else if (mii != NULL) {
415235288Sadrian		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
416235288Sadrian		    &mii->mii_media, SIOCGIFMEDIA);
417235288Sadrian		if (err)
418235288Sadrian			return (err);
419235288Sadrian	} else {
420235288Sadrian		return (ENXIO);
421235288Sadrian	}
422235288Sadrian	return (0);
423235288Sadrian}
424235288Sadrian
425235288Sadrian/*
426235288Sadrian * XXX doesn't yet work?
427235288Sadrian */
428235288Sadrianstatic int
429235288Sadrianarswitch_setport(device_t dev, etherswitch_port_t *p)
430235288Sadrian{
431235288Sadrian	int err;
432235288Sadrian	struct arswitch_softc *sc;
433235288Sadrian	struct ifmedia *ifm;
434235288Sadrian	struct mii_data *mii;
435235288Sadrian	struct ifnet *ifp;
436235288Sadrian
437235288Sadrian	/*
438235288Sadrian	 * XXX check the sc numphys, or the #define ?
439235288Sadrian	 */
440235288Sadrian	if (p->es_port < 0 || p->es_port >= AR8X16_NUM_PHYS)
441235288Sadrian		return (ENXIO);
442235288Sadrian
443235288Sadrian	sc = device_get_softc(dev);
444235288Sadrian
445235288Sadrian	/*
446235288Sadrian	 * XXX TODO: don't set the CPU port?
447235288Sadrian	 */
448235288Sadrian
449235288Sadrian	mii = arswitch_miiforport(sc, p->es_port);
450235288Sadrian	if (mii == NULL)
451235288Sadrian		return (ENXIO);
452235288Sadrian
453235288Sadrian	ifp = arswitch_ifpforport(sc, p->es_port);
454235288Sadrian
455235288Sadrian	ifm = &mii->mii_media;
456235288Sadrian	err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
457235288Sadrian	return (err);
458235288Sadrian}
459235288Sadrian
460235288Sadrianstatic int
461235288Sadrianarswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
462235288Sadrian{
463235288Sadrian
464235288Sadrian	/* XXX not implemented yet */
465235288Sadrian	vg->es_vid = 0;
466235288Sadrian	vg->es_member_ports = 0;
467235288Sadrian	vg->es_untagged_ports = 0;
468235288Sadrian	vg->es_fid = 0;
469235288Sadrian	return (0);
470235288Sadrian}
471235288Sadrian
472235288Sadrianstatic int
473235288Sadrianarswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
474235288Sadrian{
475235288Sadrian
476235288Sadrian	/* XXX not implemented yet */
477235288Sadrian	return (0);
478235288Sadrian}
479235288Sadrian
480235288Sadrianstatic void
481235288Sadrianarswitch_statchg(device_t dev)
482235288Sadrian{
483235288Sadrian
484235288Sadrian	DPRINTF(dev, "%s\n", __func__);
485235288Sadrian}
486235288Sadrian
487235288Sadrianstatic int
488235288Sadrianarswitch_ifmedia_upd(struct ifnet *ifp)
489235288Sadrian{
490235288Sadrian	struct arswitch_softc *sc = ifp->if_softc;
491235288Sadrian	struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
492235288Sadrian
493235288Sadrian	if (mii == NULL)
494235288Sadrian		return (ENXIO);
495235288Sadrian	mii_mediachg(mii);
496235288Sadrian	return (0);
497235288Sadrian}
498235288Sadrian
499235288Sadrianstatic void
500235288Sadrianarswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
501235288Sadrian{
502235288Sadrian	struct arswitch_softc *sc = ifp->if_softc;
503235288Sadrian	struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
504235288Sadrian
505235288Sadrian	DPRINTF(sc->sc_dev, "%s\n", __func__);
506235288Sadrian
507235288Sadrian	if (mii == NULL)
508235288Sadrian		return;
509235288Sadrian	mii_pollstat(mii);
510235288Sadrian	ifmr->ifm_active = mii->mii_media_active;
511235288Sadrian	ifmr->ifm_status = mii->mii_media_status;
512235288Sadrian}
513235288Sadrian
514235288Sadrianstatic device_method_t arswitch_methods[] = {
515235288Sadrian	/* Device interface */
516235288Sadrian	DEVMETHOD(device_identify,	arswitch_identify),
517235288Sadrian	DEVMETHOD(device_probe,		arswitch_probe),
518235288Sadrian	DEVMETHOD(device_attach,	arswitch_attach),
519235288Sadrian	DEVMETHOD(device_detach,	arswitch_detach),
520235288Sadrian
521235288Sadrian	/* bus interface */
522235288Sadrian	DEVMETHOD(bus_add_child,	device_add_child_ordered),
523235288Sadrian
524235288Sadrian	/* MII interface */
525235288Sadrian	DEVMETHOD(miibus_readreg,	arswitch_readphy),
526235288Sadrian	DEVMETHOD(miibus_writereg,	arswitch_writephy),
527235288Sadrian	DEVMETHOD(miibus_statchg,	arswitch_statchg),
528235288Sadrian
529235288Sadrian	/* MDIO interface */
530235288Sadrian	DEVMETHOD(mdio_readreg,		arswitch_readphy),
531235288Sadrian	DEVMETHOD(mdio_writereg,	arswitch_writephy),
532235288Sadrian
533235288Sadrian	/* etherswitch interface */
534235288Sadrian	DEVMETHOD(etherswitch_getinfo,	arswitch_getinfo),
535235288Sadrian	DEVMETHOD(etherswitch_readreg,	arswitch_readreg),
536235288Sadrian	DEVMETHOD(etherswitch_writereg,	arswitch_writereg),
537235288Sadrian	DEVMETHOD(etherswitch_readphyreg,	arswitch_readphy),
538235288Sadrian	DEVMETHOD(etherswitch_writephyreg,	arswitch_writephy),
539235288Sadrian	DEVMETHOD(etherswitch_getport,	arswitch_getport),
540235288Sadrian	DEVMETHOD(etherswitch_setport,	arswitch_setport),
541235288Sadrian	DEVMETHOD(etherswitch_getvgroup,	arswitch_getvgroup),
542235288Sadrian	DEVMETHOD(etherswitch_setvgroup,	arswitch_setvgroup),
543235288Sadrian
544235288Sadrian	DEVMETHOD_END
545235288Sadrian};
546235288Sadrian
547235288SadrianDEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods,
548235288Sadrian    sizeof(struct arswitch_softc));
549235288Sadrianstatic devclass_t arswitch_devclass;
550235288Sadrian
551235288SadrianDRIVER_MODULE(arswitch, mdio, arswitch_driver, arswitch_devclass, 0, 0);
552235288SadrianDRIVER_MODULE(miibus, arswitch, miibus_driver, miibus_devclass, 0, 0);
553235288SadrianDRIVER_MODULE(mdio, arswitch, mdio_driver, mdio_devclass, 0, 0);
554235288SadrianDRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, etherswitch_devclass, 0, 0);
555235288SadrianMODULE_VERSION(arswitch, 1);
556235288SadrianMODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */
557235288SadrianMODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */
558