ramips: backport mt7530/762x switch fixes
authorJo-Philipp Wich <jo@mein.io>
Thu, 15 Feb 2018 09:47:04 +0000 (10:47 +0100)
committerJo-Philipp Wich <jo@mein.io>
Thu, 15 Feb 2018 09:48:02 +0000 (10:48 +0100)
dc7a1e8555 ("ramips: fix reporting effective VLAN ID on MT7621 switches")
341b1427fc ("ramips: properly map pvid for vlans with remapped vid on mt7530/762x switches")
bb4002c79d ("ramips: don't clobber vlans with remapped vid on mt7530/762x switches")

Fixes FS#991, FS#1147, FS#1341

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
target/linux/ramips/patches-4.4/0519-gsw_mt7621.patch

index e146de2..5f0594c 100644 (file)
 --- 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);