aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ramips
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ramips')
-rw-r--r--target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c119
1 files changed, 119 insertions, 0 deletions
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 <linux/lockdep.h>
#include <linux/workqueue.h>
#include <linux/of_device.h>
+#include <asm/byteorder.h>
#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[] = {