diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c index d1e56a76e9..367b8d9ac4 100644 --- a/target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c +++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "mt7530.h" @@ -43,6 +44,8 @@ #endif #define MT7530_MAX_VID 4095 #define MT7530_MIN_VID 0 +#define MT7530_NUM_ARL_RECORDS 2048 +#define ARL_LINE_LENGTH 30 #define MT7530_PORT_MIB_TXB_ID 2 /* TxGOC */ #define MT7530_PORT_MIB_RXB_ID 6 /* RxGOC */ @@ -61,6 +64,20 @@ #define REG_ESW_VLAN_VAWD2 0x98 #define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2)) +#define REG_ESW_WT_MAC_ATC 0x80 +#define REG_ESW_TABLE_ATRD 0x8C +#define REG_ESW_TABLE_TSRA1 0x84 +#define REG_ESW_TABLE_TSRA2 0x88 + +#define REG_MAC_ATC_START 0x8004 +#define REG_MAC_ATC_NEXT 0x8005 + +#define REG_MAC_ATC_BUSY 0x8000U +#define REG_MAC_ATC_SRCH_HIT 0x2000U +#define REG_MAC_ATC_SRCH_END 0x4000U +#define REG_ATRD_VALID 0xff000000U +#define REG_ATRD_PORT_MASK 0xff0U + #define REG_ESW_VLAN_VAWD1_IVL_MAC BIT(30) #define REG_ESW_VLAN_VAWD1_VTAG_EN BIT(28) #define REG_ESW_VLAN_VAWD1_VALID BIT(0) @@ -212,6 +229,7 @@ struct mt7530_priv { bool global_vlan_enable; struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS]; struct mt7530_port_entry port_entries[MT7530_NUM_PORTS]; + char arl_buf[MT7530_NUM_ARL_RECORDS * ARL_LINE_LENGTH + 1]; }; struct mt7530_mapping { @@ -865,6 +883,100 @@ static int mt7530_sw_get_mib(struct switch_dev *dev, return 0; } +static char *mt7530_print_arl_table_row(u32 atrd, + u32 mac1, + u32 mac2, + char *buf, + size_t *size) +{ + int ret; + size_t port; + size_t i; + u8 port_map; + u8 mac[ETH_ALEN]; + + mac1 = ntohl(mac1); + mac2 = ntohl(mac2); + port_map = (u8)((atrd & REG_ATRD_PORT_MASK) >> 4); + memcpy(mac, &mac1, sizeof(mac1)); + memcpy(mac + sizeof(mac1), &mac2, sizeof(mac) - sizeof(mac1)); + for (port = 0, i = 1; port < MT7530_NUM_PORTS; ++port, i <<= 1) { + if (port_map & i) { + ret = snprintf(buf, *size, "Port %d: MAC %pM\n", port, mac); + if (ret >= *size || ret <= 0) { + *buf = 0; + buf = NULL; + goto out; + } + buf += ret; + *size = *size - ret; + } + } +out: + return buf; +} + +static int mt7530_get_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev); + char *buf = priv->arl_buf; + size_t size = sizeof(priv->arl_buf); + size_t count = 0; + size_t retry_times = 100; + int ret; + u32 atc; + + ret = snprintf(buf, size, "address resolution table\n"); + if (ret >= size || ret <= 0) { + priv->arl_buf[0] = 0; + goto out; + } + buf += ret; + size = size - ret; + + mt7530_w32(priv, REG_ESW_WT_MAC_ATC, REG_MAC_ATC_START); + + do { + atc = mt7530_r32(priv, REG_ESW_WT_MAC_ATC); + if (atc & REG_MAC_ATC_SRCH_HIT && !(atc & REG_MAC_ATC_BUSY)) { + u32 atrd; + + ++count; + atrd = mt7530_r32(priv, REG_ESW_TABLE_ATRD); + if (atrd & REG_ATRD_VALID) { + u32 mac1; + u32 mac2; + + mac1 = mt7530_r32(priv, REG_ESW_TABLE_TSRA1); + mac2 = mt7530_r32(priv, REG_ESW_TABLE_TSRA2); + + if (!(atc & REG_MAC_ATC_SRCH_END)) + mt7530_w32(priv, REG_ESW_WT_MAC_ATC, REG_MAC_ATC_NEXT); + + buf = mt7530_print_arl_table_row(atrd, mac1, mac2, buf, &size); + if (!buf) { + pr_warn("%s: too many addresses\n", __func__); + goto out; + } + } else if (!(atc & REG_MAC_ATC_SRCH_END)) { + mt7530_w32(priv, REG_ESW_WT_MAC_ATC, REG_MAC_ATC_NEXT); + } + } else { + --retry_times; + usleep_range(1000, 5000); + } + } while (!(atc & REG_MAC_ATC_SRCH_END) && + count < MT7530_NUM_ARL_RECORDS && + retry_times > 0); +out: + val->value.s = priv->arl_buf; + val->len = strlen(priv->arl_buf); + + return 0; +} + static int mt7530_sw_get_port_mib(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) @@ -944,6 +1056,13 @@ static const struct switch_attr mt7530_global[] = { .get = mt7530_get_mirror_monitor_port, .max = MT7530_NUM_PORTS - 1 }, + { + .type = SWITCH_TYPE_STRING, + .name = "arl_table", + .description = "Get ARL table", + .set = NULL, + .get = mt7530_get_arl_table, + }, }; static const struct switch_attr mt7621_port[] = {