Author: adrian
Date: Fri Feb  2 22:05:36 2018
New Revision: 328812
URL: https://svnweb.freebsd.org/changeset/base/328812

Log:
  [arswitch] begin tidying up the learning and ATU management, introduce ATU 
APIs.
  
  * Refactor the initial learning configuration (port learning, address expiry,
    handling address moving between ports, etc, etc) into a separate HAL routine
  * and ensure that it's consistent between switch chips - the 
AR8216,8316,724x,9331
    SoCs all share the same switch code.
  * .. the AR8327 needs doing - the defaults seem OK for now
  * .. the AR9340 is different but it's also programmed now.
  
  * Add support for flushing a single port worth of ATU entries
  * Add support for fetching the ATU table from AR8216 and derived chips
  
  Tested:
  
  * AR9344, Carambola 2
  
  TODO:
  
  * Further testing on other chips
  * Add AR9340 support
  * Add AR8327 support

Modified:
  head/sys/dev/etherswitch/arswitch/arswitch.c
  head/sys/dev/etherswitch/arswitch/arswitch_7240.c
  head/sys/dev/etherswitch/arswitch/arswitch_8316.c
  head/sys/dev/etherswitch/arswitch/arswitch_8327.c
  head/sys/dev/etherswitch/arswitch/arswitch_9340.c
  head/sys/dev/etherswitch/arswitch/arswitchreg.h
  head/sys/dev/etherswitch/arswitch/arswitchvar.h

Modified: head/sys/dev/etherswitch/arswitch/arswitch.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch.c        Fri Feb  2 21:57:00 
2018        (r328811)
+++ head/sys/dev/etherswitch/arswitch/arswitch.c        Fri Feb  2 22:05:36 
2018        (r328812)
@@ -289,16 +289,34 @@ ar8xxx_port_init(struct arswitch_softc *sc, int port)
 }
 
 static int
-ar8xxx_atu_flush(struct arswitch_softc *sc)
+ar8xxx_atu_wait_ready(struct arswitch_softc *sc)
 {
        int ret;
 
+       ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
        ret = arswitch_waitreg(sc->sc_dev,
            AR8216_REG_ATU,
            AR8216_ATU_ACTIVE,
            0,
            1000);
 
+       return (ret);
+}
+
+/*
+ * Flush all ATU entries.
+ */
+static int
+ar8xxx_atu_flush(struct arswitch_softc *sc)
+{
+       int ret;
+
+       ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
+       DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: flushing all ports\n", __func__);
+
+       ret = ar8xxx_atu_wait_ready(sc);
        if (ret)
                device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__);
 
@@ -310,7 +328,166 @@ ar8xxx_atu_flush(struct arswitch_softc *sc)
        return (ret);
 }
 
+/*
+ * Flush ATU entries for a single port.
+ */
 static int
