Skip to contentSkip to conversation

add VLAN support to DSA MT7530

PATCH Superseded [email protected] 4 participants 9 messages Dec 13, 2017 – Dec 15, 2017

Subsystems (5)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover add VLAN support to DSA MT7530

From: Sean Wang <[email protected]>

Changes since v1:
- fix up the typo
- prefer ordering declarations longest to shortest
- update that vlan_prepare callback should not change any state
- use lower case letter for function naming

The patchset extends DSA MT7530 to VLAN support through filling required callbacks in patch 1 and merging the special tag with VLAN tag in patch 2 for allowing that the hardware can handle these packets with VID from the CPU port.

Sean Wang (3):
net: dsa: mediatek: add VLAN support for MT7530
net: dsa: mediatek: combine MediaTek tag with VLAN tag
net: dsa: mediatek: update MAINTAINERS entry with MediaTek switch
driver

 MAINTAINERS              |   7 ++
 drivers/net/dsa/mt7530.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/dsa/mt7530.h |  83 +++++++++++++-
 net/dsa/tag_mtk.c        |  38 +++++--
 4 files changed, 403 insertions(+), 16 deletions(-)
Signature · 1 line
2.7.4
#1 lore raw

PATCH v2 1/3 net: dsa: mediatek: add VLAN support for MT7530

From: Sean Wang <[email protected]>

MT7530 can treat each port as either VLAN-unaware port or VLAN-aware port through the implementation of port matrix mode or port security mode on the ingress port, respectively. On one hand, Each port has been acting as the VLAN-unaware one whenever the device is created in the initial or certain port joins or leaves into/from the bridge at the runtime. On the other hand, the patch just filling the required callbacks for VLAN operations is achieved via extending the port to be into port security mode when the port is configured as VLAN-aware port. Which mode can make the port be able to recognize VID from incoming packets and look up VLAN table to validate and judge which port it should be going to. And the range for VID from 1 to 4094 is valid for the hardware.

---
 drivers/net/dsa/mt7530.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/dsa/mt7530.h |  83 +++++++++++++-
 2 files changed, 367 insertions(+), 7 deletions(-)
drivers/net/dsa/mt7530.c +290 -1
index 2820d69..252e8ba 100644
@@ -805,6 +805,69 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
 }
 
 static void
+mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
+{
+	struct mt7530_priv *priv = ds->priv;
+	bool all_user_ports_removed = true;
+	int i;
+
+	/* When a port is removed from the bridge, the port would be set up
+	 * back to the default as is at initial boot which is a VLAN-unaware
+	 * port.
+	 */
+	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
+		   MT7530_PORT_MATRIX_MODE);
+	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
+		   VLAN_ATTR(MT7530_VLAN_TRANSPARENT));
+
+	priv->ports[port].vlan_filtering = false;
+
+	for (i = 0; i < MT7530_NUM_PORTS; i++) {
+		if (dsa_is_user_port(ds, i) &&
+		    priv->ports[i].vlan_filtering) {
+			all_user_ports_removed = false;
+			break;
+		}
+	}
+
+	/* CPU port also does the same thing until all user ports belonging to
+	 * the CPU port get out of VLAN filtering mode.
+	 */
+	if (all_user_ports_removed) {
+		mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT),
+			     PCR_MATRIX(dsa_user_ports(priv->ds)));
+		mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT),
+			     PORT_SPEC_TAG);
+	}
+}
+
+static void
+mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)
+{
+	struct mt7530_priv *priv = ds->priv;
+
+	/* The real fabric path would be decided on the membership in the
+	 * entry of VLAN table. PCR_MATRIX set up here with ALL_MEMBERS
+	 * means potential VLAN can be consisting of certain subset of all
+	 * ports.
+	 */
+	mt7530_rmw(priv, MT7530_PCR_P(port),
+		   PCR_MATRIX_MASK, PCR_MATRIX(MT7530_ALL_MEMBERS));
+
+	/* Trapped into security mode allows packet forwarding through VLAN
+	 * table lookup.
+	 */
+	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
+		   MT7530_PORT_SECURITY_MODE);
+
+	/* Set the port as a user port which is to be able to recognize VID
+	 * from incoming packets before fetching entry within the VLAN table.
+	 */
+	mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
+		   VLAN_ATTR(MT7530_VLAN_USER));
+}
+
+static void
 mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
 			 struct net_device *bridge)
 {
@@ -817,8 +880,11 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
 		/* Remove this port from the port matrix of the other ports
 		 * in the same bridge. If the port is disabled, port matrix
 		 * is kept and not being setup until the port becomes enabled.
+		 * And the other port's port matrix cannot be broken when the
+		 * other port is still a VLAN-aware port.
 		 */
-		if (dsa_is_user_port(ds, i) && i != port) {
+		if (!priv->ports[i].vlan_filtering &&
+		    dsa_is_user_port(ds, i) && i != port) {
 			if (dsa_to_port(ds, i)->bridge_dev != bridge)
 				continue;
 			if (priv->ports[i].enable)
@@ -836,6 +902,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
 			   PCR_MATRIX(BIT(MT7530_CPU_PORT)));
 	priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
 
+	mt7530_port_set_vlan_unaware(ds, port);
+
 	mutex_unlock(&priv->reg_mutex);
 }
 
@@ -906,6 +974,223 @@ mt7530_port_fdb_dump(struct dsa_switch *ds, int port,
 	return 0;
 }
 
+static int
+mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
+{
+	struct mt7530_dummy_poll p;
+	u32 val;
+	int ret;
+
+	val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
+	mt7530_write(priv, MT7530_VTCR, val);
+
+	INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
+	ret = readx_poll_timeout(_mt7530_read, &p, val,
+				 !(val & VTCR_BUSY), 20, 20000);
+	if (ret < 0) {
+		dev_err(priv->dev, "poll timeout\n");
+		return ret;
+	}
+
+	val = mt7530_read(priv, MT7530_VTCR);
+	if (val & VTCR_INVALID) {
+		dev_err(priv->dev, "read VTCR invalid\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+mt7530_port_vlan_filtering(struct dsa_switch *ds, int port,
+			   bool vlan_filtering)
+{
+	struct mt7530_priv *priv = ds->priv;
+
+	priv->ports[port].vlan_filtering = vlan_filtering;
+
+	if (vlan_filtering) {
+		/* The port is being kept as VLAN-unaware port when bridge is
+		 * set up with vlan_filtering not being set, Otherwise, the
+		 * port and the corresponding CPU port is required the setup
+		 * for becoming a VLAN-aware port.
+		 */
+		mt7530_port_set_vlan_aware(ds, port);
+		mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT);
+	}
+
+	return 0;
+}
+
+static int
+mt7530_port_vlan_prepare(struct dsa_switch *ds, int port,
+			 const struct switchdev_obj_port_vlan *vlan,
+			 struct switchdev_trans *trans)
+{
+	/* nothing needed */
+
+	return 0;
+}
+
+static void
+mt7530_hw_vlan_add(struct mt7530_priv *priv,
+		   struct mt7530_hw_vlan_entry *entry)
+{
+	u8 new_members;
+	u32 val;
+
+	new_members = entry->old_members | BIT(entry->port) |
+		      BIT(MT7530_CPU_PORT);
+
+	/* Validate the entry with independent learning, create egress tag per
+	 * VLAN and joining the port as one of the port members.
+	 */
+	val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | VLAN_VALID;
+	mt7530_write(priv, MT7530_VAWD1, val);
+
+	/* Decide whether adding tag or not for those outgoing packets from the
+	 * port inside the VLAN.
+	 */
+	val = entry->untagged ? MT7530_VLAN_EGRESS_UNTAG :
+				MT7530_VLAN_EGRESS_TAG;
+	mt7530_rmw(priv, MT7530_VAWD2,
+		   ETAG_CTRL_P_MASK(entry->port),
+		   ETAG_CTRL_P(entry->port, val));
+
+	/* CPU port is always taken as a tagged port for serving more than one
+	 * VLANs across and also being applied with egress type stack mode for
+	 * that VLAN tags would be appended after hardware special tag used as
+	 * DSA tag.
+	 */
+	mt7530_rmw(priv, MT7530_VAWD2,
+		   ETAG_CTRL_P_MASK(MT7530_CPU_PORT),
+		   ETAG_CTRL_P(MT7530_CPU_PORT,
+			       MT7530_VLAN_EGRESS_STACK));
+}
+
+static void
+mt7530_hw_vlan_del(struct mt7530_priv *priv,
+		   struct mt7530_hw_vlan_entry *entry)
+{
+	u8 new_members;
+	u32 val;
+
+	new_members = entry->old_members & ~BIT(entry->port);
+
+	val = mt7530_read(priv, MT7530_VAWD1);
+	if (!(val & VLAN_VALID)) {
+		dev_err(priv->dev,
+			"Cannot be deleted due to invalid entry\n");
+		return;
+	}
+
+	/* If certain member apart from CPU port is still alive in the VLAN,
+	 * the entry would be kept valid. Otherwise, the entry is got to be
+	 * disabled.
+	 */
+	if (new_members && new_members != BIT(MT7530_CPU_PORT)) {
+		val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) |
+		      VLAN_VALID;
+		mt7530_write(priv, MT7530_VAWD1, val);
+	} else {
+		mt7530_write(priv, MT7530_VAWD1, 0);
+		mt7530_write(priv, MT7530_VAWD2, 0);
+	}
+}
+
+static void
+mt7530_hw_vlan_update(struct mt7530_priv *priv, u16 vid,
+		      struct mt7530_hw_vlan_entry *entry,
+		      mt7530_vlan_op vlan_op)
+{
+	u32 val;
+
+	/* Fetch entry */
+	mt7530_vlan_cmd(priv, MT7530_VTCR_RD_VID, vid);
+
+	val = mt7530_read(priv, MT7530_VAWD1);
+
+	entry->old_members = (val >> PORT_MEM_SHFT) & PORT_MEM_MASK;
+
+	/* Manipulate entry */
+	vlan_op(priv, entry);
+
+	/* Flush result to hardware */
+	mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, vid);
+}
+
+static void
+mt7530_port_vlan_add(struct dsa_switch *ds, int port,
+		     const struct switchdev_obj_port_vlan *vlan,
+		     struct switchdev_trans *trans)
+{
+	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+	struct mt7530_hw_vlan_entry new_entry;
+	struct mt7530_priv *priv = ds->priv;
+	int ret;
+	u16 vid;
+
+	/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
+	 * being set.
+	 */
+	if (!priv->ports[port].vlan_filtering)
+		return;
+
+	mutex_lock(&priv->reg_mutex);
+
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
+		mt7530_hw_vlan_entry_init(&new_entry, port, untagged);
+		mt7530_hw_vlan_update(priv, vid, &new_entry,
+				      mt7530_hw_vlan_add);
+	}
+
+	if (pvid) {
+		mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
+			   G0_PORT_VID(vlan->vid_end));
+		priv->ports[port].pvid = vlan->vid_end;
+	}
+
+	mutex_unlock(&priv->reg_mutex);
+}
+
+static int
+mt7530_port_vlan_del(struct dsa_switch *ds, int port,
+		     const struct switchdev_obj_port_vlan *vlan)
+{
+	struct mt7530_hw_vlan_entry target_entry;
+	struct mt7530_priv *priv = ds->priv;
+	u16 vid, pvid;
+
+	/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
+	 * being set.
+	 */
+	if (!priv->ports[port].vlan_filtering)
+		return 0;
+
+	mutex_lock(&priv->reg_mutex);
+
+	pvid = priv->ports[port].pvid;
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
+		mt7530_hw_vlan_entry_init(&target_entry, port, 0);
+		mt7530_hw_vlan_update(priv, vid, &target_entry,
+				      mt7530_hw_vlan_del);
+
+		/* PVID is being restored to the default whenever the PVID port
+		 * is being removed from the VLAN.
+		 */
+		if (pvid == vid)
+			pvid = G0_PORT_VID_DEF;
+	}
+
+	mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, pvid);
+	priv->ports[port].pvid = pvid;
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
 static enum dsa_tag_protocol
 mtk_get_tag_protocol(struct dsa_switch *ds, int port)
 {
@@ -1035,6 +1320,10 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
 	.port_fdb_add		= mt7530_port_fdb_add,
 	.port_fdb_del		= mt7530_port_fdb_del,
 	.port_fdb_dump		= mt7530_port_fdb_dump,
+	.port_vlan_filtering	= mt7530_port_vlan_filtering,
+	.port_vlan_prepare	= mt7530_port_vlan_prepare,
+	.port_vlan_add		= mt7530_port_vlan_add,
+	.port_vlan_del		= mt7530_port_vlan_del,
 };
 
 static int
