]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/etherswitch/arswitch/arswitch.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / etherswitch / arswitch / arswitch.c
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/module.h>
35 #include <sys/socket.h>
36 #include <sys/sockio.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
39
40 #include <net/if.h>
41 #include <net/if_arp.h>
42 #include <net/ethernet.h>
43 #include <net/if_dl.h>
44 #include <net/if_media.h>
45 #include <net/if_types.h>
46
47 #include <machine/bus.h>
48 #include <dev/iicbus/iic.h>
49 #include <dev/iicbus/iiconf.h>
50 #include <dev/iicbus/iicbus.h>
51 #include <dev/mii/mii.h>
52 #include <dev/mii/miivar.h>
53 #include <dev/etherswitch/mdio.h>
54
55 #include <dev/etherswitch/etherswitch.h>
56
57 #include <dev/etherswitch/arswitch/arswitchreg.h>
58 #include <dev/etherswitch/arswitch/arswitchvar.h>
59 #include <dev/etherswitch/arswitch/arswitch_reg.h>
60 #include <dev/etherswitch/arswitch/arswitch_phy.h>
61 #include <dev/etherswitch/arswitch/arswitch_vlans.h>
62
63 #include <dev/etherswitch/arswitch/arswitch_7240.h>
64 #include <dev/etherswitch/arswitch/arswitch_8216.h>
65 #include <dev/etherswitch/arswitch/arswitch_8226.h>
66 #include <dev/etherswitch/arswitch/arswitch_8316.h>
67
68 #include "mdio_if.h"
69 #include "miibus_if.h"
70 #include "etherswitch_if.h"
71
72 #if     defined(DEBUG)
73 static SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch");
74 #endif
75
76 static inline int arswitch_portforphy(int phy);
77 static void arswitch_tick(void *arg);
78 static int arswitch_ifmedia_upd(struct ifnet *);
79 static void arswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *);
80
81 static int
82 arswitch_probe(device_t dev)
83 {
84         struct arswitch_softc *sc;
85         uint32_t id;
86         char *chipname, desc[256];
87
88         sc = device_get_softc(dev);
89         bzero(sc, sizeof(*sc));
90         sc->page = -1;
91
92         /* AR7240 probe */
93         if (ar7240_probe(dev) == 0) {
94                 chipname = "AR7240";
95                 sc->sc_switchtype = AR8X16_SWITCH_AR7240;
96                 id = 0;
97                 goto done;
98         }
99
100         /* AR8xxx probe */
101         id = arswitch_readreg(dev, AR8X16_REG_MASK_CTRL);
102         switch ((id & AR8X16_MASK_CTRL_VER_MASK) >>
103             AR8X16_MASK_CTRL_VER_SHIFT) {
104         case 1:
105                 chipname = "AR8216";
106                 sc->sc_switchtype = AR8X16_SWITCH_AR8216;
107                 break;
108         case 2:
109                 chipname = "AR8226";
110                 sc->sc_switchtype = AR8X16_SWITCH_AR8226;
111                 break;
112         case 16:
113                 chipname = "AR8316";
114                 sc->sc_switchtype = AR8X16_SWITCH_AR8316;
115                 break;
116         default:
117                 chipname = NULL;
118         }
119
120 done:
121         DPRINTF(dev, "chipname=%s, rev=%02x\n", chipname,
122             id & AR8X16_MASK_CTRL_REV_MASK);
123         if (chipname != NULL) {
124                 snprintf(desc, sizeof(desc),
125                     "Atheros %s Ethernet Switch",
126                     chipname);
127                 device_set_desc_copy(dev, desc);
128                 return (BUS_PROBE_DEFAULT);
129         }
130         return (ENXIO);
131 }
132
133 static int
134 arswitch_attach_phys(struct arswitch_softc *sc)
135 {
136         int phy, err = 0;
137         char name[IFNAMSIZ];
138
139         /* PHYs need an interface, so we generate a dummy one */
140         snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
141         for (phy = 0; phy < sc->numphys; phy++) {
142                 sc->ifp[phy] = if_alloc(IFT_ETHER);
143                 sc->ifp[phy]->if_softc = sc;
144                 sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST |
145                     IFF_DRV_RUNNING | IFF_SIMPLEX;
146                 sc->ifname[phy] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK);
147                 bcopy(name, sc->ifname[phy], strlen(name)+1);
148                 if_initname(sc->ifp[phy], sc->ifname[phy],
149                     arswitch_portforphy(phy));
150                 err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy],
151                     arswitch_ifmedia_upd, arswitch_ifmedia_sts, \
152                     BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
153                 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
154                     device_get_nameunit(sc->miibus[phy]),
155                     sc->ifp[phy]->if_xname);
156                 if (err != 0) {
157                         device_printf(sc->sc_dev,
158                             "attaching PHY %d failed\n",
159                             phy);
160                 }
161         }
162         return (err);
163 }
164
165 static int
166 arswitch_reset(device_t dev)
167 {
168
169         arswitch_writereg(dev, AR8X16_REG_MASK_CTRL,
170             AR8X16_MASK_CTRL_SOFT_RESET);
171         DELAY(1000);
172         if (arswitch_readreg(dev, AR8X16_REG_MASK_CTRL) &
173             AR8X16_MASK_CTRL_SOFT_RESET) {
174                 device_printf(dev, "unable to reset switch\n");
175                 return (-1);
176         }
177         return (0);
178 }
179
180 static int
181 arswitch_set_vlan_mode(struct arswitch_softc *sc, uint32_t mode)
182 {
183
184         /* Check for invalid modes. */
185         if ((mode & sc->info.es_vlan_caps) != mode)
186                 return (EINVAL);
187
188         switch (mode) {
189         case ETHERSWITCH_VLAN_DOT1Q:
190                 sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
191                 break;
192         case ETHERSWITCH_VLAN_PORT:
193                 sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
194                 break;
195         default:
196                 sc->vlan_mode = 0;
197         };
198
199         /* Reset VLANs. */
200         arswitch_reset_vlans(sc);
201
202         return (0);
203 }
204
205 static void
206 arswitch_ports_init(struct arswitch_softc *sc)
207 {
208         int port;
209
210         /* Port0 - CPU */
211         arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_STS(0),
212             (AR8X16_IS_SWITCH(sc, AR8216) ?
213             AR8X16_PORT_STS_SPEED_100 : AR8X16_PORT_STS_SPEED_1000) |
214             (AR8X16_IS_SWITCH(sc, AR8216) ? 0 : AR8X16_PORT_STS_RXFLOW) |
215             (AR8X16_IS_SWITCH(sc, AR8216) ? 0 : AR8X16_PORT_STS_TXFLOW) |
216             AR8X16_PORT_STS_RXMAC |
217             AR8X16_PORT_STS_TXMAC |
218             AR8X16_PORT_STS_DUPLEX);
219         arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_CTRL(0),
220             arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(0)) &
221             ~AR8X16_PORT_CTRL_HEADER);
222
223         for (port = 1; port <= sc->numphys; port++) { 
224                 /* Set ports to auto negotiation. */
225                 arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_STS(port),
226                     AR8X16_PORT_STS_LINK_AUTO);
227                 arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_CTRL(port),
228                     arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(port)) &
229                     ~AR8X16_PORT_CTRL_HEADER);
230         }
231 }
232
233 static int
234 arswitch_attach(device_t dev)
235 {
236         struct arswitch_softc *sc;
237         int err = 0;
238
239         sc = device_get_softc(dev);
240
241         /* sc->sc_switchtype is already decided in arswitch_probe() */
242         sc->sc_dev = dev;
243         mtx_init(&sc->sc_mtx, "arswitch", NULL, MTX_DEF);
244         sc->page = -1;
245         strlcpy(sc->info.es_name, device_get_desc(dev),
246             sizeof(sc->info.es_name));
247
248         /*
249          * Attach switch related functions
250          */
251         if (AR8X16_IS_SWITCH(sc, AR7240))
252                 ar7240_attach(sc);
253         else if (AR8X16_IS_SWITCH(sc, AR8216))
254                 ar8216_attach(sc);
255         else if (AR8X16_IS_SWITCH(sc, AR8226))
256                 ar8226_attach(sc);
257         else if (AR8X16_IS_SWITCH(sc, AR8316))
258                 ar8316_attach(sc);
259         else
260                 return (ENXIO);
261
262         /* Common defaults. */
263         sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */
264
265         /* XXX Defaults for externally connected AR8316 */
266         sc->numphys = 4;
267         sc->phy4cpu = 1;
268         sc->is_rgmii = 1;
269         sc->is_gmii = 0;
270
271         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
272             "numphys", &sc->numphys);
273         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
274             "phy4cpu", &sc->phy4cpu);
275         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
276             "is_rgmii", &sc->is_rgmii);
277         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
278             "is_gmii", &sc->is_gmii);
279
280         if (sc->numphys > AR8X16_NUM_PHYS)
281                 sc->numphys = AR8X16_NUM_PHYS;
282
283         /* Reset the switch. */
284         if (arswitch_reset(dev))
285                 return (ENXIO);
286
287         err = sc->hal.arswitch_hw_global_setup(sc);
288         if (err != 0)
289                 return (err);
290
291         /* Initialize the switch ports. */
292         arswitch_ports_init(sc);
293
294         /*
295          * Attach the PHYs and complete the bus enumeration.
296          */
297         err = arswitch_attach_phys(sc);
298         if (err != 0)
299                 return (err);
300
301         /* Default to ingress filters off. */
302         err = arswitch_set_vlan_mode(sc, 0);
303         if (err != 0)
304                 return (err);
305
306         err = sc->hal.arswitch_hw_setup(sc);
307         if (err != 0)
308                 return (err);
309
310         bus_generic_probe(dev);
311         bus_enumerate_hinted_children(dev);
312         err = bus_generic_attach(dev);
313         if (err != 0)
314                 return (err);
315         
316         callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0);
317
318         ARSWITCH_LOCK(sc);
319         arswitch_tick(sc);
320         ARSWITCH_UNLOCK(sc);
321         
322         return (err);
323 }
324
325 static int
326 arswitch_detach(device_t dev)
327 {
328         struct arswitch_softc *sc = device_get_softc(dev);
329         int i;
330
331         callout_drain(&sc->callout_tick);
332
333         for (i=0; i < sc->numphys; i++) {
334                 if (sc->miibus[i] != NULL)
335                         device_delete_child(dev, sc->miibus[i]);
336                 if (sc->ifp[i] != NULL)
337                         if_free(sc->ifp[i]);
338                 free(sc->ifname[i], M_DEVBUF);
339         }
340
341         bus_generic_detach(dev);
342         mtx_destroy(&sc->sc_mtx);
343
344         return (0);
345 }
346
347 /*
348  * Convert PHY number to port number. PHY0 is connected to port 1, PHY1 to
349  * port 2, etc.
350  */
351 static inline int
352 arswitch_portforphy(int phy)
353 {
354         return (phy+1);
355 }
356
357 static inline struct mii_data *
358 arswitch_miiforport(struct arswitch_softc *sc, int port)
359 {
360         int phy = port-1;
361
362         if (phy < 0 || phy >= sc->numphys)
363                 return (NULL);
364         return (device_get_softc(sc->miibus[phy]));
365 }
366
367 static inline struct ifnet *
368 arswitch_ifpforport(struct arswitch_softc *sc, int port)
369 {
370         int phy = port-1;
371
372         if (phy < 0 || phy >= sc->numphys)
373                 return (NULL);
374         return (sc->ifp[phy]);
375 }
376
377 /*
378  * Convert port status to ifmedia.
379  */
380 static void
381 arswitch_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active)
382 {
383         *media_active = IFM_ETHER;
384         *media_status = IFM_AVALID;
385
386         if ((portstatus & AR8X16_PORT_STS_LINK_UP) != 0)
387                 *media_status |= IFM_ACTIVE;
388         else {
389                 *media_active |= IFM_NONE;
390                 return;
391         }
392         switch (portstatus & AR8X16_PORT_STS_SPEED_MASK) {
393         case AR8X16_PORT_STS_SPEED_10:
394                 *media_active |= IFM_10_T;
395                 break;
396         case AR8X16_PORT_STS_SPEED_100:
397                 *media_active |= IFM_100_TX;
398                 break;
399         case AR8X16_PORT_STS_SPEED_1000:
400                 *media_active |= IFM_1000_T;
401                 break;
402         }
403         if ((portstatus & AR8X16_PORT_STS_DUPLEX) == 0)
404                 *media_active |= IFM_FDX;
405         else
406                 *media_active |= IFM_HDX;
407         if ((portstatus & AR8X16_PORT_STS_TXFLOW) != 0)
408                 *media_active |= IFM_ETH_TXPAUSE;
409         if ((portstatus & AR8X16_PORT_STS_RXFLOW) != 0)
410                 *media_active |= IFM_ETH_RXPAUSE;
411 }
412
413 /*
414  * Poll the status for all PHYs.  We're using the switch port status because
415  * thats a lot quicker to read than talking to all the PHYs.  Care must be
416  * taken that the resulting ifmedia_active is identical to what the PHY will
417  * compute, or gratuitous link status changes will occur whenever the PHYs
418  * update function is called.
419  */
420 static void
421 arswitch_miipollstat(struct arswitch_softc *sc)
422 {
423         int i;
424         struct mii_data *mii;
425         struct mii_softc *miisc;
426         int portstatus;
427
428         ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
429
430         for (i = 0; i < sc->numphys; i++) {
431                 if (sc->miibus[i] == NULL)
432                         continue;
433                 mii = device_get_softc(sc->miibus[i]);
434                 portstatus = arswitch_readreg(sc->sc_dev,
435                     AR8X16_REG_PORT_STS(arswitch_portforphy(i)));
436 #if 0
437                 DPRINTF(sc->sc_dev, "p[%d]=%b\n",
438                     arge_portforphy(i),
439                     portstatus,
440                     "\20\3TXMAC\4RXMAC\5TXFLOW\6RXFLOW\7"
441                     "DUPLEX\11LINK_UP\12LINK_AUTO\13LINK_PAUSE");
442 #endif
443                 arswitch_update_ifmedia(portstatus, &mii->mii_media_status,
444                     &mii->mii_media_active);
445                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
446                         if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
447                             miisc->mii_inst)
448                                 continue;
449                         mii_phy_update(miisc, MII_POLLSTAT);
450                 }
451         }
452 }
453
454 static void
455 arswitch_tick(void *arg)
456 {
457         struct arswitch_softc *sc = arg;
458
459         arswitch_miipollstat(sc);
460         callout_reset(&sc->callout_tick, hz, arswitch_tick, sc);
461 }
462
463 static void
464 arswitch_lock(device_t dev)
465 {
466         struct arswitch_softc *sc = device_get_softc(dev);
467
468         ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
469         ARSWITCH_LOCK(sc);
470 }
471
472 static void
473 arswitch_unlock(device_t dev)
474 {
475         struct arswitch_softc *sc = device_get_softc(dev);
476
477         ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
478         ARSWITCH_UNLOCK(sc);
479 }
480
481 static etherswitch_info_t *
482 arswitch_getinfo(device_t dev)
483 {
484         struct arswitch_softc *sc = device_get_softc(dev);
485         
486         return (&sc->info);
487 }
488
489 static int
490 arswitch_getport(device_t dev, etherswitch_port_t *p)
491 {
492         struct arswitch_softc *sc;
493         struct ifmediareq *ifmr;
494         struct mii_data *mii;
495         uint32_t reg;
496         int err;
497
498         sc = device_get_softc(dev);
499         if (p->es_port < 0 || p->es_port > sc->numphys)
500                 return (ENXIO);
501
502         ARSWITCH_LOCK(sc);
503
504         /* Retrieve the PVID. */
505         arswitch_get_pvid(sc, p->es_port, &p->es_pvid);
506
507         /* Port flags. */
508         reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(p->es_port));
509         if (reg & AR8X16_PORT_CTRL_DOUBLE_TAG)
510                 p->es_flags |= ETHERSWITCH_PORT_DOUBLE_TAG;
511         reg >>= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
512         if ((reg & 0x3) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD)
513                 p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
514         if ((reg & 0x3) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP)
515                 p->es_flags |= ETHERSWITCH_PORT_STRIPTAG;
516         ARSWITCH_UNLOCK(sc);
517
518         mii = arswitch_miiforport(sc, p->es_port);
519         if (p->es_port == 0) {
520                 /* fill in fixed values for CPU port */
521                 p->es_flags |= ETHERSWITCH_PORT_CPU;
522                 ifmr = &p->es_ifmr;
523                 ifmr->ifm_count = 0;
524                 ifmr->ifm_current = ifmr->ifm_active =
525                     IFM_ETHER | IFM_1000_T | IFM_FDX;
526                 ifmr->ifm_mask = 0;
527                 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
528         } else if (mii != NULL) {
529                 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
530                     &mii->mii_media, SIOCGIFMEDIA);
531                 if (err)
532                         return (err);
533         } else {
534                 return (ENXIO);
535         }
536         return (0);
537 }
538
539 static int
540 arswitch_setport(device_t dev, etherswitch_port_t *p)
541 {
542         int err;
543         uint32_t reg;
544         struct arswitch_softc *sc;
545         struct ifmedia *ifm;
546         struct mii_data *mii;
547         struct ifnet *ifp;
548
549         sc = device_get_softc(dev);
550         if (p->es_port < 0 || p->es_port > sc->numphys)
551                 return (ENXIO);
552
553         /* Port flags. */
554         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
555
556                 ARSWITCH_LOCK(sc);
557                 /* Set the PVID. */
558                 if (p->es_pvid != 0)
559                         arswitch_set_pvid(sc, p->es_port, p->es_pvid);
560
561                 /* Mutually exclusive. */
562                 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG &&
563                     p->es_flags & ETHERSWITCH_PORT_STRIPTAG) {
564                         ARSWITCH_UNLOCK(sc);
565                         return (EINVAL);
566                 }
567
568                 reg = 0;
569                 if (p->es_flags & ETHERSWITCH_PORT_DOUBLE_TAG)
570                         reg |= AR8X16_PORT_CTRL_DOUBLE_TAG;
571                 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
572                         reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD <<
573                             AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
574                 if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
575                         reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP <<
576                             AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
577
578                 err = arswitch_modifyreg(sc->sc_dev,
579                     AR8X16_REG_PORT_CTRL(p->es_port),
580                     0x3 << AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT |
581                     AR8X16_PORT_CTRL_DOUBLE_TAG, reg);
582
583                 ARSWITCH_UNLOCK(sc);
584                 if (err)
585                         return (err);
586         }
587
588         /* Do not allow media changes on CPU port. */
589         if (p->es_port == AR8X16_PORT_CPU)
590                 return (0);
591
592         mii = arswitch_miiforport(sc, p->es_port);
593         if (mii == NULL)
594                 return (ENXIO);
595
596         ifp = arswitch_ifpforport(sc, p->es_port);
597
598         ifm = &mii->mii_media;
599         return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA));
600 }
601
602 static void
603 arswitch_statchg(device_t dev)
604 {
605
606         DPRINTF(dev, "%s\n", __func__);
607 }
608
609 static int
610 arswitch_ifmedia_upd(struct ifnet *ifp)
611 {
612         struct arswitch_softc *sc = ifp->if_softc;
613         struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
614
615         if (mii == NULL)
616                 return (ENXIO);
617         mii_mediachg(mii);
618         return (0);
619 }
620
621 static void
622 arswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
623 {
624         struct arswitch_softc *sc = ifp->if_softc;
625         struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit);
626
627         DPRINTF(sc->sc_dev, "%s\n", __func__);
628
629         if (mii == NULL)
630                 return;
631         mii_pollstat(mii);
632         ifmr->ifm_active = mii->mii_media_active;
633         ifmr->ifm_status = mii->mii_media_status;
634 }
635
636 static int
637 arswitch_getconf(device_t dev, etherswitch_conf_t *conf)
638 {
639         struct arswitch_softc *sc;
640
641         sc = device_get_softc(dev);
642
643         /* Return the VLAN mode. */
644         conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
645         conf->vlan_mode = sc->vlan_mode;
646
647         return (0);
648 }
649
650 static int
651 arswitch_setconf(device_t dev, etherswitch_conf_t *conf)
652 {
653         struct arswitch_softc *sc;
654         int err;
655
656         sc = device_get_softc(dev);
657
658         /* Set the VLAN mode. */
659         if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
660                 err = arswitch_set_vlan_mode(sc, conf->vlan_mode);
661                 if (err != 0)
662                         return (err);
663         }
664
665         return (0);
666 }
667
668 static device_method_t arswitch_methods[] = {
669         /* Device interface */
670         DEVMETHOD(device_probe,         arswitch_probe),
671         DEVMETHOD(device_attach,        arswitch_attach),
672         DEVMETHOD(device_detach,        arswitch_detach),
673         
674         /* bus interface */
675         DEVMETHOD(bus_add_child,        device_add_child_ordered),
676         
677         /* MII interface */
678         DEVMETHOD(miibus_readreg,       arswitch_readphy),
679         DEVMETHOD(miibus_writereg,      arswitch_writephy),
680         DEVMETHOD(miibus_statchg,       arswitch_statchg),
681
682         /* MDIO interface */
683         DEVMETHOD(mdio_readreg,         arswitch_readphy),
684         DEVMETHOD(mdio_writereg,        arswitch_writephy),
685
686         /* etherswitch interface */
687         DEVMETHOD(etherswitch_lock,     arswitch_lock),
688         DEVMETHOD(etherswitch_unlock,   arswitch_unlock),
689         DEVMETHOD(etherswitch_getinfo,  arswitch_getinfo),
690         DEVMETHOD(etherswitch_readreg,  arswitch_readreg),
691         DEVMETHOD(etherswitch_writereg, arswitch_writereg),
692         DEVMETHOD(etherswitch_readphyreg,       arswitch_readphy),
693         DEVMETHOD(etherswitch_writephyreg,      arswitch_writephy),
694         DEVMETHOD(etherswitch_getport,  arswitch_getport),
695         DEVMETHOD(etherswitch_setport,  arswitch_setport),
696         DEVMETHOD(etherswitch_getvgroup,        arswitch_getvgroup),
697         DEVMETHOD(etherswitch_setvgroup,        arswitch_setvgroup),
698         DEVMETHOD(etherswitch_getconf,  arswitch_getconf),
699         DEVMETHOD(etherswitch_setconf,  arswitch_setconf),
700
701         DEVMETHOD_END
702 };
703
704 DEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods,
705     sizeof(struct arswitch_softc));
706 static devclass_t arswitch_devclass;
707
708 DRIVER_MODULE(arswitch, mdio, arswitch_driver, arswitch_devclass, 0, 0);
709 DRIVER_MODULE(miibus, arswitch, miibus_driver, miibus_devclass, 0, 0);
710 DRIVER_MODULE(mdio, arswitch, mdio_driver, mdio_devclass, 0, 0);
711 DRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, etherswitch_devclass, 0, 0);
712 MODULE_VERSION(arswitch, 1);
713 MODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */
714 MODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */