arswitch.c revision 241578
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 241578 2012-10-15 12:20:40Z ray $
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
62235323Sadrian#include <dev/etherswitch/arswitch/arswitch_7240.h>
63235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8216.h>
64235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8226.h>
65235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8316.h>
66235288Sadrian
67235288Sadrian#include "mdio_if.h"
68235288Sadrian#include "miibus_if.h"
69235288Sadrian#include "etherswitch_if.h"
70235288Sadrian
71235288Sadrian#if	defined(DEBUG)
72235288Sadrianstatic SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch");
73235288Sadrian#endif
74235288Sadrian
75235288Sadrianstatic inline int arswitch_portforphy(int phy);
76235288Sadrianstatic void arswitch_tick(void *arg);
77235288Sadrianstatic int arswitch_ifmedia_upd(struct ifnet *);
78235288Sadrianstatic void arswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *);
79235288Sadrian
80235288Sadrianstatic void
81235288Sadrianarswitch_identify(driver_t *driver, device_t parent)
82235288Sadrian{
83235288Sadrian	device_t child;
84235288Sadrian
85235288Sadrian	if (device_find_child(parent, driver->name, -1) == NULL) {
86235288Sadrian		child = BUS_ADD_CHILD(parent, 0, driver->name, -1);
87235288Sadrian	}
88235288Sadrian}
89235288Sadrian
90235288Sadrianstatic int
91235288Sadrianarswitch_probe(device_t dev)
92235288Sadrian{
93235288Sadrian	struct arswitch_softc *sc;
94235288Sadrian	uint32_t id;
95235288Sadrian	char *chipname, desc[256];
96235288Sadrian
97235288Sadrian	sc = device_get_softc(dev);
98235288Sadrian	bzero(sc, sizeof(*sc));
99235288Sadrian	sc->page = -1;
100235323Sadrian
101235323Sadrian	/* AR7240 probe */
102235323Sadrian	if (ar7240_probe(dev) == 0) {
103235323Sadrian		chipname = "AR7240";
104235323Sadrian		sc->sc_switchtype = AR8X16_SWITCH_AR7240;
105241577Sray		id = 0;
106235323Sadrian		goto done;
107235323Sadrian	}
108235323Sadrian
109235323Sadrian	/* AR8xxx probe */
110235288Sadrian	id = arswitch_readreg(dev, AR8X16_REG_MASK_CTRL);
111235288Sadrian	switch ((id & AR8X16_MASK_CTRL_VER_MASK) >>
112235288Sadrian	    AR8X16_MASK_CTRL_VER_SHIFT) {
113235288Sadrian	case 1:
114235288Sadrian		chipname = "AR8216";
115235288Sadrian		sc->sc_switchtype = AR8X16_SWITCH_AR8216;
116235288Sadrian		break;
117235288Sadrian	case 2:
118235288Sadrian		chipname = "AR8226";
119235288Sadrian		sc->sc_switchtype = AR8X16_SWITCH_AR8226;
120235288Sadrian		break;
121235288Sadrian	case 16:
122235288Sadrian		chipname = "AR8316";
123235288Sadrian		sc->sc_switchtype = AR8X16_SWITCH_AR8316;
124235288Sadrian		break;
125235288Sadrian	default:
126235288Sadrian		chipname = NULL;
127235288Sadrian	}
128235323Sadrian
129235323Sadriandone:
130235288Sadrian	DPRINTF(dev, "chipname=%s, rev=%02x\n", chipname,
131235288Sadrian	    id & AR8X16_MASK_CTRL_REV_MASK);
132235288Sadrian	if (chipname != NULL) {
133235288Sadrian		snprintf(desc, sizeof(desc),
134235288Sadrian		    "Atheros %s Ethernet Switch",
135235288Sadrian		    chipname);
136235288Sadrian		device_set_desc_copy(dev, desc);
137235288Sadrian		return (BUS_PROBE_DEFAULT);
138235288Sadrian	}
139235288Sadrian	return (ENXIO);
140235288Sadrian}
141235288Sadrian
142235288Sadrianstatic int
143235288Sadrianarswitch_attach_phys(struct arswitch_softc *sc)
144235288Sadrian{
145235288Sadrian	int phy, err = 0;
146235288Sadrian	char name[IFNAMSIZ];
147235288Sadrian
148235288Sadrian	/* PHYs need an interface, so we generate a dummy one */
149235288Sadrian	snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
150235288Sadrian	for (phy = 0; phy < sc->numphys; phy++) {
151235288Sadrian		sc->ifp[phy] = if_alloc(IFT_ETHER);
152235288Sadrian		sc->ifp[phy]->if_softc = sc;
153235288Sadrian		sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST |
154235288Sadrian		    IFF_DRV_RUNNING | IFF_SIMPLEX;
155235288Sadrian		sc->ifname[phy] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK);
156235288Sadrian		bcopy(name, sc->ifname[phy], strlen(name)+1);
157235288Sadrian		if_initname(sc->ifp[phy], sc->ifname[phy],
158235288Sadrian		    arswitch_portforphy(phy));
159235288Sadrian		err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy],
160235288Sadrian		    arswitch_ifmedia_upd, arswitch_ifmedia_sts, \
161235288Sadrian		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
162235288Sadrian		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
163235288Sadrian		    device_get_nameunit(sc->miibus[phy]),
164235288Sadrian		    sc->ifp[phy]->if_xname);
165235288Sadrian		if (err != 0) {
166235288Sadrian			device_printf(sc->sc_dev,
167235288Sadrian			    "attaching PHY %d failed\n",
168235288Sadrian			    phy);
169235288Sadrian		}
170235288Sadrian	}
171235288Sadrian	return (err);
172235288Sadrian}
173235288Sadrian
174235288Sadrianstatic int
175235288Sadrianarswitch_attach(device_t dev)
176235288Sadrian{
177235288Sadrian	struct arswitch_softc *sc;
178235288Sadrian	int err = 0;
179235288Sadrian
180235288Sadrian	sc = device_get_softc(dev);
181235288Sadrian
182235288Sadrian	/* sc->sc_switchtype is already decided in arswitch_probe() */
183235288Sadrian	sc->sc_dev = dev;
184235288Sadrian	mtx_init(&sc->sc_mtx, "arswitch", NULL, MTX_DEF);
185235288Sadrian	sc->page = -1;
186235288Sadrian	strlcpy(sc->info.es_name, device_get_desc(dev),
187235288Sadrian	    sizeof(sc->info.es_name));
188235288Sadrian
189235288Sadrian	/*
190235288Sadrian	 * Attach switch related functions
191235288Sadrian	 */
192235323Sadrian	if (AR8X16_IS_SWITCH(sc, AR7240))
193235323Sadrian		ar7240_attach(sc);
194235323Sadrian	else if (AR8X16_IS_SWITCH(sc, AR8216))
195235288Sadrian		ar8216_attach(sc);
196235288Sadrian	else if (AR8X16_IS_SWITCH(sc, AR8226))
197235288Sadrian		ar8226_attach(sc);
198235288Sadrian	else if (AR8X16_IS_SWITCH(sc, AR8316))
199235288Sadrian		ar8316_attach(sc);
200235288Sadrian	else
201235288Sadrian		return (ENXIO);
202235288Sadrian
203235288Sadrian	/*
204235288Sadrian	 * XXX these two should be part of the switch attach function
205235288Sadrian	 */
206235288Sadrian	sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */
207235288Sadrian	sc->info.es_nvlangroups = 16;
208235288Sadrian
209235288Sadrian	/* XXX Defaults for externally connected AR8316 */
210235288Sadrian	sc->numphys = 4;
211235288Sadrian	sc->phy4cpu = 1;
212235288Sadrian	sc->is_rgmii = 1;
213235288Sadrian	sc->is_gmii = 0;
214235288Sadrian
215235288Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
216235288Sadrian	    "numphys", &sc->numphys);
217235288Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
218235288Sadrian	    "phy4cpu", &sc->phy4cpu);
219235288Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
220235288Sadrian	    "is_rgmii", &sc->is_rgmii);
221235288Sadrian	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
222235288Sadrian	    "is_gmii", &sc->is_gmii);
223235288Sadrian
224235377Sadrian	/*
225235377Sadrian	 * This requires much more setup depending upon each chip, including:
226235377Sadrian	 *
227235377Sadrian	 * + Proper reinitialisation of the PHYs;
228235377Sadrian	 * + Initialising the VLAN table;
229235377Sadrian	 * + Initialising the port access table and CPU flood/broadcast
230235377Sadrian	 *   configuration;
231235377Sadrian	 * + Other things I haven't yet thought of.
232235377Sadrian	 */
233235288Sadrian#ifdef NOTYET
234235288Sadrian	arswitch_writereg(dev, AR8X16_REG_MASK_CTRL,
235235288Sadrian	    AR8X16_MASK_CTRL_SOFT_RESET);
236235288Sadrian	DELAY(1000);
237235288Sadrian	if (arswitch_readreg(dev, AR8X16_REG_MASK_CTRL) &
238235288Sadrian	    AR8X16_MASK_CTRL_SOFT_RESET) {
239235288Sadrian		device_printf(dev, "unable to reset switch\n");
240235288Sadrian		return (ENXIO);
241235288Sadrian	}
242235288Sadrian#endif
243235288Sadrian
244235288Sadrian	err = sc->hal.arswitch_hw_setup(sc);
245235288Sadrian	if (err != 0)
246235288Sadrian		return (err);
247235288Sadrian
248235288Sadrian	err = sc->hal.arswitch_hw_global_setup(sc);
249235288Sadrian	if (err != 0)
250235288Sadrian		return (err);
251235288Sadrian
252235288Sadrian	/*
253235288Sadrian	 * Attach the PHYs and complete the bus enumeration.
254235288Sadrian	 */
255235288Sadrian	err = arswitch_attach_phys(sc);
256235288Sadrian	if (err != 0)
257235288Sadrian		return (err);
258235288Sadrian
259235288Sadrian	bus_generic_probe(dev);
260235288Sadrian	bus_enumerate_hinted_children(dev);
261235288Sadrian	err = bus_generic_attach(dev);
262235288Sadrian	if (err != 0)
263235288Sadrian		return (err);
264235288Sadrian
265235288Sadrian	callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0);
266241578Sray
267241578Sray	ARSWITCH_LOCK(sc);
268235288Sadrian	arswitch_tick(sc);
269241578Sray	ARSWITCH_UNLOCK(sc);
270235288Sadrian
271235288Sadrian	return (err);
272235288Sadrian}
273235288Sadrian
274235288Sadrianstatic int
275235288Sadrianarswitch_detach(device_t dev)
276235288Sadrian{
277235288Sadrian	struct arswitch_softc *sc = device_get_softc(dev);
278235288Sadrian	int i;
279235288Sadrian
280235288Sadrian	callout_drain(&sc->callout_tick);
281235288Sadrian
282235288Sadrian	for (i=0; i < sc->numphys; i++) {
283235288Sadrian		if (sc->miibus[i] != NULL)
284235288Sadrian			device_delete_child(dev, sc->miibus[i]);
285235288Sadrian		if (sc->ifp[i] != NULL)
286235288Sadrian			if_free(sc->ifp[i]);
287235288Sadrian		free(sc->ifname[i], M_DEVBUF);
288235288Sadrian	}
289235288Sadrian
290235288Sadrian	bus_generic_detach(dev);
291235288Sadrian	mtx_destroy(&sc->sc_mtx);
292235288Sadrian
293235288Sadrian	return (0);
294235288Sadrian}
295235288Sadrian
296235288Sadrian/*
297235288Sadrian * Convert PHY number to port number. PHY0 is connected to port 1, PHY1 to
298235288Sadrian * port 2, etc.
299235288Sadrian */
300235288Sadrianstatic inline int
301235288Sadrianarswitch_portforphy(int phy)
302235288Sadrian{
303235288Sadrian	return (phy+1);
304235288Sadrian}
305235288Sadrian
306235288Sadrianstatic inline struct mii_data *
307235288Sadrianarswitch_miiforport(struct arswitch_softc *sc, int port)
308235288Sadrian{
309235288Sadrian	int phy = port-1;
310235288Sadrian
311235288Sadrian	if (phy < 0 || phy >= sc->numphys)
312235288Sadrian		return (NULL);
313235288Sadrian	return (device_get_softc(sc->miibus[phy]));
314235288Sadrian}
315235288Sadrian
316235288Sadrianstatic inline struct ifnet *
317235288Sadrianarswitch_ifpforport(struct arswitch_softc *sc, int port)
318235288Sadrian{
319235288Sadrian	int phy = port-1;
320235288Sadrian
321235288Sadrian	if (phy < 0 || phy >= sc->numphys)
322235288Sadrian		return (NULL);
323235288Sadrian	return (sc->ifp[phy]);
324235288Sadrian}
325235288Sadrian
326235288Sadrian/*
327235288Sadrian * Convert port status to ifmedia.
328235288Sadrian */
329235288Sadrianstatic void
330235288Sadrianarswitch_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active)
331235288Sadrian{
332235288Sadrian	*media_active = IFM_ETHER;
333235288Sadrian	*media_status = IFM_AVALID;
334235288Sadrian
335235288Sadrian	if ((portstatus & AR8X16_PORT_STS_LINK_UP) != 0)
336235288Sadrian		*media_status |= IFM_ACTIVE;
337235288Sadrian	else {
338235288Sadrian		*media_active |= IFM_NONE;
339235288Sadrian		return;
340235288Sadrian	}
341235288Sadrian	switch (portstatus & AR8X16_PORT_STS_SPEED_MASK) {
342235288Sadrian	case AR8X16_PORT_STS_SPEED_10:
343235288Sadrian		*media_active |= IFM_10_T;
344235288Sadrian		break;
345235288Sadrian	case AR8X16_PORT_STS_SPEED_100:
346235288Sadrian		*media_active |= IFM_100_TX;
347235288Sadrian		break;
348235288Sadrian	case AR8X16_PORT_STS_SPEED_1000:
349235288Sadrian		*media_active |= IFM_1000_T;
350235288Sadrian		break;
351235288Sadrian	}
352235288Sadrian	if ((portstatus & AR8X16_PORT_STS_DUPLEX) == 0)
353235288Sadrian		*media_active |= IFM_FDX;
354235288Sadrian	else
355235288Sadrian		*media_active |= IFM_HDX;
356235288Sadrian	if ((portstatus & AR8X16_PORT_STS_TXFLOW) != 0)
357235288Sadrian		*media_active |= IFM_ETH_TXPAUSE;
358235288Sadrian	if ((portstatus & AR8X16_PORT_STS_RXFLOW) != 0)
359235288Sadrian		*media_active |= IFM_ETH_RXPAUSE;
360235288Sadrian}
361235288Sadrian
362235288Sadrian/*
363235288Sadrian * Poll the status for all PHYs.  We're using the switch port status because
364235288Sadrian * thats a lot quicker to read than talking to all the PHYs.  Care must be
365235288Sadrian * taken that the resulting ifmedia_active is identical to what the PHY will
366235288Sadrian * compute, or gratuitous link status changes will occur whenever the PHYs
367235288Sadrian * update function is called.
368235288Sadrian */
369235288Sadrianstatic void
370235288Sadrianarswitch_miipollstat(struct arswitch_softc *sc)
371235288Sadrian{
372235288Sadrian	int i;
373235288Sadrian	struct mii_data *mii;
374235288Sadrian	struct mii_softc *miisc;
375235288Sadrian	int portstatus;
376235288Sadrian
377241578Sray	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
378241578Sray
379235288Sadrian	for (i = 0; i < sc->numphys; i++) {
380235288Sadrian		if (sc->miibus[i] == NULL)
381235288Sadrian			continue;
382235288Sadrian		mii = device_get_softc(sc->miibus[i]);
383235288Sadrian		portstatus = arswitch_readreg(sc->sc_dev,
384235288Sadrian		    AR8X16_REG_PORT_STS(arswitch_portforphy(i)));
385235288Sadrian#if 0
386235288Sadrian		DPRINTF(sc->sc_dev, "p[%d]=%b\n",
387235288Sadrian		    arge_portforphy(i),
388235288Sadrian		    portstatus,
389235288Sadrian		    "\20\3TXMAC\4RXMAC\5TXFLOW\6RXFLOW\7"
390235288Sadrian		    "DUPLEX\11LINK_UP\12LINK_AUTO\13LINK_PAUSE");
391235288Sadrian#endif
392235288Sadrian		arswitch_update_ifmedia(portstatus, &mii->mii_media_status,
393235288Sadrian		    &mii->mii_media_active);
394235288Sadrian		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
395235288Sadrian			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
396235288Sadrian			    miisc->mii_inst)
397235288Sadrian				continue;
398235288Sadrian			mii_phy_update(miisc, MII_POLLSTAT);
399235288Sadrian		}
400235288Sadrian	}
401235288Sadrian}
402235288Sadrian
403235288Sadrianstatic void
404235288Sadrianarswitch_tick(void *arg)
405235288Sadrian{
406235288Sadrian	struct arswitch_softc *sc = arg;
407235288Sadrian
408235288Sadrian	arswitch_miipollstat(sc);
409235288Sadrian	callout_reset(&sc->callout_tick, hz, arswitch_tick, sc);
410235288Sadrian}
411235288Sadrian
412241578Sraystatic void
413241578Srayarswitch_lock(device_t dev)
414241578Sray{
415241578Sray	struct arswitch_softc *sc = device_get_softc(dev);
416241578Sray
417241578Sray	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
418241578Sray	ARSWITCH_LOCK(sc);
419241578Sray}
420241578Sray
421241578Sraystatic void
422241578Srayarswitch_unlock(device_t dev)
423241578Sray{
424241578Sray	struct arswitch_softc *sc = device_get_softc(dev);
425241578Sray
426241578Sray	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
427241578Sray	ARSWITCH_UNLOCK(sc);
428241578Sray}
429241578Sray
430235288Sadrianstatic etherswitch_info_t *
431235288Sadrianarswitch_getinfo(device_t dev)
432235288Sadrian{
433235288Sadrian	struct arswitch_softc *sc = device_get_softc(dev);
434235288Sadrian
435235288Sadrian	return (&sc->info);
436235288Sadrian}
437235288Sadrian
438235288Sadrianstatic int
439235288Sadrianarswitch_getport(device_t dev, etherswitch_port_t *p)
440235288Sadrian{
441235288Sadrian	struct arswitch_softc *sc = device_get_softc(dev);
442235288Sadrian	struct mii_data *mii;
443235288Sadrian	struct ifmediareq *ifmr = &p->es_ifmr;
444235288Sadrian	int err;
445235288Sadrian
446235288Sadrian	if (p->es_port < 0 || p->es_port >= AR8X16_NUM_PORTS)
447235288Sadrian		return (ENXIO);
448235288Sadrian	p->es_vlangroup = 0;
449235288Sadrian
450235288Sadrian	mii = arswitch_miiforport(sc, p->es_port);
451235288Sadrian	if (p->es_port == 0) {
452235288Sadrian		/* fill in fixed values for CPU port */
453235288Sadrian		ifmr->ifm_count = 0;
454235288Sadrian		ifmr->ifm_current = ifmr->ifm_active =
455235288Sadrian		    IFM_ETHER | IFM_1000_T | IFM_FDX;
456235288Sadrian		ifmr->ifm_mask = 0;
457235288Sadrian		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
458235288Sadrian	} else if (mii != NULL) {
459235288Sadrian		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
460235288Sadrian		    &mii->mii_media, SIOCGIFMEDIA);
461235288Sadrian		if (err)
462235288Sadrian			return (err);
463235288Sadrian	} else {
464235288Sadrian		return (ENXIO);
465235288Sadrian	}
466235288Sadrian	return (0);
467235288Sadrian}
468235288Sadrian
469235288Sadrian/*
470235288Sadrian * XXX doesn't yet work?
471235288Sadrian */
472235288Sadrianstatic int
473235288Sadrianarswitch_setport(device_t dev, etherswitch_port_t *p)
474235288Sadrian{
475235288Sadrian	int err;
476235288Sadrian	struct arswitch_softc *sc;
477235288Sadrian	struct ifmedia *ifm;
478235288Sadrian	struct mii_data *mii;
479235288Sadrian	struct ifnet *ifp;
480235288Sadrian
481235288Sadrian	/*
482235288Sadrian	 * XXX check the sc numphys, or the #define ?
483235288Sadrian	 */
484235288Sadrian	if (p->es_port < 0 || p->es_port >= AR8X16_NUM_PHYS)
485235288Sadrian		return (ENXIO);
486235288Sadrian
487235288Sadrian	sc = device_get_softc(dev);
488235288Sadrian
489235288Sadrian	/*
490235288Sadrian	 * XXX TODO: don't set the CPU port?
491235288Sadrian	 */
492235288Sadrian
493235288Sadrian	mii = arswitch_miiforport(sc, p->es_port);
494235288Sadrian	if (mii == NULL)
495235288Sadrian		return (ENXIO);
496235288Sadrian
497235288Sadrian	ifp = arswitch_ifpforport(sc, p->es_port);
498235288Sadrian
499235288Sadrian	ifm = &mii->mii_media;
500235288Sadrian	err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
501235288Sadrian	return (err);
502235288Sadrian}
503235288Sadrian
504235288Sadrianstatic int
505235288Sadrianarswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
506235288Sadrian{
507235288Sadrian
508235288Sadrian	/* XXX not implemented yet */
509235288Sadrian	vg->es_vid = 0;
510235288Sadrian	vg->es_member_ports = 0;
511235288Sadrian	vg->es_untagged_ports = 0;
512235288Sadrian	vg->es_fid = 0;
513235288Sadrian	return (0);
514235288Sadrian}
515235288Sadrian
516235288Sadrianstatic int
517235288Sadrianarswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
518235288Sadrian{
519235288Sadrian
520235288Sadrian	/* XXX not implemented yet */
521235288Sadrian	return (0);
522235288Sadrian}
523235288Sadrian
524235288Sadrianstatic void
525235288Sadrianarswitch_statchg(device_t dev)
526235288Sadrian{
527235288Sadrian
528235288Sadrian	DPRINTF(dev, "%s\n", __func__);
529235288Sadrian}
530235288Sadrian
531235288Sadrianstatic int
532235288Sadrianarswitch_ifmedia_upd(struct ifnet *ifp)
533235288Sadrian{
534235288Sadrian	struct arswitch_softc *sc = ifp->if_softc;
535235288Sadrian	struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
536235288Sadrian
537235288Sadrian	if (mii == NULL)
538235288Sadrian		return (ENXIO);
539235288Sadrian	mii_mediachg(mii);
540235288Sadrian	return (0);
541235288Sadrian}
542235288Sadrian
543235288Sadrianstatic void
544235288Sadrianarswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
545235288Sadrian{
546235288Sadrian	struct arswitch_softc *sc = ifp->if_softc;
547235288Sadrian	struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
548235288Sadrian
549235288Sadrian	DPRINTF(sc->sc_dev, "%s\n", __func__);
550235288Sadrian
551235288Sadrian	if (mii == NULL)
552235288Sadrian		return;
553235288Sadrian	mii_pollstat(mii);
554235288Sadrian	ifmr->ifm_active = mii->mii_media_active;
555235288Sadrian	ifmr->ifm_status = mii->mii_media_status;
556235288Sadrian}
557235288Sadrian
558235288Sadrianstatic device_method_t arswitch_methods[] = {
559235288Sadrian	/* Device interface */
560235288Sadrian	DEVMETHOD(device_identify,	arswitch_identify),
561235288Sadrian	DEVMETHOD(device_probe,		arswitch_probe),
562235288Sadrian	DEVMETHOD(device_attach,	arswitch_attach),
563235288Sadrian	DEVMETHOD(device_detach,	arswitch_detach),
564235288Sadrian
565235288Sadrian	/* bus interface */
566235288Sadrian	DEVMETHOD(bus_add_child,	device_add_child_ordered),
567235288Sadrian
568235288Sadrian	/* MII interface */
569235288Sadrian	DEVMETHOD(miibus_readreg,	arswitch_readphy),
570235288Sadrian	DEVMETHOD(miibus_writereg,	arswitch_writephy),
571235288Sadrian	DEVMETHOD(miibus_statchg,	arswitch_statchg),
572235288Sadrian
573235288Sadrian	/* MDIO interface */
574235288Sadrian	DEVMETHOD(mdio_readreg,		arswitch_readphy),
575235288Sadrian	DEVMETHOD(mdio_writereg,	arswitch_writephy),
576235288Sadrian
577235288Sadrian	/* etherswitch interface */
578241578Sray	DEVMETHOD(etherswitch_lock,	arswitch_lock),
579241578Sray	DEVMETHOD(etherswitch_unlock,	arswitch_unlock),
580235288Sadrian	DEVMETHOD(etherswitch_getinfo,	arswitch_getinfo),
581235288Sadrian	DEVMETHOD(etherswitch_readreg,	arswitch_readreg),
582235288Sadrian	DEVMETHOD(etherswitch_writereg,	arswitch_writereg),
583235288Sadrian	DEVMETHOD(etherswitch_readphyreg,	arswitch_readphy),
584235288Sadrian	DEVMETHOD(etherswitch_writephyreg,	arswitch_writephy),
585235288Sadrian	DEVMETHOD(etherswitch_getport,	arswitch_getport),
586235288Sadrian	DEVMETHOD(etherswitch_setport,	arswitch_setport),
587235288Sadrian	DEVMETHOD(etherswitch_getvgroup,	arswitch_getvgroup),
588235288Sadrian	DEVMETHOD(etherswitch_setvgroup,	arswitch_setvgroup),
589235288Sadrian
590235288Sadrian	DEVMETHOD_END
591235288Sadrian};
592235288Sadrian
593235288SadrianDEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods,
594235288Sadrian    sizeof(struct arswitch_softc));
595235288Sadrianstatic devclass_t arswitch_devclass;
596235288Sadrian
597235288SadrianDRIVER_MODULE(arswitch, mdio, arswitch_driver, arswitch_devclass, 0, 0);
598235288SadrianDRIVER_MODULE(miibus, arswitch, miibus_driver, miibus_devclass, 0, 0);
599235288SadrianDRIVER_MODULE(mdio, arswitch, mdio_driver, mdio_devclass, 0, 0);
600235288SadrianDRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, etherswitch_devclass, 0, 0);
601235288SadrianMODULE_VERSION(arswitch, 1);
602235288SadrianMODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */
603235288SadrianMODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */
604