arswitch.c revision 279767
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: head/sys/dev/etherswitch/arswitch/arswitch.c 279767 2015-03-08 03:53:36Z adrian $
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)
77static SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch");
78#endif
79
80static inline int arswitch_portforphy(int phy);
81static void arswitch_tick(void *arg);
82static int arswitch_ifmedia_upd(struct ifnet *);
83static void arswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *);
84static int ar8xxx_port_vlan_setup(struct arswitch_softc *sc,
85    etherswitch_port_t *p);
86static int ar8xxx_port_vlan_get(struct arswitch_softc *sc,
87    etherswitch_port_t *p);
88
89static int
90arswitch_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
147done:
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
162static int
163arswitch_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
196static int
197arswitch_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
211static int
212arswitch_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
236static void
237ar8xxx_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
263static int
264ar8xxx_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
285static int
286arswitch_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
409static int
410arswitch_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 */
435static inline int
436arswitch_portforphy(int phy)
437{
438	return (phy+1);
439}
440
441static inline struct mii_data *
442arswitch_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
451static inline struct ifnet *
452arswitch_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 */
464static void
465arswitch_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 */
504static void
505arswitch_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
570static void
571arswitch_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
579static void
580arswitch_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
588static void
589arswitch_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
597static etherswitch_info_t *
598arswitch_getinfo(device_t dev)
599{
600	struct arswitch_softc *sc = device_get_softc(dev);
601
602	return (&sc->info);
603}
604
605static int
606ar8xxx_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
629static int
630arswitch_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
667static int
668ar8xxx_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
705static int
706arswitch_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
739static void
740arswitch_statchg(device_t dev)
741{
742
743	DPRINTF(dev, "%s\n", __func__);
744}
745
746static int
747arswitch_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
758static void
759arswitch_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
773static int
774arswitch_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
787static int
788arswitch_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
805static int
806arswitch_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
813static int
814arswitch_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
821static int
822arswitch_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
829static int
830arswitch_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
837static 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
873DEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods,
874    sizeof(struct arswitch_softc));
875static devclass_t arswitch_devclass;
876
877DRIVER_MODULE(arswitch, mdio, arswitch_driver, arswitch_devclass, 0, 0);
878DRIVER_MODULE(miibus, arswitch, miibus_driver, miibus_devclass, 0, 0);
879DRIVER_MODULE(mdio, arswitch, mdio_driver, mdio_devclass, 0, 0);
880DRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, etherswitch_devclass, 0, 0);
881MODULE_VERSION(arswitch, 1);
882MODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */
883MODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */
884