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/ar40xx/ar40xx_hw_port.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) 2022 Adrian Chadd <adrian@FreeBSD.org>.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/param.h>
   29 #include <sys/bus.h>
   30 #include <sys/errno.h>
   31 #include <sys/kernel.h>
   32 #include <sys/malloc.h>
   33 #include <sys/module.h>
   34 #include <sys/socket.h>
   35 #include <sys/sockio.h>
   36 #include <sys/sysctl.h>
   37 #include <sys/systm.h>
   38 
   39 #include <net/if.h>
   40 #include <net/if_var.h>
   41 #include <net/if_arp.h>
   42 #include <net/ethernet.h>
   43 #include <net/if_dl.h>
   44 #include <net/if_media.h>
   45 #include <net/if_types.h>
   46 
   47 #include <machine/bus.h>
   48 #include <dev/iicbus/iic.h>
   49 #include <dev/iicbus/iiconf.h>
   50 #include <dev/iicbus/iicbus.h>
   51 #include <dev/mii/mii.h>
   52 #include <dev/mii/miivar.h>
   53 #include <dev/mdio/mdio.h>
   54 #include <dev/extres/clk/clk.h>
   55 #include <dev/extres/hwreset/hwreset.h>
   56 
   57 #include <dev/fdt/fdt_common.h>
   58 #include <dev/ofw/ofw_bus.h>
   59 #include <dev/ofw/ofw_bus_subr.h>
   60 
   61 #include <dev/etherswitch/etherswitch.h>
   62 
   63 #include <dev/etherswitch/ar40xx/ar40xx_var.h>
   64 #include <dev/etherswitch/ar40xx/ar40xx_reg.h>
   65 #include <dev/etherswitch/ar40xx/ar40xx_debug.h>
   66 #include <dev/etherswitch/ar40xx/ar40xx_hw_port.h>
   67 
   68 #include "mdio_if.h"
   69 #include "miibus_if.h"
   70 #include "etherswitch_if.h"
   71 
   72 
   73 int
   74 ar40xx_hw_port_init(struct ar40xx_softc *sc, int port)
   75 {
   76         uint32_t reg;
   77 
   78         AR40XX_DPRINTF(sc, AR40XX_DBG_HW_PORT_INIT,
   79             "%s: called; port %d\n", __func__, port);
   80 
   81         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_STATUS(port), 0);
   82         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_HEADER(port), 0);
   83         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_VLAN0(port), 0);
   84         AR40XX_REG_BARRIER_WRITE(sc);
   85 
   86         DELAY(20);
   87 
   88         /*
   89          * Ok! Here is where things get super fun in the AR40xx
   90          * driver in uboot/linux.
   91          *
   92          * The earlier chipset switch drivers enable auto link enable here.
   93          * The switch will poll the PHYs too, and configure appropriately.
   94          *
   95          * The ar40xx code in linux/u-boot instead has a whole workaround
   96          * path that polls things directly and does some weird hijinx.
   97          * NOTABLY - they do NOT enable the TX/RX MAC here or autoneg -
   98          * it's done in the work around path.
   99          *
  100          * SO - for now the port is left off until the PHY state changes.
  101          * And then we flip it on and off based on the PHY state.
  102          */
  103 #if 0
  104         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_STATUS(port),
  105             AR40XX_PORT_AUTO_LINK_EN);
  106 #endif
  107 
  108         /*
  109          * Configure the VLAN egress mode (don't touch them) and
  110          * learning state for STP/ATU.  This isn't currently
  111          * configurable so it's just nailed up here and left alone.
  112          */
  113         reg = AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH
  114              << AR40XX_PORT_VLAN1_OUT_MODE_S;
  115         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_VLAN1(port), reg);
  116 
  117         reg = AR40XX_PORT_LOOKUP_LEARN;
  118         reg |= AR40XX_PORT_STATE_FORWARD << AR40XX_PORT_LOOKUP_STATE_S;
  119         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_LOOKUP(port), reg);
  120         AR40XX_REG_BARRIER_WRITE(sc);
  121 
  122         return (0);
  123 }
  124 
  125 /*
  126  * Call when the link for a non-CPU port is down.
  127  *
  128  * This will turn off the MAC/forwarding path for this port.
  129  */
  130 int
  131 ar40xx_hw_port_link_down(struct ar40xx_softc *sc, int port)
  132 {
  133 
  134         AR40XX_DPRINTF(sc, AR40XX_DBG_HW_PORT_INIT,
  135             "%s: called; port %d\n", __func__, port);
  136 
  137         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_STATUS(port), 0);
  138 
  139         return (0);
  140 }
  141 
  142 /*
  143  * Call when the link for a non-CPU port is up.
  144  *
  145  * This will turn on the default auto-link checking and
  146  * eventually enable the TX/RX MAC.
  147  */
  148 int
  149 ar40xx_hw_port_link_up(struct ar40xx_softc *sc, int port)
  150 {
  151         uint32_t reg;
  152 
  153         AR40XX_DPRINTF(sc, AR40XX_DBG_HW_PORT_INIT,
  154             "%s: called; port %d\n", __func__, port);
  155 
  156         /* Auto-link enable */
  157         AR40XX_REG_BARRIER_READ(sc);
  158         reg = AR40XX_REG_READ(sc, AR40XX_REG_PORT_STATUS(port));
  159         reg |= AR40XX_PORT_AUTO_LINK_EN;
  160         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_STATUS(port), reg);
  161         AR40XX_REG_BARRIER_WRITE(sc);
  162 
  163         return (0);
  164 }
  165 
  166 /*
  167  * Setup the CPU facing port.  For this device it'll only
  168  * be port 0.
  169  */
  170 int
  171 ar40xx_hw_port_cpuport_setup(struct ar40xx_softc *sc)
  172 {
  173         uint32_t reg;
  174 
  175         AR40XX_DPRINTF(sc, AR40XX_DBG_HW_PORT_INIT, "%s: called\n",
  176             __func__);
  177 
  178         reg = AR40XX_PORT_STATUS_TXFLOW
  179             | AR40XX_PORT_STATUS_RXFLOW
  180             | AR40XX_PORT_TXHALF_FLOW
  181             | AR40XX_PORT_DUPLEX
  182             | AR40XX_PORT_SPEED_1000M;
  183         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_STATUS(0), reg);
  184         DELAY(20);
  185 
  186         reg |= AR40XX_PORT_TX_EN | AR40XX_PORT_RX_EN;
  187         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_STATUS(0), reg);
  188         AR40XX_REG_BARRIER_WRITE(sc);
  189 
  190         return (0);
  191 }
  192 
  193 /*
  194  * Fetch the port PVID.
  195  *
  196  * For 802.1q mode this is the default VLAN ID for the port.
  197  * Frames without an 802.1q VLAN will assume this VLAN ID for
  198  * transmit/receive.
  199  */
  200 int
  201 ar40xx_hw_get_port_pvid(struct ar40xx_softc *sc, int port, int *pvid)
  202 {
  203         uint32_t reg;
  204 
  205         AR40XX_LOCK_ASSERT(sc);
  206 
  207         AR40XX_REG_BARRIER_READ(sc);
  208         reg = AR40XX_REG_READ(sc, AR40XX_REG_PORT_VLAN0(port));
  209 
  210         reg = reg >> AR40XX_PORT_VLAN0_DEF_CVID_S;
  211         reg = reg & 0x0fff; /* XXX */
  212 
  213         *pvid = reg;
  214         return (0);
  215 }
  216 
  217 /*
  218  * Set the port PVID.
  219  *
  220  * For now, since double-tagged frames aren't currently supported,
  221  * CVID=SVID here.
  222  */
  223 int
  224 ar40xx_hw_set_port_pvid(struct ar40xx_softc *sc, int port, int pvid)
  225 {
  226         uint32_t reg;
  227 
  228         AR40XX_LOCK_ASSERT(sc);
  229 
  230         pvid &= ETHERSWITCH_VID_MASK;
  231 
  232         reg = pvid << AR40XX_PORT_VLAN0_DEF_SVID_S;
  233         reg |= pvid << AR40XX_PORT_VLAN0_DEF_CVID_S;
  234         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_VLAN0(port), reg);
  235         AR40XX_REG_BARRIER_WRITE(sc);
  236 
  237         return (0);
  238 }
  239 
  240 /*
  241  * Setup the default port membership configuration.
  242  *
  243  * This configures the PVID for the port in the sc_vlan config,
  244  * along with a set of ports that constitute the "membership"
  245  * of this particular VID.
  246  *
  247  * For 802.1q mode the membership can be viewed as the default
  248  * learning port group, but this can be added to via VLAN membership.
  249  * (Eg you could in theory split two LAN ports into separate "member"
  250  * groups and they'd not learn MAC addresses from each other even
  251  * inside a VLAN; you'd then end up with the traffic being flooded to
  252  * the CPU port.)
  253  */
  254 int
  255 ar40xx_hw_port_setup(struct ar40xx_softc *sc, int port, uint32_t members)
  256 {
  257         uint32_t egress, ingress, reg;
  258         uint32_t pvid = sc->sc_vlan.vlan_id[sc->sc_vlan.pvid[port]]
  259             & ETHERSWITCH_VID_MASK;
  260 
  261         if (sc->sc_vlan.vlan) {
  262                 egress = AR40XX_PORT_VLAN1_OUT_MODE_UNMOD;
  263                 ingress = AR40XX_IN_SECURE;
  264         } else {
  265                 egress = AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH;
  266                 ingress = AR40XX_IN_PORT_ONLY;
  267         }
  268 
  269         reg = pvid << AR40XX_PORT_VLAN0_DEF_SVID_S;
  270         reg |= pvid << AR40XX_PORT_VLAN0_DEF_CVID_S;
  271         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_VLAN0(port), reg);
  272         AR40XX_REG_BARRIER_WRITE(sc);
  273 
  274         reg = AR40XX_PORT_VLAN1_PORT_VLAN_PROP;
  275         reg |= egress << AR40XX_PORT_VLAN1_OUT_MODE_S;
  276         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_VLAN1(port), reg);
  277         AR40XX_REG_BARRIER_WRITE(sc);
  278 
  279         reg = members;
  280         reg |= AR40XX_PORT_LOOKUP_LEARN;
  281         reg |= ingress << AR40XX_PORT_LOOKUP_IN_MODE_S;
  282         reg |= AR40XX_PORT_STATE_FORWARD << AR40XX_PORT_LOOKUP_STATE_S;
  283         AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_LOOKUP(port), reg);
  284         AR40XX_REG_BARRIER_WRITE(sc);
  285 
  286         return (0);
  287 }

Cache object: cfdb9fe7fb0672f130b880041a39183b


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