drivers/net/dsa/mt7530.h +77 -6

140 lines not on this page · raw message

Signature · 1 line
2.7.4
#2 lore raw

Re: [PATCH v2 net-next 1/3] net: dsa: mediatek: add VLAN support for MT7530

I love your patch! Yet something to improve:

Hi Sean,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url: https://github.com/0day-ci/linux/commits/sean-wang-mediatek-com/add-VLAN-support-to-DSA-MT7530/20171215-214450
config: i386-randconfig-x019-201750 (attached as .config)
compiler: gcc-7 (Debian 7.2.0-12) 7.2.1 20171025 reproduce:

        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

drivers/net/dsa/mt7530.c: In function 'mt7530_port_vlan_add':
drivers/net/dsa/mt7530.c:1131:6: warning: unused variable 'ret' [-Wunused-variable]

     int ret;
         ^~~
   drivers/net/dsa/mt7530.c: At top level:
>> drivers/net/dsa/mt7530.c:1324:23: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .port_vlan_prepare = mt7530_port_vlan_prepare,
                          ^~~~~~~~~~~~~~~~~~~~~~~~
   drivers/net/dsa/mt7530.c:1324:23: note: (near initialization for 'mt7530_switch_ops.port_vlan_prepare')
   drivers/net/dsa/mt7530.c:1325:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .port_vlan_add  = mt7530_port_vlan_add,
                       ^~~~~~~~~~~~~~~~~~~~

drivers/net/dsa/mt7530.c:1325:20: note: (near initialization for 'mt7530_switch_ops.port_vlan_add')
cc1: some warnings being treated as errors

vim +1324 drivers/net/dsa/mt7530.c