+ar8xxx_atu_flush_port(struct arswitch_softc *sc, int port)
+{
+       int ret, val;
+
+       DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: flushing port %d\n", __func__,
+           port);
+
+       ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
+       /* Flush unicast entries on port */
+       val = AR8216_ATU_OP_FLUSH_UNICAST;
+
+       /* TODO: bit 4 indicates whether to flush dynamic (0) or static (1) */
+
+       /* Which port */
+       val |= SM(port, AR8216_ATU_PORT_NUM);
+
+       ret = ar8xxx_atu_wait_ready(sc);
+       if (ret)
+               device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__);
+
+       if (!ret)
+               arswitch_writereg(sc->sc_dev,
+                   AR8216_REG_ATU,
+                   val | AR8216_ATU_ACTIVE);
+
+       return (ret);
+}
+
+/*
+ * XXX TODO: flush a single MAC address.
+ */
+
+/*
+ * Fetch a single entry from the ATU.
+ */
+static int
+ar8xxx_atu_fetch_table(struct arswitch_softc *sc, etherswitch_atu_entry_t *e,
+    int atu_fetch_op)
+{
+       uint32_t ret0, ret1, ret2, val;
+
+       ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
+       switch (atu_fetch_op) {
+       case 0:
+               /* Initialise things for the first fetch */
+
+               DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: initializing\n", __func__);
+               (void) ar8xxx_atu_wait_ready(sc);
+
+               arswitch_writereg(sc->sc_dev,
+                   AR8216_REG_ATU, AR8216_ATU_OP_GET_NEXT);
+               arswitch_writereg(sc->sc_dev,
+                   AR8216_REG_ATU_DATA, 0);
+               arswitch_writereg(sc->sc_dev,
+                   AR8216_REG_ATU_CTRL2, 0);
+
+               return (0);
+       case 1:
+               DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: reading next\n", __func__);
+               /*
+                * Attempt to read the next address entry; don't modify what
+                * is there in AT_ADDR{4,5} as its used for the next fetch
+                */
+               (void) ar8xxx_atu_wait_ready(sc);
+
+               /* Begin the next read event; not modifying anything */
+               val = arswitch_readreg(sc->sc_dev, AR8216_REG_ATU);
+               val |= AR8216_ATU_ACTIVE;
+               arswitch_writereg(sc->sc_dev, AR8216_REG_ATU, val);
+
+               /* Wait for it to complete */
+               (void) ar8xxx_atu_wait_ready(sc);
+
+               /* Fetch the ethernet address and ATU status */
+               ret0 = arswitch_readreg(sc->sc_dev, AR8216_REG_ATU);
+               ret1 = arswitch_readreg(sc->sc_dev, AR8216_REG_ATU_DATA);
+               ret2 = arswitch_readreg(sc->sc_dev, AR8216_REG_ATU_CTRL2);
+
+               /* If the status is zero, then we're done */
+               if (MS(ret2, AR8216_ATU_CTRL2_AT_STATUS) == 0)
+                       return (-1);
+
+               /* MAC address */
+               e->es_macaddr[5] = MS(ret0, AR8216_ATU_ADDR5);
+               e->es_macaddr[4] = MS(ret0, AR8216_ATU_ADDR4);
+               e->es_macaddr[3] = MS(ret1, AR8216_ATU_ADDR3);
+               e->es_macaddr[2] = MS(ret1, AR8216_ATU_ADDR2);
+               e->es_macaddr[1] = MS(ret1, AR8216_ATU_ADDR1);
+               e->es_macaddr[0] = MS(ret1, AR8216_ATU_ADDR0);
+
+               /* Bitmask of ports this entry is for */
+               e->es_portmask = MS(ret2, AR8216_ATU_CTRL2_DESPORT);
+
+               /* TODO: other flags that are interesting */
+
+               DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: MAC %6D portmask 0x%08x\n",
+                   __func__,
+                   e->es_macaddr, ":", e->es_portmask);
+               return (0);
+       default:
+               return (-1);
+       }
+       return (-1);
+}
+
+/*
+ * Configure aging register defaults.
+ */
+static int
+ar8xxx_atu_learn_default(struct arswitch_softc *sc)
+{
+       int ret;
+       uint32_t val;
+
+       DPRINTF(sc, ARSWITCH_DBG_ATU, "%s: resetting learning\n", __func__);
+
+       /*
+        * For now, configure the aging defaults:
+        *
+        * + ARP_EN - enable "acknowledgement" of ARP frames - they are
+        *   forwarded to the CPU port
+        * + LEARN_CHANGE_EN - hash table violations when learning MAC addresses
+        *   will force an entry to be expired/updated and a new one to be
+        *   programmed in.
+        * + AGE_EN - enable address table aging
+        * + AGE_TIME - set to 5 minutes
+        */
+       val = 0;
+       val |= AR8216_ATU_CTRL_ARP_EN;
+       val |= AR8216_ATU_CTRL_LEARN_CHANGE;
+       val |= AR8216_ATU_CTRL_AGE_EN;
+       val |= 0x2b;    /* 5 minutes; bits 15:0 */
+
+       ret = arswitch_writereg(sc->sc_dev,
+           AR8216_REG_ATU_CTRL,
+           val);
+
+       if (ret)
+               device_printf(sc->sc_dev, "%s: writereg failed\n", __func__);
+
+       return (ret);
+}
+
+/*
+ * XXX TODO: add another routine to configure the leaky behaviour
+ * when unknown frames are received.  These must be consistent
+ * between ethernet switches.
+ */
+
+/*
+ * XXX TODO: this attach routine does NOT free all memory, resources
+ * upon failure!
+ */
+static int
 arswitch_attach(device_t dev)
 {
        struct arswitch_softc *sc = device_get_softc(dev);
@@ -333,6 +510,18 @@ arswitch_attach(device_t dev)
            "debug", CTLFLAG_RW, &sc->sc_debug, 0,
            "control debugging printfs");
 
+       /* Allocate a 128 entry ATU table; hopefully its big enough! */
+       /* XXX TODO: make this per chip */
+       sc->atu.entries = malloc(sizeof(etherswitch_atu_entry_t) * 128,
+           M_DEVBUF, M_NOWAIT);
+       if (sc->atu.entries == NULL) {
+               device_printf(sc->sc_dev, "%s: failed to allocate ATU table\n",
+                   __func__);
+               return (ENXIO);
+       }
+       sc->atu.count = 0;
+       sc->atu.size = 128;
+
        /* Default HAL methods */
        sc->hal.arswitch_port_init = ar8xxx_port_init;
        sc->hal.arswitch_port_vlan_setup = ar8xxx_port_vlan_setup;
@@ -353,11 +542,13 @@ arswitch_attach(device_t dev)
        sc->hal.arswitch_set_port_vlan = ar8xxx_set_port_vlan;
 
        sc->hal.arswitch_atu_flush = ar8xxx_atu_flush;
+       sc->hal.arswitch_atu_flush_port = ar8xxx_atu_flush_port;
+       sc->hal.arswitch_atu_learn_default = ar8xxx_atu_learn_default;
+       sc->hal.arswitch_atu_fetch_table = ar8xxx_atu_fetch_table;
 
        sc->hal.arswitch_phy_read = arswitch_readphy_internal;
        sc->hal.arswitch_phy_write = arswitch_writephy_internal;
 
-
        /*
         * Attach switch related functions
         */
@@ -424,6 +615,17 @@ arswitch_attach(device_t dev)
                return (err);
        }
 
+       /*
+        * Configure the default address table learning parameters for this
+        * switch.
+        */
+       err = sc->hal.arswitch_atu_learn_default(sc);
+       if (err != 0) {
+               DPRINTF(sc, ARSWITCH_DBG_ANY,
+                   "%s: atu_learn_default: err=%d\n", __func__, err);
+               return (err);
+       }
+
        /* Initialize the switch ports. */
        for (port = 0; port <= sc->numphys; port++) {
                sc->hal.arswitch_port_init(sc, port);
@@ -481,6 +683,8 @@ arswitch_detach(device_t dev)
                free(sc->ifname[i], M_DEVBUF);
        }
 
+       free(sc->atu.entries, M_DEVBUF);
+
        bus_generic_detach(dev);
        mtx_destroy(&sc->sc_mtx);
 
@@ -940,6 +1144,86 @@ arswitch_setconf(device_t dev, etherswitch_conf_t *con
 }
 
 static int
