[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
This commit is contained in:
parent
5725799a3b
commit
62042c979d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=328812
@ -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,6 +328,165 @@ 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)
|
||||
{
|
||||
@ -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);
|
||||
|
||||
@ -939,6 +1143,86 @@ arswitch_setconf(device_t dev, etherswitch_conf_t *conf)
|
||||
return (0);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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, int pvid)
|
||||
}
|
||||
|
||||
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__);
|
||||
|
||||
@ -1058,6 +1077,39 @@ ar8327_atu_flush(struct arswitch_softc *sc)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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 |
|
||||
|
@ -137,25 +137,42 @@
|
||||
#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 AR8X16_REG_AT_CTRL 0x005c
|
||||
#define AR8X16_AT_CTRL_ARP_EN (1 << 20)
|
||||
#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_IP_PRIORITY_1 0x0060
|
||||
#define AR8X16_REG_IP_PRIORITY_2 0x0064
|
||||
@ -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)
|
||||
|
@ -87,6 +87,13 @@ 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 *);
|
||||
@ -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 *,
|
||||
|
Loading…
Reference in New Issue
Block a user