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