+arswitch_atu_flush_all(device_t dev)
+{
+       struct arswitch_softc *sc;
+       int err;
+
+       sc = device_get_softc(dev);
+       ARSWITCH_LOCK(sc);
+       err = sc->hal.arswitch_atu_flush(sc);
+       /* Invalidate cached ATU */
+       sc->atu.count = 0;
+       ARSWITCH_UNLOCK(sc);
+       return (err);
+}
+
+static int
+arswitch_atu_flush_port(device_t dev, int port)
+{
+       struct arswitch_softc *sc;
+       int err;
+
+       sc = device_get_softc(dev);
+       ARSWITCH_LOCK(sc);
+       err = sc->hal.arswitch_atu_flush_port(sc, port);
+       /* Invalidate cached ATU */
+       sc->atu.count = 0;
+       ARSWITCH_UNLOCK(sc);
+       return (err);
+}
+
+static int
+arswitch_atu_fetch_table(device_t dev, etherswitch_atu_table_t *table)
+{
+       struct arswitch_softc *sc;
+       int err, nitems;
+
+       sc = device_get_softc(dev);
+
+       ARSWITCH_LOCK(sc);
+       /* Initial setup */
+       nitems = 0;
+       err = sc->hal.arswitch_atu_fetch_table(sc, NULL, 0);
+
+       /* fetch - ideally yes we'd fetch into a separate table then switch */
+       while (err != -1 && nitems < sc->atu.size) {
+               err = sc->hal.arswitch_atu_fetch_table(sc,
+                   &sc->atu.entries[nitems], 1);
+               if (err == 0) {
+                       sc->atu.entries[nitems].id = nitems;
+                       nitems++;
+               }
+       }
+       sc->atu.count = nitems;
+       ARSWITCH_UNLOCK(sc);
+
+       table->es_nitems = nitems;
+
+       return (0);
+}
+
+static int
+arswitch_atu_fetch_table_entry(device_t dev, etherswitch_atu_entry_t *e)
+{
+       struct arswitch_softc *sc;
+       int id;
+
+       sc = device_get_softc(dev);
+       id = e->id;
+
+       ARSWITCH_LOCK(sc);
+       if (id > sc->atu.count) {
+               ARSWITCH_UNLOCK(sc);
+               return (ENOENT);
+       }
+
+       memcpy(e, &sc->atu.entries[id], sizeof(*e));
+       ARSWITCH_UNLOCK(sc);
+       return (0);
+}
+
+static int
 arswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *e)
 {
        struct arswitch_softc *sc = device_get_softc(dev);
@@ -1003,6 +1287,10 @@ static device_method_t arswitch_methods[] = {
        DEVMETHOD(etherswitch_setvgroup,        arswitch_setvgroup),
        DEVMETHOD(etherswitch_getconf,  arswitch_getconf),
        DEVMETHOD(etherswitch_setconf,  arswitch_setconf),
+       DEVMETHOD(etherswitch_flush_all, arswitch_atu_flush_all),
+       DEVMETHOD(etherswitch_flush_port, arswitch_atu_flush_port),
+       DEVMETHOD(etherswitch_fetch_table, arswitch_atu_fetch_table),
+       DEVMETHOD(etherswitch_fetch_table_entry, 
arswitch_atu_fetch_table_entry),
 
        DEVMETHOD_END
 };

Modified: head/sys/dev/etherswitch/arswitch/arswitch_7240.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_7240.c   Fri Feb  2 21:57:00 
2018        (r328811)
+++ head/sys/dev/etherswitch/arswitch/arswitch_7240.c   Fri Feb  2 22:05:36 
2018        (r328812)
@@ -101,8 +101,6 @@ ar7240_hw_global_setup(struct arswitch_softc *sc)
            AR7240_GLOBAL_CTRL_MTU_MASK,
            SM(1536, AR7240_GLOBAL_CTRL_MTU_MASK));
 
-       /* XXX ARP? Frame Age enable? */
-
        /* Service Tag */
        arswitch_modifyreg(sc->sc_dev, AR8X16_REG_SERVICE_TAG,
            AR8X16_SERVICE_TAG_MASK, 0);

Modified: head/sys/dev/etherswitch/arswitch/arswitch_8316.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_8316.c   Fri Feb  2 21:57:00 
2018        (r328811)
+++ head/sys/dev/etherswitch/arswitch/arswitch_8316.c   Fri Feb  2 22:05:36 
2018        (r328812)
@@ -140,11 +140,6 @@ ar8316_hw_global_setup(struct arswitch_softc *sc)
        /* Setup TAG priority mapping. */
        arswitch_writereg(sc->sc_dev, AR8X16_REG_TAG_PRIO, 0xfa50);
 
-       /* Enable ARP frame acknowledge. */
-       /* XXX TODO: aging? */
-       arswitch_modifyreg(sc->sc_dev, AR8X16_REG_AT_CTRL, 0,
-           AR8X16_AT_CTRL_ARP_EN);
-
        /*
         * Flood address table misses to all ports, and enable forwarding of
         * broadcasts to the cpu port.

Modified: head/sys/dev/etherswitch/arswitch/arswitch_8327.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_8327.c   Fri Feb  2 21:57:00 
2018        (r328811)
+++ head/sys/dev/etherswitch/arswitch/arswitch_8327.c   Fri Feb  2 22:05:36 
2018        (r328812)
@@ -702,6 +702,14 @@ ar8327_hw_setup(struct arswitch_softc *sc)
        return (0);
 }
 
+static int
+ar8327_atu_learn_default(struct arswitch_softc *sc)
+{
+
+       device_printf(sc->sc_dev, "%s: TODO!\n", __func__);
+       return (0);
+}
+
 /*
  * Initialise other global values, for the AR8327.
  */
