The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/etherswitch/arswitch/arswitch.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2011-2012 Stefan Bethke.
    5  * Copyright (c) 2012 Adrian Chadd.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD$
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/bus.h>
   34 #include <sys/errno.h>
   35 #include <sys/kernel.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 #include <sys/socket.h>
   39 #include <sys/sockio.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/systm.h>
   42 
   43 #include <net/if.h>
   44 #include <net/if_var.h>
   45 #include <net/if_arp.h>
   46 #include <net/ethernet.h>
   47 #include <net/if_dl.h>
   48 #include <net/if_media.h>
   49 #include <net/if_types.h>
   50 
   51 #include <machine/bus.h>
   52 #include <dev/iicbus/iic.h>
   53 #include <dev/iicbus/iiconf.h>
   54 #include <dev/iicbus/iicbus.h>
   55 #include <dev/mii/mii.h>
   56 #include <dev/mii/miivar.h>
   57 #include <dev/mdio/mdio.h>
   58 
   59 #include <dev/etherswitch/etherswitch.h>
   60 
   61 #include <dev/etherswitch/arswitch/arswitchreg.h>
   62 #include <dev/etherswitch/arswitch/arswitchvar.h>
   63 #include <dev/etherswitch/arswitch/arswitch_reg.h>
   64 #include <dev/etherswitch/arswitch/arswitch_phy.h>
   65 #include <dev/etherswitch/arswitch/arswitch_vlans.h>
   66 
   67 #include <dev/etherswitch/arswitch/arswitch_7240.h>
   68 #include <dev/etherswitch/arswitch/arswitch_8216.h>
   69 #include <dev/etherswitch/arswitch/arswitch_8226.h>
   70 #include <dev/etherswitch/arswitch/arswitch_8316.h>
   71 #include <dev/etherswitch/arswitch/arswitch_8327.h>
   72 #include <dev/etherswitch/arswitch/arswitch_9340.h>
   73 
   74 #include "mdio_if.h"
   75 #include "miibus_if.h"
   76 #include "etherswitch_if.h"
   77 
   78 /* Map ETHERSWITCH_PORT_LED_* to Atheros pattern codes */
   79 static int led_pattern_table[] = {
   80         [ETHERSWITCH_PORT_LED_DEFAULT] = 0x3,
   81         [ETHERSWITCH_PORT_LED_ON] = 0x2,
   82         [ETHERSWITCH_PORT_LED_OFF] = 0x0,
   83         [ETHERSWITCH_PORT_LED_BLINK] = 0x1
   84 };
   85 
   86 static inline int arswitch_portforphy(int phy);
   87 static void arswitch_tick(void *arg);
   88 static int arswitch_ifmedia_upd(if_t );
   89 static void arswitch_ifmedia_sts(if_t , struct ifmediareq *);
   90 static int ar8xxx_port_vlan_setup(struct arswitch_softc *sc,
   91     etherswitch_port_t *p);
   92 static int ar8xxx_port_vlan_get(struct arswitch_softc *sc,
   93     etherswitch_port_t *p);
   94 static int arswitch_setled(struct arswitch_softc *sc, int phy, int led,
   95     int style);
   96 
   97 static int
   98 arswitch_probe(device_t dev)
   99 {
  100         struct arswitch_softc *sc;
  101         uint32_t id;
  102         char *chipname, desc[256];
  103 
  104         sc = device_get_softc(dev);
  105         bzero(sc, sizeof(*sc));
  106         sc->page = -1;
  107 
  108         /* AR7240 probe */
  109         if (ar7240_probe(dev) == 0) {
  110                 chipname = "AR7240";
  111                 sc->sc_switchtype = AR8X16_SWITCH_AR7240;
  112                 sc->is_internal_switch = 1;
  113                 id = 0;
  114                 goto done;
  115         }
  116 
  117         /* AR9340 probe */
  118         if (ar9340_probe(dev) == 0) {
  119                 chipname = "AR9340";
  120                 sc->sc_switchtype = AR8X16_SWITCH_AR9340;
  121                 sc->is_internal_switch = 1;
  122                 id = 0;
  123                 goto done;
  124         }
  125 
  126         /* AR8xxx probe */
  127         id = arswitch_readreg(dev, AR8X16_REG_MASK_CTRL);
  128         sc->chip_rev = (id & AR8X16_MASK_CTRL_REV_MASK);
  129         sc->chip_ver = (id & AR8X16_MASK_CTRL_VER_MASK) > AR8X16_MASK_CTRL_VER_SHIFT;
  130         switch (id & (AR8X16_MASK_CTRL_VER_MASK | AR8X16_MASK_CTRL_REV_MASK)) {
  131         case 0x0101:
  132                 chipname = "AR8216";
  133                 sc->sc_switchtype = AR8X16_SWITCH_AR8216;
  134                 break;
  135         case 0x0201:
  136                 chipname = "AR8226";
  137                 sc->sc_switchtype = AR8X16_SWITCH_AR8226;
  138                 break;
  139         /* 0x0301 - AR8236 */
  140         case 0x1000:
  141         case 0x1001:
  142                 chipname = "AR8316";
  143                 sc->sc_switchtype = AR8X16_SWITCH_AR8316;
  144                 break;
  145         case 0x1202:
  146         case 0x1204:
  147                 chipname = "AR8327";
  148                 sc->sc_switchtype = AR8X16_SWITCH_AR8327;
  149                 sc->mii_lo_first = 1;
  150                 break;
  151         default:
  152                 chipname = NULL;
  153         }
  154 
  155 done:
  156 
  157         DPRINTF(sc, ARSWITCH_DBG_ANY, "chipname=%s, id=%08x\n", chipname, id);
  158         if (chipname != NULL) {
  159                 snprintf(desc, sizeof(desc),
  160                     "Atheros %s Ethernet Switch (ver %d rev %d)",
  161                     chipname,
  162                     sc->chip_ver,
  163                     sc->chip_rev);
  164                 device_set_desc_copy(dev, desc);
  165                 return (BUS_PROBE_DEFAULT);
  166         }
  167         return (ENXIO);
  168 }
  169 
  170 static int
  171 arswitch_attach_phys(struct arswitch_softc *sc)
  172 {
  173         int phy, err = 0;
  174         char name[IFNAMSIZ];
  175 
  176         /* PHYs need an interface, so we generate a dummy one */
  177         snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
  178         for (phy = 0; phy < sc->numphys; phy++) {
  179                 sc->ifp[phy] = if_alloc(IFT_ETHER);
  180                 if (sc->ifp[phy] == NULL) {
  181                         device_printf(sc->sc_dev, "couldn't allocate ifnet structure\n");
  182                         err = ENOMEM;
  183                         break;
  184                 }
  185 
  186                 if_setsoftc(sc->ifp[phy], sc);
  187                 if_setflagbits(sc->ifp[phy], IFF_UP | IFF_BROADCAST |
  188                     IFF_DRV_RUNNING | IFF_SIMPLEX, 0);
  189                 sc->ifname[phy] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK);
  190                 bcopy(name, sc->ifname[phy], strlen(name)+1);
  191                 if_initname(sc->ifp[phy], sc->ifname[phy],
  192                     arswitch_portforphy(phy));
  193                 err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy],
  194                     arswitch_ifmedia_upd, arswitch_ifmedia_sts, \
  195                     BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
  196 #if 0
  197                 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
  198                     device_get_nameunit(sc->miibus[phy]),
  199                     sc->ifp[phy]->if_xname);
  200 #endif
  201                 if (err != 0) {
  202                         device_printf(sc->sc_dev,
  203                             "attaching PHY %d failed\n",
  204                             phy);
  205                         return (err);
  206                 }
  207 
  208                 if (AR8X16_IS_SWITCH(sc, AR8327)) {
  209                         int led;
  210                         char ledname[IFNAMSIZ+4];
  211 
  212                         for (led = 0; led < 3; led++) {
  213                                 sprintf(ledname, "%s%dled%d", name,
  214                                     arswitch_portforphy(phy), led+1);
  215                                 sc->dev_led[phy][led].sc = sc;
  216                                 sc->dev_led[phy][led].phy = phy;
  217                                 sc->dev_led[phy][led].lednum = led;
  218                         }
  219                 }
  220         }
  221         return (0);
  222 }
  223 
  224 static int
  225 arswitch_reset(device_t dev)
  226 {
  227 
  228         arswitch_writereg(dev, AR8X16_REG_MASK_CTRL,
  229             AR8X16_MASK_CTRL_SOFT_RESET);
  230         DELAY(1000);
  231         if (arswitch_readreg(dev, AR8X16_REG_MASK_CTRL) &
  232             AR8X16_MASK_CTRL_SOFT_RESET) {
  233                 device_printf(dev, "unable to reset switch\n");
  234                 return (-1);
  235         }
  236         return (0);
  237 }
  238 
  239 static int
  240 arswitch_set_vlan_mode(struct arswitch_softc *sc, uint32_t mode)
  241 {
  242 
  243         /* Check for invalid modes. */
  244         if ((mode & sc->info.es_vlan_caps) != mode)
  245                 return (EINVAL);
  246 
  247         switch (mode) {
  248         case ETHERSWITCH_VLAN_DOT1Q:
  249                 sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
  250                 break;
  251         case ETHERSWITCH_VLAN_PORT:
  252                 sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
  253                 break;
  254         default:
  255                 sc->vlan_mode = 0;
  256         }
  257 
  258         /* Reset VLANs. */
  259         sc->hal.arswitch_vlan_init_hw(sc);
  260 
  261         return (0);
  262 }
  263 
  264 static void
  265 ar8xxx_port_init(struct arswitch_softc *sc, int port)
  266 {
  267 
  268         /* Port0 - CPU */
  269         if (port == AR8X16_PORT_CPU) {
  270                 arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_STS(0),
  271                     (AR8X16_IS_SWITCH(sc, AR8216) ?
  272                     AR8X16_PORT_STS_SPEED_100 : AR8X16_PORT_STS_SPEED_1000) |
  273                     (AR8X16_IS_SWITCH(sc, AR8216) ? 0 : AR8X16_PORT_STS_RXFLOW) |
  274                     (AR8X16_IS_SWITCH(sc, AR8216) ? 0 : AR8X16_PORT_STS_TXFLOW) |
  275                     AR8X16_PORT_STS_RXMAC |
  276                     AR8X16_PORT_STS_TXMAC |
  277                     AR8X16_PORT_STS_DUPLEX);
  278                 arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_CTRL(0),
  279                     arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(0)) &
  280                     ~AR8X16_PORT_CTRL_HEADER);
  281         } else {
  282                 /* Set ports to auto negotiation. */
  283                 arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_STS(port),
  284                     AR8X16_PORT_STS_LINK_AUTO);
  285                 arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_CTRL(port),
  286                     arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(port)) &
  287                     ~AR8X16_PORT_CTRL_HEADER);
  288         }
  289 }
  290 
  291 static int
  292 ar8xxx_atu_wait_ready(struct arswitch_softc *sc)
  293 {
  294         int ret;
  295 
  296         ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
  297 
  298         ret = arswitch_waitreg(sc->sc_dev,
  299             AR8216_REG_ATU,
  300             AR8216_ATU_ACTIVE,
  301             0,
  302             1000);
  303 
  304         return (ret);
  305 }
  306 
  307 /*
  308  * Flush all ATU entries.
  309  */
  310 static int
  311 ar8xxx_atu_flush(struct arswitch_softc *sc)
  312 {
  313         int ret;
  314 
  315         ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
  316 
  317         DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: flushing all ports\n", __func__);
  318 
  319         ret = ar8xxx_atu_wait_ready(sc);
  320         if (ret)
  321                 device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__);
  322 
  323         if (!ret)
  324                 arswitch_writereg(sc->sc_dev,
  325                     AR8216_REG_ATU,
  326                     AR8216_ATU_OP_FLUSH | AR8216_ATU_ACTIVE);
  327 
  328         return (ret);
  329 }
  330 
  331 /*
  332  * Flush ATU entries for a single port.
  333  */
  334 static int
  335 ar8xxx_atu_flush_port(struct arswitch_softc *sc, int port)
  336 {
  337         int ret, val;
  338 
  339         DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: flushing port %d\n", __func__,
  340             port);
  341 
  342         ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
  343 
  344         /* Flush unicast entries on port */
  345         val = AR8216_ATU_OP_FLUSH_UNICAST;
  346 
  347         /* TODO: bit 4 indicates whether to flush dynamic (0) or static (1) */
  348 
  349         /* Which port */
  350         val |= SM(port, AR8216_ATU_PORT_NUM);
  351 
  352         ret = ar8xxx_atu_wait_ready(sc);
  353         if (ret)
  354                 device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__);
  355 
  356         if (!ret)
  357                 arswitch_writereg(sc->sc_dev,
  358                     AR8216_REG_ATU,
  359                     val | AR8216_ATU_ACTIVE);
  360 
  361         return (ret);
  362 }
  363 
  364 /*
  365  * XXX TODO: flush a single MAC address.
  366  */
  367 
  368 /*
  369  * Fetch a single entry from the ATU.
  370  */
  371 static int
  372 ar8xxx_atu_fetch_table(struct arswitch_softc *sc, etherswitch_atu_entry_t *e,
  373     int atu_fetch_op)
  374 {
  375         uint32_t ret0, ret1, ret2, val;
  376 
  377         ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
  378 
  379         switch (atu_fetch_op) {
  380         case 0:
  381                 /* Initialise things for the first fetch */
  382 
  383                 DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: initializing\n", __func__);
  384                 (void) ar8xxx_atu_wait_ready(sc);
  385 
  386                 arswitch_writereg(sc->sc_dev,
  387                     AR8216_REG_ATU, AR8216_ATU_OP_GET_NEXT);
  388                 arswitch_writereg(sc->sc_dev,
  389                     AR8216_REG_ATU_DATA, 0);
  390                 arswitch_writereg(sc->sc_dev,
  391                     AR8216_REG_ATU_CTRL2, 0);
  392 
  393                 return (0);
  394         case 1:
  395                 DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: reading next\n", __func__);
  396                 /*
  397                  * Attempt to read the next address entry; don't modify what
  398                  * is there in AT_ADDR{4,5} as its used for the next fetch
  399                  */
  400                 (void) ar8xxx_atu_wait_ready(sc);
  401 
  402                 /* Begin the next read event; not modifying anything */
  403                 val = arswitch_readreg(sc->sc_dev, AR8216_REG_ATU);
  404                 val |= AR8216_ATU_ACTIVE;
  405                 arswitch_writereg(sc->sc_dev, AR8216_REG_ATU, val);
  406 
  407                 /* Wait for it to complete */
  408                 (void) ar8xxx_atu_wait_ready(sc);
  409 
  410                 /* Fetch the ethernet address and ATU status */
  411                 ret0 = arswitch_readreg(sc->sc_dev, AR8216_REG_ATU);
  412                 ret1 = arswitch_readreg(sc->sc_dev, AR8216_REG_ATU_DATA);
  413                 ret2 = arswitch_readreg(sc->sc_dev, AR8216_REG_ATU_CTRL2);
  414 
  415                 /* If the status is zero, then we're done */
  416                 if (MS(ret2, AR8216_ATU_CTRL2_AT_STATUS) == 0)
  417                         return (-1);
  418 
  419                 /* MAC address */
  420                 e->es_macaddr[5] = MS(ret0, AR8216_ATU_ADDR5);
  421                 e->es_macaddr[4] = MS(ret0, AR8216_ATU_ADDR4);
  422                 e->es_macaddr[3] = MS(ret1, AR8216_ATU_ADDR3);
  423                 e->es_macaddr[2] = MS(ret1, AR8216_ATU_ADDR2);
  424                 e->es_macaddr[1] = MS(ret1, AR8216_ATU_ADDR1);
  425                 e->es_macaddr[0] = MS(ret1, AR8216_ATU_ADDR0);
  426 
  427                 /* Bitmask of ports this entry is for */
  428                 e->es_portmask = MS(ret2, AR8216_ATU_CTRL2_DESPORT);
  429 
  430                 /* TODO: other flags that are interesting */
  431 
  432                 DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: MAC %6D portmask 0x%08x\n",
  433                     __func__,
  434                     e->es_macaddr, ":", e->es_portmask);
  435                 return (0);
  436         default:
  437                 return (-1);
  438         }
  439         return (-1);
  440 }
  441 
  442 /*
  443  * Configure aging register defaults.
  444  */
  445 static int
  446 ar8xxx_atu_learn_default(struct arswitch_softc *sc)
  447 {
  448         int ret;
  449         uint32_t val;
  450 
  451         DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: resetting learning\n", __func__);
  452 
  453         /*
  454          * For now, configure the aging defaults:
  455          *
  456          * + ARP_EN - enable "acknowledgement" of ARP frames - they are
  457          *   forwarded to the CPU port
  458          * + LEARN_CHANGE_EN - hash table violations when learning MAC addresses
  459          *   will force an entry to be expired/updated and a new one to be
  460          *   programmed in.
  461          * + AGE_EN - enable address table aging
  462          * + AGE_TIME - set to 5 minutes
  463          */
  464         val = 0;
  465         val |= AR8216_ATU_CTRL_ARP_EN;
  466         val |= AR8216_ATU_CTRL_LEARN_CHANGE;
  467         val |= AR8216_ATU_CTRL_AGE_EN;
  468         val |= 0x2b;    /* 5 minutes; bits 15:0 */
  469 
  470         ret = arswitch_writereg(sc->sc_dev,
  471             AR8216_REG_ATU_CTRL,
  472             val);
  473 
  474         if (ret)
  475                 device_printf(sc->sc_dev, "%s: writereg failed\n", __func__);
  476 
  477         return (ret);
  478 }
  479 
  480 /*
  481  * XXX TODO: add another routine to configure the leaky behaviour
  482  * when unknown frames are received.  These must be consistent
  483  * between ethernet switches.
  484  */
  485 
  486 /*
  487  * Fetch the configured switch MAC address.
  488  */
  489 static int
  490 ar8xxx_hw_get_switch_macaddr(struct arswitch_softc *sc, struct ether_addr *ea)
  491 {
  492         uint32_t ret0, ret1;
  493         char *s;
  494 
  495         s = (void *) ea;
  496 
  497         ret0 = arswitch_readreg(sc->sc_dev, AR8X16_REG_SW_MAC_ADDR0);
  498         ret1 = arswitch_readreg(sc->sc_dev, AR8X16_REG_SW_MAC_ADDR1);
  499 
  500         s[5] = MS(ret0, AR8X16_REG_SW_MAC_ADDR0_BYTE5);
  501         s[4] = MS(ret0, AR8X16_REG_SW_MAC_ADDR0_BYTE4);
  502         s[3] = MS(ret1, AR8X16_REG_SW_MAC_ADDR1_BYTE3);
  503         s[2] = MS(ret1, AR8X16_REG_SW_MAC_ADDR1_BYTE2);
  504         s[1] = MS(ret1, AR8X16_REG_SW_MAC_ADDR1_BYTE1);
  505         s[0] = MS(ret1, AR8X16_REG_SW_MAC_ADDR1_BYTE0);
  506 
  507         return (0);
  508 }
  509 
  510 /*
  511  * Set the switch mac address.
  512  */
  513 static int
  514 ar8xxx_hw_set_switch_macaddr(struct arswitch_softc *sc,
  515     const struct ether_addr *ea)
  516 {
  517 
  518         return (ENXIO);
  519 }
  520 
  521 /*
  522  * XXX TODO: this attach routine does NOT free all memory, resources
  523  * upon failure!
  524  */
  525 static int
  526 arswitch_attach(device_t dev)
  527 {
  528         struct arswitch_softc *sc = device_get_softc(dev);
  529         struct sysctl_ctx_list *ctx;
  530         struct sysctl_oid *tree;
  531         int err = 0;
  532         int port;
  533 
  534         /* sc->sc_switchtype is already decided in arswitch_probe() */
  535         sc->sc_dev = dev;
  536         mtx_init(&sc->sc_mtx, "arswitch", NULL, MTX_DEF);
  537         sc->page = -1;
  538         strlcpy(sc->info.es_name, device_get_desc(dev),
  539             sizeof(sc->info.es_name));
  540 
  541         /* Debugging */
  542         ctx = device_get_sysctl_ctx(sc->sc_dev);
  543         tree = device_get_sysctl_tree(sc->sc_dev);
  544         SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  545             "debug", CTLFLAG_RW, &sc->sc_debug, 0,
  546             "control debugging printfs");
  547 
  548         /* Allocate a 128 entry ATU table; hopefully its big enough! */
  549         /* XXX TODO: make this per chip */
  550         sc->atu.entries = malloc(sizeof(etherswitch_atu_entry_t) * 128,
  551             M_DEVBUF, M_NOWAIT);
  552         if (sc->atu.entries == NULL) {
  553                 device_printf(sc->sc_dev, "%s: failed to allocate ATU table\n",
  554                     __func__);
  555                 return (ENXIO);
  556         }
  557         sc->atu.count = 0;
  558         sc->atu.size = 128;
  559 
  560         /* Default HAL methods */
  561         sc->hal.arswitch_port_init = ar8xxx_port_init;
  562         sc->hal.arswitch_port_vlan_setup = ar8xxx_port_vlan_setup;
  563         sc->hal.arswitch_port_vlan_get = ar8xxx_port_vlan_get;
  564         sc->hal.arswitch_vlan_init_hw = ar8xxx_reset_vlans;
  565         sc->hal.arswitch_hw_get_switch_macaddr = ar8xxx_hw_get_switch_macaddr;
  566         sc->hal.arswitch_hw_set_switch_macaddr = ar8xxx_hw_set_switch_macaddr;
  567 
  568         sc->hal.arswitch_vlan_getvgroup = ar8xxx_getvgroup;
  569         sc->hal.arswitch_vlan_setvgroup = ar8xxx_setvgroup;
  570 
  571         sc->hal.arswitch_vlan_get_pvid = ar8xxx_get_pvid;
  572         sc->hal.arswitch_vlan_set_pvid = ar8xxx_set_pvid;
  573 
  574         sc->hal.arswitch_get_dot1q_vlan = ar8xxx_get_dot1q_vlan;
  575         sc->hal.arswitch_set_dot1q_vlan = ar8xxx_set_dot1q_vlan;
  576         sc->hal.arswitch_flush_dot1q_vlan = ar8xxx_flush_dot1q_vlan;
  577         sc->hal.arswitch_purge_dot1q_vlan = ar8xxx_purge_dot1q_vlan;
  578         sc->hal.arswitch_get_port_vlan = ar8xxx_get_port_vlan;
  579         sc->hal.arswitch_set_port_vlan = ar8xxx_set_port_vlan;
  580 
  581         sc->hal.arswitch_atu_flush = ar8xxx_atu_flush;
  582         sc->hal.arswitch_atu_flush_port = ar8xxx_atu_flush_port;
  583         sc->hal.arswitch_atu_learn_default = ar8xxx_atu_learn_default;
  584         sc->hal.arswitch_atu_fetch_table = ar8xxx_atu_fetch_table;
  585 
  586         sc->hal.arswitch_phy_read = arswitch_readphy_internal;
  587         sc->hal.arswitch_phy_write = arswitch_writephy_internal;
  588 
  589         /*
  590          * Attach switch related functions
  591          */
  592         if (AR8X16_IS_SWITCH(sc, AR7240))
  593                 ar7240_attach(sc);
  594         else if (AR8X16_IS_SWITCH(sc, AR9340))
  595                 ar9340_attach(sc);
  596         else if (AR8X16_IS_SWITCH(sc, AR8216))
  597                 ar8216_attach(sc);
  598         else if (AR8X16_IS_SWITCH(sc, AR8226))
  599                 ar8226_attach(sc);
  600         else if (AR8X16_IS_SWITCH(sc, AR8316))
  601                 ar8316_attach(sc);
  602         else if (AR8X16_IS_SWITCH(sc, AR8327))
  603                 ar8327_attach(sc);
  604         else {
  605                 DPRINTF(sc, ARSWITCH_DBG_ANY,
  606                     "%s: unknown switch (%d)?\n", __func__, sc->sc_switchtype);
  607                 return (ENXIO);
  608         }
  609 
  610         /* Common defaults. */
  611         sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */
  612 
  613         /* XXX Defaults for externally connected AR8316 */
  614         sc->numphys = 4;
  615         sc->phy4cpu = 1;
  616         sc->is_rgmii = 1;
  617         sc->is_gmii = 0;
  618         sc->is_mii = 0;
  619 
  620         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  621             "numphys", &sc->numphys);
  622         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  623             "phy4cpu", &sc->phy4cpu);
  624         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  625             "is_rgmii", &sc->is_rgmii);
  626         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  627             "is_gmii", &sc->is_gmii);
  628         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  629             "is_mii", &sc->is_mii);
  630 
  631         if (sc->numphys > AR8X16_NUM_PHYS)
  632                 sc->numphys = AR8X16_NUM_PHYS;
  633 
  634         /* Reset the switch. */
  635         if (arswitch_reset(dev)) {
  636                 DPRINTF(sc, ARSWITCH_DBG_ANY,
  637                     "%s: arswitch_reset: failed\n", __func__);
  638                 return (ENXIO);
  639         }
  640 
  641         err = sc->hal.arswitch_hw_setup(sc);
  642         if (err != 0) {
  643                 DPRINTF(sc, ARSWITCH_DBG_ANY,
  644                     "%s: hw_setup: err=%d\n", __func__, err);
  645                 return (err);
  646         }
  647 
  648         err = sc->hal.arswitch_hw_global_setup(sc);
  649         if (err != 0) {
  650                 DPRINTF(sc, ARSWITCH_DBG_ANY,
  651                     "%s: hw_global_setup: err=%d\n", __func__, err);
  652                 return (err);
  653         }
  654 
  655         /*
  656          * Configure the default address table learning parameters for this
  657          * switch.
  658          */
  659         err = sc->hal.arswitch_atu_learn_default(sc);
  660         if (err != 0) {
  661                 DPRINTF(sc, ARSWITCH_DBG_ANY,
  662                     "%s: atu_learn_default: err=%d\n", __func__, err);
  663                 return (err);
  664         }
  665 
  666         /* Initialize the switch ports. */
  667         for (port = 0; port <= sc->numphys; port++) {
  668                 sc->hal.arswitch_port_init(sc, port);
  669         }
  670 
  671         /*
  672          * Attach the PHYs and complete the bus enumeration.
  673          */
  674         err = arswitch_attach_phys(sc);
  675         if (err != 0) {
  676                 DPRINTF(sc, ARSWITCH_DBG_ANY,
  677                     "%s: attach_phys: err=%d\n", __func__, err);
  678                 return (err);
  679         }
  680 
  681         /* Default to ingress filters off. */
  682         err = arswitch_set_vlan_mode(sc, 0);
  683         if (err != 0) {
  684                 DPRINTF(sc, ARSWITCH_DBG_ANY,
  685                     "%s: set_vlan_mode: err=%d\n", __func__, err);
  686                 return (err);
  687         }
  688 
  689         bus_generic_probe(dev);
  690         bus_enumerate_hinted_children(dev);
  691         err = bus_generic_attach(dev);
  692         if (err != 0) {
  693                 DPRINTF(sc, ARSWITCH_DBG_ANY,
  694                     "%s: bus_generic_attach: err=%d\n", __func__, err);
  695                 return (err);
  696         }
  697         
  698         callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0);
  699 
  700         ARSWITCH_LOCK(sc);
  701         arswitch_tick(sc);
  702         ARSWITCH_UNLOCK(sc);
  703         
  704         return (err);
  705 }
  706 
  707 static int
  708 arswitch_detach(device_t dev)
  709 {
  710         struct arswitch_softc *sc = device_get_softc(dev);
  711         int i;
  712 
  713         callout_drain(&sc->callout_tick);
  714 
  715         for (i=0; i < sc->numphys; i++) {
  716                 if (sc->miibus[i] != NULL)
  717                         device_delete_child(dev, sc->miibus[i]);
  718                 if (sc->ifp[i] != NULL)
  719                         if_free(sc->ifp[i]);
  720                 free(sc->ifname[i], M_DEVBUF);
  721         }
  722 
  723         free(sc->atu.entries, M_DEVBUF);
  724 
  725         bus_generic_detach(dev);
  726         mtx_destroy(&sc->sc_mtx);
  727 
  728         return (0);
  729 }
  730 
  731 /*
  732  * Convert PHY number to port number. PHY0 is connected to port 1, PHY1 to
  733  * port 2, etc.
  734  */
  735 static inline int
  736 arswitch_portforphy(int phy)
  737 {
  738         return (phy+1);
  739 }
  740 
  741 static inline struct mii_data *
  742 arswitch_miiforport(struct arswitch_softc *sc, int port)
  743 {
  744         int phy = port-1;
  745 
  746         if (phy < 0 || phy >= sc->numphys)
  747                 return (NULL);
  748         return (device_get_softc(sc->miibus[phy]));
  749 }
  750 
  751 static inline if_t 
  752 arswitch_ifpforport(struct arswitch_softc *sc, int port)
  753 {
  754         int phy = port-1;
  755 
  756         if (phy < 0 || phy >= sc->numphys)
  757                 return (NULL);
  758         return (sc->ifp[phy]);
  759 }
  760 
  761 /*
  762  * Convert port status to ifmedia.
  763  */
  764 static void
  765 arswitch_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active)
  766 {
  767         *media_active = IFM_ETHER;
  768         *media_status = IFM_AVALID;
  769 
  770         if ((portstatus & AR8X16_PORT_STS_LINK_UP) != 0)
  771                 *media_status |= IFM_ACTIVE;
  772         else {
  773                 *media_active |= IFM_NONE;
  774                 return;
  775         }
  776         switch (portstatus & AR8X16_PORT_STS_SPEED_MASK) {
  777         case AR8X16_PORT_STS_SPEED_10:
  778                 *media_active |= IFM_10_T;
  779                 break;
  780         case AR8X16_PORT_STS_SPEED_100:
  781                 *media_active |= IFM_100_TX;
  782                 break;
  783         case AR8X16_PORT_STS_SPEED_1000:
  784                 *media_active |= IFM_1000_T;
  785                 break;
  786         }
  787         if ((portstatus & AR8X16_PORT_STS_DUPLEX) == 0)
  788                 *media_active |= IFM_FDX;
  789         else
  790                 *media_active |= IFM_HDX;
  791         if ((portstatus & AR8X16_PORT_STS_TXFLOW) != 0)
  792                 *media_active |= IFM_ETH_TXPAUSE;
  793         if ((portstatus & AR8X16_PORT_STS_RXFLOW) != 0)
  794                 *media_active |= IFM_ETH_RXPAUSE;
  795 }
  796 
  797 /*
  798  * Poll the status for all PHYs.  We're using the switch port status because
  799  * thats a lot quicker to read than talking to all the PHYs.  Care must be
  800  * taken that the resulting ifmedia_active is identical to what the PHY will
  801  * compute, or gratuitous link status changes will occur whenever the PHYs
  802  * update function is called.
  803  */
  804 static void
  805 arswitch_miipollstat(struct arswitch_softc *sc)
  806 {
  807         int i;
  808         struct mii_data *mii;
  809         struct mii_softc *miisc;
  810         int portstatus;
  811         int port_flap = 0;
  812 
  813         ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
  814 
  815         for (i = 0; i < sc->numphys; i++) {
  816                 if (sc->miibus[i] == NULL)
  817                         continue;
  818                 mii = device_get_softc(sc->miibus[i]);
  819                 /* XXX This would be nice to have abstracted out to be per-chip */
  820                 /* AR8327/AR8337 has a different register base */
  821                 if (AR8X16_IS_SWITCH(sc, AR8327))
  822                         portstatus = arswitch_readreg(sc->sc_dev,
  823                             AR8327_REG_PORT_STATUS(arswitch_portforphy(i)));
  824                 else
  825                         portstatus = arswitch_readreg(sc->sc_dev,
  826                             AR8X16_REG_PORT_STS(arswitch_portforphy(i)));
  827 #if 1
  828                 DPRINTF(sc, ARSWITCH_DBG_POLL, "p[%d]=0x%08x (%b)\n",
  829                     i,
  830                     portstatus,
  831                     portstatus,
  832                     "\2\3TXMAC\4RXMAC\5TXFLOW\6RXFLOW\7"
  833                     "DUPLEX\11LINK_UP\12LINK_AUTO\13LINK_PAUSE");
  834 #endif
  835                 /*
  836                  * If the current status is down, but we have a link
  837                  * status showing up, we need to do an ATU flush.
  838                  */
  839                 if ((mii->mii_media_status & IFM_ACTIVE) == 0 &&
  840                     (portstatus & AR8X16_PORT_STS_LINK_UP) != 0) {
  841                         device_printf(sc->sc_dev, "%s: port %d: port -> UP\n",
  842                             __func__,
  843                             i);
  844                         port_flap = 1;
  845                 }
  846                 /*
  847                  * and maybe if a port goes up->down?
  848                  */
  849                 if ((mii->mii_media_status & IFM_ACTIVE) != 0 &&
  850                     (portstatus & AR8X16_PORT_STS_LINK_UP) == 0) {
  851                         device_printf(sc->sc_dev, "%s: port %d: port -> DOWN\n",
  852                             __func__,
  853                             i);
  854                         port_flap = 1;
  855                 }
  856                 arswitch_update_ifmedia(portstatus, &mii->mii_media_status,
  857                     &mii->mii_media_active);
  858                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
  859                         if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
  860                             miisc->mii_inst)
  861                                 continue;
  862                         mii_phy_update(miisc, MII_POLLSTAT);
  863                 }
  864         }
  865 
  866         /* If a port went from down->up, flush the ATU */
  867         if (port_flap)
  868                 sc->hal.arswitch_atu_flush(sc);
  869 }
  870 
  871 static void
  872 arswitch_tick(void *arg)
  873 {
  874         struct arswitch_softc *sc = arg;
  875 
  876         arswitch_miipollstat(sc);
  877         callout_reset(&sc->callout_tick, hz, arswitch_tick, sc);
  878 }
  879 
  880 static void
  881 arswitch_lock(device_t dev)
  882 {
  883         struct arswitch_softc *sc = device_get_softc(dev);
  884 
  885         ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
  886         ARSWITCH_LOCK(sc);
  887 }
  888 
  889 static void
  890 arswitch_unlock(device_t dev)
  891 {
  892         struct arswitch_softc *sc = device_get_softc(dev);
  893 
  894         ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
  895         ARSWITCH_UNLOCK(sc);
  896 }
  897 
  898 static etherswitch_info_t *
  899 arswitch_getinfo(device_t dev)
  900 {
  901         struct arswitch_softc *sc = device_get_softc(dev);
  902         
  903         return (&sc->info);
  904 }
  905 
  906 static int
  907 ar8xxx_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p)
  908 {
  909         uint32_t reg;
  910 
  911         ARSWITCH_LOCK(sc);
  912 
  913         /* Retrieve the PVID. */
  914         sc->hal.arswitch_vlan_get_pvid(sc, p->es_port, &p->es_pvid);
  915 
  916         /* Port flags. */
  917         reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(p->es_port));
  918         if (reg & AR8X16_PORT_CTRL_DOUBLE_TAG)
  919                 p->es_flags |= ETHERSWITCH_PORT_DOUBLE_TAG;
  920         reg >>= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
  921         if ((reg & 0x3) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD)
  922                 p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
  923         if ((reg & 0x3) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP)
  924                 p->es_flags |= ETHERSWITCH_PORT_STRIPTAG;
  925         ARSWITCH_UNLOCK(sc);
  926 
  927         return (0);
  928 }
  929 
  930 static int
  931 arswitch_is_cpuport(struct arswitch_softc *sc, int port)
  932 {
  933 
  934         return ((port == AR8X16_PORT_CPU) ||
  935             ((AR8X16_IS_SWITCH(sc, AR8327) &&
  936               port == AR8327_PORT_GMAC6)));
  937 }
  938 
  939 static int
  940 arswitch_getport(device_t dev, etherswitch_port_t *p)
  941 {
  942         struct arswitch_softc *sc;
  943         struct mii_data *mii;
  944         struct ifmediareq *ifmr;
  945         int err;
  946 
  947         sc = device_get_softc(dev);
  948         /* XXX +1 is for AR8327; should make this configurable! */
  949         if (p->es_port < 0 || p->es_port > sc->info.es_nports)
  950                 return (ENXIO);
  951 
  952         err = sc->hal.arswitch_port_vlan_get(sc, p);
  953         if (err != 0)
  954                 return (err);
  955 
  956         mii = arswitch_miiforport(sc, p->es_port);
  957         if (arswitch_is_cpuport(sc, p->es_port)) {
  958                 /* fill in fixed values for CPU port */
  959                 /* XXX is this valid in all cases? */
  960                 p->es_flags |= ETHERSWITCH_PORT_CPU;
  961                 ifmr = &p->es_ifmr;
  962                 ifmr->ifm_count = 0;
  963                 ifmr->ifm_current = ifmr->ifm_active =
  964                     IFM_ETHER | IFM_1000_T | IFM_FDX;
  965                 ifmr->ifm_mask = 0;
  966                 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
  967         } else if (mii != NULL) {
  968                 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
  969                     &mii->mii_media, SIOCGIFMEDIA);
  970                 if (err)
  971                         return (err);
  972         } else {
  973                 return (ENXIO);
  974         }
  975         
  976         if (!arswitch_is_cpuport(sc, p->es_port) &&
  977             AR8X16_IS_SWITCH(sc, AR8327)) {
  978                 int led;
  979                 p->es_nleds = 3;
  980 
  981                 for (led = 0; led < p->es_nleds; led++)
  982                 {
  983                         int style;
  984                         uint32_t val;
  985                         
  986                         /* Find the right style enum for our pattern */
  987                         val = arswitch_readreg(dev,
  988                             ar8327_led_mapping[p->es_port-1][led].reg);
  989                         val = (val>>ar8327_led_mapping[p->es_port-1][led].shift)&0x03;
  990 
  991                         for (style = 0; style < ETHERSWITCH_PORT_LED_MAX; style++)
  992                         {
  993                                 if (led_pattern_table[style] == val) break;
  994                         }
  995                         
  996                         /* can't happen */
  997                         if (style == ETHERSWITCH_PORT_LED_MAX)
  998                                 style = ETHERSWITCH_PORT_LED_DEFAULT;
  999                         
 1000                         p->es_led[led] = style;
 1001                 }
 1002         } else
 1003         {
 1004                 p->es_nleds = 0;
 1005         }
 1006         
 1007         return (0);
 1008 }
 1009 
 1010 static int
 1011 ar8xxx_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p)
 1012 {
 1013         uint32_t reg;
 1014         int err;
 1015 
 1016         ARSWITCH_LOCK(sc);
 1017 
 1018         /* Set the PVID. */
 1019         if (p->es_pvid != 0)
 1020                 sc->hal.arswitch_vlan_set_pvid(sc, p->es_port, p->es_pvid);
 1021 
 1022         /* Mutually exclusive. */
 1023         if (p->es_flags & ETHERSWITCH_PORT_ADDTAG &&
 1024             p->es_flags & ETHERSWITCH_PORT_STRIPTAG) {
 1025                 ARSWITCH_UNLOCK(sc);
 1026                 return (EINVAL);
 1027         }
 1028 
 1029         reg = 0;
 1030         if (p->es_flags & ETHERSWITCH_PORT_DOUBLE_TAG)
 1031                 reg |= AR8X16_PORT_CTRL_DOUBLE_TAG;
 1032         if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
 1033                 reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD <<
 1034                     AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
 1035         if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
 1036                 reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP <<
 1037                     AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT;
 1038 
 1039         err = arswitch_modifyreg(sc->sc_dev,
 1040             AR8X16_REG_PORT_CTRL(p->es_port),
 1041             0x3 << AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT |
 1042             AR8X16_PORT_CTRL_DOUBLE_TAG, reg);
 1043 
 1044         ARSWITCH_UNLOCK(sc);
 1045         return (err);
 1046 }
 1047 
 1048 static int
 1049 arswitch_setport(device_t dev, etherswitch_port_t *p)
 1050 {
 1051         int err, i;
 1052         struct arswitch_softc *sc;
 1053         struct ifmedia *ifm;
 1054         struct mii_data *mii;
 1055         if_t ifp;
 1056 
 1057         sc = device_get_softc(dev);
 1058         if (p->es_port < 0 || p->es_port > sc->info.es_nports)
 1059                 return (ENXIO);
 1060 
 1061         /* Port flags. */
 1062         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
 1063                 err = sc->hal.arswitch_port_vlan_setup(sc, p);
 1064                 if (err)
 1065                         return (err);
 1066         }
 1067 
 1068         /* Do not allow media or led changes on CPU port. */
 1069         if (arswitch_is_cpuport(sc, p->es_port))
 1070                 return (0);
 1071         
 1072         if (AR8X16_IS_SWITCH(sc, AR8327))
 1073         {
 1074                 for (i = 0; i < 3; i++)
 1075                 {       
 1076                         int err;
 1077                         err = arswitch_setled(sc, p->es_port-1, i, p->es_led[i]);
 1078                         if (err)
 1079                                 return (err);
 1080                 }
 1081         }
 1082 
 1083         mii = arswitch_miiforport(sc, p->es_port);
 1084         if (mii == NULL)
 1085                 return (ENXIO);
 1086 
 1087         ifp = arswitch_ifpforport(sc, p->es_port);
 1088 
 1089         ifm = &mii->mii_media;
 1090         return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA));
 1091 }
 1092 
 1093 static int
 1094 arswitch_setled(struct arswitch_softc *sc, int phy, int led, int style)
 1095 {
 1096         int shift;
 1097         int err;
 1098 
 1099         if (phy < 0 || phy > sc->numphys)
 1100                 return EINVAL;
 1101 
 1102         if (style < 0 || style > ETHERSWITCH_PORT_LED_MAX)
 1103                 return (EINVAL);
 1104 
 1105         ARSWITCH_LOCK(sc);
 1106 
 1107         shift = ar8327_led_mapping[phy][led].shift;
 1108         err = (arswitch_modifyreg(sc->sc_dev,
 1109             ar8327_led_mapping[phy][led].reg,
 1110             0x03 << shift, led_pattern_table[style] << shift));
 1111         ARSWITCH_UNLOCK(sc);
 1112 
 1113         return (err);
 1114 }
 1115 
 1116 static void
 1117 arswitch_statchg(device_t dev)
 1118 {
 1119         struct arswitch_softc *sc = device_get_softc(dev);
 1120 
 1121         DPRINTF(sc, ARSWITCH_DBG_POLL, "%s\n", __func__);
 1122 }
 1123 
 1124 static int
 1125 arswitch_ifmedia_upd(if_t ifp)
 1126 {
 1127         struct arswitch_softc *sc = if_getsoftc(ifp);
 1128         struct mii_data *mii = arswitch_miiforport(sc, if_getdunit(ifp));
 1129 
 1130         if (mii == NULL)
 1131                 return (ENXIO);
 1132         mii_mediachg(mii);
 1133         return (0);
 1134 }
 1135 
 1136 static void
 1137 arswitch_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
 1138 {
 1139         struct arswitch_softc *sc = if_getsoftc(ifp);
 1140         struct mii_data *mii = arswitch_miiforport(sc, if_getdunit(ifp));
 1141 
 1142         DPRINTF(sc, ARSWITCH_DBG_POLL, "%s\n", __func__);
 1143 
 1144         if (mii == NULL)
 1145                 return;
 1146         mii_pollstat(mii);
 1147         ifmr->ifm_active = mii->mii_media_active;
 1148         ifmr->ifm_status = mii->mii_media_status;
 1149 }
 1150 
 1151 static int
 1152 arswitch_getconf(device_t dev, etherswitch_conf_t *conf)
 1153 {
 1154         struct arswitch_softc *sc;
 1155         int ret;
 1156 
 1157         sc = device_get_softc(dev);
 1158 
 1159         /* Return the VLAN mode. */
 1160         conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
 1161         conf->vlan_mode = sc->vlan_mode;
 1162 
 1163         /* Return the switch ethernet address. */
 1164         ret = sc->hal.arswitch_hw_get_switch_macaddr(sc,
 1165             &conf->switch_macaddr);
 1166         if (ret == 0) {
 1167                 conf->cmd |= ETHERSWITCH_CONF_SWITCH_MACADDR;
 1168         }
 1169 
 1170         return (0);
 1171 }
 1172 
 1173 static int
 1174 arswitch_setconf(device_t dev, etherswitch_conf_t *conf)
 1175 {
 1176         struct arswitch_softc *sc;
 1177         int err;
 1178 
 1179         sc = device_get_softc(dev);
 1180 
 1181         /* Set the VLAN mode. */
 1182         if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
 1183                 err = arswitch_set_vlan_mode(sc, conf->vlan_mode);
 1184                 if (err != 0)
 1185                         return (err);
 1186         }
 1187 
 1188         /* TODO: Set the switch ethernet address. */
 1189 
 1190         return (0);
 1191 }
 1192 
 1193 static int
 1194 arswitch_atu_flush_all(device_t dev)
 1195 {
 1196         struct arswitch_softc *sc;
 1197         int err;
 1198 
 1199         sc = device_get_softc(dev);
 1200         ARSWITCH_LOCK(sc);
 1201         err = sc->hal.arswitch_atu_flush(sc);
 1202         /* Invalidate cached ATU */
 1203         sc->atu.count = 0;
 1204         ARSWITCH_UNLOCK(sc);
 1205         return (err);
 1206 }
 1207 
 1208 static int
 1209 arswitch_atu_flush_port(device_t dev, int port)
 1210 {
 1211         struct arswitch_softc *sc;
 1212         int err;
 1213 
 1214         sc = device_get_softc(dev);
 1215         ARSWITCH_LOCK(sc);
 1216         err = sc->hal.arswitch_atu_flush_port(sc, port);
 1217         /* Invalidate cached ATU */
 1218         sc->atu.count = 0;
 1219         ARSWITCH_UNLOCK(sc);
 1220         return (err);
 1221 }
 1222 
 1223 static int
 1224 arswitch_atu_fetch_table(device_t dev, etherswitch_atu_table_t *table)
 1225 {
 1226         struct arswitch_softc *sc;
 1227         int err, nitems;
 1228 
 1229         sc = device_get_softc(dev);
 1230 
 1231         ARSWITCH_LOCK(sc);
 1232         /* Initial setup */
 1233         nitems = 0;
 1234         err = sc->hal.arswitch_atu_fetch_table(sc, NULL, 0);
 1235 
 1236         /* fetch - ideally yes we'd fetch into a separate table then switch */
 1237         while (err == 0 && nitems < sc->atu.size) {
 1238                 err = sc->hal.arswitch_atu_fetch_table(sc,
 1239                     &sc->atu.entries[nitems], 1);
 1240                 if (err == 0) {
 1241                         sc->atu.entries[nitems].id = nitems;
 1242                         nitems++;
 1243                 }
 1244         }
 1245         sc->atu.count = nitems;
 1246         ARSWITCH_UNLOCK(sc);
 1247 
 1248         table->es_nitems = nitems;
 1249 
 1250         return (0);
 1251 }
 1252 
 1253 static int
 1254 arswitch_atu_fetch_table_entry(device_t dev, etherswitch_atu_entry_t *e)
 1255 {
 1256         struct arswitch_softc *sc;
 1257         int id;
 1258 
 1259         sc = device_get_softc(dev);
 1260         id = e->id;
 1261 
 1262         ARSWITCH_LOCK(sc);
 1263         if (id > sc->atu.count) {
 1264                 ARSWITCH_UNLOCK(sc);
 1265                 return (ENOENT);
 1266         }
 1267 
 1268         memcpy(e, &sc->atu.entries[id], sizeof(*e));
 1269         ARSWITCH_UNLOCK(sc);
 1270         return (0);
 1271 }
 1272 
 1273 static int
 1274 arswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *e)
 1275 {
 1276         struct arswitch_softc *sc = device_get_softc(dev);
 1277 
 1278         return (sc->hal.arswitch_vlan_getvgroup(sc, e));
 1279 }
 1280 
 1281 static int
 1282 arswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *e)
 1283 {
 1284         struct arswitch_softc *sc = device_get_softc(dev);
 1285 
 1286         return (sc->hal.arswitch_vlan_setvgroup(sc, e));
 1287 }
 1288 
 1289 static int
 1290 arswitch_readphy(device_t dev, int phy, int reg)
 1291 {
 1292         struct arswitch_softc *sc = device_get_softc(dev);
 1293 
 1294         return (sc->hal.arswitch_phy_read(dev, phy, reg));
 1295 }
 1296 
 1297 static int
 1298 arswitch_writephy(device_t dev, int phy, int reg, int val)
 1299 {
 1300         struct arswitch_softc *sc = device_get_softc(dev);
 1301 
 1302         return (sc->hal.arswitch_phy_write(dev, phy, reg, val));
 1303 }
 1304 
 1305 static device_method_t arswitch_methods[] = {
 1306         /* Device interface */
 1307         DEVMETHOD(device_probe,         arswitch_probe),
 1308         DEVMETHOD(device_attach,        arswitch_attach),
 1309         DEVMETHOD(device_detach,        arswitch_detach),
 1310         
 1311         /* bus interface */
 1312         DEVMETHOD(bus_add_child,        device_add_child_ordered),
 1313         
 1314         /* MII interface */
 1315         DEVMETHOD(miibus_readreg,       arswitch_readphy),
 1316         DEVMETHOD(miibus_writereg,      arswitch_writephy),
 1317         DEVMETHOD(miibus_statchg,       arswitch_statchg),
 1318 
 1319         /* MDIO interface */
 1320         DEVMETHOD(mdio_readreg,         arswitch_readphy),
 1321         DEVMETHOD(mdio_writereg,        arswitch_writephy),
 1322 
 1323         /* etherswitch interface */
 1324         DEVMETHOD(etherswitch_lock,     arswitch_lock),
 1325         DEVMETHOD(etherswitch_unlock,   arswitch_unlock),
 1326         DEVMETHOD(etherswitch_getinfo,  arswitch_getinfo),
 1327         DEVMETHOD(etherswitch_readreg,  arswitch_readreg),
 1328         DEVMETHOD(etherswitch_writereg, arswitch_writereg),
 1329         DEVMETHOD(etherswitch_readphyreg,       arswitch_readphy),
 1330         DEVMETHOD(etherswitch_writephyreg,      arswitch_writephy),
 1331         DEVMETHOD(etherswitch_getport,  arswitch_getport),
 1332         DEVMETHOD(etherswitch_setport,  arswitch_setport),
 1333         DEVMETHOD(etherswitch_getvgroup,        arswitch_getvgroup),
 1334         DEVMETHOD(etherswitch_setvgroup,        arswitch_setvgroup),
 1335         DEVMETHOD(etherswitch_getconf,  arswitch_getconf),
 1336         DEVMETHOD(etherswitch_setconf,  arswitch_setconf),
 1337         DEVMETHOD(etherswitch_flush_all, arswitch_atu_flush_all),
 1338         DEVMETHOD(etherswitch_flush_port, arswitch_atu_flush_port),
 1339         DEVMETHOD(etherswitch_fetch_table, arswitch_atu_fetch_table),
 1340         DEVMETHOD(etherswitch_fetch_table_entry, arswitch_atu_fetch_table_entry),
 1341 
 1342         DEVMETHOD_END
 1343 };
 1344 
 1345 DEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods,
 1346     sizeof(struct arswitch_softc));
 1347 
 1348 DRIVER_MODULE(arswitch, mdio, arswitch_driver, 0, 0);
 1349 DRIVER_MODULE(miibus, arswitch, miibus_driver, 0, 0);
 1350 DRIVER_MODULE(mdio, arswitch, mdio_driver, 0, 0);
 1351 DRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, 0, 0);
 1352 MODULE_VERSION(arswitch, 1);
 1353 MODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */
 1354 MODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */

Cache object: 098c1492d9ece76d9361f9e09468f80e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.