1121
1122 static void
1123 mt7530_port_vlan_add(struct dsa_switch *ds, int port,
1124 const struct switchdev_obj_port_vlan *vlan,
1125 struct switchdev_trans *trans)
1126 {
1127 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1128 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1129 struct mt7530_hw_vlan_entry new_entry;
1130 struct mt7530_priv *priv = ds->priv;

> 1131		int ret;
  1132		u16 vid;
  1133	
  1134		/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
  1135		 * being set.
  1136		 */
  1137		if (!priv->ports[port].vlan_filtering)
  1138			return;
  1139	
  1140		mutex_lock(&priv->reg_mutex);
  1141	
  1142		for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
  1143			mt7530_hw_vlan_entry_init(&new_entry, port, untagged);
  1144			mt7530_hw_vlan_update(priv, vid, &new_entry,
  1145					      mt7530_hw_vlan_add);
  1146		}
  1147	
  1148		if (pvid) {
  1149			mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
  1150				   G0_PORT_VID(vlan->vid_end));
  1151			priv->ports[port].pvid = vlan->vid_end;
  1152		}
  1153	
  1154		mutex_unlock(&priv->reg_mutex);
  1155	}
  1156	
  1157	static int
  1158	mt7530_port_vlan_del(struct dsa_switch *ds, int port,
  1159			     const struct switchdev_obj_port_vlan *vlan)
  1160	{
  1161		struct mt7530_hw_vlan_entry target_entry;
  1162		struct mt7530_priv *priv = ds->priv;
  1163		u16 vid, pvid;
  1164	
  1165		/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
  1166		 * being set.
  1167		 */
  1168		if (!priv->ports[port].vlan_filtering)
  1169			return 0;
  1170	
  1171		mutex_lock(&priv->reg_mutex);
  1172	
  1173		pvid = priv->ports[port].pvid;
  1174		for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
  1175			mt7530_hw_vlan_entry_init(&target_entry, port, 0);
  1176			mt7530_hw_vlan_update(priv, vid, &target_entry,
  1177					      mt7530_hw_vlan_del);
  1178	
  1179			/* PVID is being restored to the default whenever the PVID port
  1180			 * is being removed from the VLAN.
  1181			 */
  1182			if (pvid == vid)
  1183				pvid = G0_PORT_VID_DEF;
  1184		}
  1185	
  1186		mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, pvid);
  1187		priv->ports[port].pvid = pvid;
  1188	
  1189		mutex_unlock(&priv->reg_mutex);
  1190	
  1191		return 0;
  1192	}
  1193	
  1194	static enum dsa_tag_protocol
  1195	mtk_get_tag_protocol(struct dsa_switch *ds, int port)
  1196	{
  1197		struct mt7530_priv *priv = ds->priv;
  1198	
  1199		if (port != MT7530_CPU_PORT) {
  1200			dev_warn(priv->dev,
  1201				 "port not matched with tagging CPU port\n");
  1202			return DSA_TAG_PROTO_NONE;
  1203		} else {
  1204			return DSA_TAG_PROTO_MTK;
  1205		}
  1206	}
  1207	
  1208	static int
  1209	mt7530_setup(struct dsa_switch *ds)
  1210	{
  1211		struct mt7530_priv *priv = ds->priv;
  1212		int ret, i;
  1213		u32 id, val;
  1214		struct device_node *dn;
  1215		struct mt7530_dummy_poll p;
  1216	
  1217		/* The parent node of master netdev which holds the common system
  1218		 * controller also is the container for two GMACs nodes representing
  1219		 * as two netdev instances.
  1220		 */
  1221		dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent;
  1222		priv->ethernet = syscon_node_to_regmap(dn);
  1223		if (IS_ERR(priv->ethernet))
  1224			return PTR_ERR(priv->ethernet);
  1225	
  1226		regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
  1227		ret = regulator_enable(priv->core_pwr);
  1228		if (ret < 0) {
  1229			dev_err(priv->dev,
  1230				"Failed to enable core power: %d\n", ret);
  1231			return ret;
  1232		}
  1233	
  1234		regulator_set_voltage(priv->io_pwr, 3300000, 3300000);
  1235		ret = regulator_enable(priv->io_pwr);
  1236		if (ret < 0) {
  1237			dev_err(priv->dev, "Failed to enable io pwr: %d\n",
  1238				ret);
  1239			return ret;
  1240		}
  1241	
  1242		/* Reset whole chip through gpio pin or memory-mapped registers for
  1243		 * different type of hardware
  1244		 */
  1245		if (priv->mcm) {
  1246			reset_control_assert(priv->rstc);
  1247			usleep_range(1000, 1100);
  1248			reset_control_deassert(priv->rstc);
  1249		} else {
  1250			gpiod_set_value_cansleep(priv->reset, 0);
  1251			usleep_range(1000, 1100);
  1252			gpiod_set_value_cansleep(priv->reset, 1);
  1253		}
  1254	
  1255		/* Waiting for MT7530 got to stable */
  1256		INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP);
  1257		ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
  1258					 20, 1000000);
  1259		if (ret < 0) {
  1260			dev_err(priv->dev, "reset timeout\n");
  1261			return ret;
  1262		}
  1263	
  1264		id = mt7530_read(priv, MT7530_CREV);
  1265		id >>= CHIP_NAME_SHIFT;
  1266		if (id != MT7530_ID) {
  1267			dev_err(priv->dev, "chip %x can't be supported\n", id);
  1268			return -ENODEV;
  1269		}
  1270	
  1271		/* Reset the switch through internal reset */
  1272		mt7530_write(priv, MT7530_SYS_CTRL,
  1273			     SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
  1274			     SYS_CTRL_REG_RST);
  1275	
  1276		/* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
  1277		val = mt7530_read(priv, MT7530_MHWTRAP);
  1278		val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
  1279		val |= MHWTRAP_MANUAL;
  1280		mt7530_write(priv, MT7530_MHWTRAP, val);
  1281	
  1282		/* Enable and reset MIB counters */
  1283		mt7530_mib_reset(ds);
  1284	
  1285		mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
  1286	
  1287		for (i = 0; i < MT7530_NUM_PORTS; i++) {
  1288			/* Disable forwarding by default on all ports */
  1289			mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
  1290				   PCR_MATRIX_CLR);
  1291	
  1292			if (dsa_is_cpu_port(ds, i))
  1293				mt7530_cpu_port_enable(priv, i);
  1294			else
  1295				mt7530_port_disable(ds, i, NULL);
  1296		}
  1297	
  1298		/* Flush the FDB table */
  1299		ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0);
  1300		if (ret < 0)
  1301			return ret;
  1302	
  1303		return 0;
  1304	}
  1305	
  1306	static const struct dsa_switch_ops mt7530_switch_ops = {
  1307		.get_tag_protocol	= mtk_get_tag_protocol,
  1308		.setup			= mt7530_setup,
  1309		.get_strings		= mt7530_get_strings,
  1310		.phy_read		= mt7530_phy_read,
  1311		.phy_write		= mt7530_phy_write,
  1312		.get_ethtool_stats	= mt7530_get_ethtool_stats,
  1313		.get_sset_count		= mt7530_get_sset_count,
  1314		.adjust_link		= mt7530_adjust_link,
  1315		.port_enable		= mt7530_port_enable,
  1316		.port_disable		= mt7530_port_disable,
  1317		.port_stp_state_set	= mt7530_stp_state_set,
  1318		.port_bridge_join	= mt7530_port_bridge_join,
  1319		.port_bridge_leave	= mt7530_port_bridge_leave,
  1320		.port_fdb_add		= mt7530_port_fdb_add,
  1321		.port_fdb_del		= mt7530_port_fdb_del,
  1322		.port_fdb_dump		= mt7530_port_fdb_dump,
  1323		.port_vlan_filtering	= mt7530_port_vlan_filtering,
> 1324		.port_vlan_prepare	= mt7530_port_vlan_prepare,

1325 .port_vlan_add = mt7530_port_vlan_add,
1326 .port_vlan_del = mt7530_port_vlan_del,
1327 };
1328

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#3 lore raw