@@ -1037,9 +1045,8 @@ ar8327_set_pvid(struct arswitch_softc *sc, int port, i
 }
 
 static int
-ar8327_atu_flush(struct arswitch_softc *sc)
+ar8327_atu_wait_ready(struct arswitch_softc *sc)
 {
-
        int ret;
 
        ret = arswitch_waitreg(sc->sc_dev,
@@ -1048,6 +1055,18 @@ ar8327_atu_flush(struct arswitch_softc *sc)
            0,
            1000);
 
+       return (ret);
+}
+
+static int
+ar8327_atu_flush(struct arswitch_softc *sc)
+{
+
+       int ret;
+
+       ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
+       ret = ar8327_atu_wait_ready(sc);
        if (ret)
                device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__);
 
@@ -1059,6 +1078,39 @@ ar8327_atu_flush(struct arswitch_softc *sc)
 }
 
 static int
+ar8327_atu_flush_port(struct arswitch_softc *sc, int port)
+{
+       int ret;
+       uint32_t val;
+
+       ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
+       ret = ar8327_atu_wait_ready(sc);
+       if (ret)
+               device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__);
+
+       val = AR8327_ATU_FUNC_OP_FLUSH_UNICAST;
+       val |= SM(port, AR8327_ATU_FUNC_PORT_NUM);
+
+       if (!ret)
+               arswitch_writereg(sc->sc_dev,
+                   AR8327_REG_ATU_FUNC,
+                   val | AR8327_ATU_FUNC_BUSY);
+
+       return (ret);
+}
+
+static int
+ar8327_atu_fetch_table(struct arswitch_softc *sc, etherswitch_atu_entry_t *e,
+    int atu_fetch_op)
+{
+
+       /* XXX TODO */
+       return (ENXIO);
+}
+
+
+static int
 ar8327_flush_dot1q_vlan(struct arswitch_softc *sc)
 {
 
@@ -1175,7 +1227,10 @@ ar8327_attach(struct arswitch_softc *sc)
        sc->hal.arswitch_get_port_vlan = ar8327_vlan_get_port;
        sc->hal.arswitch_set_port_vlan = ar8327_vlan_set_port;
 
+       sc->hal.arswitch_atu_learn_default = ar8327_atu_learn_default;
        sc->hal.arswitch_atu_flush = ar8327_atu_flush;
+       sc->hal.arswitch_atu_flush_port = ar8327_atu_flush_port;
+       sc->hal.arswitch_atu_fetch_table = ar8327_atu_fetch_table;
 
        /*
         * Reading the PHY via the MDIO interface currently doesn't

Modified: head/sys/dev/etherswitch/arswitch/arswitch_9340.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_9340.c   Fri Feb  2 21:57:00 
2018        (r328811)
+++ head/sys/dev/etherswitch/arswitch/arswitch_9340.c   Fri Feb  2 22:05:36 
2018        (r328812)
@@ -76,6 +76,27 @@ ar9340_hw_setup(struct arswitch_softc *sc)
        return (0);
 }
 
+static int
+ar9340_atu_learn_default(struct arswitch_softc *sc)
+{
+
+       /* Enable aging, MAC replacing */
+       arswitch_writereg(sc->sc_dev, AR934X_REG_AT_CTRL,
+           0x2b /* 5 min age time */ |
+           AR934X_AT_CTRL_AGE_EN |
+           AR934X_AT_CTRL_LEARN_CHANGE);
+
+       /* Enable ARP frame acknowledge */
+       arswitch_modifyreg(sc->sc_dev, AR934X_REG_QM_CTRL,
+           AR934X_QM_CTRL_ARP_EN, AR934X_QM_CTRL_ARP_EN);
+
+       /* Copy frame to CPU port, not just redirect it */
+       arswitch_modifyreg(sc->sc_dev, AR934X_REG_QM_CTRL,
+           AR934X_QM_CTRL_ARP_COPY_EN, AR934X_QM_CTRL_ARP_COPY_EN);
+
+       return (0);
+}
+
 /*
  * Initialise other global values for the AR9340.
  */
