--- a/drivers/net/ethernet/mediatek/mt7530.c
+++ b/drivers/net/ethernet/mediatek/mt7530.c
-@@ -547,6 +547,7 @@ mt7530_apply_config(struct switch_dev *d
- u8 etags = priv->vlan_entries[i].etags;
- u32 val;
+@@ -44,6 +44,12 @@
+ #define MT7530_MAX_VID 4095
+ #define MT7530_MIN_VID 0
+
++#define MT7530_PORT_MIB_TXB_ID 2 /* TxGOC */
++#define MT7530_PORT_MIB_RXB_ID 6 /* RxGOC */
++
++#define MT7621_PORT_MIB_TXB_ID 18 /* TxByte */
++#define MT7621_PORT_MIB_RXB_ID 37 /* RxByte */
++
+ /* registers */
+ #define REG_ESW_VLAN_VTCR 0x90
+ #define REG_ESW_VLAN_VAWD1 0x94
+@@ -214,6 +220,12 @@ struct mt7530_mapping {
+ .members = { 0, 0x7e, 0x41 },
+ .etags = { 0, 0x40, 0x40 },
+ .vids = { 0, 1, 2 },
++ }, {
++ .name = "lwlll",
++ .pvids = { 1, 2, 1, 1, 1, 1, 1 },
++ .members = { 0, 0x7d, 0x42 },
++ .etags = { 0, 0x40, 0x40 },
++ .vids = { 0, 1, 2 },
+ },
+ };
+@@ -467,6 +479,14 @@ mt7530_set_vid(struct switch_dev *dev, c
+ }
+
+ static int
++mt7621_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ val->value.i = val->port_vlan;
++ return 0;
++}
++
++static int
+ mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+ struct switch_val *val)
+ {
+@@ -485,6 +505,52 @@ mt7530_get_vid(struct switch_dev *dev, c
+ return 0;
+ }
+
++static void
++mt7530_write_vlan_entry(struct mt7530_priv *priv, int vlan, u16 vid,
++ u8 ports, u8 etags)
++{
++ int port;
++ u32 val;
++
+#ifndef CONFIG_SOC_MT7621
- /* vid of vlan */
- val = mt7530_r32(priv, REG_ESW_VLAN_VTIM(i));
- if (i % 2 == 0) {
-@@ -557,7 +558,7 @@ mt7530_apply_config(struct switch_dev *d
- val |= (vid << 12);
- }
- mt7530_w32(priv, REG_ESW_VLAN_VTIM(i), val);
--
++ /* vid of vlan */
++ val = mt7530_r32(priv, REG_ESW_VLAN_VTIM(vlan));
++ if (vlan % 2 == 0) {
++ val &= 0xfff000;
++ val |= vid;
++ } else {
++ val &= 0xfff;
++ val |= (vid << 12);
++ }
++ mt7530_w32(priv, REG_ESW_VLAN_VTIM(vlan), val);
+#endif
- /* vlan port membership */
- if (member)
- mt7530_w32(priv, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
-@@ -577,7 +578,11 @@ mt7530_apply_config(struct switch_dev *d
- mt7530_w32(priv, REG_ESW_VLAN_VAWD2, val);
-
- /* write to vlan table */
++
++ /* vlan port membership */
++ if (ports)
++ mt7530_w32(priv, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
++ REG_ESW_VLAN_VAWD1_VTAG_EN | (ports << 16) |
++ REG_ESW_VLAN_VAWD1_VALID);
++ else
++ mt7530_w32(priv, REG_ESW_VLAN_VAWD1, 0);
++
++ /* egress mode */
++ val = 0;
++ for (port = 0; port < MT7530_NUM_PORTS; port++) {
++ if (etags & BIT(port))
++ val |= ETAG_CTRL_TAG << (port * 2);
++ else
++ val |= ETAG_CTRL_UNTAG << (port * 2);
++ }
++ mt7530_w32(priv, REG_ESW_VLAN_VAWD2, val);
++
++ /* write to vlan table */
+#ifdef CONFIG_SOC_MT7621
-+ mt7530_vtcr(priv, 1, vid);
++ mt7530_vtcr(priv, 1, vid);
+#else
- mt7530_vtcr(priv, 1, i);
++ mt7530_vtcr(priv, 1, vlan);
+#endif
++}
++
+ static int
+ mt7530_apply_config(struct switch_dev *dev)
+ {
+@@ -541,51 +607,33 @@ mt7530_apply_config(struct switch_dev *d
+ mt7530_w32(priv, REG_ESW_PORT_PVC(i), pvc_mode);
+ }
+
++ /* first clear the swtich vlan table */
++ for (i = 0; i < MT7530_NUM_VLANS; i++)
++ mt7530_write_vlan_entry(priv, i, i, 0, 0);
++
++ /* now program only vlans with members to avoid
++ clobbering remapped entries in later iterations */
+ for (i = 0; i < MT7530_NUM_VLANS; i++) {
+ u16 vid = priv->vlan_entries[i].vid;
+ u8 member = priv->vlan_entries[i].member;
+ u8 etags = priv->vlan_entries[i].etags;
+- u32 val;
+
+- /* vid of vlan */
+- val = mt7530_r32(priv, REG_ESW_VLAN_VTIM(i));
+- if (i % 2 == 0) {
+- val &= 0xfff000;
+- val |= vid;
+- } else {
+- val &= 0xfff;
+- val |= (vid << 12);
+- }
+- mt7530_w32(priv, REG_ESW_VLAN_VTIM(i), val);
+-
+- /* vlan port membership */
+ if (member)
+- mt7530_w32(priv, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
+- REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) |
+- REG_ESW_VLAN_VAWD1_VALID);
+- else
+- mt7530_w32(priv, REG_ESW_VLAN_VAWD1, 0);
+-
+- /* egress mode */
+- val = 0;
+- for (j = 0; j < MT7530_NUM_PORTS; j++) {
+- if (etags & BIT(j))
+- val |= ETAG_CTRL_TAG << (j * 2);
+- else
+- val |= ETAG_CTRL_UNTAG << (j * 2);
+- }
+- mt7530_w32(priv, REG_ESW_VLAN_VAWD2, val);
+-
+- /* write to vlan table */
+- mt7530_vtcr(priv, 1, i);
++ mt7530_write_vlan_entry(priv, i, vid, member, etags);
}
/* Port Default PVID */
+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
++ int vlan = priv->port_entries[i].pvid;
++ u16 pvid = 0;
+ u32 val;
++
++ if (vlan < MT7530_NUM_VLANS && priv->vlan_entries[vlan].member)
++ pvid = priv->vlan_entries[vlan].vid;
++
+ val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(i));
+ val &= ~0xfff;
+- val |= priv->port_entries[i].pvid;
++ val |= pvid;
+ mt7530_w32(priv, REG_ESW_PORT_PPBV1(i), val);
+ }
+
+@@ -739,6 +787,34 @@ static int mt7530_sw_get_port_mib(struct
+ return 0;
+ }
+
++static int mt7530_get_port_stats(struct switch_dev *dev, int port,
++ struct switch_port_stats *stats)
++{
++ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
++
++ if (port < 0 || port >= MT7530_NUM_PORTS)
++ return -EINVAL;
++
++ stats->tx_bytes = get_mib_counter_port_7620(priv, MT7530_PORT_MIB_TXB_ID, port);
++ stats->rx_bytes = get_mib_counter_port_7620(priv, MT7530_PORT_MIB_RXB_ID, port);
++
++ return 0;
++}
++
++static int mt7621_get_port_stats(struct switch_dev *dev, int port,
++ struct switch_port_stats *stats)
++{
++ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
++
++ if (port < 0 || port >= MT7530_NUM_PORTS)
++ return -EINVAL;
++
++ stats->tx_bytes = get_mib_counter(priv, MT7621_PORT_MIB_TXB_ID, port);
++ stats->rx_bytes = get_mib_counter(priv, MT7621_PORT_MIB_RXB_ID, port);
++
++ return 0;
++}
++
+ static const struct switch_attr mt7530_global[] = {
+ {
+ .type = SWITCH_TYPE_INT,
+@@ -767,6 +843,17 @@ static const struct switch_attr mt7621_p
+ },
+ };
+
++static const struct switch_attr mt7621_vlan[] = {
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "vid",
++ .description = "VLAN ID (0-4094)",
++ .set = mt7530_set_vid,
++ .get = mt7621_get_vid,
++ .max = 4094,
++ },
++};
++
+ static const struct switch_attr mt7530_port[] = {
+ {
+ .type = SWITCH_TYPE_STRING,
+@@ -798,14 +885,15 @@ static const struct switch_dev_ops mt762
+ .n_attr = ARRAY_SIZE(mt7621_port),
+ },
+ .attr_vlan = {
+- .attr = mt7530_vlan,
+- .n_attr = ARRAY_SIZE(mt7530_vlan),
++ .attr = mt7621_vlan,
++ .n_attr = ARRAY_SIZE(mt7621_vlan),
+ },
+ .get_vlan_ports = mt7530_get_vlan_ports,
+ .set_vlan_ports = mt7530_set_vlan_ports,
+ .get_port_pvid = mt7530_get_port_pvid,
+ .set_port_pvid = mt7530_set_port_pvid,
+ .get_port_link = mt7530_get_port_link,
++ .get_port_stats = mt7621_get_port_stats,
+ .apply_config = mt7530_apply_config,
+ .reset_switch = mt7530_reset_switch,
+ };
+@@ -828,6 +916,7 @@ static const struct switch_dev_ops mt753
+ .get_port_pvid = mt7530_get_port_pvid,
+ .set_port_pvid = mt7530_set_port_pvid,
+ .get_port_link = mt7530_get_port_link,
++ .get_port_stats = mt7530_get_port_stats,
+ .apply_config = mt7530_apply_config,
+ .reset_switch = mt7530_reset_switch,
+ };
+@@ -881,7 +970,7 @@ mt7530_probe(struct device *dev, void __
+
+ /* magic vodoo */
+ if (!IS_ENABLED(CONFIG_SOC_MT7621) && bus && mt7530_r32(mt7530, REG_HWTRAP) != 0x1117edf) {
+- dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n");
++ dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n");
+ mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf);
+ }
+ dev_info(dev, "loaded %s driver\n", swdev->name);