ramips: add arl_table support for MT7530
authorSalvatore Mesoraca <salvatore@samknows.com>
Wed, 17 Jun 2020 13:07:58 +0000 (14:07 +0100)
committerPetr Štetiar <ynezz@true.cz>
Fri, 17 Jul 2020 09:00:33 +0000 (11:00 +0200)
Use switch.h API to expose MT7530's ARL table to
user space.

Signed-off-by: Salvatore Mesoraca <salvatore@samknows.com>
target/linux/ramips/files/drivers/net/ethernet/ralink/mt7530.c

index d1e56a76e92d8b44363bfcf7460d8a080c8d314e..367b8d9ac4569f00972e89f3a48e45b09718293b 100644 (file)
@@ -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 */
 #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[] = {