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-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"