Re: [PATCH v2 net-next 1/3] net: dsa: mediatek: add VLAN support for MT7530

In reply to [email protected]
I love your patch! Perhaps something to improve:

Hi Sean,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url: https://github.com/0day-ci/linux/commits/sean-wang-mediatek-com/add-VLAN-support-to-DSA-MT7530/20171215-214450
reproduce:

        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__

sparse warnings: (new ones prefixed by >>)

vim +1324 drivers/net/dsa/mt7530.c

1305
1306 static const struct dsa_switch_ops mt7530_switch_ops = {
1307 .get_tag_protocol = mtk_get_tag_protocol,
1308 .setup = mt7530_setup,
1309 .get_strings = mt7530_get_strings,
1310 .phy_read = mt7530_phy_read,
1311 .phy_write = mt7530_phy_write,
1312 .get_ethtool_stats = mt7530_get_ethtool_stats,
1313 .get_sset_count = mt7530_get_sset_count,
1314 .adjust_link = mt7530_adjust_link,
1315 .port_enable = mt7530_port_enable,
1316 .port_disable = mt7530_port_disable,
1317 .port_stp_state_set = mt7530_stp_state_set,
1318 .port_bridge_join = mt7530_port_bridge_join,
1319 .port_bridge_leave = mt7530_port_bridge_leave,
1320 .port_fdb_add = mt7530_port_fdb_add,
1321 .port_fdb_del = mt7530_port_fdb_del,
1322 .port_fdb_dump = mt7530_port_fdb_dump,
1323 .port_vlan_filtering = mt7530_port_vlan_filtering,

> 1324		.port_vlan_prepare	= mt7530_port_vlan_prepare,
> 1325		.port_vlan_add		= mt7530_port_vlan_add,

1326 .port_vlan_del = mt7530_port_vlan_del,
1327 };
1328

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#4 lore raw

Re: [PATCH v2 net-next 1/3] net: dsa: mediatek: add VLAN support for MT7530

In reply to [email protected]
I love your patch! Perhaps something to improve:

Hi Sean,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url: https://github.com/0day-ci/linux/commits/sean-wang-mediatek-com/add-VLAN-support-to-DSA-MT7530/20171215-214450
config: x86_64-randconfig-g0-12151942 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4 reproduce:

        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

drivers/net/dsa/mt7530.c: In function 'mt7530_port_vlan_add':
drivers/net/dsa/mt7530.c:1131:6: warning: unused variable 'ret' [-Wunused-variable]

     int ret;
         ^
   drivers/net/dsa/mt7530.c: At top level:
>> drivers/net/dsa/mt7530.c:1324:2: warning: initialization from incompatible pointer type
     .port_vlan_prepare = mt7530_port_vlan_prepare,
     ^
   drivers/net/dsa/mt7530.c:1324:2: warning: (near initialization for 'mt7530_switch_ops.port_vlan_prepare')
   drivers/net/dsa/mt7530.c:1325:2: warning: initialization from incompatible pointer type
     .port_vlan_add  = mt7530_port_vlan_add,
     ^