@@ -92,16 +113,6 @@ ar9340_hw_global_setup(struct arswitch_softc *sc)
        /* Setup TAG priority mapping */
        arswitch_writereg(sc->sc_dev, AR8X16_REG_TAG_PRIO, 0xfa50);
 
-       /* Enable aging, MAC replacing */
-       arswitch_writereg(sc->sc_dev, AR934X_REG_AT_CTRL,
-           0x2b /* 5 min age time */ |
-           AR934X_AT_CTRL_AGE_EN |
-           AR934X_AT_CTRL_LEARN_CHANGE);
-
-       /* Enable ARP frame acknowledge */
-       arswitch_modifyreg(sc->sc_dev, AR934X_REG_QM_CTRL,
-           AR934X_QM_CTRL_ARP_EN, AR934X_QM_CTRL_ARP_EN);
-
        /* Enable Broadcast frames transmitted to the CPU */
        arswitch_modifyreg(sc->sc_dev, AR934X_REG_FLOOD_MASK,
            AR934X_FLOOD_MASK_BC_DP(0),
@@ -201,6 +212,7 @@ ar9340_attach(struct arswitch_softc *sc)
 
        sc->hal.arswitch_hw_setup = ar9340_hw_setup;
        sc->hal.arswitch_hw_global_setup = ar9340_hw_global_setup;
+       sc->hal.arswitch_atu_learn_default = ar9340_atu_learn_default;
 
        /* Set the switch vlan capabilities. */
        sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q |

Modified: head/sys/dev/etherswitch/arswitch/arswitchreg.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitchreg.h     Fri Feb  2 21:57:00 
2018        (r328811)
+++ head/sys/dev/etherswitch/arswitch/arswitchreg.h     Fri Feb  2 22:05:36 
2018        (r328812)
@@ -137,26 +137,43 @@
 #define                AR8216_ATU_OP_GET_NEXT          0x6
 #define                AR8216_ATU_ACTIVE               BIT(3)
 #define                AR8216_ATU_PORT_NUM             BITS(8, 4)
+#define                AR8216_ATU_PORT_NUM_S           8
 #define                AR8216_ATU_FULL_VIO             BIT(12)
 #define                AR8216_ATU_ADDR4                BITS(16, 8)
+#define                AR8216_ATU_ADDR4_S              16
 #define                AR8216_ATU_ADDR5                BITS(24, 8)
+#define                AR8216_ATU_ADDR5_S              24
 
 #define        AR8216_REG_ATU_DATA             0x0054
 #define                AR8216_ATU_ADDR3                BITS(0, 8)
+#define                AR8216_ATU_ADDR3_S              0
 #define                AR8216_ATU_ADDR2                BITS(8, 8)
+#define                AR8216_ATU_ADDR2_S              8
 #define                AR8216_ATU_ADDR1                BITS(16, 8)
+#define                AR8216_ATU_ADDR1_S              16
 #define                AR8216_ATU_ADDR0                BITS(24, 8)
+#define                AR8216_ATU_ADDR0_S              24
 
-#define        AR8X16_REG_ARL_CTRL2            0x0058
+#define        AR8216_REG_ATU_CTRL2            0x0058
+#define                AR8216_ATU_CTRL2_DESPORT        BITS(0, 5)
+#define                AR8216_ATU_CTRL2_DESPORT_S      0
+#define                AR8216_ATU_CTRL2_AT_PRIORITY    BITS(10, 2)
+#define                AR8216_ATU_CTRL2_AT_PRIORITY_EN BIT(12)
+#define                AR8216_ATU_CTRL2_MIRROR_EN      BIT(13)
+#define                AR8216_ATU_CTRL2_SA_DROP_EN     BIT(14)
+#define                AR8216_ATU_CTRL2_AT_STATUS      BITS(16, 4)
+#define                AR8216_ATU_CTRL2_AT_STATUS_S    16
+#define                AR8216_ATU_CTRL2_VLAN_LEAKY_EN  BIT(24)
+#define                AR8216_ATU_CTRL2_REDIRECT2CPU   BIT(25)
+#define                AR8216_ATU_CTRL2_COPY2CPU       BIT(26)
 
 #define        AR8216_REG_ATU_CTRL             0x005C
-#define                AR8216_ATU_CTRL_AGE_EN          BIT(17)
 #define                AR8216_ATU_CTRL_AGE_TIME        BITS(0, 16)
 #define                AR8216_ATU_CTRL_AGE_TIME_S      0
+#define                AR8216_ATU_CTRL_AGE_EN          BIT(17)
+#define                AR8216_ATU_CTRL_LEARN_CHANGE    BIT(18)
+#define                AR8216_ATU_CTRL_ARP_EN          BIT(20)
 
-#define        AR8X16_REG_AT_CTRL              0x005c
-#define                AR8X16_AT_CTRL_ARP_EN           (1 << 20)
-
 #define        AR8X16_REG_IP_PRIORITY_1        0x0060
 #define        AR8X16_REG_IP_PRIORITY_2        0x0064
 #define        AR8X16_REG_IP_PRIORITY_3        0x0068
@@ -339,6 +356,7 @@
 
 #define        AR934X_REG_QM_CTRL              0x3c
 #define                AR934X_QM_CTRL_ARP_EN   (1 << 15)
+#define                AR934X_QM_CTRL_ARP_COPY_EN      (1 << 14)
 
 #define        AR934X_REG_AT_CTRL              0x5c
 #define                AR934X_AT_CTRL_AGE_TIME         BITS(0, 15)
@@ -471,7 +489,7 @@
 #define        AR8327_REG_ATU_DATA2            0x608
 
 #define        AR8327_REG_ATU_FUNC             0x60c
-#define                AR8327_ATU_FUNC_OP              BITS(0, 4)
+#define                AR8327_ATU_FUNC_OP              BITS(0, 3)
 #define                AR8327_ATU_FUNC_OP_NOOP                 0x0
 #define                AR8327_ATU_FUNC_OP_FLUSH                0x1
 #define                AR8327_ATU_FUNC_OP_LOAD                 0x2
@@ -481,7 +499,9 @@
 #define                AR8327_ATU_FUNC_OP_GET_NEXT             0x6
 #define                AR8327_ATU_FUNC_OP_SEARCH_MAC           0x7
 #define                AR8327_ATU_FUNC_OP_CHANGE_TRUNK         0x8
-#define                AR8327_ATU_FUNC_BUSY                    (1U << 31)
+#define                AR8327_ATU_FUNC_BUSY                    BIT(3)
+#define                AR8327_ATU_FUNC_PORT_NUM                BITS(8, 4)
+#define                AR8327_ATU_FUNC_PORT_NUM_S              8
 
 #define        AR8327_REG_VTU_FUNC0            0x0610
 #define                AR8327_VTU_FUNC0_EG_MODE        BITS(4, 14)

Modified: head/sys/dev/etherswitch/arswitch/arswitchvar.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitchvar.h     Fri Feb  2 21:57:00 
2018        (r328811)
+++ head/sys/dev/etherswitch/arswitch/arswitchvar.h     Fri Feb  2 22:05:36 
2018        (r328812)
@@ -87,7 +87,14 @@ struct arswitch_softc {
        int             vid[AR8X16_MAX_VLANS];
        uint32_t        vlan_mode;
 
+       /* ATU (address table unit) support */
        struct {
+               int count;
+               int size;
+               etherswitch_atu_entry_t *entries;
+       } atu;
+
+       struct {
                /* Global setup */
                int (* arswitch_hw_setup) (struct arswitch_softc *);
                int (* arswitch_hw_global_setup) (struct arswitch_softc *);
@@ -99,6 +106,8 @@ struct arswitch_softc {
                int (* arswitch_atu_flush) (struct arswitch_softc *);
                int (* arswitch_atu_flush_port) (struct arswitch_softc *, int);
                int (* arswitch_atu_learn_default) (struct arswitch_softc *);
+               int (* arswitch_atu_fetch_table) (struct arswitch_softc *,
+                   etherswitch_atu_entry_t *, int atu_fetch_op);
 
                /* VLAN functions */
                int (* arswitch_port_vlan_setup) (struct arswitch_softc *,
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to