ramips: add arl_table support for MT7530

Use switch.h API to expose MT7530's ARL table to
user space.

Signed-off-by: Salvatore Mesoraca <salvatore@samknows.com>
master
Salvatore Mesoraca 4 years ago committed by Petr Štetiar
parent cc66580293
commit 2a43ab4a18

@ -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[] = {

Loading…
Cancel
Save