drivers/net/dsa/mt7530.c:1325:2: warning: (near initialization for 'mt7530_switch_ops.port_vlan_add') Cyclomatic Complexity 3 include/linux/string.h:strncpy
Cyclomatic Complexity 1 include/linux/err.h:ERR_PTR
Cyclomatic Complexity 1 include/linux/err.h:PTR_ERR
Cyclomatic Complexity 1 include/linux/err.h:IS_ERR
Cyclomatic Complexity 3 include/linux/ktime.h:ktime_compare
Cyclomatic Complexity 1 include/linux/ktime.h:ktime_add_us
Cyclomatic Complexity 1 include/linux/device.h:devm_kzalloc
Cyclomatic Complexity 1 include/linux/device.h:dev_get_drvdata
Cyclomatic Complexity 1 include/linux/device.h:dev_set_drvdata
Cyclomatic Complexity 5 include/linux/mii.h:mii_resolve_flowctrl_fdx
Cyclomatic Complexity 1 include/linux/of.h:of_property_read_bool
Cyclomatic Complexity 1 include/linux/phy.h:phy_is_pseudo_fixed_link
Cyclomatic Complexity 1 include/linux/reset.h:reset_control_assert
Cyclomatic Complexity 1 include/linux/reset.h:reset_control_deassert
Cyclomatic Complexity 2 include/linux/reset.h:__devm_reset_control_get
Cyclomatic Complexity 2 include/linux/reset.h:devm_reset_control_get_exclusive Cyclomatic Complexity 1 include/linux/reset.h:devm_reset_control_get
Cyclomatic Complexity 1 include/net/dsa.h:dsa_to_port
Cyclomatic Complexity 1 include/net/dsa.h:dsa_is_cpu_port
Cyclomatic Complexity 1 include/net/dsa.h:dsa_is_user_port
Cyclomatic Complexity 3 include/net/dsa.h:dsa_user_ports
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.h:mt7530_hw_vlan_entry_init Cyclomatic Complexity 1 drivers/net/dsa/mt7530.h:INIT_MT7530_DUMMY_POLL
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7530_get_strings
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_get_sset_count
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_port_vlan_prepare
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mdio_module_init
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7530_mii_read
Cyclomatic Complexity 4 drivers/net/dsa/mt7530.c:mt7530_mii_write
Cyclomatic Complexity 4 drivers/net/dsa/mt7530.c:core_read_mmd_indirect
Cyclomatic Complexity 5 drivers/net/dsa/mt7530.c:core_write_mmd_indirect
Cyclomatic Complexity 3 drivers/net/dsa/mt7530.c:mt7530_remove
Cyclomatic Complexity 9 drivers/net/dsa/mt7530.c:mt7530_probe
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:_mt7530_read
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_read
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7530_fdb_read
Cyclomatic Complexity 3 drivers/net/dsa/mt7530.c:mt7530_get_ethtool_stats
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_write
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7530_fdb_write
Cyclomatic Complexity 3 drivers/net/dsa/mt7530.c:mt7530_hw_vlan_del
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_mib_reset
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_rmw
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7530_hw_vlan_add
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_port_set_vlan_aware Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7530_port_vlan_filtering Cyclomatic Complexity 5 drivers/net/dsa/mt7530.c:mt7530_stp_state_set
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_clear
Cyclomatic Complexity 5 drivers/net/dsa/mt7530.c:mt7530_port_set_vlan_unaware Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_set
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7530_port_set_status
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_cpu_port_enable
Cyclomatic Complexity 8 drivers/net/dsa/mt7530.c:mt7530_port_bridge_leave
Cyclomatic Complexity 7 drivers/net/dsa/mt7530.c:mt7530_port_bridge_join
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_port_disable
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_port_enable
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:core_rmw
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:core_clear
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:core_set
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:core_write
Cyclomatic Complexity 11 drivers/net/dsa/mt7530.c:mt7530_fdb_cmd
Cyclomatic Complexity 8 drivers/net/dsa/mt7530.c:mt7530_port_fdb_dump
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_port_fdb_del
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_port_fdb_add
Cyclomatic Complexity 9 drivers/net/dsa/mt7530.c:mt7530_vlan_cmd
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_hw_vlan_update
Cyclomatic Complexity 4 drivers/net/dsa/mt7530.c:mt7530_port_vlan_del
Cyclomatic Complexity 4 drivers/net/dsa/mt7530.c:mt7530_port_vlan_add
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7623_trgmii_read
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7623_trgmii_write
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7623_trgmii_rmw
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7623_trgmii_set
Cyclomatic Complexity 7 drivers/net/dsa/mt7530.c:mt7530_pad_clk_setup
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7623_trgmii_clear
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mt7623_pad_clk_setup
Cyclomatic Complexity 12 drivers/net/dsa/mt7530.c:mt7530_adjust_link
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_phy_write
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mt7530_phy_read
Cyclomatic Complexity 16 drivers/net/dsa/mt7530.c:mt7530_setup
Cyclomatic Complexity 2 drivers/net/dsa/mt7530.c:mtk_get_tag_protocol
Cyclomatic Complexity 1 drivers/net/dsa/mt7530.c:mdio_module_exit

vim +1324 drivers/net/dsa/mt7530.c

