svn commit: r328812 - head/sys/dev/etherswitch/arswitch

Adrian Chadd adrian at FreeBSD.org
Fri Feb 2 22:05:38 UTC 2018


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 *,


More information about the svn-src-all mailing list