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/e6000sw/e6060sw.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  * Copyright (c) 2016-2017 Hiroki Mori
    3  * Copyright (c) 2013 Luiz Otavio O Souza.
    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 /*
   33  * This code is Marvell 88E6060 ethernet switch support code on etherswitch
   34  * framework. 
   35  * 88E6060 support is only port vlan support. Not support ingress/egress
   36  * trailer.
   37  * 88E6065 support is port and dot1q vlan. Also group base tag support.
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/bus.h>
   42 #include <sys/errno.h>
   43 #include <sys/kernel.h>
   44 #include <sys/lock.h>
   45 #include <sys/malloc.h>
   46 #include <sys/module.h>
   47 #include <sys/mutex.h>
   48 #include <sys/socket.h>
   49 #include <sys/sockio.h>
   50 #include <sys/sysctl.h>
   51 #include <sys/systm.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_var.h>
   55 #include <net/ethernet.h>
   56 #include <net/if_media.h>
   57 #include <net/if_types.h>
   58 
   59 #include <machine/bus.h>
   60 #include <dev/mii/mii.h>
   61 #include <dev/mii/miivar.h>
   62 #include <dev/mdio/mdio.h>
   63 
   64 #include <dev/etherswitch/etherswitch.h>
   65 
   66 #include "mdio_if.h"
   67 #include "miibus_if.h"
   68 #include "etherswitch_if.h"
   69 
   70 #define CORE_REGISTER   0x8
   71 #define SWITCH_ID       3
   72 
   73 #define PORT_CONTROL    4
   74 #define ENGRESSFSHIFT   2
   75 #define ENGRESSFMASK    3
   76 #define ENGRESSTAGSHIFT 12
   77 #define ENGRESSTAGMASK  3
   78 
   79 #define PORT_VLAN_MAP   6
   80 #define FORCEMAPSHIFT   8
   81 #define FORCEMAPMASK    1
   82 
   83 #define PORT_DEFVLAN    7
   84 #define DEFVIDMASK      0xfff
   85 #define DEFPRIMASK      7
   86 
   87 #define PORT_CONTROL2   8
   88 #define DOT1QMODESHIFT  10
   89 #define DOT1QMODEMASK   3
   90 #define DOT1QNONE       0
   91 #define DOT1QFALLBACK   1
   92 #define DOT1QCHECK      2
   93 #define DOT1QSECURE     3
   94 
   95 #define GLOBAL_REGISTER 0xf
   96 
   97 #define VTU_OPERATION   5
   98 #define VTU_VID_REG     6
   99 #define VTU_DATA1_REG   7
  100 #define VTU_DATA2_REG   8
  101 #define VTU_DATA3_REG   9
  102 #define VTU_BUSY        0x8000
  103 #define VTU_FLASH       1
  104 #define VTU_LOAD_PURGE  3
  105 #define VTU_GET_NEXT    4
  106 #define VTU_VIOLATION   7
  107 
  108 MALLOC_DECLARE(M_E6060SW);
  109 MALLOC_DEFINE(M_E6060SW, "e6060sw", "e6060sw data structures");
  110 
  111 struct e6060sw_softc {
  112         struct mtx      sc_mtx;         /* serialize access to softc */
  113         device_t        sc_dev;
  114         int             vlan_mode;
  115         int             media;          /* cpu port media */
  116         int             cpuport;        /* which PHY is connected to the CPU */
  117         int             phymask;        /* PHYs we manage */
  118         int             numports;       /* number of ports */
  119         int             ifpport[MII_NPHY];
  120         int             *portphy;
  121         char            **ifname;
  122         device_t        **miibus;
  123         if_t *ifp;
  124         struct callout  callout_tick;
  125         etherswitch_info_t      info;
  126         int             smi_offset;
  127         int             sw_model;
  128 };
  129 
  130 /* Switch Identifier DeviceID */
  131 
  132 #define E6060           0x60
  133 #define E6063           0x63            
  134 #define E6065           0x65            
  135 
  136 #define E6060SW_LOCK(_sc)                       \
  137             mtx_lock(&(_sc)->sc_mtx)
  138 #define E6060SW_UNLOCK(_sc)                     \
  139             mtx_unlock(&(_sc)->sc_mtx)
  140 #define E6060SW_LOCK_ASSERT(_sc, _what) \
  141             mtx_assert(&(_sc)->sc_mtx, (_what))
  142 #define E6060SW_TRYLOCK(_sc)                    \
  143             mtx_trylock(&(_sc)->sc_mtx)
  144 
  145 #if defined(DEBUG)
  146 #define DPRINTF(dev, args...) device_printf(dev, args)
  147 #else
  148 #define DPRINTF(dev, args...)
  149 #endif
  150 
  151 static inline int e6060sw_portforphy(struct e6060sw_softc *, int);
  152 static void e6060sw_tick(void *);
  153 static int e6060sw_ifmedia_upd(if_t );
  154 static void e6060sw_ifmedia_sts(if_t , struct ifmediareq *);
  155 
  156 static void e6060sw_setup(device_t dev);
  157 static int e6060sw_read_vtu(device_t dev, int num, int *data1, int *data2);
  158 static void e6060sw_set_vtu(device_t dev, int num, int data1, int data2);
  159 
  160 static int
  161 e6060sw_probe(device_t dev)
  162 {
  163         int data;
  164         struct e6060sw_softc *sc;
  165         int devid, i;
  166         char *devname;
  167         char desc[80];
  168 
  169         sc = device_get_softc(dev);
  170         bzero(sc, sizeof(*sc));
  171 
  172         devid = 0;
  173         for (i = 0; i < 2; ++i) {
  174                 data = MDIO_READREG(device_get_parent(dev), 
  175                     CORE_REGISTER + i * 0x10, SWITCH_ID);
  176                 if (bootverbose)
  177                         device_printf(dev,"Switch Identifier Register %x\n",
  178                             data);
  179 
  180                 devid = data >> 4;
  181                 if (devid == E6060 || 
  182                     devid == E6063 || devid == E6065) {
  183                         sc->sw_model = devid;
  184                         sc->smi_offset = i * 0x10;
  185                         break;
  186                 }
  187         }
  188 
  189         if (devid == E6060)
  190                 devname = "88E6060";
  191         else if (devid == E6063)
  192                 devname = "88E6063";
  193         else if (devid == E6065)
  194                 devname = "88E6065";
  195         else
  196                 return (ENXIO);
  197 
  198         sprintf(desc, "Marvell %s MDIO switch driver at 0x%02x",
  199             devname, sc->smi_offset);
  200         device_set_desc_copy(dev, desc);
  201 
  202         return (BUS_PROBE_DEFAULT);
  203 }
  204 
  205 static int
  206 e6060sw_attach_phys(struct e6060sw_softc *sc)
  207 {
  208         int phy, port, err;
  209         char name[IFNAMSIZ];
  210 
  211         port = 0;
  212         err = 0;
  213         /* PHYs need an interface, so we generate a dummy one */
  214         snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
  215         for (phy = 0; phy < sc->numports; phy++) {
  216                 if (((1 << phy) & sc->phymask) == 0)
  217                         continue;
  218                 sc->ifpport[phy] = port;
  219                 sc->portphy[port] = phy;
  220                 sc->ifp[port] = if_alloc(IFT_ETHER);
  221                 if (sc->ifp[port] == NULL) {
  222                         device_printf(sc->sc_dev, "couldn't allocate ifnet structure\n");
  223                         err = ENOMEM;
  224                         break;
  225                 }
  226 
  227                 sc->ifp[port]->if_softc = sc;
  228                 sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
  229                     IFF_DRV_RUNNING | IFF_SIMPLEX;
  230                 if_initname(sc->ifp[port], name, port);
  231                 sc->miibus[port] = malloc(sizeof(device_t), M_E6060SW,
  232                     M_WAITOK | M_ZERO);
  233                 err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
  234                     e6060sw_ifmedia_upd, e6060sw_ifmedia_sts, \
  235                     BMSR_DEFCAPMASK, phy + sc->smi_offset, MII_OFFSET_ANY, 0);
  236                 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
  237                     device_get_nameunit(*sc->miibus[port]),
  238                     sc->ifp[port]->if_xname);
  239                 if (err != 0) {
  240                         device_printf(sc->sc_dev,
  241                             "attaching PHY %d failed\n",
  242                             phy);
  243                         break;
  244                 }
  245                 ++port;
  246         }
  247         sc->info.es_nports = port;
  248         if (sc->cpuport != -1) {
  249                 /* assume cpuport is last one */
  250                 sc->ifpport[sc->cpuport] = port;
  251                 sc->portphy[port] = sc->cpuport;
  252                 ++sc->info.es_nports;
  253         }
  254         return (err);
  255 }
  256 
  257 static int
  258 e6060sw_attach(device_t dev)
  259 {
  260         struct e6060sw_softc *sc;
  261         int err;
  262 
  263         sc = device_get_softc(dev);
  264         err = 0;
  265 
  266         sc->sc_dev = dev;
  267         mtx_init(&sc->sc_mtx, "e6060sw", NULL, MTX_DEF);
  268         strlcpy(sc->info.es_name, device_get_desc(dev),
  269             sizeof(sc->info.es_name));
  270 
  271         /* XXX Defaults */
  272         if (sc->sw_model == E6063) {
  273                 sc->numports = 3;
  274                 sc->phymask = 0x07;
  275                 sc->cpuport = 2;
  276         } else {
  277                 sc->numports = 6;
  278                 sc->phymask = 0x1f;
  279                 sc->cpuport = 5;
  280         }
  281         sc->media = 100;
  282 
  283         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  284             "numports", &sc->numports);
  285         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  286             "phymask", &sc->phymask);
  287         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  288             "cpuport", &sc->cpuport);
  289         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  290             "media", &sc->media);
  291 
  292         if (sc->sw_model == E6060) {
  293                 sc->info.es_nvlangroups = sc->numports;
  294                 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT;
  295         } else {
  296                 sc->info.es_nvlangroups = 64;
  297                 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT | 
  298                     ETHERSWITCH_VLAN_DOT1Q;
  299         }
  300 
  301         e6060sw_setup(dev);
  302 
  303         sc->ifp = malloc(sizeof(if_t ) * sc->numports, M_E6060SW,
  304             M_WAITOK | M_ZERO);
  305         sc->ifname = malloc(sizeof(char *) * sc->numports, M_E6060SW,
  306             M_WAITOK | M_ZERO);
  307         sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_E6060SW,
  308             M_WAITOK | M_ZERO);
  309         sc->portphy = malloc(sizeof(int) * sc->numports, M_E6060SW,
  310             M_WAITOK | M_ZERO);
  311 
  312         /*
  313          * Attach the PHYs and complete the bus enumeration.
  314          */
  315         err = e6060sw_attach_phys(sc);
  316         if (err != 0)
  317                 return (err);
  318 
  319         bus_generic_probe(dev);
  320         bus_enumerate_hinted_children(dev);
  321         err = bus_generic_attach(dev);
  322         if (err != 0)
  323                 return (err);
  324         
  325         callout_init(&sc->callout_tick, 0);
  326 
  327         e6060sw_tick(sc);
  328         
  329         return (err);
  330 }
  331 
  332 static int
  333 e6060sw_detach(device_t dev)
  334 {
  335         struct e6060sw_softc *sc;
  336         int i, port;
  337 
  338         sc = device_get_softc(dev);
  339 
  340         callout_drain(&sc->callout_tick);
  341 
  342         for (i = 0; i < MII_NPHY; i++) {
  343                 if (((1 << i) & sc->phymask) == 0)
  344                         continue;
  345                 port = e6060sw_portforphy(sc, i);
  346                 if (sc->miibus[port] != NULL)
  347                         device_delete_child(dev, (*sc->miibus[port]));
  348                 if (sc->ifp[port] != NULL)
  349                         if_free(sc->ifp[port]);
  350                 free(sc->ifname[port], M_E6060SW);
  351                 free(sc->miibus[port], M_E6060SW);
  352         }
  353 
  354         free(sc->portphy, M_E6060SW);
  355         free(sc->miibus, M_E6060SW);
  356         free(sc->ifname, M_E6060SW);
  357         free(sc->ifp, M_E6060SW);
  358 
  359         bus_generic_detach(dev);
  360         mtx_destroy(&sc->sc_mtx);
  361 
  362         return (0);
  363 }
  364 
  365 /*
  366  * Convert PHY number to port number.
  367  */
  368 static inline int
  369 e6060sw_portforphy(struct e6060sw_softc *sc, int phy)
  370 {
  371 
  372         return (sc->ifpport[phy]);
  373 }
  374 
  375 static inline struct mii_data *
  376 e6060sw_miiforport(struct e6060sw_softc *sc, int port)
  377 {
  378 
  379         if (port < 0 || port > sc->numports)
  380                 return (NULL);
  381         if (port == sc->cpuport)
  382                 return (NULL);
  383         return (device_get_softc(*sc->miibus[port]));
  384 }
  385 
  386 static inline if_t 
  387 e6060sw_ifpforport(struct e6060sw_softc *sc, int port)
  388 {
  389 
  390         if (port < 0 || port > sc->numports)
  391                 return (NULL);
  392         return (sc->ifp[port]);
  393 }
  394 
  395 /*
  396  * Poll the status for all PHYs.
  397  */
  398 static void
  399 e6060sw_miipollstat(struct e6060sw_softc *sc)
  400 {
  401         int i, port;
  402         struct mii_data *mii;
  403         struct mii_softc *miisc;
  404 
  405         E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
  406 
  407         for (i = 0; i < MII_NPHY; i++) {
  408                 if (((1 << i) & sc->phymask) == 0)
  409                         continue;
  410                 port = e6060sw_portforphy(sc, i);
  411                 if ((*sc->miibus[port]) == NULL)
  412                         continue;
  413                 mii = device_get_softc(*sc->miibus[port]);
  414                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
  415                         if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
  416                             miisc->mii_inst)
  417                                 continue;
  418                         ukphy_status(miisc);
  419                         mii_phy_update(miisc, MII_POLLSTAT);
  420                 }
  421         }
  422 }
  423 
  424 static void
  425 e6060sw_tick(void *arg)
  426 {
  427         struct e6060sw_softc *sc;
  428 
  429         sc = arg;
  430 
  431         e6060sw_miipollstat(sc);
  432         callout_reset(&sc->callout_tick, hz, e6060sw_tick, sc);
  433 }
  434 
  435 static void
  436 e6060sw_lock(device_t dev)
  437 {
  438         struct e6060sw_softc *sc;
  439 
  440         sc = device_get_softc(dev);
  441 
  442         E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
  443         E6060SW_LOCK(sc);
  444 }
  445 
  446 static void
  447 e6060sw_unlock(device_t dev)
  448 {
  449         struct e6060sw_softc *sc;
  450 
  451         sc = device_get_softc(dev);
  452 
  453         E6060SW_LOCK_ASSERT(sc, MA_OWNED);
  454         E6060SW_UNLOCK(sc);
  455 }
  456 
  457 static etherswitch_info_t *
  458 e6060sw_getinfo(device_t dev)
  459 {
  460         struct e6060sw_softc *sc;
  461         
  462         sc = device_get_softc(dev);
  463 
  464         return (&sc->info);
  465 }
  466 
  467 static int
  468 e6060sw_getport(device_t dev, etherswitch_port_t *p)
  469 {
  470         struct e6060sw_softc *sc;
  471         struct mii_data *mii;
  472         struct ifmediareq *ifmr;
  473         int err, phy;
  474 
  475         sc = device_get_softc(dev);
  476         ifmr = &p->es_ifmr;
  477 
  478         if (p->es_port < 0 || p->es_port >= sc->numports)
  479                 return (ENXIO);
  480 
  481         p->es_pvid = 0;
  482         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  483                 p->es_pvid = MDIO_READREG(device_get_parent(dev), 
  484                     CORE_REGISTER + sc->smi_offset + p->es_port,
  485                     PORT_DEFVLAN) & 0xfff;
  486         }
  487 
  488         phy = sc->portphy[p->es_port];
  489         mii = e6060sw_miiforport(sc, p->es_port);
  490         if (sc->cpuport != -1 && phy == sc->cpuport) {
  491                 /* fill in fixed values for CPU port */
  492                 p->es_flags |= ETHERSWITCH_PORT_CPU;
  493                 ifmr->ifm_count = 0;
  494                 if (sc->media == 100)
  495                         ifmr->ifm_current = ifmr->ifm_active =
  496                             IFM_ETHER | IFM_100_TX | IFM_FDX;
  497                 else
  498                         ifmr->ifm_current = ifmr->ifm_active =
  499                             IFM_ETHER | IFM_1000_T | IFM_FDX;
  500                 ifmr->ifm_mask = 0;
  501                 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
  502         } else if (mii != NULL) {
  503                 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
  504                     &mii->mii_media, SIOCGIFMEDIA);
  505                 if (err)
  506                         return (err);
  507         } else {
  508                 return (ENXIO);
  509         }
  510         return (0);
  511 }
  512 
  513 static int
  514 e6060sw_setport(device_t dev, etherswitch_port_t *p)
  515 {
  516         struct e6060sw_softc *sc;
  517         struct ifmedia *ifm;
  518         struct mii_data *mii;
  519         if_t ifp;
  520         int err;
  521         int data;
  522 
  523         sc = device_get_softc(dev);
  524 
  525         if (p->es_port < 0 || p->es_port >= sc->numports)
  526                 return (ENXIO);
  527 
  528         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  529                 data = MDIO_READREG(device_get_parent(dev), 
  530                     CORE_REGISTER + sc->smi_offset + p->es_port,
  531                     PORT_DEFVLAN);
  532                 data &= ~0xfff;
  533                 data |= p->es_pvid;
  534                 data |= 1 << 12;
  535                 MDIO_WRITEREG(device_get_parent(dev), 
  536                     CORE_REGISTER + sc->smi_offset + p->es_port,
  537                     PORT_DEFVLAN, data);
  538         }
  539 
  540         if (sc->portphy[p->es_port] == sc->cpuport)
  541                 return(0);
  542 
  543         mii = e6060sw_miiforport(sc, p->es_port);
  544         if (mii == NULL)
  545                 return (ENXIO);
  546 
  547         ifp = e6060sw_ifpforport(sc, p->es_port);
  548 
  549         ifm = &mii->mii_media;
  550         err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
  551         return (err);
  552 }
  553 
  554 static int
  555 e6060sw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
  556 {
  557         struct e6060sw_softc *sc;
  558         int data1, data2;
  559         int vid;
  560         int i, tag;
  561 
  562         sc = device_get_softc(dev);
  563 
  564         if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
  565                 vg->es_vid = ETHERSWITCH_VID_VALID;
  566                 vg->es_vid |= vg->es_vlangroup;
  567                 data1 = MDIO_READREG(device_get_parent(dev), 
  568                     CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
  569                     PORT_VLAN_MAP);
  570                 vg->es_member_ports = data1 & 0x3f;
  571                 vg->es_untagged_ports = vg->es_member_ports;
  572                 vg->es_fid = 0;
  573         } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  574                 if (vg->es_vlangroup == 0)
  575                         return (0);
  576                 vid = e6060sw_read_vtu(dev, vg->es_vlangroup, &data1, &data2);
  577                 if (vid > 0) {
  578                         vg->es_vid = ETHERSWITCH_VID_VALID;
  579                         vg->es_vid |= vid;
  580                         vg->es_member_ports = 0;
  581                         vg->es_untagged_ports = 0;
  582                         for (i = 0; i < 4; ++i) {
  583                                 tag = data1 >> (i * 4) & 3;
  584                                 if (tag == 0 || tag == 1) {
  585                                         vg->es_member_ports |= 1 << i;
  586                                         vg->es_untagged_ports |= 1 << i;
  587                                 } else if (tag == 2) {
  588                                         vg->es_member_ports |= 1 << i;
  589                                 }
  590                         }
  591                         for (i = 0; i < 2; ++i) {
  592                                 tag = data2 >> (i * 4) & 3;
  593                                 if (tag == 0 || tag == 1) {
  594                                         vg->es_member_ports |= 1 << (i + 4);
  595                                         vg->es_untagged_ports |= 1 << (i + 4);
  596                                 } else if (tag == 2) {
  597                                         vg->es_member_ports |= 1 << (i + 4);
  598                                 }
  599                         }
  600 
  601                 }
  602         } else {
  603                 vg->es_vid = 0;
  604         }
  605         return (0);
  606 }
  607 
  608 static int
  609 e6060sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
  610 {
  611         struct e6060sw_softc *sc;
  612         int data1, data2;
  613         int i;
  614 
  615         sc = device_get_softc(dev);
  616 
  617         if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
  618                 data1 = MDIO_READREG(device_get_parent(dev),
  619                     CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
  620                     PORT_VLAN_MAP);
  621                 data1 &= ~0x3f;
  622                 data1 |= vg->es_member_ports;
  623                 MDIO_WRITEREG(device_get_parent(dev),
  624                     CORE_REGISTER + sc->smi_offset + vg->es_vlangroup,
  625                     PORT_VLAN_MAP, data1); 
  626         } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  627                 if (vg->es_vlangroup == 0)
  628                         return (0);
  629                 data1 = 0;
  630                 data2 = 0;
  631                 for (i = 0; i < 6; ++i) {
  632                         if (vg->es_member_ports & 
  633                             vg->es_untagged_ports & (1 << i)) {
  634                                 if (i < 4) {
  635                                         data1 |= (0xd << i * 4);
  636                                 } else {
  637                                         data2 |= (0xd << (i - 4) * 4);
  638                                 }
  639                         } else if (vg->es_member_ports & (1 << i)) {
  640                                 if (i < 4) {
  641                                         data1 |= (0xe << i * 4);
  642                                 } else {
  643                                         data2 |= (0xe << (i - 4) * 4);
  644                                 }
  645                         } else {
  646                                 if (i < 4) {
  647                                         data1 |= (0x3 << i * 4);
  648                                 } else {
  649                                         data2 |= (0x3 << (i - 4) * 4);
  650                                 }
  651                         }
  652                 }
  653                 e6060sw_set_vtu(dev, vg->es_vlangroup, data1, data2);
  654         }
  655         return (0);
  656 }
  657 
  658 static void
  659 e6060sw_reset_vlans(device_t dev)
  660 {
  661         struct e6060sw_softc *sc;
  662         uint32_t ports;
  663         int i;
  664         int data;
  665 
  666         sc = device_get_softc(dev);
  667 
  668         for (i = 0; i <= sc->numports; i++) {
  669                 ports = (1 << (sc->numports + 1)) - 1;
  670                 ports &= ~(1 << i);
  671                 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
  672                         data = i << 12;
  673                 } else if (sc->vlan_mode == 0) {
  674                         data = 1 << 8;
  675                 } else {
  676                         data = 0;
  677                 }
  678                 data |= ports;
  679                 MDIO_WRITEREG(device_get_parent(dev),
  680                     CORE_REGISTER + sc->smi_offset + i, PORT_VLAN_MAP, data);
  681         }
  682 }
  683 
  684 static void
  685 e6060sw_setup(device_t dev)
  686 {
  687         struct e6060sw_softc *sc;
  688         int i;
  689         int data;
  690 
  691         sc = device_get_softc(dev);
  692 
  693         for (i = 0; i <= sc->numports; i++) {
  694                 if (sc->sw_model == E6063 || sc->sw_model == E6065) {
  695                         data = MDIO_READREG(device_get_parent(dev),
  696                             CORE_REGISTER + sc->smi_offset + i, PORT_VLAN_MAP);
  697                         data &= ~(FORCEMAPMASK << FORCEMAPSHIFT);
  698                         MDIO_WRITEREG(device_get_parent(dev),
  699                             CORE_REGISTER + sc->smi_offset + i,
  700                             PORT_VLAN_MAP, data);
  701 
  702                         data = MDIO_READREG(device_get_parent(dev),
  703                             CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL);
  704                         data |= 3 << ENGRESSFSHIFT;
  705                         MDIO_WRITEREG(device_get_parent(dev),
  706                             CORE_REGISTER + sc->smi_offset + i, 
  707                             PORT_CONTROL, data);
  708                 }
  709         }
  710 }
  711 
  712 static void
  713 e6060sw_dot1q_mode(device_t dev, int mode)
  714 {
  715         struct e6060sw_softc *sc;
  716         int i;
  717         int data;
  718 
  719         sc = device_get_softc(dev);
  720 
  721         for (i = 0; i <= sc->numports; i++) {
  722                 data = MDIO_READREG(device_get_parent(dev),
  723                     CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL2);
  724                 data &= ~(DOT1QMODEMASK << DOT1QMODESHIFT);
  725                 data |= mode << DOT1QMODESHIFT;
  726                 MDIO_WRITEREG(device_get_parent(dev),
  727                     CORE_REGISTER + sc->smi_offset + i, PORT_CONTROL2, data);
  728 
  729                 data = MDIO_READREG(device_get_parent(dev), 
  730                     CORE_REGISTER + sc->smi_offset + i,
  731                     PORT_DEFVLAN);
  732                 data &= ~0xfff;
  733                 data |= 1;
  734                 MDIO_WRITEREG(device_get_parent(dev), 
  735                     CORE_REGISTER + sc->smi_offset + i,
  736                     PORT_DEFVLAN, data);
  737         }
  738 }
  739 
  740 static int
  741 e6060sw_getconf(device_t dev, etherswitch_conf_t *conf)
  742 {
  743         struct e6060sw_softc *sc;
  744         
  745         sc = device_get_softc(dev);
  746 
  747         /* Return the VLAN mode. */
  748         conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
  749         conf->vlan_mode = sc->vlan_mode;
  750 
  751         return (0);
  752 }
  753 
  754 static void
  755 e6060sw_init_vtu(device_t dev)
  756 {
  757         struct e6060sw_softc *sc;
  758         int busy;
  759 
  760         sc = device_get_softc(dev);
  761 
  762         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  763             VTU_OPERATION, VTU_BUSY | (VTU_FLASH << 12));
  764         while (1) {
  765                 busy = MDIO_READREG(device_get_parent(dev),
  766                     GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
  767                 if ((busy & VTU_BUSY) == 0)
  768                         break;
  769         }
  770 
  771         /* initial member set at vlan 1*/
  772         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  773             VTU_DATA1_REG, 0xcccc);
  774         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  775             VTU_DATA2_REG, 0x00cc);
  776         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  777             VTU_VID_REG, 0x1000 | 1);
  778         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  779             VTU_OPERATION, VTU_BUSY | (VTU_LOAD_PURGE << 12) | 1);
  780         while (1) {
  781                 busy = MDIO_READREG(device_get_parent(dev),
  782                     GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
  783                 if ((busy & VTU_BUSY) == 0)
  784                         break;
  785         }
  786 }
  787 
  788 static void
  789 e6060sw_set_vtu(device_t dev, int num, int data1, int data2)
  790 {
  791         struct e6060sw_softc *sc;
  792         int busy;
  793 
  794         sc = device_get_softc(dev);
  795 
  796         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  797             VTU_DATA1_REG, data1);
  798         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  799             VTU_DATA2_REG, data2);
  800         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  801             VTU_VID_REG, 0x1000 | num);
  802         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  803             VTU_OPERATION, VTU_BUSY | (VTU_LOAD_PURGE << 12) | num);
  804         while (1) {
  805                 busy = MDIO_READREG(device_get_parent(dev),
  806                     GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
  807                 if ((busy & VTU_BUSY) == 0)
  808                         break;
  809         }
  810 
  811 }
  812 
  813 static int
  814 e6060sw_read_vtu(device_t dev, int num, int *data1, int *data2)
  815 {
  816         struct e6060sw_softc *sc;
  817         int busy;
  818 
  819         sc = device_get_softc(dev);
  820 
  821         num = num - 1;
  822 
  823         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  824             VTU_VID_REG, num & 0xfff);
  825         /* Get Next */
  826         MDIO_WRITEREG(device_get_parent(dev), GLOBAL_REGISTER + sc->smi_offset,
  827             VTU_OPERATION, VTU_BUSY | (VTU_GET_NEXT << 12));
  828         while (1) {
  829                 busy = MDIO_READREG(device_get_parent(dev),
  830                     GLOBAL_REGISTER + sc->smi_offset, VTU_OPERATION);
  831                 if ((busy & VTU_BUSY) == 0)
  832                         break;
  833         }
  834 
  835         int vid = MDIO_READREG(device_get_parent(dev),
  836             GLOBAL_REGISTER + sc->smi_offset, VTU_VID_REG);
  837         if (vid & 0x1000) {
  838                 *data1 = MDIO_READREG(device_get_parent(dev),
  839                     GLOBAL_REGISTER + sc->smi_offset, VTU_DATA1_REG);
  840                 *data2 = MDIO_READREG(device_get_parent(dev),
  841                     GLOBAL_REGISTER + sc->smi_offset, VTU_DATA2_REG);
  842                     
  843                 return (vid & 0xfff);
  844         }
  845 
  846         return (-1);
  847 }
  848 
  849 static int
  850 e6060sw_setconf(device_t dev, etherswitch_conf_t *conf)
  851 {
  852         struct e6060sw_softc *sc;
  853 
  854         sc = device_get_softc(dev);
  855 
  856         /* Set the VLAN mode. */
  857         if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
  858                 if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) {
  859                         sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
  860                         e6060sw_dot1q_mode(dev, DOT1QNONE);
  861                         e6060sw_reset_vlans(dev);
  862                 } else if ((sc->sw_model == E6063 || sc->sw_model == E6065) &&
  863                     conf->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  864                         sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
  865                         e6060sw_dot1q_mode(dev, DOT1QSECURE);
  866                         e6060sw_init_vtu(dev);
  867                 } else {
  868                         sc->vlan_mode = 0;
  869                         /* Reset VLANs. */
  870                         e6060sw_dot1q_mode(dev, DOT1QNONE);
  871                         e6060sw_reset_vlans(dev);
  872                 }
  873         }
  874 
  875         return (0);
  876 }
  877 
  878 static void
  879 e6060sw_statchg(device_t dev)
  880 {
  881 
  882         DPRINTF(dev, "%s\n", __func__);
  883 }
  884 
  885 static int
  886 e6060sw_ifmedia_upd(if_t ifp)
  887 {
  888         struct e6060sw_softc *sc;
  889         struct mii_data *mii;
  890 
  891         sc = if_getsoftc(ifp);
  892         mii = e6060sw_miiforport(sc, ifp->if_dunit); /* XXX - DRVAPI */
  893 
  894         DPRINTF(sc->sc_dev, "%s\n", __func__);
  895         if (mii == NULL)
  896                 return (ENXIO);
  897         mii_mediachg(mii);
  898         return (0);
  899 }
  900 
  901 static void
  902 e6060sw_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
  903 {
  904         struct e6060sw_softc *sc;
  905         struct mii_data *mii;
  906 
  907         sc = if_getsoftc(ifp);
  908         mii = e6060sw_miiforport(sc, ifp->if_dunit); /* XXX - DRVAPI */
  909 
  910         DPRINTF(sc->sc_dev, "%s\n", __func__);
  911 
  912         if (mii == NULL)
  913                 return;
  914         mii_pollstat(mii);
  915         ifmr->ifm_active = mii->mii_media_active;
  916         ifmr->ifm_status = mii->mii_media_status;
  917 }
  918 
  919 static int
  920 e6060sw_readphy(device_t dev, int phy, int reg)
  921 {
  922         struct e6060sw_softc *sc;
  923         int data;
  924 
  925         sc = device_get_softc(dev);
  926         E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
  927 
  928         if (phy < 0 || phy >= 32)
  929                 return (ENXIO);
  930         if (reg < 0 || reg >= 32)
  931                 return (ENXIO);
  932 
  933         E6060SW_LOCK(sc);
  934         data = MDIO_READREG(device_get_parent(dev), phy, reg);
  935         E6060SW_UNLOCK(sc);
  936 
  937         return (data);
  938 }
  939 
  940 static int
  941 e6060sw_writephy(device_t dev, int phy, int reg, int data)
  942 {
  943         struct e6060sw_softc *sc;
  944         int err;
  945 
  946         sc = device_get_softc(dev);
  947         E6060SW_LOCK_ASSERT(sc, MA_NOTOWNED);
  948 
  949         if (phy < 0 || phy >= 32)
  950                 return (ENXIO);
  951         if (reg < 0 || reg >= 32)
  952                 return (ENXIO);
  953 
  954         E6060SW_LOCK(sc);
  955         err = MDIO_WRITEREG(device_get_parent(dev), phy, reg, data);
  956         E6060SW_UNLOCK(sc);
  957 
  958         return (err);
  959 }
  960 
  961 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */
  962 
  963 static int
  964 e6060sw_readreg(device_t dev, int addr)
  965 {
  966         int devaddr, regaddr;
  967 
  968         devaddr = (addr >> 5) & 0x1f;
  969         regaddr = addr & 0x1f;
  970 
  971         return MDIO_READREG(device_get_parent(dev), devaddr, regaddr);
  972 }
  973 
  974 /* addr is 5-8 bit is SMI Device Addres, 0-4 bit is SMI Register Address */
  975 
  976 static int
  977 e6060sw_writereg(device_t dev, int addr, int value)
  978 {
  979         int devaddr, regaddr;
  980 
  981         devaddr = (addr >> 5) & 0x1f;
  982         regaddr = addr & 0x1f;
  983 
  984         return (MDIO_WRITEREG(device_get_parent(dev), devaddr, regaddr, value));
  985 }
  986 
  987 static device_method_t e6060sw_methods[] = {
  988         /* Device interface */
  989         DEVMETHOD(device_probe,         e6060sw_probe),
  990         DEVMETHOD(device_attach,        e6060sw_attach),
  991         DEVMETHOD(device_detach,        e6060sw_detach),
  992         
  993         /* bus interface */
  994         DEVMETHOD(bus_add_child,        device_add_child_ordered),
  995         
  996         /* MII interface */
  997         DEVMETHOD(miibus_readreg,       e6060sw_readphy),
  998         DEVMETHOD(miibus_writereg,      e6060sw_writephy),
  999         DEVMETHOD(miibus_statchg,       e6060sw_statchg),
 1000 
 1001         /* MDIO interface */
 1002         DEVMETHOD(mdio_readreg,         e6060sw_readphy),
 1003         DEVMETHOD(mdio_writereg,        e6060sw_writephy),
 1004 
 1005         /* etherswitch interface */
 1006         DEVMETHOD(etherswitch_lock,     e6060sw_lock),
 1007         DEVMETHOD(etherswitch_unlock,   e6060sw_unlock),
 1008         DEVMETHOD(etherswitch_getinfo,  e6060sw_getinfo),
 1009         DEVMETHOD(etherswitch_readreg,  e6060sw_readreg),
 1010         DEVMETHOD(etherswitch_writereg, e6060sw_writereg),
 1011         DEVMETHOD(etherswitch_readphyreg,       e6060sw_readphy),
 1012         DEVMETHOD(etherswitch_writephyreg,      e6060sw_writephy),
 1013         DEVMETHOD(etherswitch_getport,  e6060sw_getport),
 1014         DEVMETHOD(etherswitch_setport,  e6060sw_setport),
 1015         DEVMETHOD(etherswitch_getvgroup,        e6060sw_getvgroup),
 1016         DEVMETHOD(etherswitch_setvgroup,        e6060sw_setvgroup),
 1017         DEVMETHOD(etherswitch_setconf,  e6060sw_setconf),
 1018         DEVMETHOD(etherswitch_getconf,  e6060sw_getconf),
 1019 
 1020         DEVMETHOD_END
 1021 };
 1022 
 1023 DEFINE_CLASS_0(e6060sw, e6060sw_driver, e6060sw_methods,
 1024     sizeof(struct e6060sw_softc));
 1025 
 1026 DRIVER_MODULE(e6060sw, mdio, e6060sw_driver, 0, 0);
 1027 DRIVER_MODULE(miibus, e6060sw, miibus_driver, 0, 0);
 1028 DRIVER_MODULE(mdio, e6060sw, mdio_driver, 0, 0);
 1029 DRIVER_MODULE(etherswitch, e6060sw, etherswitch_driver, 0, 0);
 1030 MODULE_VERSION(e6060sw, 1);
 1031 MODULE_DEPEND(e6060sw, miibus, 1, 1, 1); /* XXX which versions? */
 1032 MODULE_DEPEND(e6060sw, etherswitch, 1, 1, 1); /* XXX which versions? */

Cache object: 23def91188093c05bab7a4f2a2710651


[ 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.