1121
1122 static void
1123 mt7530_port_vlan_add(struct dsa_switch *ds, int port,
1124 const struct switchdev_obj_port_vlan *vlan,
1125 struct switchdev_trans *trans)
1126 {
1127 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1128 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1129 struct mt7530_hw_vlan_entry new_entry;
1130 struct mt7530_priv *priv = ds->priv;

> 1131		int ret;
  1132		u16 vid;
  1133	
  1134		/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
  1135		 * being set.
  1136		 */
  1137		if (!priv->ports[port].vlan_filtering)
  1138			return;
  1139	
  1140		mutex_lock(&priv->reg_mutex);
  1141	
  1142		for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
  1143			mt7530_hw_vlan_entry_init(&new_entry, port, untagged);
  1144			mt7530_hw_vlan_update(priv, vid, &new_entry,
  1145					      mt7530_hw_vlan_add);
  1146		}
  1147	
  1148		if (pvid) {
  1149			mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
  1150				   G0_PORT_VID(vlan->vid_end));
  1151			priv->ports[port].pvid = vlan->vid_end;
  1152		}
  1153	
  1154		mutex_unlock(&priv->reg_mutex);
  1155	}
  1156	
  1157	static int
  1158	mt7530_port_vlan_del(struct dsa_switch *ds, int port,
  1159			     const struct switchdev_obj_port_vlan *vlan)
  1160	{
  1161		struct mt7530_hw_vlan_entry target_entry;
  1162		struct mt7530_priv *priv = ds->priv;
  1163		u16 vid, pvid;
  1164	
  1165		/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
  1166		 * being set.
  1167		 */
  1168		if (!priv->ports[port].vlan_filtering)
  1169			return 0;
  1170	
  1171		mutex_lock(&priv->reg_mutex);
  1172	
  1173		pvid = priv->ports[port].pvid;
  1174		for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
  1175			mt7530_hw_vlan_entry_init(&target_entry, port, 0);
  1176			mt7530_hw_vlan_update(priv, vid, &target_entry,
  1177					      mt7530_hw_vlan_del);
  1178	
  1179			/* PVID is being restored to the default whenever the PVID port
  1180			 * is being removed from the VLAN.
  1181			 */
  1182			if (pvid == vid)
  1183				pvid = G0_PORT_VID_DEF;
  1184		}
  1185	
  1186		mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, pvid);
  1187		priv->ports[port].pvid = pvid;
  1188	
  1189		mutex_unlock(&priv->reg_mutex);
  1190	
  1191		return 0;
  1192	}
  1193	
  1194	static enum dsa_tag_protocol
  1195	mtk_get_tag_protocol(struct dsa_switch *ds, int port)
  1196	{
  1197		struct mt7530_priv *priv = ds->priv;
  1198	
  1199		if (port != MT7530_CPU_PORT) {
  1200			dev_warn(priv->dev,
  1201				 "port not matched with tagging CPU port\n");
  1202			return DSA_TAG_PROTO_NONE;
  1203		} else {
  1204			return DSA_TAG_PROTO_MTK;
  1205		}
  1206	}
  1207	
  1208	static int
  1209	mt7530_setup(struct dsa_switch *ds)
  1210	{
  1211		struct mt7530_priv *priv = ds->priv;
  1212		int ret, i;
  1213		u32 id, val;
  1214		struct device_node *dn;
  1215		struct mt7530_dummy_poll p;
  1216	
  1217		/* The parent node of master netdev which holds the common system
  1218		 * controller also is the container for two GMACs nodes representing
  1219		 * as two netdev instances.
  1220		 */
  1221		dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent;
  1222		priv->ethernet = syscon_node_to_regmap(dn);
  1223		if (IS_ERR(priv->ethernet))
  1224			return PTR_ERR(priv->ethernet);
  1225	
  1226		regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
  1227		ret = regulator_enable(priv->core_pwr);
  1228		if (ret < 0) {
  1229			dev_err(priv->dev,
  1230				"Failed to enable core power: %d\n", ret);
  1231			return ret;
  1232		}
  1233	
  1234		regulator_set_voltage(priv->io_pwr, 3300000, 3300000);
  1235		ret = regulator_enable(priv->io_pwr);
  1236		if (ret < 0) {
  1237			dev_err(priv->dev, "Failed to enable io pwr: %d\n",
  1238				ret);
  1239			return ret;
  1240		}
  1241	
  1242		/* Reset whole chip through gpio pin or memory-mapped registers for
  1243		 * different type of hardware
  1244		 */
  1245		if (priv->mcm) {
  1246			reset_control_assert(priv->rstc);
  1247			usleep_range(1000, 1100);
  1248			reset_control_deassert(priv->rstc);
  1249		} else {
  1250			gpiod_set_value_cansleep(priv->reset, 0);
  1251			usleep_range(1000, 1100);
  1252			gpiod_set_value_cansleep(priv->reset, 1);
  1253		}
  1254	
  1255		/* Waiting for MT7530 got to stable */
  1256		INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP);
  1257		ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
  1258					 20, 1000000);
  1259		if (ret < 0) {
  1260			dev_err(priv->dev, "reset timeout\n");
  1261			return ret;
  1262		}
  1263	
  1264		id = mt7530_read(priv, MT7530_CREV);
  1265		id >>= CHIP_NAME_SHIFT;
  1266		if (id != MT7530_ID) {
  1267			dev_err(priv->dev, "chip %x can't be supported\n", id);
  1268			return -ENODEV;
  1269		}
  1270	
  1271		/* Reset the switch through internal reset */
  1272		mt7530_write(priv, MT7530_SYS_CTRL,
  1273			     SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
  1274			     SYS_CTRL_REG_RST);
  1275	
  1276		/* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
  1277		val = mt7530_read(priv, MT7530_MHWTRAP);
  1278		val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
  1279		val |= MHWTRAP_MANUAL;
  1280		mt7530_write(priv, MT7530_MHWTRAP, val);
  1281	
  1282		/* Enable and reset MIB counters */
  1283		mt7530_mib_reset(ds);
  1284	
  1285		mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
  1286	
  1287		for (i = 0; i < MT7530_NUM_PORTS; i++) {
  1288			/* Disable forwarding by default on all ports */
  1289			mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
  1290				   PCR_MATRIX_CLR);
  1291	
  1292			if (dsa_is_cpu_port(ds, i))
  1293				mt7530_cpu_port_enable(priv, i);
  1294			else
  1295				mt7530_port_disable(ds, i, NULL);
  1296		}
  1297	
  1298		/* Flush the FDB table */
  1299		ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0);
  1300		if (ret < 0)
  1301			return ret;
  1302	
  1303		return 0;
  1304	}
  1305	
  1306	static const struct dsa_switch_ops mt7530_switch_ops = {
  1307		.get_tag_protocol	= mtk_get_tag_protocol,
  1308		.setup			= mt7530_setup,
  1309		.get_strings		= mt7530_get_strings,
  1310		.phy_read		= mt7530_phy_read,
  1311		.phy_write		= mt7530_phy_write,
  1312		.get_ethtool_stats	= mt7530_get_ethtool_stats,
  1313		.get_sset_count		= mt7530_get_sset_count,
  1314		.adjust_link		= mt7530_adjust_link,
  1315		.port_enable		= mt7530_port_enable,
  1316		.port_disable		= mt7530_port_disable,
  1317		.port_stp_state_set	= mt7530_stp_state_set,
  1318		.port_bridge_join	= mt7530_port_bridge_join,
  1319		.port_bridge_leave	= mt7530_port_bridge_leave,
  1320		.port_fdb_add		= mt7530_port_fdb_add,
  1321		.port_fdb_del		= mt7530_port_fdb_del,
  1322		.port_fdb_dump		= mt7530_port_fdb_dump,
  1323		.port_vlan_filtering	= mt7530_port_vlan_filtering,
> 1324		.port_vlan_prepare	= mt7530_port_vlan_prepare,

1325 .port_vlan_add = mt7530_port_vlan_add,
1326 .port_vlan_del = mt7530_port_vlan_del,
1327 };
1328

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#5 lore raw

PATCH v2 2/3 net: dsa: mediatek: combine MediaTek tag with VLAN tag

In reply to [email protected]

From: Sean Wang <sean.wang-NuS5LvNUpcJWk0Htik3J/[email protected]>

