1 /*-
2  * Copyright (c) 2011-2012 Stefan Bethke.
3  * Copyright (c) 2012 Adrian Chadd.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/errno.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/sysctl.h>
39 #include <sys/systm.h>
40 
41 #include <net/if.h>
42 #include <net/if_var.h>
43 #include <net/if_arp.h>
44 #include <net/ethernet.h>
45 #include <net/if_dl.h>
46 #include <net/if_media.h>
47 #include <net/if_types.h>
48 
49 #include <machine/bus.h>
50 #include <dev/iicbus/iic.h>
51 #include <dev/iicbus/iiconf.h>
52 #include <dev/iicbus/iicbus.h>
53 #include <dev/mii/mii.h>
54 #include <dev/mii/miivar.h>
55 #include <dev/etherswitch/mdio.h>
56 
57 #include <dev/etherswitch/etherswitch.h>
58 
59 #include <dev/etherswitch/arswitch/arswitchreg.h>
60 #include <dev/etherswitch/arswitch/arswitchvar.h>
61 #include <dev/etherswitch/arswitch/arswitch_reg.h>
62 #include <dev/etherswitch/arswitch/arswitch_phy.h>
63 #include <dev/etherswitch/arswitch/arswitch_vlans.h>
64 
65 #include <dev/etherswitch/arswitch/arswitch_7240.h>
66 #include <dev/etherswitch/arswitch/arswitch_8216.h>
67 #include <dev/etherswitch/arswitch/arswitch_8226.h>
68 #include <dev/etherswitch/arswitch/arswitch_8316.h>
69 #include <dev/etherswitch/arswitch/arswitch_8327.h>
70 #include <dev/etherswitch/arswitch/arswitch_9340.h>
71 
72 #include "mdio_if.h"
73 #include "miibus_if.h"
74 #include "etherswitch_if.h"
75 
76 #if	defined(DEBUG)
77 static SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch");
78 #endif
79 
80 static inline int arswitch_portforphy(int phy);
81 static void arswitch_tick(void *arg);
82 static int arswitch_ifmedia_upd(struct ifnet *);
83 static void arswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *);
84 static int ar8xxx_port_vlan_setup(struct arswitch_softc *sc,
85     etherswitch_port_t *p);
86 static int ar8xxx_port_vlan_get(struct arswitch_softc *sc,
87     etherswitch_port_t *p);
88 
89 static int
90 arswitch_probe(device_t dev)
91 {
92 	struct arswitch_softc *sc;
93 	uint32_t id;
94 	char *chipname, desc[256];
95 
96 	sc = device_get_softc(dev);
97 	bzero(sc, sizeof(*sc));
98 	sc->page = -1;
99 
100 	/* AR7240 probe */
101 	if (ar7240_probe(dev) == 0) {
102 		chipname = "AR7240";
103 		sc->sc_switchtype = AR8X16_SWITCH_AR7240;
104 		sc->is_internal_switch = 1;
105 		id = 0;
106 		goto done;
107 	}
108 
109 	/* AR9340 probe */
110 	if (ar9340_probe(dev) == 0) {
111 		chipname = "AR9340";
112 		sc->sc_switchtype = AR8X16_SWITCH_AR9340;
113 		sc->is_internal_switch = 1;
114 		id = 0;
115 		goto done;
116 	}
117 
118 	/* AR8xxx probe */
119 	id = arswitch_readreg(dev, AR8X16_REG_MASK_CTRL);
120 	sc->chip_rev = (id & AR8X16_MASK_CTRL_REV_MASK);
121 	sc->chip_ver = (id & AR8X16_MASK_CTRL_VER_MASK) > AR8X16_MASK_CTRL_VER_SHIFT;
122 	switch (id & (AR8X16_MASK_CTRL_VER_MASK | AR8X16_MASK_CTRL_REV_MASK)) {
123 	case 0x0101:
124 		chipname = "AR8216";
125 		sc->sc_switchtype = AR8X16_SWITCH_AR8216;
126 		break;
127 	case 0x0201:
128 		chipname = "AR8226";
129 		sc->sc_switchtype = AR8X16_SWITCH_AR8226;
130 		break;
131 	/* 0x0301 - AR8236 */
132 	case 0x1000:
133 	case 0x1001:
134 		chipname = "AR8316";
135 		sc->sc_switchtype = AR8X16_SWITCH_AR8316;
136 		break;
137 	case 0x1202:
138 	case 0x1204:
139 		chipname = "AR8327";
140 		sc->sc_switchtype = AR8X16_SWITCH_AR8327;
141 		sc->mii_lo_first = 1;
142 		break;
143 	default:
144 		chipname = NULL;
145 	}
146 
147 done:
148 
149 	DPRINTF(dev, "chipname=%s, id=%08x\n", chipname, id);
150 	if (chipname != NULL) {
151 		snprintf(desc, sizeof(desc),
152 		    "Atheros %s Ethernet Switch (ver %d rev %d)",
153 		    chipname,
154 		    sc->chip_ver,
155 		    sc->chip_rev);
156 		device_set_desc_copy(dev, desc);
157 		return (BUS_PROBE_DEFAULT);
158 	}
159 	return (ENXIO);
160 }
161 
162 static int
163 arswitch_attach_phys(struct arswitch_softc *sc)
164 {
165 	int phy, err = 0;
166 	char name[IFNAMSIZ];
167 
168 	/* PHYs need an interface, so we generate a dummy one */
169 	snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
170 	for (phy = 0; phy < sc->numphys; phy++) {
171 		sc->ifp[phy] = if_alloc(IFT_ETHER);
172 		sc->ifp[phy]->if_softc = sc;
173 		sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST |
174 		    IFF_DRV_RUNNING | IFF_SIMPLEX;
175 		sc->ifname[phy] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK);
176 		bcopy(name, sc->ifname[phy], strlen(name)+1);
177 		if_initname(sc->ifp[phy], sc->ifname[phy],
178 		    arswitch_portforphy(phy));
179 		err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy],
180 		    arswitch_ifmedia_upd, arswitch_ifmedia_sts, \
181 		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
182 #if 0
183 		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
184 		    device_get_nameunit(sc->miibus[phy]),
185 		    sc->ifp[phy]->if_xname);
186 #endif
187 		if (err != 0) {
188 			device_printf(sc->sc_dev,
189 			    "attaching PHY %d failed\n",
190 			    phy);
191 		}
192 	}
193 	return (err);
194 }
195 
196 static int
197 arswitch_reset(device_t dev)
198 {
199 
200 	arswitch_writereg(dev, AR8X16_REG_MASK_CTRL,
201 	    AR8X16_MASK_CTRL_SOFT_RESET);
202 	DELAY(1000);
203 	if (arswitch_readreg(dev, AR8X16_REG_MASK_CTRL) &
204 	    AR8X16_MASK_CTRL_SOFT_RESET) {
205 		device_printf(dev, "unable to reset switch\n");
206 		return (-1);
207 	}
208 	return (0);
209 }
210 
211 static int
212 arswitch_set_vlan_mode(struct arswitch_softc *sc, uint32_t mode)
213 {
214 
215 	/* Check for invalid modes. */
216 	if ((mode & sc->info.es_vlan_caps) != mode)
217 		return (EINVAL);
218 
219 	switch (mode) {
220 	case ETHERSWITCH_VLAN_DOT1Q:
221 		sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
222 		break;
223 	case ETHERSWITCH_VLAN_PORT:
224 		sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
225 		break;
226 	default:
227 		sc->vlan_mode = 0;
228 	};
229 
230 	/* Reset VLANs. */
231 	sc->hal.arswitch_vlan_init_hw(sc);
232 
233 	return (0);
234 }
235 
236 static void
237 ar8xxx_port_init(struct arswitch_softc *sc, int port)
238 {
239 
240 	/* Port0 - CPU */
241 	if (port == AR8X16_PORT_CPU) {
242 		arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_STS(0),
243 		    (AR8X16_IS_SWITCH(sc, AR8216) ?
244 		    AR8X16_PORT_STS_SPEED_100 : AR8X16_PORT_STS_SPEED_1000) |
245 		    (AR8X16_IS_SWITCH(sc, AR8216) ? 0 : AR8X16_PORT_STS_RXFLOW) |
246 		    (AR8X16_IS_SWITCH(sc, AR8216) ? 0 : AR8X16_PORT_STS_TXFLOW) |
247 		    AR8X16_PORT_STS_RXMAC |
248 		    AR8X16_PORT_STS_TXMAC |
249 		    AR8X16_PORT_STS_DUPLEX);
250 		arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_CTRL(0),
251 		    arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(0)) &
252 		    ~AR8X16_PORT_CTRL_HEADER);
253 	} else {
254 		/* Set ports to auto negotiation. */
255 		arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_STS(port),
256 		    AR8X16_PORT_STS_LINK_AUTO);
257 		arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_CTRL(port),
258 		    arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(port)) &
259 		    ~AR8X16_PORT_CTRL_HEADER);
260 	}
261 }
262 
263 static int
264 ar8xxx_atu_flush(struct arswitch_softc *sc)
265 {
266 	int ret;
267 
268 	ret = arswitch_waitreg(sc->sc_dev,
269 	    AR8216_REG_ATU,
270 	    AR8216_ATU_ACTIVE,
271 	    0,
272 	    1000);
273 
274 	if (ret)
275 		device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__);
276 
277 	if (!ret)
278 		arswitch_writereg(sc->sc_dev,
279 		    AR8216_REG_ATU,
280 		    AR8216_ATU_OP_FLUSH);
281 
282 	return (ret);
283 }
284 
285 static int
286 arswitch_attach(device_t dev)
287 {
288 	struct arswitch_softc *sc;
289 	int err = 0;
290 	int port;
291 
292 	sc = device_get_softc(dev);
293 
294 	/* sc->sc_switchtype is already decided in arswitch_probe() */
295 	sc->sc_dev = dev;
296 	mtx_init(&sc->sc_mtx, "arswitch", NULL, MTX_DEF);
297 	sc->page = -1;
298 	strlcpy(sc->info.es_name, device_get_desc(dev),
299 	    sizeof(sc->info.es_name));
300 
301 	/* Default HAL methods */
302 	sc->hal.arswitch_port_init = ar8xxx_port_init;
303 	sc->hal.arswitch_port_vlan_setup = ar8xxx_port_vlan_setup;
304 	sc->hal.arswitch_port_vlan_get = ar8xxx_port_vlan_get;
305 	sc->hal.arswitch_vlan_init_hw = ar8xxx_reset_vlans;
306 	sc->hal.arswitch_vlan_getvgroup = ar8xxx_getvgroup;
307 	sc->hal.arswitch_vlan_setvgroup = ar8xxx_setvgroup;
308 	sc->hal.arswitch_vlan_get_pvid = ar8xxx_get_pvid;
309 	sc->hal.arswitch_vlan_set_pvid = ar8xxx_set_pvid;
310 	sc->hal.arswitch_atu_flush = ar8xxx_atu_flush;
311 	sc->hal.arswitch_phy_read = arswitch_readphy_internal;
312 	sc->hal.arswitch_phy_write = arswitch_writephy_internal;
313 
314 	/*
315 	 * Attach switch related functions
316 	 */
317 	if (AR8X16_IS_SWITCH(sc, AR7240))
318 		ar7240_attach(sc);
319 	else if (AR8X16_IS_SWITCH(sc, AR9340))
320 		ar9340_attach(sc);
321 	else if (AR8X16_IS_SWITCH(sc, AR8216))
322 		ar8216_attach(sc);
323 	else if (AR8X16_IS_SWITCH(sc, AR8226))
324 		ar8226_attach(sc);
325 	else if (AR8X16_IS_SWITCH(sc, AR8316))
326 		ar8316_attach(sc);
327 	else if (AR8X16_IS_SWITCH(sc, AR8327))
328 		ar8327_attach(sc);
329 	else {
330 		DPRINTF(dev, "%s: unknown switch (%d)?\n", __func__, sc->sc_switchtype);
331 		return (ENXIO);
332 	}
333 
334 	/* Common defaults. */
335 	sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */
336 
337 	/* XXX Defaults for externally connected AR8316 */
338 	sc->numphys = 4;
339 	sc->phy4cpu = 1;
340 	sc->is_rgmii = 1;
341 	sc->is_gmii = 0;
342 	sc->is_mii = 0;
343 
344 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
345 	    "numphys", &sc->numphys);
346 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
347 	    "phy4cpu", &sc->phy4cpu);
348 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
349 	    "is_rgmii", &sc->is_rgmii);
350 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
351 	    "is_gmii", &sc->is_gmii);
352 	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
353 	    "is_mii", &sc->is_mii);
354 
355 	if (sc->numphys > AR8X16_NUM_PHYS)
356 		sc->numphys = AR8X16_NUM_PHYS;
357 
358 	/* Reset the switch. */
359 	if (arswitch_reset(dev)) {
360 		DPRINTF(dev, "%s: arswitch_reset: failed\n", __func__);
361 		return (ENXIO);
362 	}
363 
364 	err = sc->hal.arswitch_hw_setup(sc);
365 	DPRINTF(dev, "%s: hw_setup: err=%d\n", __func__, err);
366 	if (err != 0)
367 		return (err);
368 
369 	err = sc->hal.arswitch_hw_global_setup(sc);
370 	DPRINTF(dev, "%s: hw_global_setup: err=%d\n", __func__, err);
371 	if (err != 0)
372 		return (err);
373 
374 	/* Initialize the switch ports. */
375 	for (port = 0; port <= sc->numphys; port++) {
376 		sc->hal.arswitch_port_init(sc, port);
377 	}
378 
379 	/*
380 	 * Attach the PHYs and complete the bus enumeration.
381 	 */
382 	err = arswitch_attach_phys(sc);
383 	DPRINTF(dev, "%s: attach_phys: err=%d\n", __func__, err);
384 	if (err != 0)
385 		return (err);
386 
387 	/* Default to ingress filters off. */
388 	err = arswitch_set_vlan_mode(sc, 0);
389 	DPRINTF(dev, "%s: set_vlan_mode: err=%d\n", __func__, err);
390 	if (err != 0)
391 		return (err);
392 
393 	bus_generic_probe(dev);
394 	bus_enumerate_hinted_children(dev);
395 	err = bus_generic_attach(dev);
396 	DPRINTF(dev, "%s: bus_generic_attach: err=%d\n", __func__, err);
397 	if (err != 0)
398 		return (err);
399 
400 	callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0);
401 
402 	ARSWITCH_LOCK(sc);
403 	arswitch_tick(sc);
404 	ARSWITCH_UNLOCK(sc);
405 
406 	return (err);
407 }
408 
409 static int
410 arswitch_detach(device_t dev)
411 {
412 	struct arswitch_softc *sc = device_get_softc(dev);
413 	int i;
414 
415 	callout_drain(&sc->callout_tick);
416 
417 	for (i=0; i < sc->numphys; i++) {
418 		if (sc->miibus[i] != NULL)
419 			device_delete_child(dev, sc->miibus[i]);
420 		if (sc->ifp[i] != NULL)
421 			if_free(sc->ifp[i]);
422 		free(sc->ifname[i], M_DEVBUF);
423 	}
424 
425 	bus_generic_detach(dev);
426 	mtx_destroy(&sc->sc_mtx);
427 
428 	return (0);
429 }
430 
431 /*
432  * Convert PHY number to port number. PHY0 is connected to port 1, PHY1 to
433  * port 2, etc.
434  */
435 static inline int
436 arswitch_portforphy(int phy)
437 {
438 	return (phy+1);
439 }
440 
441 static inline struct mii_data *
442 arswitch_miiforport(struct arswitch_softc *sc, int port)
443 {
444 	int phy = port-1;
445 
446 	if (phy < 0 || phy >= sc->numphys)
447 		return (NULL);
448 	return (device_get_softc(sc->miibus[phy]));
449 }
450 
451 static inline struct ifnet *
452 arswitch_ifpforport(struct arswitch_softc *sc, int port)
453 {
454 	int phy = port-1;
455 
456 	if (phy < 0 || phy >= sc->numphys)
457 		return (NULL);
458 	return (sc->ifp[phy]);
459 }
460 
461 /*
462  * Convert port status to ifmedia.
463  */
464 static void
465 arswitch_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active)
466 {
467 	*media_active = IFM_ETHER;
468 	*media_status = IFM_AVALID;
469 
470 	if ((portstatus & AR8X16_PORT_STS_LINK_UP) != 0)
471 		*media_status |= IFM_ACTIVE;
472 	else {
473 		*media_active |= IFM_NONE;
474 		return;
475 	}
476 	switch (portstatus & AR8X16_PORT_STS_SPEED_MASK) {
477 	case AR8X16_PORT_STS_SPEED_10:
478 		*media_active |= IFM_10_T;
479 		break;
480 	case AR8X16_PORT_STS_SPEED_100:
481 		*media_active |= IFM_100_TX;
482 		break;
483 	case AR8X16_PORT_STS_SPEED_1000:
484 		*media_active |= IFM_1000_T;
485 		break;
486 	}
487 	if ((portstatus & AR8X16_PORT_STS_DUPLEX) == 0)
488 		*media_active |= IFM_FDX;
489 	else
490 		*media_active |= IFM_HDX;
491 	if ((portstatus & AR8X16_PORT_STS_TXFLOW) != 0)
492 		*media_active |= IFM_ETH_TXPAUSE;
493 	if ((portstatus & AR8X16_PORT_STS_RXFLOW) != 0)
494 		*media_active |= IFM_ETH_RXPAUSE;
495 }
496 
497 /*
498  * Poll the status for all PHYs.  We're using the switch port status because
499  * thats a lot quicker to read than talking to all the PHYs.  Care must be
500  * taken that the resulting ifmedia_active is identical to what the PHY will
501  * compute, or gratuitous link status changes will occur whenever the PHYs
502  * update function is called.
503  */
504 static void
505 arswitch_miipollstat(struct arswitch_softc *sc)
506 {
507 	int i;
508 	struct mii_data *mii;
509 	struct mii_softc *miisc;
510 	int portstatus;
511 	int port_flap = 0;
512 
513 	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
514 
515 	for (i = 0; i < sc->numphys; i++) {
516 		if (sc->miibus[i] == NULL)
517 			continue;
518 		mii = device_get_softc(sc->miibus[i]);
519 		/* XXX This would be nice to have abstracted out to be per-chip */
520 		/* AR8327/AR8337 has a different register base */
521 		if (AR8X16_IS_SWITCH(sc, AR8327))
522 			portstatus = arswitch_readreg(sc->sc_dev,
523 			    AR8327_REG_PORT_STATUS(arswitch_portforphy(i)));
524 		else
525 			portstatus = arswitch_readreg(sc->sc_dev,
526 			    AR8X16_REG_PORT_STS(arswitch_portforphy(i)));
527 #if 0
528 		DPRINTF(sc->sc_dev, "p[%d]=%b\n",
529 		    i,
530 		    portstatus,
531 		    "\20\3TXMAC\4RXMAC\5TXFLOW\6RXFLOW\7"
532 		    "DUPLEX\11LINK_UP\12LINK_AUTO\13LINK_PAUSE");
533 #endif
534 		/*
535 		 * If the current status is down, but we have a link
536 		 * status showing up, we need to do an ATU flush.
537 		 */
538 		if ((mii->mii_media_status & IFM_ACTIVE) == 0 &&
539 		    (portstatus & AR8X16_PORT_STS_LINK_UP) != 0) {
540 			device_printf(sc->sc_dev, "%s: port %d: port -> UP\n",
541 			    __func__,
542 			    i);
543 			port_flap = 1;
544 		}
545 		/*
546 		 * and maybe if a port goes up->down?
547 		 */
548 		if ((mii->mii_media_status & IFM_ACTIVE) != 0 &&
549 		    (portstatus & AR8X16_PORT_STS_LINK_UP) == 0) {
550 			device_printf(sc->sc_dev, "%s: port %d: port -> DOWN\n",
551 			    __func__,
552 			    i);
553 			port_flap = 1;
554 		}
555 		arswitch_update_ifmedia(portstatus, &mii->mii_media_status,
556 		    &mii->mii_media_active);
557 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
558 			if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
559 			    miisc->mii_inst)
560 				continue;
561 			mii_phy_update(miisc, MII_POLLSTAT);
562 		}
563 	}
564 
565 	/* If a port went from down->up, flush the ATU */
566 	if (port_flap)
567 		sc->hal.arswitch_atu_flush(sc);
568 }
569 
570 static void
571 arswitch_tick(void *arg)
572 {
573 	struct arswitch_softc *sc = arg;
574 
575 	arswitch_miipollstat(sc);
576 	callout_reset(&sc->callout_tick, hz, arswitch_tick, sc);
577 }
578 
579 static void
580 arswitch_lock(device_t dev)
581 {
582 	struct arswitch_softc *sc = device_get_softc(dev);
583 
584 	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
585 	ARSWITCH_LOCK(sc);
586 }
587 
588 static void
589 arswitch_unlock(device_t dev)
590 {
591 	struct arswitch_softc *sc = device_get_softc(dev);
592 
593 	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
594 	ARSWITCH_UNLOCK(sc);
595 }
596 
597 static etherswitch_info_t *
598 arswitch_getinfo(device_t dev)
599 {
600 	struct arswitch_softc *sc = device_get_softc(dev);
601 
602 	return (&sc->info);
603 }
604 
605 static int
606 ar8xxx_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p)
607 {
608 	uint32_t reg;
609 
610 	ARSWITCH_LOCK(sc);
611 
612 	/* Retrieve the PVID. */
613 	sc->hal.arswitch_vlan_get_pvid(sc, p->es_port, &p->es_pvid);
614 
615 	/* Port flags. */
616 	reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(p->es_port));
617 	if (reg & AR8X16_PORT_CTRL_DOUBLE_TAG)
618 		p->es_flags |= ETHERSWITCH_PORT_DOUBLE_TAG;
619 	reg >>= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
620 	if ((reg & 0x3) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD)
621 		p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
622 	if ((reg & 0x3) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP)
623 		p->es_flags |= ETHERSWITCH_PORT_STRIPTAG;
624 	ARSWITCH_UNLOCK(sc);
625 
626 	return (0);
627 }
628 
629 static int
630 arswitch_getport(device_t dev, etherswitch_port_t *p)
631 {
632 	struct arswitch_softc *sc;
633 	struct mii_data *mii;
634 	struct ifmediareq *ifmr;
635 	int err;
636 
637 	sc = device_get_softc(dev);
638 	if (p->es_port < 0 || p->es_port > sc->numphys)
639 		return (ENXIO);
640 
641 	err = sc->hal.arswitch_port_vlan_get(sc, p);
642 	if (err != 0)
643 		return (err);
644 
645 	mii = arswitch_miiforport(sc, p->es_port);
646 	if (p->es_port == AR8X16_PORT_CPU) {
647 		/* fill in fixed values for CPU port */
648 		/* XXX is this valid in all cases? */
649 		p->es_flags |= ETHERSWITCH_PORT_CPU;
650 		ifmr = &p->es_ifmr;
651 		ifmr->ifm_count = 0;
652 		ifmr->ifm_current = ifmr->ifm_active =
653 		    IFM_ETHER | IFM_1000_T | IFM_FDX;
654 		ifmr->ifm_mask = 0;
655 		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
656 	} else if (mii != NULL) {
657 		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
658 		    &mii->mii_media, SIOCGIFMEDIA);
659 		if (err)
660 			return (err);
661 	} else {
662 		return (ENXIO);
663 	}
664 	return (0);
665 }
666 
667 static int
668 ar8xxx_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p)
669 {
670 	uint32_t reg;
671 	int err;
672 
673 	ARSWITCH_LOCK(sc);
674 
675 	/* Set the PVID. */
676 	if (p->es_pvid != 0)
677 		sc->hal.arswitch_vlan_set_pvid(sc, p->es_port, p->es_pvid);
678 
679 	/* Mutually exclusive. */
680 	if (p->es_flags & ETHERSWITCH_PORT_ADDTAG &&
681 	    p->es_flags & ETHERSWITCH_PORT_STRIPTAG) {
682 		ARSWITCH_UNLOCK(sc);
683 		return (EINVAL);
684 	}
685 
686 	reg = 0;
687 	if (p->es_flags & ETHERSWITCH_PORT_DOUBLE_TAG)
688 		reg |= AR8X16_PORT_CTRL_DOUBLE_TAG;
689 	if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
690 		reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD <<
691 		    AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
692 	if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
693 		reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP <<
694 		    AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
695 
696 	err = arswitch_modifyreg(sc->sc_dev,
697 	    AR8X16_REG_PORT_CTRL(p->es_port),
698 	    0x3 << AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT |
699 	    AR8X16_PORT_CTRL_DOUBLE_TAG, reg);
700 
701 	ARSWITCH_UNLOCK(sc);
702 	return (err);
703 }
704 
705 static int
706 arswitch_setport(device_t dev, etherswitch_port_t *p)
707 {
708 	int err;
709 	struct arswitch_softc *sc;
710 	struct ifmedia *ifm;
711 	struct mii_data *mii;
712 	struct ifnet *ifp;
713 
714 	sc = device_get_softc(dev);
715 	if (p->es_port < 0 || p->es_port > sc->numphys)
716 		return (ENXIO);
717 
718 	/* Port flags. */
719 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
720 		err = sc->hal.arswitch_port_vlan_setup(sc, p);
721 		if (err)
722 			return (err);
723 	}
724 
725 	/* Do not allow media changes on CPU port. */
726 	if (p->es_port == AR8X16_PORT_CPU)
727 		return (0);
728 
729 	mii = arswitch_miiforport(sc, p->es_port);
730 	if (mii == NULL)
731 		return (ENXIO);
732 
733 	ifp = arswitch_ifpforport(sc, p->es_port);
734 
735 	ifm = &mii->mii_media;
736 	return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA));
737 }
738 
739 static void
740 arswitch_statchg(device_t dev)
741 {
742 
743 	DPRINTF(dev, "%s\n", __func__);
744 }
745 
746 static int
747 arswitch_ifmedia_upd(struct ifnet *ifp)
748 {
749 	struct arswitch_softc *sc = ifp->if_softc;
750 	struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
751 
752 	if (mii == NULL)
753 		return (ENXIO);
754 	mii_mediachg(mii);
755 	return (0);
756 }
757 
758 static void
759 arswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
760 {
761 	struct arswitch_softc *sc = ifp->if_softc;
762 	struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
763 
764 	DPRINTF(sc->sc_dev, "%s\n", __func__);
765 
766 	if (mii == NULL)
767 		return;
768 	mii_pollstat(mii);
769 	ifmr->ifm_active = mii->mii_media_active;
770 	ifmr->ifm_status = mii->mii_media_status;
771 }
772 
773 static int
774 arswitch_getconf(device_t dev, etherswitch_conf_t *conf)
775 {
776 	struct arswitch_softc *sc;
777 
778 	sc = device_get_softc(dev);
779 
780 	/* Return the VLAN mode. */
781 	conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
782 	conf->vlan_mode = sc->vlan_mode;
783 
784 	return (0);
785 }
786 
787 static int
788 arswitch_setconf(device_t dev, etherswitch_conf_t *conf)
789 {
790 	struct arswitch_softc *sc;
791 	int err;
792 
793 	sc = device_get_softc(dev);
794 
795 	/* Set the VLAN mode. */
796 	if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
797 		err = arswitch_set_vlan_mode(sc, conf->vlan_mode);
798 		if (err != 0)
799 			return (err);
800 	}
801 
802 	return (0);
803 }
804 
805 static int
806 arswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *e)
807 {
808 	struct arswitch_softc *sc = device_get_softc(dev);
809 
810 	return (sc->hal.arswitch_vlan_getvgroup(sc, e));
811 }
812 
813 static int
814 arswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *e)
815 {
816 	struct arswitch_softc *sc = device_get_softc(dev);
817 
818 	return (sc->hal.arswitch_vlan_setvgroup(sc, e));
819 }
820 
821 static int
822 arswitch_readphy(device_t dev, int phy, int reg)
823 {
824 	struct arswitch_softc *sc = device_get_softc(dev);
825 
826 	return (sc->hal.arswitch_phy_read(dev, phy, reg));
827 }
828 
829 static int
830 arswitch_writephy(device_t dev, int phy, int reg, int val)
831 {
832 	struct arswitch_softc *sc = device_get_softc(dev);
833 
834 	return (sc->hal.arswitch_phy_write(dev, phy, reg, val));
835 }
836 
837 static device_method_t arswitch_methods[] = {
838 	/* Device interface */
839 	DEVMETHOD(device_probe,		arswitch_probe),
840 	DEVMETHOD(device_attach,	arswitch_attach),
841 	DEVMETHOD(device_detach,	arswitch_detach),
842 
843 	/* bus interface */
844 	DEVMETHOD(bus_add_child,	device_add_child_ordered),
845 
846 	/* MII interface */
847 	DEVMETHOD(miibus_readreg,	arswitch_readphy),
848 	DEVMETHOD(miibus_writereg,	arswitch_writephy),
849 	DEVMETHOD(miibus_statchg,	arswitch_statchg),
850 
851 	/* MDIO interface */
852 	DEVMETHOD(mdio_readreg,		arswitch_readphy),
853 	DEVMETHOD(mdio_writereg,	arswitch_writephy),
854 
855 	/* etherswitch interface */
856 	DEVMETHOD(etherswitch_lock,	arswitch_lock),
857 	DEVMETHOD(etherswitch_unlock,	arswitch_unlock),
858 	DEVMETHOD(etherswitch_getinfo,	arswitch_getinfo),
859 	DEVMETHOD(etherswitch_readreg,	arswitch_readreg),
860 	DEVMETHOD(etherswitch_writereg,	arswitch_writereg),
861 	DEVMETHOD(etherswitch_readphyreg,	arswitch_readphy),
862 	DEVMETHOD(etherswitch_writephyreg,	arswitch_writephy),
863 	DEVMETHOD(etherswitch_getport,	arswitch_getport),
864 	DEVMETHOD(etherswitch_setport,	arswitch_setport),
865 	DEVMETHOD(etherswitch_getvgroup,	arswitch_getvgroup),
866 	DEVMETHOD(etherswitch_setvgroup,	arswitch_setvgroup),
867 	DEVMETHOD(etherswitch_getconf,	arswitch_getconf),
868 	DEVMETHOD(etherswitch_setconf,	arswitch_setconf),
869 
870 	DEVMETHOD_END
871 };
872 
873 DEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods,
874     sizeof(struct arswitch_softc));
875 static devclass_t arswitch_devclass;
876 
877 DRIVER_MODULE(arswitch, mdio, arswitch_driver, arswitch_devclass, 0, 0);
878 DRIVER_MODULE(miibus, arswitch, miibus_driver, miibus_devclass, 0, 0);
879 DRIVER_MODULE(mdio, arswitch, mdio_driver, mdio_devclass, 0, 0);
880 DRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, etherswitch_devclass, 0, 0);
881 MODULE_VERSION(arswitch, 1);
882 MODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */
883 MODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */
884