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/felix/felix.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) 2021 Alstom Group.
    5  * Copyright (c) 2021 Semihalf.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/bus.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/socket.h>
   37 #include <sys/sockio.h>
   38 #include <sys/sysctl.h>
   39 #include <sys/rman.h>
   40 
   41 #include <machine/bus.h>
   42 #include <machine/resource.h>
   43 
   44 #include <net/if.h>
   45 #include <net/if_media.h>
   46 #include <net/if_types.h>
   47 
   48 #include <dev/enetc/enetc_mdio.h>
   49 
   50 #include <dev/etherswitch/etherswitch.h>
   51 #include <dev/mii/mii.h>
   52 #include <dev/mii/miivar.h>
   53 #include <dev/pci/pcireg.h>
   54 #include <dev/pci/pcivar.h>
   55 
   56 #include <dev/ofw/ofw_bus.h>
   57 #include <dev/ofw/ofw_bus_subr.h>
   58 
   59 #include <dev/etherswitch/felix/felix_var.h>
   60 #include <dev/etherswitch/felix/felix_reg.h>
   61 
   62 #include "etherswitch_if.h"
   63 #include "miibus_if.h"
   64 
   65 MALLOC_DECLARE(M_FELIX);
   66 MALLOC_DEFINE(M_FELIX, "felix", "felix switch");
   67 
   68 static device_probe_t felix_probe;
   69 static device_attach_t felix_attach;
   70 static device_detach_t felix_detach;
   71 
   72 static etherswitch_info_t* felix_getinfo(device_t);
   73 static int felix_getconf(device_t, etherswitch_conf_t *);
   74 static int felix_setconf(device_t, etherswitch_conf_t *);
   75 static void felix_lock(device_t);
   76 static void felix_unlock(device_t);
   77 static int felix_getport(device_t, etherswitch_port_t *);
   78 static int felix_setport(device_t, etherswitch_port_t *);
   79 static int felix_readreg_wrapper(device_t, int);
   80 static int felix_writereg_wrapper(device_t, int, int);
   81 static int felix_readphy(device_t, int, int);
   82 static int felix_writephy(device_t, int, int, int);
   83 static int felix_setvgroup(device_t, etherswitch_vlangroup_t *);
   84 static int felix_getvgroup(device_t, etherswitch_vlangroup_t *);
   85 
   86 static int felix_parse_port_fdt(felix_softc_t, phandle_t, int *);
   87 static int felix_setup(felix_softc_t);
   88 static void felix_setup_port(felix_softc_t, int);
   89 
   90 static void felix_tick(void *);
   91 static int felix_ifmedia_upd(if_t );
   92 static void felix_ifmedia_sts(if_t , struct ifmediareq *);
   93 
   94 static void felix_get_port_cfg(felix_softc_t, etherswitch_port_t *);
   95 static void felix_set_port_cfg(felix_softc_t, etherswitch_port_t *);
   96 
   97 static bool felix_is_phyport(felix_softc_t, int);
   98 static struct mii_data *felix_miiforport(felix_softc_t, unsigned int);
   99 
  100 static struct felix_pci_id felix_pci_ids[] = {
  101         {PCI_VENDOR_FREESCALE, FELIX_DEV_ID, FELIX_DEV_NAME},
  102         {0, 0, NULL}
  103 };
  104 
  105 static device_method_t felix_methods[] = {
  106         /* device interface */
  107         DEVMETHOD(device_probe,                 felix_probe),
  108         DEVMETHOD(device_attach,                felix_attach),
  109         DEVMETHOD(device_detach,                felix_detach),
  110 
  111         /* bus interface */
  112         DEVMETHOD(bus_add_child,                device_add_child_ordered),
  113         DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
  114         DEVMETHOD(bus_teardown_intr,            bus_generic_teardown_intr),
  115         DEVMETHOD(bus_release_resource,         bus_generic_release_resource),
  116         DEVMETHOD(bus_activate_resource,        bus_generic_activate_resource),
  117         DEVMETHOD(bus_deactivate_resource,      bus_generic_deactivate_resource),
  118         DEVMETHOD(bus_adjust_resource,          bus_generic_adjust_resource),
  119         DEVMETHOD(bus_alloc_resource,           bus_generic_alloc_resource),
  120 
  121         /* etherswitch interface */
  122         DEVMETHOD(etherswitch_getinfo,          felix_getinfo),
  123         DEVMETHOD(etherswitch_getconf,          felix_getconf),
  124         DEVMETHOD(etherswitch_setconf,          felix_setconf),
  125         DEVMETHOD(etherswitch_lock,             felix_lock),
  126         DEVMETHOD(etherswitch_unlock,           felix_unlock),
  127         DEVMETHOD(etherswitch_getport,          felix_getport),
  128         DEVMETHOD(etherswitch_setport,          felix_setport),
  129         DEVMETHOD(etherswitch_readreg,          felix_readreg_wrapper),
  130         DEVMETHOD(etherswitch_writereg,         felix_writereg_wrapper),
  131         DEVMETHOD(etherswitch_readphyreg,       felix_readphy),
  132         DEVMETHOD(etherswitch_writephyreg,      felix_writephy),
  133         DEVMETHOD(etherswitch_setvgroup,        felix_setvgroup),
  134         DEVMETHOD(etherswitch_getvgroup,        felix_getvgroup),
  135 
  136         /* miibus interface */
  137         DEVMETHOD(miibus_readreg,               felix_readphy),
  138         DEVMETHOD(miibus_writereg,              felix_writephy),
  139 
  140         DEVMETHOD_END
  141 };
  142 
  143 DEFINE_CLASS_0(felix, felix_driver, felix_methods,
  144     sizeof(struct felix_softc));
  145 
  146 DRIVER_MODULE_ORDERED(felix, pci, felix_driver, NULL, NULL, SI_ORDER_ANY);
  147 DRIVER_MODULE(miibus, felix, miibus_fdt_driver, NULL, NULL);
  148 DRIVER_MODULE(etherswitch, felix, etherswitch_driver, NULL, NULL);
  149 MODULE_VERSION(felix, 1);
  150 MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, felix,
  151     felix_pci_ids, nitems(felix_pci_ids) - 1);
  152 
  153 static int
  154 felix_probe(device_t dev)
  155 {
  156         struct felix_pci_id *id;
  157         felix_softc_t sc;
  158 
  159         sc = device_get_softc(dev);
  160         sc->dev = dev;
  161 
  162         for (id = felix_pci_ids; id->vendor != 0; ++id) {
  163                 if (pci_get_device(dev) != id->device ||
  164                     pci_get_vendor(dev) != id->vendor)
  165                         continue;
  166 
  167                 device_set_desc(dev, id->desc);
  168 
  169                 return (BUS_PROBE_DEFAULT);
  170         }
  171 
  172         return (ENXIO);
  173 }
  174 
  175 static int
  176 felix_parse_port_fdt(felix_softc_t sc, phandle_t child, int *pport)
  177 {
  178         uint32_t port, status;
  179         phandle_t node;
  180 
  181         if (OF_getencprop(child, "reg", (void *)&port, sizeof(port)) < 0) {
  182                 device_printf(sc->dev, "Port node doesn't have reg property\n");
  183                 return (ENXIO);
  184         }
  185 
  186         *pport = port;
  187 
  188         node = OF_getproplen(child, "ethernet");
  189         if (node <= 0)
  190                 sc->ports[port].cpu_port = false;
  191         else
  192                 sc->ports[port].cpu_port = true;
  193 
  194         node = ofw_bus_find_child(child, "fixed-link");
  195         if (node <= 0) {
  196                 sc->ports[port].fixed_port = false;
  197                 return (0);
  198         }
  199 
  200         sc->ports[port].fixed_port = true;
  201 
  202         if (OF_getencprop(node, "speed", &status, sizeof(status)) <= 0) {
  203                 device_printf(sc->dev,
  204                     "Port has fixed-link node without link speed specified\n");
  205                 return (ENXIO);
  206         }
  207 
  208         switch (status) {
  209         case 2500:
  210                 status = IFM_2500_T;
  211                 break;
  212         case 1000:
  213                 status = IFM_1000_T;
  214                 break;
  215         case 100:
  216                 status = IFM_100_T;
  217                 break;
  218         case 10:
  219                 status = IFM_10_T;
  220                 break;
  221         default:
  222                 device_printf(sc->dev,
  223                     "Unsupported link speed value of %d\n",
  224                     status);
  225                 return (ENXIO);
  226         }
  227 
  228         if (OF_hasprop(node, "full-duplex"))
  229                 status |= IFM_FDX;
  230         else
  231                 status |= IFM_HDX;
  232 
  233         status |= IFM_ETHER;
  234         sc->ports[port].fixed_link_status = status;
  235         return (0);
  236 }
  237 
  238 static int
  239 felix_init_interface(felix_softc_t sc, int port)
  240 {
  241         char name[IFNAMSIZ];
  242 
  243         snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->dev));
  244 
  245         sc->ports[port].ifp = if_alloc(IFT_ETHER);
  246         if (sc->ports[port].ifp == NULL)
  247                 return (ENOMEM);
  248 
  249         if_setsoftc(sc->ports[port].ifp, sc);
  250         if_setflags(sc->ports[port].ifp, IFF_UP | IFF_BROADCAST | IFF_MULTICAST |
  251             IFF_DRV_RUNNING | IFF_SIMPLEX);
  252         sc->ports[port].ifname = malloc(strlen(name) + 1, M_FELIX, M_NOWAIT);
  253         if (sc->ports[port].ifname == NULL) {
  254                 if_free(sc->ports[port].ifp);
  255                 return (ENOMEM);
  256         }
  257 
  258         memcpy(sc->ports[port].ifname, name, strlen(name) + 1);
  259         if_initname(sc->ports[port].ifp, sc->ports[port].ifname, port);
  260         return (0);
  261 }
  262 
  263 static void
  264 felix_setup_port(felix_softc_t sc, int port)
  265 {
  266 
  267         /* Link speed has to be always set to 1000 in the clock register. */
  268         FELIX_DEVGMII_PORT_WR4(sc, port, FELIX_DEVGMII_CLK_CFG,
  269             FELIX_DEVGMII_CLK_CFG_SPEED_1000);
  270         FELIX_DEVGMII_PORT_WR4(sc, port, FELIX_DEVGMII_MAC_CFG,
  271             FELIX_DEVGMII_MAC_CFG_TX_ENA | FELIX_DEVGMII_MAC_CFG_RX_ENA);
  272         FELIX_WR4(sc, FELIX_QSYS_PORT_MODE(port),
  273             FELIX_QSYS_PORT_MODE_PORT_ENA);
  274 
  275         /*
  276          * Enable "VLANMTU". Each port has a configurable MTU.
  277          * Accept frames that are 8 and 4 bytes longer than it
  278          * for double and single tagged frames respectively.
  279          * Since etherswitch API doesn't provide an option to change
  280          * MTU don't touch it for now.
  281          */
  282         FELIX_DEVGMII_PORT_WR4(sc, port, FELIX_DEVGMII_VLAN_CFG,
  283             FELIX_DEVGMII_VLAN_CFG_ENA |
  284             FELIX_DEVGMII_VLAN_CFG_LEN_ENA |
  285             FELIX_DEVGMII_VLAN_CFG_DOUBLE_ENA);
  286 }
  287 
  288 static int
  289 felix_setup(felix_softc_t sc)
  290 {
  291         int timeout, i;
  292         uint32_t reg;
  293 
  294         /* Trigger soft reset, bit is self-clearing, with 5s timeout. */
  295         FELIX_WR4(sc, FELIX_DEVCPU_GCB_RST, FELIX_DEVCPU_GCB_RST_EN);
  296         timeout = FELIX_INIT_TIMEOUT;
  297         do {
  298                 DELAY(1000);
  299                 reg = FELIX_RD4(sc, FELIX_DEVCPU_GCB_RST);
  300                 if ((reg & FELIX_DEVCPU_GCB_RST_EN) == 0)
  301                         break;
  302         } while (timeout-- > 0);
  303         if (timeout == 0) {
  304                 device_printf(sc->dev,
  305                     "Timeout while waiting for switch to reset\n");
  306                 return (ETIMEDOUT);
  307         }
  308 
  309         FELIX_WR4(sc, FELIX_SYS_RAM_CTRL, FELIX_SYS_RAM_CTRL_INIT);
  310         timeout = FELIX_INIT_TIMEOUT;
  311         do {
  312                 DELAY(1000);
  313                 reg = FELIX_RD4(sc, FELIX_SYS_RAM_CTRL);
  314                 if ((reg & FELIX_SYS_RAM_CTRL_INIT) == 0)
  315                         break;
  316         } while (timeout-- > 0);
  317         if (timeout == 0) {
  318                 device_printf(sc->dev,
  319                     "Timeout while waiting for switch RAM init.\n");
  320                 return (ETIMEDOUT);
  321         }
  322 
  323         FELIX_WR4(sc, FELIX_SYS_CFG, FELIX_SYS_CFG_CORE_EN);
  324 
  325         for (i = 0; i < sc->info.es_nports; i++)
  326                 felix_setup_port(sc, i);
  327 
  328         return (0);
  329 }
  330 
  331 static int
  332 felix_timer_rate(SYSCTL_HANDLER_ARGS)
  333 {
  334         felix_softc_t sc;
  335         int error, value, old;
  336 
  337         sc = arg1;
  338 
  339         old = value = sc->timer_ticks;
  340         error = sysctl_handle_int(oidp, &value, 0, req);
  341         if (error != 0 || req->newptr == NULL)
  342                 return (error);
  343 
  344         if (value < 0)
  345                 return (EINVAL);
  346 
  347         if (value == old)
  348                 return (0);
  349 
  350         FELIX_LOCK(sc);
  351         sc->timer_ticks = value;
  352         callout_reset(&sc->tick_callout, sc->timer_ticks, felix_tick, sc);
  353         FELIX_UNLOCK(sc);
  354 
  355         return (0);
  356 }
  357 
  358 static int
  359 felix_attach(device_t dev)
  360 {
  361         phandle_t child, ports, node;
  362         int error, port, rid;
  363         felix_softc_t sc;
  364         uint32_t phy_addr;
  365         ssize_t size;
  366 
  367         sc = device_get_softc(dev);
  368         sc->info.es_nports = 0;
  369         sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q;
  370         strlcpy(sc->info.es_name, "Felix TSN Switch", sizeof(sc->info.es_name));
  371 
  372         rid = PCIR_BAR(FELIX_BAR_MDIO);
  373         sc->mdio = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  374             RF_ACTIVE);
  375         if (sc->mdio == NULL) {
  376                 device_printf(dev, "Failed to allocate MDIO registers.\n");
  377                 return (ENXIO);
  378         }
  379 
  380         rid = PCIR_BAR(FELIX_BAR_REGS);
  381         sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  382             RF_ACTIVE);
  383         if (sc->regs == NULL) {
  384                 device_printf(dev, "Failed to allocate registers BAR.\n");
  385                 error = ENXIO;
  386                 goto out_fail;
  387         }
  388 
  389         mtx_init(&sc->mtx, "felix lock",  NULL, MTX_DEF);
  390         callout_init_mtx(&sc->tick_callout, &sc->mtx, 0);
  391 
  392         node = ofw_bus_get_node(dev);
  393         if (node <= 0) {
  394                 error = ENXIO;
  395                 goto out_fail;
  396         }
  397 
  398         ports = ofw_bus_find_child(node, "ports");
  399         if (ports == 0) {
  400                 device_printf(dev,
  401                     "Failed to find \"ports\" property in DTS.\n");
  402                 error = ENXIO;
  403                 goto out_fail;
  404         }
  405 
  406         for (child = OF_child(ports); child != 0; child = OF_peer(child)) {
  407                 /* Do not parse disabled ports. */
  408                 if (ofw_bus_node_status_okay(child) == 0)
  409                         continue;
  410 
  411                 error = felix_parse_port_fdt(sc, child, &port);
  412                 if (error != 0)
  413                         goto out_fail;
  414 
  415                 error = felix_init_interface(sc, port);
  416                 if (error != 0) {
  417                         device_printf(sc->dev,
  418                             "Failed to initialize interface.\n");
  419                         goto out_fail;
  420                 }
  421 
  422                 if (sc->ports[port].fixed_port) {
  423                         sc->info.es_nports++;
  424                         continue;
  425                 }
  426 
  427                 size = OF_getencprop(child, "phy-handle", &node, sizeof(node));
  428                 if (size <= 0) {
  429                         device_printf(sc->dev,
  430                             "Failed to acquire PHY handle from FDT.\n");
  431                         error = ENXIO;
  432                         goto out_fail;
  433                 }
  434 
  435                 node = OF_node_from_xref(node);
  436                 size = OF_getencprop(node, "reg", &phy_addr, sizeof(phy_addr));
  437                 if (size <= 0) {
  438                         device_printf(sc->dev,
  439                             "Failed to obtain PHY address.\n");
  440                         error = ENXIO;
  441                         goto out_fail;
  442                 }
  443 
  444                 sc->ports[port].phyaddr = phy_addr;
  445                 sc->ports[port].miibus = NULL;
  446                 error = mii_attach(dev, &sc->ports[port].miibus, sc->ports[port].ifp,
  447                     felix_ifmedia_upd, felix_ifmedia_sts, BMSR_DEFCAPMASK,
  448                     phy_addr, MII_OFFSET_ANY, 0);
  449                 if (error != 0)
  450                         goto out_fail;
  451 
  452                 sc->info.es_nports++;
  453         }
  454 
  455         error = felix_setup(sc);
  456         if (error != 0)
  457                 goto out_fail;
  458 
  459         sc->timer_ticks = hz;   /* Default to 1s. */
  460         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  461             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  462             OID_AUTO, "timer_ticks", CTLTYPE_INT | CTLFLAG_RW,
  463             sc, 0, felix_timer_rate, "I",
  464             "Number of ticks between timer invocations");
  465 
  466         /* The tick routine has to be called with the lock held. */
  467         FELIX_LOCK(sc);
  468         felix_tick(sc);
  469         FELIX_UNLOCK(sc);
  470 
  471         /* Allow etherswitch to attach as our child. */
  472         bus_generic_probe(dev);
  473         bus_generic_attach(dev);
  474 
  475         return (0);
  476 
  477 out_fail:
  478         felix_detach(dev);
  479         return (error);
  480 }
  481 
  482 static int
  483 felix_detach(device_t dev)
  484 {
  485         felix_softc_t sc;
  486         int error;
  487         int i;
  488 
  489         error = 0;
  490         sc = device_get_softc(dev);
  491         bus_generic_detach(dev);
  492 
  493         mtx_lock(&sc->mtx);
  494         callout_stop(&sc->tick_callout);
  495         mtx_unlock(&sc->mtx);
  496         mtx_destroy(&sc->mtx);
  497 
  498         /*
  499          * If we have been fully attached do a soft reset.
  500          * This way after when driver is unloaded switch is left in unmanaged mode.
  501          */
  502         if (device_is_attached(dev))
  503                 felix_setup(sc);
  504 
  505         for (i = 0; i < sc->info.es_nports; i++) {
  506                 if (sc->ports[i].miibus != NULL)
  507                         device_delete_child(dev, sc->ports[i].miibus);
  508                 if (sc->ports[i].ifp != NULL)
  509                         if_free(sc->ports[i].ifp);
  510                 if (sc->ports[i].ifname != NULL)
  511                         free(sc->ports[i].ifname, M_FELIX);
  512         }
  513 
  514         if (sc->regs != NULL)
  515                 error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
  516                     rman_get_rid(sc->regs), sc->regs);
  517 
  518         if (sc->mdio != NULL)
  519                 error = bus_release_resource(sc->dev, SYS_RES_MEMORY,
  520                     rman_get_rid(sc->mdio), sc->mdio);
  521 
  522         return (error);
  523 }
  524 
  525 static etherswitch_info_t*
  526 felix_getinfo(device_t dev)
  527 {
  528         felix_softc_t sc;
  529 
  530         sc = device_get_softc(dev);
  531         return (&sc->info);
  532 }
  533 
  534 static int
  535 felix_getconf(device_t dev, etherswitch_conf_t *conf)
  536 {
  537         felix_softc_t sc;
  538 
  539         sc = device_get_softc(dev);
  540 
  541         /* Return the VLAN mode. */
  542         conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
  543         conf->vlan_mode = sc->vlan_mode;
  544         return (0);
  545 }
  546 
  547 static int
  548 felix_init_vlan(felix_softc_t sc)
  549 {
  550         int timeout = FELIX_INIT_TIMEOUT;
  551         uint32_t reg;
  552         int i;
  553 
  554         /* Flush VLAN table in hardware. */
  555         FELIX_WR4(sc, FELIX_ANA_VT, FELIX_ANA_VT_RESET);
  556         do {
  557                 DELAY(1000);
  558                 reg = FELIX_RD4(sc, FELIX_ANA_VT);
  559                 if ((reg & FELIX_ANA_VT_STS) == FELIX_ANA_VT_IDLE)
  560                         break;
  561         } while (timeout-- > 0);
  562         if (timeout == 0) {
  563                 device_printf(sc->dev,
  564                     "Timeout during VLAN table reset.\n");
  565                 return (ETIMEDOUT);
  566         }
  567 
  568         /* Flush VLAN table in sc. */
  569         for (i = 0; i < sc->info.es_nvlangroups; i++)
  570                 sc->vlans[i] = 0;
  571 
  572         /*
  573          * Make all ports VLAN aware.
  574          * Read VID from incoming frames and use it for port grouping
  575          * purposes.
  576          * Don't set this if pvid is set.
  577          */
  578         for (i = 0; i < sc->info.es_nports; i++) {
  579                 reg = FELIX_ANA_PORT_RD4(sc, i, FELIX_ANA_PORT_VLAN_CFG);
  580                 if ((reg & FELIX_ANA_PORT_VLAN_CFG_VID_MASK) != 0)
  581                         continue;
  582 
  583                 reg |= FELIX_ANA_PORT_VLAN_CFG_VID_AWARE;
  584                 FELIX_ANA_PORT_WR4(sc, i, FELIX_ANA_PORT_VLAN_CFG, reg);
  585         }
  586         return (0);
  587 }
  588 
  589 static int
  590 felix_setconf(device_t dev, etherswitch_conf_t *conf)
  591 {
  592         felix_softc_t sc;
  593         int error;
  594 
  595         error = 0;
  596         /* Set the VLAN mode. */
  597         sc = device_get_softc(dev);
  598         FELIX_LOCK(sc);
  599         if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) {
  600                 switch (conf->vlan_mode) {
  601                 case ETHERSWITCH_VLAN_DOT1Q:
  602                         sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
  603                         sc->info.es_nvlangroups = FELIX_NUM_VLANS;
  604                         error = felix_init_vlan(sc);
  605                         break;
  606                 default:
  607                         error = EINVAL;
  608                 }
  609         }
  610         FELIX_UNLOCK(sc);
  611         return (error);
  612 }
  613 
  614 static void
  615 felix_lock(device_t dev)
  616 {
  617         felix_softc_t sc;
  618 
  619         sc = device_get_softc(dev);
  620         FELIX_LOCK_ASSERT(sc, MA_NOTOWNED);
  621         FELIX_LOCK(sc);
  622 }
  623 
  624 static void
  625 felix_unlock(device_t dev)
  626 {
  627         felix_softc_t sc;
  628 
  629         sc = device_get_softc(dev);
  630         FELIX_LOCK_ASSERT(sc, MA_OWNED);
  631         FELIX_UNLOCK(sc);
  632 }
  633 
  634 static void
  635 felix_get_port_cfg(felix_softc_t sc, etherswitch_port_t *p)
  636 {
  637         uint32_t reg;
  638 
  639         p->es_flags = 0;
  640 
  641         reg = FELIX_ANA_PORT_RD4(sc, p->es_port, FELIX_ANA_PORT_DROP_CFG);
  642         if (reg & FELIX_ANA_PORT_DROP_CFG_TAGGED)
  643                 p->es_flags |= ETHERSWITCH_PORT_DROPTAGGED;
  644 
  645         if (reg & FELIX_ANA_PORT_DROP_CFG_UNTAGGED)
  646                 p->es_flags |= ETHERSWITCH_PORT_DROPUNTAGGED;
  647 
  648         reg = FELIX_DEVGMII_PORT_RD4(sc, p->es_port, FELIX_DEVGMII_VLAN_CFG);
  649         if (reg & FELIX_DEVGMII_VLAN_CFG_DOUBLE_ENA)
  650                 p->es_flags |= ETHERSWITCH_PORT_DOUBLE_TAG;
  651 
  652         reg = FELIX_REW_PORT_RD4(sc, p->es_port, FELIX_REW_PORT_TAG_CFG);
  653         if (reg & FELIX_REW_PORT_TAG_CFG_ALL)
  654                 p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
  655 
  656         reg = FELIX_ANA_PORT_RD4(sc, p->es_port, FELIX_ANA_PORT_VLAN_CFG);
  657         if (reg & FELIX_ANA_PORT_VLAN_CFG_POP)
  658                 p->es_flags |= ETHERSWITCH_PORT_STRIPTAGINGRESS;
  659 
  660         p->es_pvid = reg & FELIX_ANA_PORT_VLAN_CFG_VID_MASK;
  661 }
  662 
  663 static int
  664 felix_getport(device_t dev, etherswitch_port_t *p)
  665 {
  666         struct ifmediareq *ifmr;
  667         struct mii_data *mii;
  668         felix_softc_t sc;
  669         int error;
  670 
  671         error = 0;
  672         sc = device_get_softc(dev);
  673         FELIX_LOCK_ASSERT(sc, MA_NOTOWNED);
  674 
  675         if (p->es_port >= sc->info.es_nports || p->es_port < 0)
  676                 return (EINVAL);
  677 
  678         FELIX_LOCK(sc);
  679         felix_get_port_cfg(sc, p);
  680         if (sc->ports[p->es_port].fixed_port) {
  681                 ifmr = &p->es_ifmr;
  682                 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
  683                 ifmr->ifm_count = 0;
  684                 ifmr->ifm_active = sc->ports[p->es_port].fixed_link_status;
  685                 ifmr->ifm_current = ifmr->ifm_active;
  686                 ifmr->ifm_mask = 0;
  687         } else {
  688                 mii = felix_miiforport(sc, p->es_port);
  689                 error = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
  690                     &mii->mii_media, SIOCGIFMEDIA);
  691         }
  692         FELIX_UNLOCK(sc);
  693         return (error);
  694 }
  695 
  696 static void
  697 felix_set_port_cfg(felix_softc_t sc, etherswitch_port_t *p)
  698 {
  699         uint32_t reg;
  700 
  701         reg = FELIX_ANA_PORT_RD4(sc, p->es_port, FELIX_ANA_PORT_DROP_CFG);
  702         if (p->es_flags & ETHERSWITCH_PORT_DROPTAGGED)
  703                 reg |= FELIX_ANA_PORT_DROP_CFG_TAGGED;
  704         else
  705                 reg &= ~FELIX_ANA_PORT_DROP_CFG_TAGGED;
  706 
  707         if (p->es_flags & ETHERSWITCH_PORT_DROPUNTAGGED)
  708                 reg |= FELIX_ANA_PORT_DROP_CFG_UNTAGGED;
  709         else
  710                 reg &= ~FELIX_ANA_PORT_DROP_CFG_UNTAGGED;
  711 
  712         FELIX_ANA_PORT_WR4(sc, p->es_port, FELIX_ANA_PORT_DROP_CFG, reg);
  713 
  714         reg = FELIX_REW_PORT_RD4(sc, p->es_port, FELIX_REW_PORT_TAG_CFG);
  715         if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
  716                 reg |= FELIX_REW_PORT_TAG_CFG_ALL;
  717         else
  718                 reg &= ~FELIX_REW_PORT_TAG_CFG_ALL;
  719 
  720         FELIX_REW_PORT_WR4(sc, p->es_port, FELIX_REW_PORT_TAG_CFG, reg);
  721 
  722         reg = FELIX_ANA_PORT_RD4(sc, p->es_port, FELIX_ANA_PORT_VLAN_CFG);
  723         if (p->es_flags & ETHERSWITCH_PORT_STRIPTAGINGRESS)
  724                 reg |= FELIX_ANA_PORT_VLAN_CFG_POP;
  725         else
  726                 reg &= ~FELIX_ANA_PORT_VLAN_CFG_POP;
  727 
  728         reg &= ~FELIX_ANA_PORT_VLAN_CFG_VID_MASK;
  729         reg |= p->es_pvid & FELIX_ANA_PORT_VLAN_CFG_VID_MASK;
  730         /*
  731          * If port VID is set use it for VLAN classification,
  732          * instead of frame VID.
  733          * By default the frame tag takes precedence.
  734          * Force the switch to ignore it.
  735          */
  736         if (p->es_pvid != 0)
  737                 reg &= ~FELIX_ANA_PORT_VLAN_CFG_VID_AWARE;
  738         else
  739                 reg |= FELIX_ANA_PORT_VLAN_CFG_VID_AWARE;
  740 
  741         FELIX_ANA_PORT_WR4(sc, p->es_port, FELIX_ANA_PORT_VLAN_CFG, reg);
  742 }
  743 
  744 static int
  745 felix_setport(device_t dev, etherswitch_port_t *p)
  746 {
  747         felix_softc_t sc;
  748         struct mii_data *mii;
  749         int error;
  750 
  751         error = 0;
  752         sc = device_get_softc(dev);
  753         FELIX_LOCK_ASSERT(sc, MA_NOTOWNED);
  754 
  755         if (p->es_port >= sc->info.es_nports || p->es_port < 0)
  756                 return (EINVAL);
  757 
  758         FELIX_LOCK(sc);
  759         felix_set_port_cfg(sc, p);
  760         if (felix_is_phyport(sc, p->es_port)) {
  761                 mii = felix_miiforport(sc, p->es_port);
  762                 error = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media,
  763                     SIOCSIFMEDIA);
  764         }
  765         FELIX_UNLOCK(sc);
  766 
  767         return (error);
  768 }
  769 
  770 static int
  771 felix_readreg_wrapper(device_t dev, int addr_reg)
  772 {
  773         felix_softc_t sc;
  774 
  775         sc = device_get_softc(dev);
  776         if (addr_reg > rman_get_size(sc->regs))
  777                 return (UINT32_MAX);    /* Can't return errors here. */
  778 
  779         return (FELIX_RD4(sc, addr_reg));
  780 }
  781 
  782 static int
  783 felix_writereg_wrapper(device_t dev, int addr_reg, int val)
  784 {
  785         felix_softc_t sc;
  786 
  787         sc = device_get_softc(dev);
  788         if (addr_reg > rman_get_size(sc->regs))
  789                 return (EINVAL);
  790 
  791         FELIX_WR4(sc, addr_reg, val);
  792         return (0);
  793 }
  794 
  795 static int
  796 felix_readphy(device_t dev, int phy, int reg)
  797 {
  798         felix_softc_t sc;
  799 
  800         sc = device_get_softc(dev);
  801 
  802         return (enetc_mdio_read(sc->mdio, FELIX_MDIO_BASE, phy, reg));
  803 }
  804 
  805 static int
  806 felix_writephy(device_t dev, int phy, int reg, int data)
  807 {
  808         felix_softc_t sc;
  809 
  810         sc = device_get_softc(dev);
  811 
  812         return (enetc_mdio_write(sc->mdio, FELIX_MDIO_BASE, phy, reg, data));
  813 }
  814 
  815 static int
  816 felix_set_dot1q_vlan(felix_softc_t sc, etherswitch_vlangroup_t *vg)
  817 {
  818         uint32_t reg;
  819         int i, vid;
  820 
  821         vid = vg->es_vid & ETHERSWITCH_VID_MASK;
  822 
  823         /* Tagged mode is not supported. */
  824         if (vg->es_member_ports != vg->es_untagged_ports)
  825                 return (EINVAL);
  826 
  827         /*
  828          * Hardware support 4096 groups, but we can't do group_id == vid.
  829          * Note that hw_group_id == vid.
  830          */
  831         if (vid == 0) {
  832                 /* Clear VLAN table entry using old VID. */
  833                 FELIX_WR4(sc, FELIX_ANA_VTIDX, sc->vlans[vg->es_vlangroup]);
  834                 FELIX_WR4(sc, FELIX_ANA_VT, FELIX_ANA_VT_WRITE);
  835                 sc->vlans[vg->es_vlangroup] = 0;
  836                 return (0);
  837         }
  838 
  839         /* The VID is already used in a different group. */
  840         for (i = 0; i < sc->info.es_nvlangroups; i++)
  841                 if (i != vg->es_vlangroup && vid == sc->vlans[i])
  842                         return (EINVAL);
  843 
  844         /* This group already uses a different VID. */
  845         if (sc->vlans[vg->es_vlangroup] != 0 &&
  846             sc->vlans[vg->es_vlangroup] != vid)
  847                 return (EINVAL);
  848 
  849         sc->vlans[vg->es_vlangroup] = vid;
  850 
  851         /* Assign members to the given group. */
  852         reg = vg->es_member_ports & FELIX_ANA_VT_PORTMASK_MASK;
  853         reg <<= FELIX_ANA_VT_PORTMASK_SHIFT;
  854         reg |= FELIX_ANA_VT_WRITE;
  855 
  856         FELIX_WR4(sc, FELIX_ANA_VTIDX, vid);
  857         FELIX_WR4(sc, FELIX_ANA_VT, reg);
  858 
  859         /*
  860          * According to documentation read and write commands
  861          * are instant.
  862          * Add a small delay just to be safe.
  863          */
  864         mb();
  865         DELAY(100);
  866         reg = FELIX_RD4(sc, FELIX_ANA_VT);
  867         if ((reg & FELIX_ANA_VT_STS) != FELIX_ANA_VT_IDLE)
  868                 return (ENXIO);
  869 
  870         return (0);
  871 }
  872 
  873 static int
  874 felix_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
  875 {
  876         felix_softc_t sc;
  877         int error;
  878 
  879         sc = device_get_softc(dev);
  880 
  881         FELIX_LOCK(sc);
  882         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
  883                 error = felix_set_dot1q_vlan(sc, vg);
  884         else
  885                 error = EINVAL;
  886 
  887         FELIX_UNLOCK(sc);
  888         return (error);
  889 }
  890 
  891 static int
  892 felix_get_dot1q_vlan(felix_softc_t sc, etherswitch_vlangroup_t *vg)
  893 {
  894         uint32_t reg;
  895         int vid;
  896 
  897         vid = sc->vlans[vg->es_vlangroup];
  898 
  899         if (vid == 0)
  900                 return (0);
  901 
  902         FELIX_WR4(sc, FELIX_ANA_VTIDX, vid);
  903         FELIX_WR4(sc, FELIX_ANA_VT, FELIX_ANA_VT_READ);
  904 
  905         /*
  906          * According to documentation read and write commands
  907          * are instant.
  908          * Add a small delay just to be safe.
  909          */
  910         mb();
  911         DELAY(100);
  912         reg = FELIX_RD4(sc, FELIX_ANA_VT);
  913         if ((reg & FELIX_ANA_VT_STS) != FELIX_ANA_VT_IDLE)
  914                 return (ENXIO);
  915 
  916         reg >>= FELIX_ANA_VT_PORTMASK_SHIFT;
  917         reg &= FELIX_ANA_VT_PORTMASK_MASK;
  918 
  919         vg->es_untagged_ports = vg->es_member_ports = reg;
  920         vg->es_fid = 0;
  921         vg->es_vid = vid | ETHERSWITCH_VID_VALID;
  922         return (0);
  923 }
  924 
  925 static int
  926 felix_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
  927 {
  928         felix_softc_t sc;
  929         int error;
  930 
  931         sc = device_get_softc(dev);
  932 
  933         FELIX_LOCK(sc);
  934         if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
  935                 error = felix_get_dot1q_vlan(sc, vg);
  936         else
  937                 error = EINVAL;
  938 
  939         FELIX_UNLOCK(sc);
  940         return (error);
  941 }
  942 
  943 static void
  944 felix_tick(void *arg)
  945 {
  946         struct mii_data *mii;
  947         felix_softc_t sc;
  948         int port;
  949 
  950         sc = arg;
  951 
  952         FELIX_LOCK_ASSERT(sc, MA_OWNED);
  953 
  954         for (port = 0; port < sc->info.es_nports; port++) {
  955                 if (!felix_is_phyport(sc, port))
  956                         continue;
  957 
  958                 mii = felix_miiforport(sc, port);
  959                 MPASS(mii != NULL);
  960                 mii_tick(mii);
  961         }
  962         if (sc->timer_ticks != 0)
  963                 callout_reset(&sc->tick_callout, sc->timer_ticks, felix_tick, sc);
  964 }
  965 
  966 static int
  967 felix_ifmedia_upd(if_t ifp)
  968 {
  969         struct mii_data *mii;
  970         felix_softc_t sc;
  971 
  972         sc = if_getsoftc(ifp);
  973         mii = felix_miiforport(sc, ifp->if_dunit); /* XXX - DRVAPI */
  974         if (mii == NULL)
  975                 return (ENXIO);
  976 
  977         mii_mediachg(mii);
  978         return (0);
  979 }
  980 
  981 static void
  982 felix_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
  983 {
  984         felix_softc_t sc;
  985         struct mii_data *mii;
  986 
  987         sc = if_getsoftc(ifp);
  988         mii = felix_miiforport(sc, ifp->if_dunit); /* XXX - DRVAPI */
  989         if (mii == NULL)
  990                 return;
  991 
  992         mii_pollstat(mii);
  993         ifmr->ifm_active = mii->mii_media_active;
  994         ifmr->ifm_status = mii->mii_media_status;
  995 }
  996 
  997 static  bool
  998 felix_is_phyport(felix_softc_t sc, int port)
  999 {
 1000 
 1001         return (!sc->ports[port].fixed_port);
 1002 }
 1003 
 1004 static  struct mii_data*
 1005 felix_miiforport(felix_softc_t sc, unsigned int port)
 1006 {
 1007 
 1008         if (!felix_is_phyport(sc, port))
 1009                 return (NULL);
 1010 
 1011         return (device_get_softc(sc->ports[port].miibus));
 1012 }

Cache object: 6afc72d67b2deb3dbee2ddbcbb8749c4


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