ramips: don't clobber vlans with remapped vid on mt7530/762x switches
[openwrt/openwrt.git] / target / linux / ramips / files-4.9 / drivers / net / ethernet / mtk / mt7530.c
index 1ec62e0..e61f9fd 100644 (file)
 #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 },
        },
 };
 
@@ -485,6 +497,52 @@ mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
        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(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 (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);
+#else
+       mt7530_vtcr(priv, 1, vlan);
+#endif
+}
+
 static int
 mt7530_apply_config(struct switch_dev *dev)
 {
@@ -541,48 +599,19 @@ mt7530_apply_config(struct switch_dev *dev)
                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;
 
-#ifndef CONFIG_SOC_MT7621
-               /* 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);
-#endif
-               /* 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 */
-#ifdef CONFIG_SOC_MT7621
-               mt7530_vtcr(priv, 1, vid);
-#else
-               mt7530_vtcr(priv, 1, i);
-#endif
+                       mt7530_write_vlan_entry(priv, i, vid, member, etags);
        }
 
        /* Port Default PVID */
@@ -744,6 +773,34 @@ static int mt7530_sw_get_port_mib(struct switch_dev *dev,
        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,
@@ -811,6 +868,7 @@ static const struct switch_dev_ops mt7621_ops = {
        .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,
 };
@@ -833,6 +891,7 @@ static const struct switch_dev_ops mt7530_ops = {
        .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,
 };
@@ -886,7 +945,7 @@ mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vl
 
        /* 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);