In order to let MT7530 switch can recognize well those egress packets having both special tag and VLAN tag, the information about the special tag should be carried on the existing VLAN tag. On the other hand, it's unnecessary for extra handling for ingress packets when VLAN tag is present since it is able to put the VLAN tag after the special tag and then follow the existing way to parse.

---
 net/dsa/tag_mtk.c | 38 +++++++++++++++++++++++++++++---------
 1 file changed, 29 insertions(+), 9 deletions(-)
net/dsa/tag_mtk.c +29 -9
index 8475434..11535bc 100644
@@ -13,10 +13,13 @@
  */
 
 #include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
 
 #include "dsa_priv.h"
 
 #define MTK_HDR_LEN		4
+#define MTK_HDR_XMIT_UNTAGGED		0
+#define MTK_HDR_XMIT_TAGGED_TPID_8100	1
 #define MTK_HDR_RECV_SOURCE_PORT_MASK	GENMASK(2, 0)
 #define MTK_HDR_XMIT_DP_BIT_MASK	GENMASK(5, 0)
 
@@ -25,20 +28,37 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
 {
 	struct dsa_port *dp = dsa_slave_to_port(dev);
 	u8 *mtk_tag;
+	bool is_vlan_skb = true;
 
-	if (skb_cow_head(skb, MTK_HDR_LEN) < 0)
-		return NULL;
-
-	skb_push(skb, MTK_HDR_LEN);
+	/* Build the special tag after the MAC Source Address. If VLAN header
+	 * is present, it's required that VLAN header and special tag is
+	 * being combined. Only in this way we can allow the switch can parse
+	 * the both special and VLAN tag at the same time and then look up VLAN
+	 * table with VID.
+	 */
+	if (!skb_vlan_tagged(skb)) {
+		if (skb_cow_head(skb, MTK_HDR_LEN) < 0)
+			return NULL;
 
-	memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
+		skb_push(skb, MTK_HDR_LEN);
+		memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
+		is_vlan_skb = false;
+	}
 
-	/* Build the tag after the MAC Source Address */
 	mtk_tag = skb->data + 2 * ETH_ALEN;
-	mtk_tag[0] = 0;
+
+	/* Mark tag attribute on special tag insertion to notify hardware
+	 * whether that's a combined special tag with 802.1Q header.
+	 */
+	mtk_tag[0] = is_vlan_skb ? MTK_HDR_XMIT_TAGGED_TPID_8100 :
+		     MTK_HDR_XMIT_UNTAGGED;
 	mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
-	mtk_tag[2] = 0;
-	mtk_tag[3] = 0;
+
+	/* Tag control information is kept for 802.1Q */
+	if (!is_vlan_skb) {
+		mtk_tag[2] = 0;
+		mtk_tag[3] = 0;
+	}
 
 	return skb;
 }
Signature · 1 line
2.7.4
#6 lore raw

PATCH v2 3/3 net: dsa: mediatek: update MAINTAINERS entry with MediaTek switch driver

In reply to [email protected]

From: Sean Wang <sean.wang-NuS5LvNUpcJWk0Htik3J/[email protected]>

I work for MediaTek and maintain SoC targeting to home gateway and also will keep extending and testing the function from MediaTek switch.

---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)
MAINTAINERS +7 -0
index c0edf30..070fd91 100644
@@ -8723,6 +8723,13 @@ L:	[email protected]
 S:	Maintained
 F:	drivers/net/ethernet/mediatek/
 
+MEDIATEK SWITCH DRIVER
+M:	Sean Wang <sean.wang-NuS5LvNUpcJWk0Htik3J/[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	drivers/net/dsa/mt7530.*
+F:	net/dsa/tag_mtk.c
+
 MEDIATEK JPEG DRIVER
 M:	Rick Chang <rick.chang-NuS5LvNUpcJWk0Htik3J/[email protected]>
 M:	Bin Liu <bin.liu-NuS5LvNUpcJWk0Htik3J/[email protected]>
Signature · 1 line
2.7.4
maintainer
#8 lore raw
In reply to [email protected]

From: <[email protected]>
Date: Wed, 13 Dec 2017 12:01:10 +0800

Quoted 8 lines

From: Sean Wang <[email protected]>

Changes since v1:
- fix up the typo
- prefer ordering declarations longest to shortest
- update that vlan_prepare callback should not change any state
- use lower case letter for function naming

Quoted 4 lines

The patchset extends DSA MT7530 to VLAN support through filling required callbacks in patch 1 and merging the special tag with VLAN tag in patch 2 for allowing that the hardware can handle these packets with VID from the CPU port.

This doesn't even compile:

drivers/net/dsa/mt7530.c: In function ‘mt7530_port_vlan_add’:
drivers/net/dsa/mt7530.c:1131:6: warning: unused variable ‘ret’ [-Wunused-variable]

  int ret;
      ^~~
drivers/net/dsa/mt7530.c: At top level:
drivers/net/dsa/mt7530.c:1324:23: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
  .port_vlan_prepare = mt7530_port_vlan_prepare,
                       ^~~~~~~~~~~~~~~~~~~~~~~~
drivers/net/dsa/mt7530.c:1324:23: note: (near initialization for ‘mt7530_switch_ops.port_vlan_prepare’)
drivers/net/dsa/mt7530.c:1325:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
  .port_vlan_add  = mt7530_port_vlan_add,
                    ^~~~~~~~~~~~~~~~~~~~

drivers/net/dsa/mt7530.c:1325:20: note: (near initialization for ‘mt7530_switch_ops.port_vlan_add’)
cc1: some warnings being treated as errors