arswitch.c revision 241578
197403Sobrien/*-
297403Sobrien * Copyright (c) 2011-2012 Stefan Bethke.
3169691Skan * Copyright (c) 2012 Adrian Chadd.
497403Sobrien * All rights reserved.
597403Sobrien *
697403Sobrien * Redistribution and use in source and binary forms, with or without
797403Sobrien * modification, are permitted provided that the following conditions
897403Sobrien * are met:
997403Sobrien * 1. Redistributions of source code must retain the above copyright
1097403Sobrien *    notice, this list of conditions and the following disclaimer.
1197403Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1297403Sobrien *    notice, this list of conditions and the following disclaimer in the
1397403Sobrien *    documentation and/or other materials provided with the distribution.
1497403Sobrien *
1597403Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1697403Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1797403Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1897403Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19169691Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2097403Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2197403Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2297403Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2397403Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2497403Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2597403Sobrien * SUCH DAMAGE.
2697403Sobrien *
2797403Sobrien * $FreeBSD: head/sys/dev/etherswitch/arswitch/arswitch.c 241578 2012-10-15 12:20:40Z ray $
2897403Sobrien */
2997403Sobrien
3097403Sobrien#include <sys/param.h>
3197403Sobrien#include <sys/bus.h>
3297403Sobrien#include <sys/errno.h>
3397403Sobrien#include <sys/kernel.h>
3497403Sobrien#include <sys/module.h>
3597403Sobrien#include <sys/socket.h>
36169691Skan#include <sys/sockio.h>
37169691Skan#include <sys/sysctl.h>
38169691Skan#include <sys/systm.h>
39169691Skan
40132720Skan#include <net/if.h>
41132720Skan#include <net/if_arp.h>
4297403Sobrien#include <net/ethernet.h>
4397403Sobrien#include <net/if_dl.h>
4497403Sobrien#include <net/if_media.h>
4597403Sobrien#include <net/if_types.h>
4697403Sobrien
47169691Skan#include <machine/bus.h>
48117397Skan#include <dev/iicbus/iic.h>
49117397Skan#include <dev/iicbus/iiconf.h>
50117397Skan#include <dev/iicbus/iicbus.h>
51169691Skan#include <dev/mii/mii.h>
5297403Sobrien#include <dev/mii/miivar.h>
53169691Skan#include <dev/etherswitch/mdio.h>
54169691Skan
5597403Sobrien#include <dev/etherswitch/etherswitch.h>
56132720Skan
57132720Skan#include <dev/etherswitch/arswitch/arswitchreg.h>
5897403Sobrien#include <dev/etherswitch/arswitch/arswitchvar.h>
59132720Skan#include <dev/etherswitch/arswitch/arswitch_reg.h>
6097403Sobrien#include <dev/etherswitch/arswitch/arswitch_phy.h>
6197403Sobrien
62132720Skan#include <dev/etherswitch/arswitch/arswitch_7240.h>
63117397Skan#include <dev/etherswitch/arswitch/arswitch_8216.h>
64117397Skan#include <dev/etherswitch/arswitch/arswitch_8226.h>
65117397Skan#include <dev/etherswitch/arswitch/arswitch_8316.h>
66117397Skan
67132720Skan#include "mdio_if.h"
68132720Skan#include "miibus_if.h"
69117397Skan#include "etherswitch_if.h"
70117397Skan
71117397Skan#if	defined(DEBUG)
72117397Skanstatic SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch");
73132720Skan#endif
74132720Skan
75117397Skanstatic inline int arswitch_portforphy(int phy);
76117397Skanstatic void arswitch_tick(void *arg);
77117397Skanstatic int arswitch_ifmedia_upd(struct ifnet *);
78132720Skanstatic void arswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *);
79132720Skan
80117397Skanstatic void
81117397Skanarswitch_identify(driver_t *driver, device_t parent)
82117397Skan{
83132720Skan	device_t child;
84132720Skan
85117397Skan	if (device_find_child(parent, driver->name, -1) == NULL) {
86117397Skan		child = BUS_ADD_CHILD(parent, 0, driver->name, -1);
87117397Skan	}
88102782Skan}
89117397Skan
90117397Skanstatic int
91117397Skanarswitch_probe(device_t dev)
92132720Skan{
93132720Skan	struct arswitch_softc *sc;
94117397Skan	uint32_t id;
95117397Skan	char *chipname, desc[256];
96102782Skan
97117397Skan	sc = device_get_softc(dev);
98117397Skan	bzero(sc, sizeof(*sc));
99117397Skan	sc->page = -1;
100117397Skan
101132720Skan	/* AR7240 probe */
102117397Skan	if (ar7240_probe(dev) == 0) {
103117397Skan		chipname = "AR7240";
104132720Skan		sc->sc_switchtype = AR8X16_SWITCH_AR7240;
105132720Skan		id = 0;
106117397Skan		goto done;
107117397Skan	}
108117397Skan
109117397Skan	/* AR8xxx probe */
110117397Skan	id = arswitch_readreg(dev, AR8X16_REG_MASK_CTRL);
111117397Skan	switch ((id & AR8X16_MASK_CTRL_VER_MASK) >>
112117397Skan	    AR8X16_MASK_CTRL_VER_SHIFT) {
113117397Skan	case 1:
114117397Skan		chipname = "AR8216";
115117397Skan		sc->sc_switchtype = AR8X16_SWITCH_AR8216;
116117397Skan		break;
117117397Skan	case 2:
118117397Skan		chipname = "AR8226";
119117397Skan		sc->sc_switchtype = AR8X16_SWITCH_AR8226;
120117397Skan		break;
121117397Skan	case 16:
122117397Skan		chipname = "AR8316";
123117397Skan		sc->sc_switchtype = AR8X16_SWITCH_AR8316;
124117397Skan		break;
125117397Skan	default:
126117397Skan		chipname = NULL;
127117397Skan	}
128117397Skan
129117397Skandone:
130117397Skan	DPRINTF(dev, "chipname=%s, rev=%02x\n", chipname,
131132720Skan	    id & AR8X16_MASK_CTRL_REV_MASK);
13297403Sobrien	if (chipname != NULL) {
13397403Sobrien		snprintf(desc, sizeof(desc),
13497403Sobrien		    "Atheros %s Ethernet Switch",
135132720Skan		    chipname);
136132720Skan		device_set_desc_copy(dev, desc);
137132720Skan		return (BUS_PROBE_DEFAULT);
138132720Skan	}
139132720Skan	return (ENXIO);
140132720Skan}
141132720Skan
142132720Skanstatic int
143132720Skanarswitch_attach_phys(struct arswitch_softc *sc)
144132720Skan{
14597403Sobrien	int phy, err = 0;
14697403Sobrien	char name[IFNAMSIZ];
14797403Sobrien
14897403Sobrien	/* PHYs need an interface, so we generate a dummy one */
14997403Sobrien	snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
150132720Skan	for (phy = 0; phy < sc->numphys; phy++) {
15197403Sobrien		sc->ifp[phy] = if_alloc(IFT_ETHER);
15297403Sobrien		sc->ifp[phy]->if_softc = sc;
153132720Skan		sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST |
154132720Skan		    IFF_DRV_RUNNING | IFF_SIMPLEX;
155132720Skan		sc->ifname[phy] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK);
156132720Skan		bcopy(name, sc->ifname[phy], strlen(name)+1);
157132720Skan		if_initname(sc->ifp[phy], sc->ifname[phy],
158132720Skan		    arswitch_portforphy(phy));
159132720Skan		err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy],
160132720Skan		    arswitch_ifmedia_upd, arswitch_ifmedia_sts, \
161132720Skan		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
162132720Skan		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
163132720Skan		    device_get_nameunit(sc->miibus[phy]),
16497403Sobrien		    sc->ifp[phy]->if_xname);
16597403Sobrien		if (err != 0) {
16697403Sobrien			device_printf(sc->sc_dev,
167132720Skan			    "attaching PHY %d failed\n",
168132720Skan			    phy);
169132720Skan		}
170132720Skan	}
171132720Skan	return (err);
172132720Skan}
173132720Skan
174132720Skanstatic int
175132720Skanarswitch_attach(device_t dev)
176132720Skan{
177132720Skan	struct arswitch_softc *sc;
178132720Skan	int err = 0;
179132720Skan
18097403Sobrien	sc = device_get_softc(dev);
181132720Skan
18297403Sobrien	/* sc->sc_switchtype is already decided in arswitch_probe() */
18397403Sobrien	sc->sc_dev = dev;
184132720Skan	mtx_init(&sc->sc_mtx, "arswitch", NULL, MTX_DEF);
185132720Skan	sc->page = -1;
186132720Skan	strlcpy(sc->info.es_name, device_get_desc(dev),
187132720Skan	    sizeof(sc->info.es_name));
188132720Skan
189132720Skan	/*
190132720Skan	 * Attach switch related functions
191132720Skan	 */
192132720Skan	if (AR8X16_IS_SWITCH(sc, AR7240))
193132720Skan		ar7240_attach(sc);
194132720Skan	else if (AR8X16_IS_SWITCH(sc, AR8216))
195132720Skan		ar8216_attach(sc);
19697403Sobrien	else if (AR8X16_IS_SWITCH(sc, AR8226))
19797403Sobrien		ar8226_attach(sc);
19897403Sobrien	else if (AR8X16_IS_SWITCH(sc, AR8316))
19997403Sobrien		ar8316_attach(sc);
200132720Skan	else
201132720Skan		return (ENXIO);
202132720Skan
203132720Skan	/*
204132720Skan	 * XXX these two should be part of the switch attach function
205132720Skan	 */
206132720Skan	sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */
207132720Skan	sc->info.es_nvlangroups = 16;
208132720Skan
209132720Skan	/* XXX Defaults for externally connected AR8316 */
210132720Skan	sc->numphys = 4;
211132720Skan	sc->phy4cpu = 1;
21297403Sobrien	sc->is_rgmii = 1;
21397403Sobrien	sc->is_gmii = 0;
21497403Sobrien
21597403Sobrien	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
216132720Skan	    "numphys", &sc->numphys);
217132720Skan	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
218132720Skan	    "phy4cpu", &sc->phy4cpu);
219132720Skan	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
220132720Skan	    "is_rgmii", &sc->is_rgmii);
221132720Skan	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
222132720Skan	    "is_gmii", &sc->is_gmii);
223132720Skan
224132720Skan	/*
225132720Skan	 * This requires much more setup depending upon each chip, including:
226132720Skan	 *
22797403Sobrien	 * + Proper reinitialisation of the PHYs;
22897403Sobrien	 * + Initialising the VLAN table;
22997403Sobrien	 * + Initialising the port access table and CPU flood/broadcast
230132720Skan	 *   configuration;
231132720Skan	 * + Other things I haven't yet thought of.
232132720Skan	 */
233132720Skan#ifdef NOTYET
234132720Skan	arswitch_writereg(dev, AR8X16_REG_MASK_CTRL,
235132720Skan	    AR8X16_MASK_CTRL_SOFT_RESET);
236132720Skan	DELAY(1000);
237132720Skan	if (arswitch_readreg(dev, AR8X16_REG_MASK_CTRL) &
238132720Skan	    AR8X16_MASK_CTRL_SOFT_RESET) {
239132720Skan		device_printf(dev, "unable to reset switch\n");
240132720Skan		return (ENXIO);
24197403Sobrien	}
24297403Sobrien#endif
24397403Sobrien
24497403Sobrien	err = sc->hal.arswitch_hw_setup(sc);
245132720Skan	if (err != 0)
246132720Skan		return (err);
247132720Skan
248132720Skan	err = sc->hal.arswitch_hw_global_setup(sc);
249132720Skan	if (err != 0)
250132720Skan		return (err);
251132720Skan
252132720Skan	/*
253132720Skan	 * Attach the PHYs and complete the bus enumeration.
254132720Skan	 */
255132720Skan	err = arswitch_attach_phys(sc);
25697403Sobrien	if (err != 0)
25797403Sobrien		return (err);
25897403Sobrien
259132720Skan	bus_generic_probe(dev);
260132720Skan	bus_enumerate_hinted_children(dev);
261132720Skan	err = bus_generic_attach(dev);
262132720Skan	if (err != 0)
263132720Skan		return (err);
264132720Skan
265132720Skan	callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0);
266132720Skan
267132720Skan	ARSWITCH_LOCK(sc);
268132720Skan	arswitch_tick(sc);
269132720Skan	ARSWITCH_UNLOCK(sc);
27097403Sobrien
27197403Sobrien	return (err);
27297403Sobrien}
27397403Sobrien
274132720Skanstatic int
275132720Skanarswitch_detach(device_t dev)
276132720Skan{
277132720Skan	struct arswitch_softc *sc = device_get_softc(dev);
278132720Skan	int i;
279132720Skan
280132720Skan	callout_drain(&sc->callout_tick);
281132720Skan
282132720Skan	for (i=0; i < sc->numphys; i++) {
283132720Skan		if (sc->miibus[i] != NULL)
284132720Skan			device_delete_child(dev, sc->miibus[i]);
285132720Skan		if (sc->ifp[i] != NULL)
286132720Skan			if_free(sc->ifp[i]);
287132720Skan		free(sc->ifname[i], M_DEVBUF);
28897403Sobrien	}
28997403Sobrien
29097403Sobrien	bus_generic_detach(dev);
291132720Skan	mtx_destroy(&sc->sc_mtx);
292132720Skan
293132720Skan	return (0);
294132720Skan}
295132720Skan
296132720Skan/*
297132720Skan * Convert PHY number to port number. PHY0 is connected to port 1, PHY1 to
298132720Skan * port 2, etc.
299132720Skan */
300132720Skanstatic inline int
301132720Skanarswitch_portforphy(int phy)
302132720Skan{
303132720Skan	return (phy+1);
304132720Skan}
305132720Skan
30697403Sobrienstatic inline struct mii_data *
30797403Sobrienarswitch_miiforport(struct arswitch_softc *sc, int port)
30897403Sobrien{
30997403Sobrien	int phy = port-1;
310132720Skan
311132720Skan	if (phy < 0 || phy >= sc->numphys)
312132720Skan		return (NULL);
313132720Skan	return (device_get_softc(sc->miibus[phy]));
314132720Skan}
315132720Skan
316132720Skanstatic inline struct ifnet *
317132720Skanarswitch_ifpforport(struct arswitch_softc *sc, int port)
318132720Skan{
319132720Skan	int phy = port-1;
320132720Skan
321132720Skan	if (phy < 0 || phy >= sc->numphys)
322132720Skan		return (NULL);
323132720Skan	return (sc->ifp[phy]);
324132720Skan}
325132720Skan
32697403Sobrien/*
32797403Sobrien * Convert port status to ifmedia.
32897403Sobrien */
329132720Skanstatic void
330132720Skanarswitch_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active)
331132720Skan{
332132720Skan	*media_active = IFM_ETHER;
333132720Skan	*media_status = IFM_AVALID;
334132720Skan
335132720Skan	if ((portstatus & AR8X16_PORT_STS_LINK_UP) != 0)
336132720Skan		*media_status |= IFM_ACTIVE;
337132720Skan	else {
338132720Skan		*media_active |= IFM_NONE;
339132720Skan		return;
340132720Skan	}
341132720Skan	switch (portstatus & AR8X16_PORT_STS_SPEED_MASK) {
342132720Skan	case AR8X16_PORT_STS_SPEED_10:
343132720Skan		*media_active |= IFM_10_T;
344132720Skan		break;
345132720Skan	case AR8X16_PORT_STS_SPEED_100:
346132720Skan		*media_active |= IFM_100_TX;
34797403Sobrien		break;
34897403Sobrien	case AR8X16_PORT_STS_SPEED_1000:
34997403Sobrien		*media_active |= IFM_1000_T;
35097403Sobrien		break;
35197403Sobrien	}
35297403Sobrien	if ((portstatus & AR8X16_PORT_STS_DUPLEX) == 0)
353132720Skan		*media_active |= IFM_FDX;
354132720Skan	else
35597403Sobrien		*media_active |= IFM_HDX;
356132720Skan	if ((portstatus & AR8X16_PORT_STS_TXFLOW) != 0)
35797403Sobrien		*media_active |= IFM_ETH_TXPAUSE;
358132720Skan	if ((portstatus & AR8X16_PORT_STS_RXFLOW) != 0)
359132720Skan		*media_active |= IFM_ETH_RXPAUSE;
360132720Skan}
361132720Skan
362132720Skan/*
363132720Skan * Poll the status for all PHYs.  We're using the switch port status because
364132720Skan * thats a lot quicker to read than talking to all the PHYs.  Care must be
365132720Skan * taken that the resulting ifmedia_active is identical to what the PHY will
366132720Skan * compute, or gratuitous link status changes will occur whenever the PHYs
367132720Skan * update function is called.
368132720Skan */
369132720Skanstatic void
370132720Skanarswitch_miipollstat(struct arswitch_softc *sc)
371132720Skan{
372132720Skan	int i;
37397403Sobrien	struct mii_data *mii;
37497403Sobrien	struct mii_softc *miisc;
375132720Skan	int portstatus;
376132720Skan
377132720Skan	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
378132720Skan
379132720Skan	for (i = 0; i < sc->numphys; i++) {
380132720Skan		if (sc->miibus[i] == NULL)
381132720Skan			continue;
382132720Skan		mii = device_get_softc(sc->miibus[i]);
383132720Skan		portstatus = arswitch_readreg(sc->sc_dev,
384132720Skan		    AR8X16_REG_PORT_STS(arswitch_portforphy(i)));
385132720Skan#if 0
386132720Skan		DPRINTF(sc->sc_dev, "p[%d]=%b\n",
387132720Skan		    arge_portforphy(i),
388132720Skan		    portstatus,
389132720Skan		    "\20\3TXMAC\4RXMAC\5TXFLOW\6RXFLOW\7"
390132720Skan		    "DUPLEX\11LINK_UP\12LINK_AUTO\13LINK_PAUSE");
39197403Sobrien#endif
392132720Skan		arswitch_update_ifmedia(portstatus, &mii->mii_media_status,
39397403Sobrien		    &mii->mii_media_active);
39497403Sobrien		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
395132720Skan			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
396132720Skan			    miisc->mii_inst)
397132720Skan				continue;
398132720Skan			mii_phy_update(miisc, MII_POLLSTAT);
399132720Skan		}
400132720Skan	}
401132720Skan}
402132720Skan
403132720Skanstatic void
404132720Skanarswitch_tick(void *arg)
405132720Skan{
406132720Skan	struct arswitch_softc *sc = arg;
407132720Skan
408132720Skan	arswitch_miipollstat(sc);
409132720Skan	callout_reset(&sc->callout_tick, hz, arswitch_tick, sc);
41097403Sobrien}
41197403Sobrien
41297403Sobrienstatic void
41397403Sobrienarswitch_lock(device_t dev)
414132720Skan{
415132720Skan	struct arswitch_softc *sc = device_get_softc(dev);
416132720Skan
417132720Skan	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
418132720Skan	ARSWITCH_LOCK(sc);
419132720Skan}
420132720Skan
421132720Skanstatic void
422132720Skanarswitch_unlock(device_t dev)
423132720Skan{
424132720Skan	struct arswitch_softc *sc = device_get_softc(dev);
425132720Skan
426132720Skan	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
427132720Skan	ARSWITCH_UNLOCK(sc);
428132720Skan}
42997403Sobrien
430132720Skanstatic etherswitch_info_t *
43197403Sobrienarswitch_getinfo(device_t dev)
43297403Sobrien{
433132720Skan	struct arswitch_softc *sc = device_get_softc(dev);
434132720Skan
435132720Skan	return (&sc->info);
436132720Skan}
437132720Skan
438132720Skanstatic int
439132720Skanarswitch_getport(device_t dev, etherswitch_port_t *p)
440132720Skan{
441132720Skan	struct arswitch_softc *sc = device_get_softc(dev);
442132720Skan	struct mii_data *mii;
443132720Skan	struct ifmediareq *ifmr = &p->es_ifmr;
444132720Skan	int err;
445132720Skan
446132720Skan	if (p->es_port < 0 || p->es_port >= AR8X16_NUM_PORTS)
447132720Skan		return (ENXIO);
44897403Sobrien	p->es_vlangroup = 0;
44997403Sobrien
450132720Skan	mii = arswitch_miiforport(sc, p->es_port);
451132720Skan	if (p->es_port == 0) {
452132720Skan		/* fill in fixed values for CPU port */
453132720Skan		ifmr->ifm_count = 0;
454132720Skan		ifmr->ifm_current = ifmr->ifm_active =
455132720Skan		    IFM_ETHER | IFM_1000_T | IFM_FDX;
456132720Skan		ifmr->ifm_mask = 0;
457132720Skan		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
458132720Skan	} else if (mii != NULL) {
459132720Skan		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
460132720Skan		    &mii->mii_media, SIOCGIFMEDIA);
461132720Skan		if (err)
462132720Skan			return (err);
463132720Skan	} else {
46497403Sobrien		return (ENXIO);
46597403Sobrien	}
46697403Sobrien	return (0);
467132720Skan}
468132720Skan
469132720Skan/*
470132720Skan * XXX doesn't yet work?
471132720Skan */
472132720Skanstatic int
473132720Skanarswitch_setport(device_t dev, etherswitch_port_t *p)
474132720Skan{
475132720Skan	int err;
476132720Skan	struct arswitch_softc *sc;
477132720Skan	struct ifmedia *ifm;
478132720Skan	struct mii_data *mii;
479132720Skan	struct ifnet *ifp;
480132720Skan
48197403Sobrien	/*
48297403Sobrien	 * XXX check the sc numphys, or the #define ?
483132720Skan	 */
484132720Skan	if (p->es_port < 0 || p->es_port >= AR8X16_NUM_PHYS)
485132720Skan		return (ENXIO);
486132720Skan
487132720Skan	sc = device_get_softc(dev);
488132720Skan
489132720Skan	/*
490132720Skan	 * XXX TODO: don't set the CPU port?
491132720Skan	 */
492132720Skan
493132720Skan	mii = arswitch_miiforport(sc, p->es_port);
494132720Skan	if (mii == NULL)
495132720Skan		return (ENXIO);
496132720Skan
49797403Sobrien	ifp = arswitch_ifpforport(sc, p->es_port);
49897403Sobrien
499132720Skan	ifm = &mii->mii_media;
500132720Skan	err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
501132720Skan	return (err);
502132720Skan}
503132720Skan
504132720Skanstatic int
505132720Skanarswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
506132720Skan{
507132720Skan
508132720Skan	/* XXX not implemented yet */
509132720Skan	vg->es_vid = 0;
510132720Skan	vg->es_member_ports = 0;
511132720Skan	vg->es_untagged_ports = 0;
512132720Skan	vg->es_fid = 0;
513132720Skan	return (0);
514132720Skan}
515132720Skan
516132720Skanstatic int
51797403Sobrienarswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
51897403Sobrien{
519132720Skan
520132720Skan	/* XXX not implemented yet */
521132720Skan	return (0);
522132720Skan}
523132720Skan
524132720Skanstatic void
525132720Skanarswitch_statchg(device_t dev)
526132720Skan{
527132720Skan
528132720Skan	DPRINTF(dev, "%s\n", __func__);
529132720Skan}
530132720Skan
531132720Skanstatic int
532132720Skanarswitch_ifmedia_upd(struct ifnet *ifp)
533132720Skan{
534132720Skan	struct arswitch_softc *sc = ifp->if_softc;
535132720Skan	struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
536132720Skan
53797403Sobrien	if (mii == NULL)
538132720Skan		return (ENXIO);
53997403Sobrien	mii_mediachg(mii);
54097403Sobrien	return (0);
541132720Skan}
542132720Skan
543132720Skanstatic void
544132720Skanarswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
545132720Skan{
546132720Skan	struct arswitch_softc *sc = ifp->if_softc;
547132720Skan	struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
548132720Skan
549132720Skan	DPRINTF(sc->sc_dev, "%s\n", __func__);
550132720Skan
551132720Skan	if (mii == NULL)
552132720Skan		return;
553132720Skan	mii_pollstat(mii);
554132720Skan	ifmr->ifm_active = mii->mii_media_active;
555132720Skan	ifmr->ifm_status = mii->mii_media_status;
556132720Skan}
557132720Skan
558132720Skanstatic device_method_t arswitch_methods[] = {
559132720Skan	/* Device interface */
56097403Sobrien	DEVMETHOD(device_identify,	arswitch_identify),
56197403Sobrien	DEVMETHOD(device_probe,		arswitch_probe),
562132720Skan	DEVMETHOD(device_attach,	arswitch_attach),
563132720Skan	DEVMETHOD(device_detach,	arswitch_detach),
564132720Skan
565132720Skan	/* bus interface */
566132720Skan	DEVMETHOD(bus_add_child,	device_add_child_ordered),
567132720Skan
568132720Skan	/* MII interface */
569132720Skan	DEVMETHOD(miibus_readreg,	arswitch_readphy),
570132720Skan	DEVMETHOD(miibus_writereg,	arswitch_writephy),
571132720Skan	DEVMETHOD(miibus_statchg,	arswitch_statchg),
572132720Skan
573132720Skan	/* MDIO interface */
574132720Skan	DEVMETHOD(mdio_readreg,		arswitch_readphy),
575132720Skan	DEVMETHOD(mdio_writereg,	arswitch_writephy),
576132720Skan
577132720Skan	/* etherswitch interface */
578132720Skan	DEVMETHOD(etherswitch_lock,	arswitch_lock),
579132720Skan	DEVMETHOD(etherswitch_unlock,	arswitch_unlock),
580132720Skan	DEVMETHOD(etherswitch_getinfo,	arswitch_getinfo),
581132720Skan	DEVMETHOD(etherswitch_readreg,	arswitch_readreg),
582132720Skan	DEVMETHOD(etherswitch_writereg,	arswitch_writereg),
58397403Sobrien	DEVMETHOD(etherswitch_readphyreg,	arswitch_readphy),
58497403Sobrien	DEVMETHOD(etherswitch_writephyreg,	arswitch_writephy),
585132720Skan	DEVMETHOD(etherswitch_getport,	arswitch_getport),
58697403Sobrien	DEVMETHOD(etherswitch_setport,	arswitch_setport),
58797403Sobrien	DEVMETHOD(etherswitch_getvgroup,	arswitch_getvgroup),
58897403Sobrien	DEVMETHOD(etherswitch_setvgroup,	arswitch_setvgroup),
589132720Skan
590132720Skan	DEVMETHOD_END
591132720Skan};
592132720Skan
593132720SkanDEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods,
594132720Skan    sizeof(struct arswitch_softc));
595132720Skanstatic devclass_t arswitch_devclass;
596132720Skan
597132720SkanDRIVER_MODULE(arswitch, mdio, arswitch_driver, arswitch_devclass, 0, 0);
598132720SkanDRIVER_MODULE(miibus, arswitch, miibus_driver, miibus_devclass, 0, 0);
599132720SkanDRIVER_MODULE(mdio, arswitch, mdio_driver, mdio_devclass, 0, 0);
600132720SkanDRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, etherswitch_devclass, 0, 0);
601132720SkanMODULE_VERSION(arswitch, 1);
602132720SkanMODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */
603132720SkanMODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */
604132720Skan