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/micrel/ksz8995ma.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 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 is Micrel KSZ8995MA driver code. KSZ8995MA use SPI bus on control.
   34  * This code development on @SRCHACK's ksz8995ma board and FON2100 with
   35  * gpiospi.
   36  * etherswitchcfg command port option support addtag, ingress, striptag, 
   37  * dropuntagged.
   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 
   63 #include <dev/etherswitch/etherswitch.h>
   64 
   65 #include <dev/spibus/spi.h>
   66 
   67 #include "spibus_if.h"
   68 #include "miibus_if.h"
   69 #include "etherswitch_if.h"
   70 
   71 #define KSZ8995MA_SPI_READ              0x03
   72 #define KSZ8995MA_SPI_WRITE             0x02
   73 
   74 #define KSZ8995MA_CID0                  0x00
   75 #define KSZ8995MA_CID1                  0x01
   76 
   77 #define KSZ8995MA_GC0                   0x02
   78 #define KSZ8995MA_GC1                   0x03
   79 #define KSZ8995MA_GC2                   0x04
   80 #define KSZ8995MA_GC3                   0x05
   81 
   82 #define KSZ8995MA_PORT_SIZE             0x10
   83 
   84 #define KSZ8995MA_PC0_BASE              0x10
   85 #define KSZ8995MA_PC1_BASE              0x11
   86 #define KSZ8995MA_PC2_BASE              0x12
   87 #define KSZ8995MA_PC3_BASE              0x13
   88 #define KSZ8995MA_PC4_BASE              0x14
   89 #define KSZ8995MA_PC5_BASE              0x15
   90 #define KSZ8995MA_PC6_BASE              0x16
   91 #define KSZ8995MA_PC7_BASE              0x17
   92 #define KSZ8995MA_PC8_BASE              0x18
   93 #define KSZ8995MA_PC9_BASE              0x19
   94 #define KSZ8995MA_PC10_BASE             0x1a
   95 #define KSZ8995MA_PC11_BASE             0x1b
   96 #define KSZ8995MA_PC12_BASE             0x1c
   97 #define KSZ8995MA_PC13_BASE             0x1d
   98 
   99 #define KSZ8995MA_PS0_BASE              0x1e
  100 
  101 #define KSZ8995MA_PC14_BASE             0x1f
  102 
  103 #define KSZ8995MA_IAC0                  0x6e
  104 #define KSZ8995MA_IAC1                  0x6f
  105 #define KSZ8995MA_IDR8                  0x70
  106 #define KSZ8995MA_IDR7                  0x71
  107 #define KSZ8995MA_IDR6                  0x72
  108 #define KSZ8995MA_IDR5                  0x73
  109 #define KSZ8995MA_IDR4                  0x74
  110 #define KSZ8995MA_IDR3                  0x75
  111 #define KSZ8995MA_IDR2                  0x76
  112 #define KSZ8995MA_IDR1                  0x77
  113 #define KSZ8995MA_IDR0                  0x78
  114 
  115 #define KSZ8995MA_FAMILI_ID             0x95
  116 #define KSZ8995MA_CHIP_ID               0x00
  117 #define KSZ8995MA_CHIP_ID_MASK          0xf0
  118 #define KSZ8995MA_START                 0x01
  119 #define KSZ8995MA_VLAN_ENABLE           0x80
  120 #define KSZ8995MA_TAG_INS               0x04
  121 #define KSZ8995MA_TAG_RM                0x02
  122 #define KSZ8995MA_INGR_FILT             0x40
  123 #define KSZ8995MA_DROP_NONPVID          0x20
  124 
  125 #define KSZ8995MA_PDOWN                 0x08
  126 #define KSZ8995MA_STARTNEG              0x20
  127 
  128 #define KSZ8995MA_MII_STAT              0x7808
  129 #define KSZ8995MA_MII_PHYID_H           0x0022
  130 #define KSZ8995MA_MII_PHYID_L           0x1450
  131 #define KSZ8995MA_MII_AA                0x0401
  132 
  133 #define KSZ8995MA_VLAN_TABLE_VALID      0x20
  134 #define KSZ8995MA_VLAN_TABLE_READ       0x14
  135 #define KSZ8995MA_VLAN_TABLE_WRITE      0x04
  136 
  137 #define KSZ8995MA_MAX_PORT              5
  138 
  139 MALLOC_DECLARE(M_KSZ8995MA);
  140 MALLOC_DEFINE(M_KSZ8995MA, "ksz8995ma", "ksz8995ma data structures");
  141 
  142 struct ksz8995ma_softc {
  143         struct mtx      sc_mtx;         /* serialize access to softc */
  144         device_t        sc_dev;
  145         int             vlan_mode;
  146         int             media;          /* cpu port media */
  147         int             cpuport;        /* which PHY is connected to the CPU */
  148         int             phymask;        /* PHYs we manage */
  149         int             numports;       /* number of ports */
  150         int             ifpport[KSZ8995MA_MAX_PORT];
  151         int             *portphy;
  152         char            **ifname;
  153         device_t        **miibus;
  154         if_t *ifp;
  155         struct callout  callout_tick;
  156         etherswitch_info_t      info;
  157 };
  158 
  159 #define KSZ8995MA_LOCK(_sc)                     \
  160             mtx_lock(&(_sc)->sc_mtx)
  161 #define KSZ8995MA_UNLOCK(_sc)                   \
  162             mtx_unlock(&(_sc)->sc_mtx)
  163 #define KSZ8995MA_LOCK_ASSERT(_sc, _what)       \
  164             mtx_assert(&(_sc)->sc_mtx, (_what))
  165 #define KSZ8995MA_TRYLOCK(_sc)                  \
  166             mtx_trylock(&(_sc)->sc_mtx)
  167 
  168 #if defined(DEBUG)
  169 #define DPRINTF(dev, args...) device_printf(dev, args)
  170 #else
  171 #define DPRINTF(dev, args...)
  172 #endif
  173 
  174 static inline int ksz8995ma_portforphy(struct ksz8995ma_softc *, int);
  175 static void ksz8995ma_tick(void *);
  176 static int ksz8995ma_ifmedia_upd(if_t );
  177 static void ksz8995ma_ifmedia_sts(if_t , struct ifmediareq *);
  178 static int ksz8995ma_readreg(device_t dev, int addr);
  179 static int ksz8995ma_writereg(device_t dev, int addr, int value);
  180 static void ksz8995ma_portvlanreset(device_t dev);
  181 
  182 static int
  183 ksz8995ma_probe(device_t dev)
  184 {
  185         int id0, id1;
  186         struct ksz8995ma_softc *sc;
  187 
  188         sc = device_get_softc(dev);
  189         bzero(sc, sizeof(*sc));
  190 
  191         id0 = ksz8995ma_readreg(dev, KSZ8995MA_CID0);
  192         id1 = ksz8995ma_readreg(dev, KSZ8995MA_CID1);
  193         if (bootverbose)
  194                 device_printf(dev,"Chip Identifier Register %x %x\n", id0, id1);
  195 
  196         /* check Product Code */
  197         if (id0 != KSZ8995MA_FAMILI_ID || (id1 & KSZ8995MA_CHIP_ID_MASK) !=
  198             KSZ8995MA_CHIP_ID) {
  199                 return (ENXIO);
  200         }
  201 
  202         device_set_desc_copy(dev, "Micrel KSZ8995MA SPI switch driver");
  203         return (BUS_PROBE_DEFAULT);
  204 }
  205 
  206 static int
  207 ksz8995ma_attach_phys(struct ksz8995ma_softc *sc)
  208 {
  209         int phy, port, err;
  210         char name[IFNAMSIZ];
  211 
  212         port = 0;
  213         err = 0;
  214         /* PHYs need an interface, so we generate a dummy one */
  215         snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
  216         for (phy = 0; phy < sc->numports; phy++) {
  217                 if (phy == sc->cpuport)
  218                         continue;
  219                 if (((1 << phy) & sc->phymask) == 0)
  220                         continue;
  221                 sc->ifpport[phy] = port;
  222                 sc->portphy[port] = phy;
  223                 sc->ifp[port] = if_alloc(IFT_ETHER);
  224                 if (sc->ifp[port] == NULL) {
  225                         device_printf(sc->sc_dev, "couldn't allocate ifnet structure\n");
  226                         err = ENOMEM;
  227                         break;
  228                 }
  229 
  230                 sc->ifp[port]->if_softc = sc;
  231                 sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
  232                     IFF_DRV_RUNNING | IFF_SIMPLEX;
  233                 if_initname(sc->ifp[port], name, port);
  234                 sc->miibus[port] = malloc(sizeof(device_t), M_KSZ8995MA,
  235                     M_WAITOK | M_ZERO);
  236                 if (sc->miibus[port] == NULL) {
  237                         err = ENOMEM;
  238                         goto failed;
  239                 }
  240                 err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
  241                     ksz8995ma_ifmedia_upd, ksz8995ma_ifmedia_sts, \
  242                     BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
  243                 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
  244                     device_get_nameunit(*sc->miibus[port]),
  245                     sc->ifp[port]->if_xname);
  246                 if (err != 0) {
  247                         device_printf(sc->sc_dev,
  248                             "attaching PHY %d failed\n",
  249                             phy);
  250                         goto failed;
  251                 }
  252                 ++port;
  253         }
  254         sc->info.es_nports = port;
  255         if (sc->cpuport != -1) {
  256                 /* cpu port is MAC5 on ksz8995ma */ 
  257                 sc->ifpport[sc->cpuport] = port;
  258                 sc->portphy[port] = sc->cpuport;
  259                 ++sc->info.es_nports;
  260         }
  261 
  262         return (0);
  263 
  264 failed:
  265         for (phy = 0; phy < sc->numports; phy++) {
  266                 if (((1 << phy) & sc->phymask) == 0)
  267                         continue;
  268                 port = ksz8995ma_portforphy(sc, phy);
  269                 if (sc->miibus[port] != NULL)
  270                         device_delete_child(sc->sc_dev, (*sc->miibus[port]));
  271                 if (sc->ifp[port] != NULL)
  272                         if_free(sc->ifp[port]);
  273                 if (sc->ifname[port] != NULL)
  274                         free(sc->ifname[port], M_KSZ8995MA);
  275                 if (sc->miibus[port] != NULL)
  276                         free(sc->miibus[port], M_KSZ8995MA);
  277         }
  278         return (err);
  279 }
  280 
  281 static int
  282 ksz8995ma_attach(device_t dev)
  283 {
  284         struct ksz8995ma_softc  *sc;
  285         int                      err, reg;
  286 
  287         err = 0;
  288         sc = device_get_softc(dev);
  289 
  290         sc->sc_dev = dev;
  291         mtx_init(&sc->sc_mtx, "ksz8995ma", NULL, MTX_DEF);
  292         strlcpy(sc->info.es_name, device_get_desc(dev),
  293             sizeof(sc->info.es_name));
  294 
  295         /* KSZ8995MA Defaults */
  296         sc->numports = KSZ8995MA_MAX_PORT;
  297         sc->phymask = (1 << (KSZ8995MA_MAX_PORT + 1)) - 1;
  298         sc->cpuport = -1;
  299         sc->media = 100;
  300 
  301         (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
  302             "cpuport", &sc->cpuport);
  303 
  304         sc->info.es_nvlangroups = 16;
  305         sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOT1Q;
  306 
  307         sc->ifp = malloc(sizeof(if_t ) * sc->numports, M_KSZ8995MA,
  308             M_WAITOK | M_ZERO);
  309         sc->ifname = malloc(sizeof(char *) * sc->numports, M_KSZ8995MA,
  310             M_WAITOK | M_ZERO);
  311         sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_KSZ8995MA,
  312             M_WAITOK | M_ZERO);
  313         sc->portphy = malloc(sizeof(int) * sc->numports, M_KSZ8995MA,
  314             M_WAITOK | M_ZERO);
  315 
  316         if (sc->ifp == NULL || sc->ifname == NULL || sc->miibus == NULL ||
  317             sc->portphy == NULL) {
  318                 err = ENOMEM;
  319                 goto failed;
  320         }
  321 
  322         /*
  323          * Attach the PHYs and complete the bus enumeration.
  324          */
  325         err = ksz8995ma_attach_phys(sc);
  326         if (err != 0)
  327                 goto failed;
  328 
  329         bus_generic_probe(dev);
  330         bus_enumerate_hinted_children(dev);
  331         err = bus_generic_attach(dev);
  332         if (err != 0)
  333                 goto failed;
  334         
  335         callout_init(&sc->callout_tick, 0);
  336 
  337         ksz8995ma_tick(sc);
  338         
  339         /* start switch */
  340         sc->vlan_mode = 0;
  341         reg = ksz8995ma_readreg(dev, KSZ8995MA_GC3);
  342         ksz8995ma_writereg(dev, KSZ8995MA_GC3, 
  343             reg & ~KSZ8995MA_VLAN_ENABLE);
  344         ksz8995ma_portvlanreset(dev);
  345         ksz8995ma_writereg(dev, KSZ8995MA_CID1, KSZ8995MA_START);
  346 
  347         return (0);
  348 
  349 failed:
  350         if (sc->portphy != NULL)
  351                 free(sc->portphy, M_KSZ8995MA);
  352         if (sc->miibus != NULL)
  353                 free(sc->miibus, M_KSZ8995MA);
  354         if (sc->ifname != NULL)
  355                 free(sc->ifname, M_KSZ8995MA);
  356         if (sc->ifp != NULL)
  357                 free(sc->ifp, M_KSZ8995MA);
  358 
  359         return (err);
  360 }
  361 
  362 static int
  363 ksz8995ma_detach(device_t dev)
  364 {
  365         struct ksz8995ma_softc  *sc;
  366         int                      i, port;
  367 
  368         sc = device_get_softc(dev);
  369 
  370         callout_drain(&sc->callout_tick);
  371 
  372         for (i = 0; i < KSZ8995MA_MAX_PORT; i++) {
  373                 if (((1 << i) & sc->phymask) == 0)
  374                         continue;
  375                 port = ksz8995ma_portforphy(sc, i);
  376                 if (sc->miibus[port] != NULL)
  377                         device_delete_child(dev, (*sc->miibus[port]));
  378                 if (sc->ifp[port] != NULL)
  379                         if_free(sc->ifp[port]);
  380                 free(sc->ifname[port], M_KSZ8995MA);
  381                 free(sc->miibus[port], M_KSZ8995MA);
  382         }
  383 
  384         free(sc->portphy, M_KSZ8995MA);
  385         free(sc->miibus, M_KSZ8995MA);
  386         free(sc->ifname, M_KSZ8995MA);
  387         free(sc->ifp, M_KSZ8995MA);
  388 
  389         bus_generic_detach(dev);
  390         mtx_destroy(&sc->sc_mtx);
  391 
  392         return (0);
  393 }
  394 
  395 /*
  396  * Convert PHY number to port number.
  397  */
  398 static inline int
  399 ksz8995ma_portforphy(struct ksz8995ma_softc *sc, int phy)
  400 {
  401 
  402         return (sc->ifpport[phy]);
  403 }
  404 
  405 static inline struct mii_data *
  406 ksz8995ma_miiforport(struct ksz8995ma_softc *sc, int port)
  407 {
  408 
  409         if (port < 0 || port > sc->numports)
  410                 return (NULL);
  411         if (port == sc->cpuport)
  412                 return (NULL);
  413         return (device_get_softc(*sc->miibus[port]));
  414 }
  415 
  416 static inline if_t 
  417 ksz8995ma_ifpforport(struct ksz8995ma_softc *sc, int port)
  418 {
  419 
  420         if (port < 0 || port > sc->numports)
  421                 return (NULL);
  422         return (sc->ifp[port]);
  423 }
  424 
  425 /*
  426  * Poll the status for all PHYs.
  427  */
  428 static void
  429 ksz8995ma_miipollstat(struct ksz8995ma_softc *sc)
  430 {
  431         int i, port;
  432         struct mii_data *mii;
  433         struct mii_softc *miisc;
  434 
  435         KSZ8995MA_LOCK_ASSERT(sc, MA_NOTOWNED);
  436 
  437         for (i = 0; i < KSZ8995MA_MAX_PORT; i++) {
  438                 if (i == sc->cpuport)
  439                         continue;
  440                 if (((1 << i) & sc->phymask) == 0)
  441                         continue;
  442                 port = ksz8995ma_portforphy(sc, i);
  443                 if ((*sc->miibus[port]) == NULL)
  444                         continue;
  445                 mii = device_get_softc(*sc->miibus[port]);
  446                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
  447                         if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
  448                             miisc->mii_inst)
  449                                 continue;
  450                         ukphy_status(miisc);
  451                         mii_phy_update(miisc, MII_POLLSTAT);
  452                 }
  453         }
  454 }
  455 
  456 static void
  457 ksz8995ma_tick(void *arg)
  458 {
  459         struct ksz8995ma_softc *sc;
  460 
  461         sc = arg;
  462 
  463         ksz8995ma_miipollstat(sc);
  464         callout_reset(&sc->callout_tick, hz, ksz8995ma_tick, sc);
  465 }
  466 
  467 static void
  468 ksz8995ma_lock(device_t dev)
  469 {
  470         struct ksz8995ma_softc *sc;
  471 
  472         sc = device_get_softc(dev);
  473 
  474         KSZ8995MA_LOCK_ASSERT(sc, MA_NOTOWNED);
  475         KSZ8995MA_LOCK(sc);
  476 }
  477 
  478 static void
  479 ksz8995ma_unlock(device_t dev)
  480 {
  481         struct ksz8995ma_softc *sc;
  482 
  483         sc = device_get_softc(dev);
  484 
  485         KSZ8995MA_LOCK_ASSERT(sc, MA_OWNED);
  486         KSZ8995MA_UNLOCK(sc);
  487 }
  488 
  489 static etherswitch_info_t *
  490 ksz8995ma_getinfo(device_t dev)
  491 {
  492         struct ksz8995ma_softc *sc;
  493 
  494         sc = device_get_softc(dev);
  495         
  496         return (&sc->info);
  497 }
  498 
  499 static int
  500 ksz8995ma_getport(device_t dev, etherswitch_port_t *p)
  501 {
  502         struct ksz8995ma_softc *sc;
  503         struct mii_data *mii;
  504         struct ifmediareq *ifmr;
  505         int phy, err;
  506         int tag1, tag2, portreg;
  507 
  508         sc = device_get_softc(dev);
  509         ifmr = &p->es_ifmr;
  510 
  511         if (p->es_port < 0 || p->es_port >= sc->numports)
  512                 return (ENXIO);
  513 
  514         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  515                 tag1 = ksz8995ma_readreg(dev, KSZ8995MA_PC3_BASE + 
  516                     KSZ8995MA_PORT_SIZE * p->es_port);
  517                 tag2 = ksz8995ma_readreg(dev, KSZ8995MA_PC4_BASE + 
  518                     KSZ8995MA_PORT_SIZE * p->es_port);
  519                 p->es_pvid = (tag1 & 0x0f) << 8 | tag2;
  520 
  521                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PC0_BASE + 
  522                     KSZ8995MA_PORT_SIZE * p->es_port);
  523                 if (portreg & KSZ8995MA_TAG_INS)
  524                         p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
  525                 if (portreg & KSZ8995MA_TAG_RM)
  526                         p->es_flags |= ETHERSWITCH_PORT_STRIPTAG;
  527 
  528                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PC2_BASE + 
  529                     KSZ8995MA_PORT_SIZE * p->es_port);
  530                 if (portreg & KSZ8995MA_DROP_NONPVID)
  531                         p->es_flags |= ETHERSWITCH_PORT_DROPUNTAGGED;
  532                 if (portreg & KSZ8995MA_INGR_FILT)
  533                         p->es_flags |= ETHERSWITCH_PORT_INGRESS;
  534         }
  535 
  536         phy = sc->portphy[p->es_port];
  537         mii = ksz8995ma_miiforport(sc, p->es_port);
  538         if (sc->cpuport != -1 && phy == sc->cpuport) {
  539                 /* fill in fixed values for CPU port */
  540                 p->es_flags |= ETHERSWITCH_PORT_CPU;
  541                 ifmr->ifm_count = 0;
  542                 if (sc->media == 100)
  543                         ifmr->ifm_current = ifmr->ifm_active =
  544                             IFM_ETHER | IFM_100_TX | IFM_FDX;
  545                 else
  546                         ifmr->ifm_current = ifmr->ifm_active =
  547                             IFM_ETHER | IFM_1000_T | IFM_FDX;
  548                 ifmr->ifm_mask = 0;
  549                 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
  550         } else if (mii != NULL) {
  551                 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
  552                     &mii->mii_media, SIOCGIFMEDIA);
  553                 if (err)
  554                         return (err);
  555         } else {
  556                 return (ENXIO);
  557         }
  558 
  559         return (0);
  560 }
  561 
  562 static int
  563 ksz8995ma_setport(device_t dev, etherswitch_port_t *p)
  564 {
  565         struct ksz8995ma_softc *sc;
  566         struct mii_data *mii;
  567         struct ifmedia *ifm;
  568         if_t ifp;
  569         int phy, err;
  570         int portreg;
  571 
  572         sc = device_get_softc(dev);
  573 
  574         if (p->es_port < 0 || p->es_port >= sc->numports)
  575                 return (ENXIO);
  576 
  577         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  578                 ksz8995ma_writereg(dev, KSZ8995MA_PC4_BASE + 
  579                     KSZ8995MA_PORT_SIZE * p->es_port, p->es_pvid & 0xff);
  580                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PC3_BASE + 
  581                     KSZ8995MA_PORT_SIZE * p->es_port);
  582                 ksz8995ma_writereg(dev, KSZ8995MA_PC3_BASE + 
  583                     KSZ8995MA_PORT_SIZE * p->es_port,
  584                     (portreg & 0xf0) | ((p->es_pvid >> 8) & 0x0f));
  585 
  586                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PC0_BASE + 
  587                     KSZ8995MA_PORT_SIZE * p->es_port);
  588                 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
  589                         portreg |= KSZ8995MA_TAG_INS;
  590                 else
  591                         portreg &= ~KSZ8995MA_TAG_INS;
  592                 if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 
  593                         portreg |= KSZ8995MA_TAG_RM;
  594                 else
  595                         portreg &= ~KSZ8995MA_TAG_RM;
  596                 ksz8995ma_writereg(dev, KSZ8995MA_PC0_BASE + 
  597                     KSZ8995MA_PORT_SIZE * p->es_port, portreg);
  598 
  599                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PC2_BASE + 
  600                     KSZ8995MA_PORT_SIZE * p->es_port);
  601                 if (p->es_flags & ETHERSWITCH_PORT_DROPUNTAGGED)
  602                         portreg |= KSZ8995MA_DROP_NONPVID;
  603                 else
  604                         portreg &= ~KSZ8995MA_DROP_NONPVID;
  605                 if (p->es_flags & ETHERSWITCH_PORT_INGRESS)
  606                         portreg |= KSZ8995MA_INGR_FILT;
  607                 else
  608                         portreg &= ~KSZ8995MA_INGR_FILT;
  609                 ksz8995ma_writereg(dev, KSZ8995MA_PC2_BASE + 
  610                     KSZ8995MA_PORT_SIZE * p->es_port, portreg);
  611         }
  612 
  613         phy = sc->portphy[p->es_port];
  614         mii = ksz8995ma_miiforport(sc, p->es_port);
  615         if (phy != sc->cpuport) {
  616                 if (mii == NULL)
  617                         return (ENXIO);
  618                 ifp = ksz8995ma_ifpforport(sc, p->es_port);
  619                 ifm = &mii->mii_media;
  620                 err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
  621         }
  622         return (0);
  623 }
  624 
  625 static int
  626 ksz8995ma_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
  627 {
  628         int data0, data1, data2;
  629         int vlantab;
  630         struct ksz8995ma_softc *sc;
  631 
  632         sc = device_get_softc(dev);
  633 
  634         if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
  635                 if (vg->es_vlangroup < sc->numports) {
  636                         vg->es_vid = ETHERSWITCH_VID_VALID;
  637                         vg->es_vid |= vg->es_vlangroup;
  638                         data0 = ksz8995ma_readreg(dev, KSZ8995MA_PC1_BASE +
  639                             KSZ8995MA_PORT_SIZE * vg->es_vlangroup);
  640                         vg->es_member_ports = data0 & 0x1f;
  641                         vg->es_untagged_ports = vg->es_member_ports;
  642                         vg->es_fid = 0;
  643                 } else {
  644                         vg->es_vid = 0;
  645                 }
  646         } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  647                 ksz8995ma_writereg(dev, KSZ8995MA_IAC0,
  648                     KSZ8995MA_VLAN_TABLE_READ);
  649                 ksz8995ma_writereg(dev, KSZ8995MA_IAC1, vg->es_vlangroup);
  650                 data2 = ksz8995ma_readreg(dev, KSZ8995MA_IDR2);
  651                 data1 = ksz8995ma_readreg(dev, KSZ8995MA_IDR1);
  652                 data0 = ksz8995ma_readreg(dev, KSZ8995MA_IDR0);
  653                 vlantab = data2 << 16 | data1 << 8 | data0;
  654                 if (data2 & KSZ8995MA_VLAN_TABLE_VALID) {
  655                         vg->es_vid = ETHERSWITCH_VID_VALID;
  656                         vg->es_vid |= vlantab & 0xfff;
  657                         vg->es_member_ports = (vlantab >> 16) & 0x1f;
  658                         vg->es_untagged_ports = vg->es_member_ports;
  659                         vg->es_fid = (vlantab >> 12) & 0x0f;
  660                 } else {
  661                         vg->es_fid = 0;
  662                 }
  663         }
  664         
  665         return (0);
  666 }
  667 
  668 static int
  669 ksz8995ma_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
  670 {
  671         struct ksz8995ma_softc *sc;
  672         int data0;
  673 
  674         sc = device_get_softc(dev);
  675 
  676         if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
  677                 data0 = ksz8995ma_readreg(dev, KSZ8995MA_PC1_BASE +
  678                     KSZ8995MA_PORT_SIZE * vg->es_vlangroup);
  679                 ksz8995ma_writereg(dev, KSZ8995MA_PC1_BASE +
  680                     KSZ8995MA_PORT_SIZE * vg->es_vlangroup,
  681                     (data0 & 0xe0) | (vg->es_member_ports & 0x1f));
  682         } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  683                 if (vg->es_member_ports != 0) {
  684                         ksz8995ma_writereg(dev, KSZ8995MA_IDR2,
  685                             KSZ8995MA_VLAN_TABLE_VALID |
  686                             (vg->es_member_ports & 0x1f));
  687                         ksz8995ma_writereg(dev, KSZ8995MA_IDR1,
  688                             vg->es_fid << 4 | vg->es_vid >> 8);
  689                         ksz8995ma_writereg(dev, KSZ8995MA_IDR0,
  690                             vg->es_vid & 0xff);
  691                 } else {
  692                         ksz8995ma_writereg(dev, KSZ8995MA_IDR2, 0);
  693                         ksz8995ma_writereg(dev, KSZ8995MA_IDR1, 0);
  694                         ksz8995ma_writereg(dev, KSZ8995MA_IDR0, 0);
  695                 }
  696                 ksz8995ma_writereg(dev, KSZ8995MA_IAC0,
  697                     KSZ8995MA_VLAN_TABLE_WRITE);
  698                 ksz8995ma_writereg(dev, KSZ8995MA_IAC1, vg->es_vlangroup);
  699         }
  700 
  701         return (0);
  702 }
  703 
  704 static int
  705 ksz8995ma_getconf(device_t dev, etherswitch_conf_t *conf)
  706 {
  707         struct ksz8995ma_softc *sc;
  708 
  709         sc = device_get_softc(dev);
  710 
  711         /* Return the VLAN mode. */
  712         conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
  713         conf->vlan_mode = sc->vlan_mode;
  714 
  715         return (0);
  716 }
  717 
  718 static void 
  719 ksz8995ma_portvlanreset(device_t dev)
  720 {
  721         int i, data;
  722         struct ksz8995ma_softc *sc;
  723 
  724         sc = device_get_softc(dev);
  725 
  726         for (i = 0; i < sc->numports; ++i) {
  727                 data = ksz8995ma_readreg(dev, KSZ8995MA_PC1_BASE +
  728                     KSZ8995MA_PORT_SIZE * i);
  729                 ksz8995ma_writereg(dev, KSZ8995MA_PC1_BASE +
  730                     KSZ8995MA_PORT_SIZE * i, (data & 0xe0) | 0x1f);
  731         }
  732 }
  733 
  734 static int
  735 ksz8995ma_setconf(device_t dev, etherswitch_conf_t *conf)
  736 {
  737         int reg;
  738         struct ksz8995ma_softc *sc;
  739 
  740         sc = device_get_softc(dev);
  741 
  742         if ((conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) == 0)
  743                 return (0);
  744 
  745         if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) {
  746                 sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
  747                 reg = ksz8995ma_readreg(dev, KSZ8995MA_GC3);
  748                 ksz8995ma_writereg(dev, KSZ8995MA_GC3, 
  749                     reg & ~KSZ8995MA_VLAN_ENABLE);
  750                 ksz8995ma_portvlanreset(dev);
  751         } else if (conf->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
  752                 sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
  753                 reg = ksz8995ma_readreg(dev, KSZ8995MA_GC3);
  754                 ksz8995ma_writereg(dev, KSZ8995MA_GC3, 
  755                     reg | KSZ8995MA_VLAN_ENABLE);
  756         } else {
  757                 sc->vlan_mode = 0;
  758                 reg = ksz8995ma_readreg(dev, KSZ8995MA_GC3);
  759                 ksz8995ma_writereg(dev, KSZ8995MA_GC3, 
  760                     reg & ~KSZ8995MA_VLAN_ENABLE);
  761                 ksz8995ma_portvlanreset(dev);
  762         }
  763         return (0);
  764 }
  765 
  766 static void
  767 ksz8995ma_statchg(device_t dev)
  768 {
  769 
  770         DPRINTF(dev, "%s\n", __func__);
  771 }
  772 
  773 static int
  774 ksz8995ma_ifmedia_upd(if_t ifp)
  775 {
  776         struct ksz8995ma_softc *sc;
  777         struct mii_data *mii;
  778 
  779         sc = if_getsoftc(ifp);
  780         mii = ksz8995ma_miiforport(sc, ifp->if_dunit); /* XXX - DRVAPI */
  781 
  782         DPRINTF(sc->sc_dev, "%s\n", __func__);
  783         if (mii == NULL)
  784                 return (ENXIO);
  785         mii_mediachg(mii);
  786         return (0);
  787 }
  788 
  789 static void
  790 ksz8995ma_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
  791 {
  792         struct ksz8995ma_softc *sc;
  793         struct mii_data *mii;
  794 
  795         sc = if_getsoftc(ifp);
  796         mii = ksz8995ma_miiforport(sc, ifp->if_dunit); /* XXX - DRVAPI */
  797 
  798         DPRINTF(sc->sc_dev, "%s\n", __func__);
  799 
  800         if (mii == NULL)
  801                 return;
  802         mii_pollstat(mii);
  803         ifmr->ifm_active = mii->mii_media_active;
  804         ifmr->ifm_status = mii->mii_media_status;
  805 }
  806 
  807 static int
  808 ksz8995ma_readphy(device_t dev, int phy, int reg)
  809 {
  810 int portreg;
  811 
  812         /* 
  813          * This is no mdio/mdc connection code.
  814          * simulate MIIM Registers via the SPI interface
  815          */
  816         if (reg == MII_BMSR) {
  817                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PS0_BASE + 
  818                         KSZ8995MA_PORT_SIZE * phy);
  819                 return (KSZ8995MA_MII_STAT | 
  820                     (portreg & 0x20 ? BMSR_LINK : 0x00) |
  821                     (portreg & 0x40 ? BMSR_ACOMP : 0x00));
  822         } else if (reg == MII_PHYIDR1) {
  823                 return (KSZ8995MA_MII_PHYID_H);
  824         } else if (reg == MII_PHYIDR2) {
  825                 return (KSZ8995MA_MII_PHYID_L);
  826         } else if (reg == MII_ANAR) {
  827                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PC12_BASE + 
  828                         KSZ8995MA_PORT_SIZE * phy);
  829                 return (KSZ8995MA_MII_AA | (portreg & 0x0f) << 5);
  830         } else if (reg == MII_ANLPAR) {
  831                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PS0_BASE + 
  832                         KSZ8995MA_PORT_SIZE * phy);
  833                 return (((portreg & 0x0f) << 5) | 0x01);
  834         }
  835 
  836         return (0);
  837 }
  838 
  839 static int
  840 ksz8995ma_writephy(device_t dev, int phy, int reg, int data)
  841 {
  842 int portreg;
  843 
  844         /* 
  845          * This is no mdio/mdc connection code.
  846          * simulate MIIM Registers via the SPI interface
  847          */
  848         if (reg == MII_BMCR) {
  849                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PC13_BASE + 
  850                         KSZ8995MA_PORT_SIZE * phy);
  851                 if (data & BMCR_PDOWN)
  852                         portreg |= KSZ8995MA_PDOWN;
  853                 else
  854                         portreg &= ~KSZ8995MA_PDOWN;
  855                 if (data & BMCR_STARTNEG)
  856                         portreg |= KSZ8995MA_STARTNEG;
  857                 else
  858                         portreg &= ~KSZ8995MA_STARTNEG;
  859                 ksz8995ma_writereg(dev, KSZ8995MA_PC13_BASE + 
  860                         KSZ8995MA_PORT_SIZE * phy, portreg);
  861         } else if (reg == MII_ANAR) {
  862                 portreg = ksz8995ma_readreg(dev, KSZ8995MA_PC12_BASE + 
  863                         KSZ8995MA_PORT_SIZE * phy);
  864                 portreg &= 0xf;
  865                 portreg |= ((data >> 5) & 0x0f);
  866                 ksz8995ma_writereg(dev, KSZ8995MA_PC12_BASE + 
  867                         KSZ8995MA_PORT_SIZE * phy, portreg);
  868         }
  869         return (0);
  870 }
  871 
  872 static int
  873 ksz8995ma_readreg(device_t dev, int addr)
  874 {
  875         uint8_t txBuf[8], rxBuf[8];
  876         struct spi_command cmd;
  877         int err;
  878 
  879         memset(&cmd, 0, sizeof(cmd));
  880         memset(txBuf, 0, sizeof(txBuf));
  881         memset(rxBuf, 0, sizeof(rxBuf));
  882 
  883         /* read spi */
  884         txBuf[0] = KSZ8995MA_SPI_READ;
  885         txBuf[1] = addr;
  886         cmd.tx_cmd = &txBuf;
  887         cmd.rx_cmd = &rxBuf;
  888         cmd.tx_cmd_sz = 3;
  889         cmd.rx_cmd_sz = 3;
  890         err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd);
  891         if (err)
  892                 return(0);
  893 
  894         return (rxBuf[2]);
  895 }
  896 
  897 static int
  898 ksz8995ma_writereg(device_t dev, int addr, int value)
  899 {
  900         uint8_t txBuf[8], rxBuf[8];
  901         struct spi_command cmd;
  902         int err;
  903 
  904         memset(&cmd, 0, sizeof(cmd));
  905         memset(txBuf, 0, sizeof(txBuf));
  906         memset(rxBuf, 0, sizeof(rxBuf));
  907 
  908         /* write spi */
  909         txBuf[0] = KSZ8995MA_SPI_WRITE;
  910         txBuf[1] = addr;
  911         txBuf[2] = value;
  912         cmd.tx_cmd = &txBuf;
  913         cmd.rx_cmd = &rxBuf;
  914         cmd.tx_cmd_sz = 3;
  915         cmd.rx_cmd_sz = 3;
  916         err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd);
  917         if (err)
  918                 return(0);
  919 
  920         return (0);
  921 }
  922 
  923 static device_method_t ksz8995ma_methods[] = {
  924         /* Device interface */
  925         DEVMETHOD(device_probe,                 ksz8995ma_probe),
  926         DEVMETHOD(device_attach,                ksz8995ma_attach),
  927         DEVMETHOD(device_detach,                ksz8995ma_detach),
  928         
  929         /* bus interface */
  930         DEVMETHOD(bus_add_child,                device_add_child_ordered),
  931         
  932         /* MII interface */
  933         DEVMETHOD(miibus_readreg,               ksz8995ma_readphy),
  934         DEVMETHOD(miibus_writereg,              ksz8995ma_writephy),
  935         DEVMETHOD(miibus_statchg,               ksz8995ma_statchg),
  936 
  937         /* etherswitch interface */
  938         DEVMETHOD(etherswitch_lock,             ksz8995ma_lock),
  939         DEVMETHOD(etherswitch_unlock,           ksz8995ma_unlock),
  940         DEVMETHOD(etherswitch_getinfo,          ksz8995ma_getinfo),
  941         DEVMETHOD(etherswitch_readreg,          ksz8995ma_readreg),
  942         DEVMETHOD(etherswitch_writereg,         ksz8995ma_writereg),
  943         DEVMETHOD(etherswitch_readphyreg,       ksz8995ma_readphy),
  944         DEVMETHOD(etherswitch_writephyreg,      ksz8995ma_writephy),
  945         DEVMETHOD(etherswitch_getport,          ksz8995ma_getport),
  946         DEVMETHOD(etherswitch_setport,          ksz8995ma_setport),
  947         DEVMETHOD(etherswitch_getvgroup,        ksz8995ma_getvgroup),
  948         DEVMETHOD(etherswitch_setvgroup,        ksz8995ma_setvgroup),
  949         DEVMETHOD(etherswitch_setconf,          ksz8995ma_setconf),
  950         DEVMETHOD(etherswitch_getconf,          ksz8995ma_getconf),
  951 
  952         DEVMETHOD_END
  953 };
  954 
  955 DEFINE_CLASS_0(ksz8995ma, ksz8995ma_driver, ksz8995ma_methods,
  956     sizeof(struct ksz8995ma_softc));
  957 
  958 DRIVER_MODULE(ksz8995ma, spibus, ksz8995ma_driver, 0, 0);
  959 DRIVER_MODULE(miibus, ksz8995ma, miibus_driver, 0, 0);
  960 DRIVER_MODULE(etherswitch, ksz8995ma, etherswitch_driver, 0, 0);
  961 MODULE_VERSION(ksz8995ma, 1);
  962 MODULE_DEPEND(ksz8995ma, spibus, 1, 1, 1); /* XXX which versions? */
  963 MODULE_DEPEND(ksz8995ma, miibus, 1, 1, 1); /* XXX which versions? */
  964 MODULE_DEPEND(ksz8995ma, etherswitch, 1, 1, 1); /* XXX which versions? */

Cache object: e9981b235bc8d36fd5edcc3af308d8e2


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