|
@@ -2814,7 +2814,7 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+#endif
|
|
|
--- /dev/null
|
|
|
+++ b/drivers/net/ethernet/ralink/mt7530.c
|
|
|
-@@ -0,0 +1,467 @@
|
|
|
+@@ -0,0 +1,571 @@
|
|
|
+/*
|
|
|
+ * This program is free software; you can redistribute it and/or
|
|
|
+ * modify it under the terms of the GNU General Public License
|
|
@@ -2851,25 +2851,45 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+#include "mt7530.h"
|
|
|
+
|
|
|
+#define MT7530_CPU_PORT 6
|
|
|
-+#define MT7530_NUM_PORTS 7
|
|
|
++#define MT7530_NUM_PORTS 8
|
|
|
+#define MT7530_NUM_VLANS 16
|
|
|
-+#define MT7530_NUM_VIDS 16
|
|
|
++#define MT7530_MAX_VID 4095
|
|
|
++#define MT7530_MIN_VID 0
|
|
|
+
|
|
|
-+#define REG_ESW_VLAN_VTCR 0x90
|
|
|
-+#define REG_ESW_VLAN_VAWD1 0x94
|
|
|
-+#define REG_ESW_VLAN_VAWD2 0x98
|
|
|
++/* registers */
|
|
|
++#define REG_ESW_VLAN_VTCR 0x90
|
|
|
++#define REG_ESW_VLAN_VAWD1 0x94
|
|
|
++#define REG_ESW_VLAN_VAWD2 0x98
|
|
|
++#define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2))
|
|
|
++
|
|
|
++#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)
|
|
|
++
|
|
|
++/* vlan egress mode */
|
|
|
++enum {
|
|
|
++ ETAG_CTRL_UNTAG = 0,
|
|
|
++ ETAG_CTRL_TAG = 2,
|
|
|
++ ETAG_CTRL_SWAP = 1,
|
|
|
++ ETAG_CTRL_STACK = 3,
|
|
|
++};
|
|
|
+
|
|
|
++#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8))
|
|
|
++#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8))
|
|
|
++#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8))
|
|
|
+enum {
|
|
|
+ /* Global attributes. */
|
|
|
+ MT7530_ATTR_ENABLE_VLAN,
|
|
|
+};
|
|
|
+
|
|
|
-+struct mt7530_port {
|
|
|
++struct mt7530_port_entry {
|
|
|
+ u16 pvid;
|
|
|
+};
|
|
|
+
|
|
|
-+struct mt7530_vlan {
|
|
|
-+ u8 ports;
|
|
|
++struct mt7530_vlan_entry {
|
|
|
++ u16 vid;
|
|
|
++ u8 member;
|
|
|
++ u8 etags;
|
|
|
+};
|
|
|
+
|
|
|
+struct mt7530_priv {
|
|
@@ -2878,23 +2898,29 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+ struct switch_dev swdev;
|
|
|
+
|
|
|
+ bool global_vlan_enable;
|
|
|
-+ struct mt7530_vlan vlans[MT7530_NUM_VLANS];
|
|
|
-+ struct mt7530_port ports[MT7530_NUM_PORTS];
|
|
|
++ struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS];
|
|
|
++ struct mt7530_port_entry port_entries[MT7530_NUM_PORTS];
|
|
|
+};
|
|
|
+
|
|
|
+struct mt7530_mapping {
|
|
|
+ char *name;
|
|
|
-+ u8 pvids[6];
|
|
|
-+ u8 vlans[8];
|
|
|
++ u16 pvids[MT7530_NUM_PORTS];
|
|
|
++ u8 members[MT7530_NUM_VLANS];
|
|
|
++ u8 etags[MT7530_NUM_VLANS];
|
|
|
++ u16 vids[MT7530_NUM_VLANS];
|
|
|
+} mt7530_defaults[] = {
|
|
|
+ {
|
|
|
+ .name = "llllw",
|
|
|
-+ .pvids = { 1, 1, 1, 1, 2, 1 },
|
|
|
-+ .vlans = { 0, 0x6f, 0x50 },
|
|
|
++ .pvids = { 1, 1, 1, 1, 2, 1, 1 },
|
|
|
++ .members = { 0x6f, 0x50 },
|
|
|
++ .etags = { 0x40, 0x40 },
|
|
|
++ .vids = { 1, 2 },
|
|
|
+ }, {
|
|
|
+ .name = "wllll",
|
|
|
-+ .pvids = { 2, 1, 1, 1, 1, 1 },
|
|
|
-+ .vlans = { 0, 0x7e, 0x41 },
|
|
|
++ .pvids = { 2, 1, 1, 1, 1, 1, 1 },
|
|
|
++ .members = { 0x7e, 0x41 },
|
|
|
++ .etags = { 0x40, 0x40 },
|
|
|
++ .vids = { 1, 2 },
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
@@ -2921,10 +2947,14 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+
|
|
|
+ mt7530->global_vlan_enable = 1;
|
|
|
+
|
|
|
-+ for (i = 0; i < 6; i++)
|
|
|
-+ mt7530->ports[i].pvid = map->pvids[i];
|
|
|
-+ for (i = 0; i < 8; i++)
|
|
|
-+ mt7530->vlans[i].ports = map->vlans[i];
|
|
|
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
|
|
|
++ mt7530->port_entries[i].pvid = map->pvids[i];
|
|
|
++
|
|
|
++ for (i = 0; i < MT7530_NUM_VLANS; i++) {
|
|
|
++ mt7530->vlan_entries[i].member = map->members[i];
|
|
|
++ mt7530->vlan_entries[i].etags = map->etags[i];
|
|
|
++ mt7530->vlan_entries[i].vid = map->vids[i];
|
|
|
++ }
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
@@ -2932,8 +2962,8 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+{
|
|
|
+ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
|
|
|
+
|
|
|
-+ memset(priv->ports, 0, sizeof(priv->ports));
|
|
|
-+ memset(priv->vlans, 0, sizeof(priv->vlans));
|
|
|
++ memset(priv->port_entries, 0, sizeof(priv->port_entries));
|
|
|
++ memset(priv->vlan_entries, 0, sizeof(priv->vlan_entries));
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
@@ -2965,6 +2995,7 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+static u32
|
|
|
+mt7530_r32(struct mt7530_priv *priv, u32 reg)
|
|
|
+{
|
|
|
++ u32 val;
|
|
|
+ if (priv->bus) {
|
|
|
+ u16 high, low;
|
|
|
+
|
|
@@ -2975,7 +3006,10 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+ return (high << 16) | (low & 0xffff);
|
|
|
+ }
|
|
|
+
|
|
|
-+ return ioread32(priv->base + reg);
|
|
|
++ val = ioread32(priv->base + reg);
|
|
|
++ pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val);
|
|
|
++
|
|
|
++ return val;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
@@ -2988,6 +3022,7 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
++ pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val);
|
|
|
+ iowrite32(val, priv->base + reg);
|
|
|
+}
|
|
|
+
|
|
@@ -3018,8 +3053,8 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+ if (port >= MT7530_NUM_PORTS)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
-+ *val = mt7530_r32(priv, 0x2014 + (0x100 * port));
|
|
|
-+ *val &= 0xff;
|
|
|
++ *val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(port));
|
|
|
++ *val &= 0xfff;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
@@ -3030,9 +3065,12 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
|
|
|
+
|
|
|
+ if (port >= MT7530_NUM_PORTS)
|
|
|
-+ return -1;
|
|
|
++ return -EINVAL;
|
|
|
++
|
|
|
++ if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID)
|
|
|
++ return -EINVAL;
|
|
|
+
|
|
|
-+ priv->ports[port].pvid = pvid;
|
|
|
++ priv->port_entries[port].pvid = pvid;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
@@ -3042,26 +3080,38 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+{
|
|
|
+ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
|
|
|
+ u32 member;
|
|
|
++ u32 etags;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ val->len = 0;
|
|
|
+
|
|
|
-+ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VIDS)
|
|
|
++ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ mt7530_vtcr(priv, 0, val->port_vlan);
|
|
|
++
|
|
|
+ member = mt7530_r32(priv, REG_ESW_VLAN_VAWD1);
|
|
|
+ member >>= 16;
|
|
|
+ member &= 0xff;
|
|
|
+
|
|
|
++ etags = mt7530_r32(priv, REG_ESW_VLAN_VAWD2);
|
|
|
++
|
|
|
+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
|
|
|
+ struct switch_port *p;
|
|
|
++ int etag;
|
|
|
++
|
|
|
+ if (!(member & BIT(i)))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ p = &val->value.ports[val->len++];
|
|
|
+ p->id = i;
|
|
|
-+ p->flags = 0;
|
|
|
++
|
|
|
++ etag = (etags >> (i * 2)) & 0x3;
|
|
|
++
|
|
|
++ if (etag == ETAG_CTRL_TAG)
|
|
|
++ p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
|
|
|
++ else if (etag != ETAG_CTRL_UNTAG)
|
|
|
++ printk("vlan egress tag control neither untag nor tag.\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
@@ -3071,10 +3121,11 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
|
|
|
+{
|
|
|
+ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
|
|
|
-+ int ports = 0;
|
|
|
++ u8 member = 0;
|
|
|
++ u8 etags = 0;
|
|
|
+ int i;
|
|
|
+
|
|
|
-+ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VIDS ||
|
|
|
++ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS ||
|
|
|
+ val->len > MT7530_NUM_PORTS)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
@@ -3084,90 +3135,135 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+ if (p->id >= MT7530_NUM_PORTS)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
-+ ports |= BIT(p->id);
|
|
|
++ member |= BIT(p->id);
|
|
|
++
|
|
|
++ if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
|
|
|
++ etags |= BIT(p->id);
|
|
|
+ }
|
|
|
-+ priv->vlans[val->port_vlan].ports = ports;
|
|
|
++ priv->vlan_entries[val->port_vlan].member = member;
|
|
|
++ priv->vlan_entries[val->port_vlan].etags = etags;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
++mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
|
|
++ struct switch_val *val)
|
|
|
++{
|
|
|
++ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
|
|
|
++ int vlan;
|
|
|
++ u16 vid;
|
|
|
++
|
|
|
++ vlan = val->port_vlan;
|
|
|
++ vid = (u16)val->value.i;
|
|
|
++
|
|
|
++ if (vlan < 0 || vlan >= MT7530_NUM_VLANS)
|
|
|
++ return -EINVAL;
|
|
|
++
|
|
|
++ if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID)
|
|
|
++ return -EINVAL;
|
|
|
++
|
|
|
++ priv->vlan_entries[vlan].vid = vid;
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
++static int
|
|
|
++mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
|
|
++ struct switch_val *val)
|
|
|
++{
|
|
|
++ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
|
|
|
++ u32 vid;
|
|
|
++ int vlan;
|
|
|
++
|
|
|
++ vlan = val->port_vlan;
|
|
|
++
|
|
|
++ vid = mt7530_r32(priv, REG_ESW_VLAN_VTIM(vlan));
|
|
|
++ if (vlan & 1)
|
|
|
++ vid = vid >> 12;
|
|
|
++ vid &= 0xfff;
|
|
|
++
|
|
|
++ val->value.i = vid;
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
++static int
|
|
|
+mt7530_apply_config(struct switch_dev *dev)
|
|
|
+{
|
|
|
+ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
|
|
|
-+ int i;
|
|
|
++ int i, j;
|
|
|
+
|
|
|
+ if (!priv->global_vlan_enable) {
|
|
|
-+ mt7530_w32(priv, 0x2004, 0xff000);
|
|
|
-+ mt7530_w32(priv, 0x2104, 0xff000);
|
|
|
-+ mt7530_w32(priv, 0x2204, 0xff000);
|
|
|
-+ mt7530_w32(priv, 0x2304, 0xff000);
|
|
|
-+ mt7530_w32(priv, 0x2404, 0xff000);
|
|
|
-+ mt7530_w32(priv, 0x2504, 0xff000);
|
|
|
-+ mt7530_w32(priv, 0x2604, 0xff000);
|
|
|
-+ mt7530_w32(priv, 0x2010, 0x810000c);
|
|
|
-+ mt7530_w32(priv, 0x2110, 0x810000c);
|
|
|
-+ mt7530_w32(priv, 0x2210, 0x810000c);
|
|
|
-+ mt7530_w32(priv, 0x2310, 0x810000c);
|
|
|
-+ mt7530_w32(priv, 0x2410, 0x810000c);
|
|
|
-+ mt7530_w32(priv, 0x2510, 0x810000c);
|
|
|
-+ mt7530_w32(priv, 0x2610, 0x810000c);
|
|
|
-+ return 0;
|
|
|
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
|
|
|
++ mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00ff0000);
|
|
|
++
|
|
|
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
|
|
|
++ mt7530_w32(priv, REG_ESW_PORT_PVC(i), 0x8100000c);
|
|
|
++
|
|
|
++ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
-+ // LAN/WAN ports as security mode
|
|
|
-+ mt7530_w32(priv, 0x2004, 0xff0003);
|
|
|
-+ mt7530_w32(priv, 0x2104, 0xff0003);
|
|
|
-+ mt7530_w32(priv, 0x2204, 0xff0003);
|
|
|
-+ mt7530_w32(priv, 0x2304, 0xff0003);
|
|
|
-+ mt7530_w32(priv, 0x2404, 0xff0003);
|
|
|
-+ mt7530_w32(priv, 0x2504, 0xff0003);
|
|
|
-+ // LAN/WAN ports as transparent port
|
|
|
-+ mt7530_w32(priv, 0x2010, 0x810000c0);
|
|
|
-+ mt7530_w32(priv, 0x2110, 0x810000c0);
|
|
|
-+ mt7530_w32(priv, 0x2210, 0x810000c0);
|
|
|
-+ mt7530_w32(priv, 0x2310, 0x810000c0);
|
|
|
-+ mt7530_w32(priv, 0x2410, 0x810000c0);
|
|
|
-+ mt7530_w32(priv, 0x2510, 0x810000c0);
|
|
|
-+
|
|
|
-+ // set CPU/P7 port as user port
|
|
|
-+ mt7530_w32(priv, 0x2610, 0x81000000);
|
|
|
-+ mt7530_w32(priv, 0x2710, 0x81000000);
|
|
|
-+
|
|
|
-+ mt7530_w32(priv, 0x2604, 0x20ff0003);
|
|
|
-+ mt7530_w32(priv, 0x2704, 0x20ff0003);
|
|
|
-+ mt7530_w32(priv, 0x2610, 0x81000000);
|
|
|
++ /* set all ports as security mode */
|
|
|
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
|
|
|
++ mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00ff0003);
|
|
|
++
|
|
|
++ /* set all ports as user port */
|
|
|
++ for (i = 0; i < MT7530_NUM_PORTS; i++)
|
|
|
++ mt7530_w32(priv, REG_ESW_PORT_PVC(i), 0x81000000);
|
|
|
+
|
|
|
+ for (i = 0; i < MT7530_NUM_VLANS; i++) {
|
|
|
-+ u8 ports = priv->vlans[i].ports;
|
|
|
-+ u32 val = mt7530_r32(priv, 0x100 + 4 * (i / 2));
|
|
|
++ 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 |= i;
|
|
|
++ val |= vid;
|
|
|
+ } else {
|
|
|
+ val &= 0xfff;
|
|
|
-+ val |= (i << 12);
|
|
|
++ val |= (vid << 12);
|
|
|
+ }
|
|
|
-+ mt7530_w32(priv, 0x100 + 4 * (i / 2), val);
|
|
|
++ mt7530_w32(priv, REG_ESW_VLAN_VTIM(i), val);
|
|
|
+
|
|
|
-+ if (ports)
|
|
|
-+ mt7530_w32(priv, REG_ESW_VLAN_VAWD1, BIT(30) | (ports << 16) | BIT(0));
|
|
|
++ /* 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);
|
|
|
+ }
|
|
|
+
|
|
|
-+ for (i = 0; i < MT7530_NUM_PORTS; i++)
|
|
|
-+ mt7530_w32(priv, 0x2014 + (0x100 * i), 0x10000 | priv->ports[i].pvid);
|
|
|
++ /* Port Default PVID */
|
|
|
++ for (i = 0; i < MT7530_NUM_PORTS; i++) {
|
|
|
++ u32 val;
|
|
|
++ val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(i));
|
|
|
++ val &= ~0xfff;
|
|
|
++ val |= priv->port_entries[i].pvid;
|
|
|
++ mt7530_w32(priv, REG_ESW_PORT_PPBV1(i), val);
|
|
|
++ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+mt7530_get_port_link(struct switch_dev *dev, int port,
|
|
|
-+ struct switch_port_link *link)
|
|
|
++ struct switch_port_link *link)
|
|
|
+{
|
|
|
+ struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
|
|
|
+ u32 speed, pmsr;
|
|
@@ -3216,6 +3312,14 @@ Signed-off-by: John Crispin <[email protected]>
|
|
|
+};
|
|
|
+
|
|
|
+static const struct switch_attr mt7530_vlan[] = {
|
|
|
++ {
|
|
|
++ .type = SWITCH_TYPE_INT,
|
|
|
++ .name = "vid",
|
|
|
++ .description = "VLAN ID (0-4094)",
|
|
|
++ .set = mt7530_set_vid,
|
|
|
++ .get = mt7530_get_vid,
|
|
|
++ .max = 4094,
|
|
|
++ },
|
|
|
+};
|
|
|
+
|
|
|
+static const struct switch_dev_ops mt7530_ops = {
|