* [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver
@ 2020-08-07 11:13 hongbo.wang
2020-08-07 11:13 ` [PATCH v5 1/2] net: dsa: Add protocol support for 802.1AD when adding or deleting vlan for dsa switch port hongbo.wang
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: hongbo.wang @ 2020-08-07 11:13 UTC (permalink / raw)
To: xiaoliang.yang_1, allan.nielsen, po.liu, claudiu.manoil,
alexandru.marginean, vladimir.oltean, leoyang.li, mingkai.hu,
andrew, f.fainelli, vivien.didelot, davem, jiri, idosch, kuba,
vinicius.gomes, nikolay, roopa, netdev, linux-kernel,
horatiu.vultur, alexandre.belloni, UNGLinuxDriver, ivecera
Cc: hongbo.wang
From: "hongbo.wang" <hongbo.wang@nxp.com>
1. the patch 0001* is for setting single port into 802.1AD(QinQ) mode,
before this patch, the function dsa_slave_vlan_rx_add_vid didn't pass
the parameter "proto" to next port level, so switch's port can't get
parameter "proto"
after applying this patch, the following command can be supported:
ip link set br0 type bridge vlan_protocol 802.1ad
ip link add link swp1 name swp1.100 type vlan protocol 802.1ad id 100
2. the patch 0002* is for setting QinQ related registers in ocelot
switch driver, after applying this patch, the switch(VSC99599)'s port can
enable or disable QinQ mode.
3. Version log
v5:
a. add devlink to enable qinq_mode of ocelot's single port
b. modify br_switchdev_port_vlan_add to pass bridge's vlan_proto to port driver
c. enable NETIF_F_HW_VLAN_STAG_FILTER in ocelot driver
v4:
a. modify slave.c to support "ip set br0 type bridge vlan_protocol 802.1ad"
b. modify ocelot.c, if enable QinQ, set VLAN_AWARE_ENA and VLAN_POP_CNT per
port when vlan_filter=1
v3: combine two patches to one post
hongbo.wang (2):
net: dsa: Add protocol support for 802.1AD when adding or deleting
vlan for dsa switch port
net: dsa: ocelot: Add support for QinQ Operation
drivers/net/dsa/ocelot/felix.c | 124 +++++++++++++++++++++++++++++
drivers/net/ethernet/mscc/ocelot.c | 40 ++++++++--
include/net/switchdev.h | 1 +
include/soc/mscc/ocelot.h | 4 +
net/bridge/br_switchdev.c | 22 +++++
net/dsa/dsa_priv.h | 4 +-
net/dsa/port.c | 6 +-
net/dsa/slave.c | 53 +++++++-----
net/dsa/tag_8021q.c | 4 +-
9 files changed, 228 insertions(+), 30 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v5 1/2] net: dsa: Add protocol support for 802.1AD when adding or deleting vlan for dsa switch port
2020-08-07 11:13 [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver hongbo.wang
@ 2020-08-07 11:13 ` hongbo.wang
2020-08-07 11:25 ` Nikolay Aleksandrov
2020-08-07 11:13 ` [PATCH v5 2/2] net: dsa: ocelot: Add support for QinQ Operation hongbo.wang
2020-08-08 0:24 ` [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver David Miller
2 siblings, 1 reply; 5+ messages in thread
From: hongbo.wang @ 2020-08-07 11:13 UTC (permalink / raw)
To: xiaoliang.yang_1, allan.nielsen, po.liu, claudiu.manoil,
alexandru.marginean, vladimir.oltean, leoyang.li, mingkai.hu,
andrew, f.fainelli, vivien.didelot, davem, jiri, idosch, kuba,
vinicius.gomes, nikolay, roopa, netdev, linux-kernel,
horatiu.vultur, alexandre.belloni, UNGLinuxDriver, ivecera
Cc: hongbo.wang
From: "hongbo.wang" <hongbo.wang@nxp.com>
the following command will be supported:
Set bridge's vlan protocol:
ip link set br0 type bridge vlan_protocol 802.1ad
Add VLAN:
ip link add link swp1 name swp1.100 type vlan protocol 802.1ad id 100
Delete VLAN:
ip link del link swp1 name swp1.100
Signed-off-by: hongbo.wang <hongbo.wang@nxp.com>
---
include/net/switchdev.h | 1 +
net/bridge/br_switchdev.c | 22 ++++++++++++++++
net/dsa/dsa_priv.h | 4 +--
net/dsa/port.c | 6 +++--
net/dsa/slave.c | 53 ++++++++++++++++++++++++++-------------
net/dsa/tag_8021q.c | 4 +--
6 files changed, 66 insertions(+), 24 deletions(-)
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index ff2246914301..7594ea82879f 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -97,6 +97,7 @@ struct switchdev_obj_port_vlan {
u16 flags;
u16 vid_begin;
u16 vid_end;
+ u16 proto;
};
#define SWITCHDEV_OBJ_PORT_VLAN(OBJ) \
diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c
index 015209bf44aa..bcfa00d6d5eb 100644
--- a/net/bridge/br_switchdev.c
+++ b/net/bridge/br_switchdev.c
@@ -146,6 +146,26 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
}
}
+static u16 br_switchdev_get_bridge_vlan_proto(struct net_device *dev)
+{
+ u16 vlan_proto = ETH_P_8021Q;
+ struct net_device *br = NULL;
+ struct net_bridge_port *p;
+
+ if (netif_is_bridge_master(dev)) {
+ br = dev;
+ } else if (netif_is_bridge_port(dev)) {
+ p = br_port_get_rcu(dev);
+ if (p && p->br)
+ br = p->br->dev;
+ }
+
+ if (br)
+ br_vlan_get_proto(br, &vlan_proto);
+
+ return vlan_proto;
+}
+
int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
struct netlink_ext_ack *extack)
{
@@ -157,6 +177,7 @@ int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
.vid_end = vid,
};
+ v.proto = br_switchdev_get_bridge_vlan_proto(dev);
return switchdev_port_obj_add(dev, &v.obj, extack);
}
@@ -169,5 +190,6 @@ int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
.vid_end = vid,
};
+ v.proto = br_switchdev_get_bridge_vlan_proto(dev);
return switchdev_port_obj_del(dev, &v.obj);
}
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 1653e3377cb3..52685b9875e5 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -164,8 +164,8 @@ int dsa_port_vlan_add(struct dsa_port *dp,
struct switchdev_trans *trans);
int dsa_port_vlan_del(struct dsa_port *dp,
const struct switchdev_obj_port_vlan *vlan);
-int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags);
-int dsa_port_vid_del(struct dsa_port *dp, u16 vid);
+int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 proto, u16 flags);
+int dsa_port_vid_del(struct dsa_port *dp, u16 vid, u16 proto);
int dsa_port_link_register_of(struct dsa_port *dp);
void dsa_port_link_unregister_of(struct dsa_port *dp);
extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
diff --git a/net/dsa/port.c b/net/dsa/port.c
index e23ece229c7e..c98bbac3980a 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -433,13 +433,14 @@ int dsa_port_vlan_del(struct dsa_port *dp,
return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
}
-int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags)
+int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 proto, u16 flags)
{
struct switchdev_obj_port_vlan vlan = {
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
.flags = flags,
.vid_begin = vid,
.vid_end = vid,
+ .proto = proto,
};
struct switchdev_trans trans;
int err;
@@ -454,12 +455,13 @@ int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags)
}
EXPORT_SYMBOL(dsa_port_vid_add);
-int dsa_port_vid_del(struct dsa_port *dp, u16 vid)
+int dsa_port_vid_del(struct dsa_port *dp, u16 vid, u16 proto)
{
struct switchdev_obj_port_vlan vlan = {
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
.vid_begin = vid,
.vid_end = vid,
+ .proto = proto,
};
return dsa_port_vlan_del(dp, &vlan);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 41d60eeefdbd..f01deda00492 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -328,6 +328,7 @@ static int dsa_slave_vlan_add(struct net_device *dev,
* it doesn't make sense to program a PVID, so clear this flag.
*/
vlan.flags &= ~BRIDGE_VLAN_INFO_PVID;
+ vlan.proto = ETH_P_8021Q;
err = dsa_port_vlan_add(dp->cpu_dp, &vlan, trans);
if (err)
@@ -1229,11 +1230,38 @@ static int dsa_slave_get_ts_info(struct net_device *dev,
return ds->ops->get_ts_info(ds, p->dp->index, ts);
}
+static bool dsa_slave_skip_vlan_configuration(struct dsa_port *dp,
+ u16 vlan_proto, u16 vid)
+{
+ struct bridge_vlan_info info;
+ bool change_proto = false;
+ u16 br_proto = 0;
+ int ret;
+
+ /* when changing bridge's vlan protocol, it will change bridge
+ * port's protocol firstly, then set bridge's protocol. if it's
+ * changing vlan protocol, should not return -EBUSY.
+ */
+ ret = br_vlan_get_proto(dp->bridge_dev, &br_proto);
+ if (ret == 0 && br_proto != vlan_proto)
+ change_proto = true;
+
+ /* br_vlan_get_info() returns -EINVAL or -ENOENT if the
+ * device, respectively the VID is not found, returning
+ * 0 means success, which is a failure for us here.
+ */
+ ret = br_vlan_get_info(dp->bridge_dev, vid, &info);
+ if (ret == 0 && !change_proto)
+ return true;
+ else
+ return false;
+}
+
static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
u16 vid)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
- struct bridge_vlan_info info;
+ u16 vlan_proto = ntohs(proto);
int ret;
/* Check for a possible bridge VLAN entry now since there is no
@@ -1243,20 +1271,15 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
if (dsa_port_skip_vlan_configuration(dp))
return 0;
- /* br_vlan_get_info() returns -EINVAL or -ENOENT if the
- * device, respectively the VID is not found, returning
- * 0 means success, which is a failure for us here.
- */
- ret = br_vlan_get_info(dp->bridge_dev, vid, &info);
- if (ret == 0)
+ if (dsa_slave_skip_vlan_configuration(dp, vlan_proto, vid))
return -EBUSY;
}
- ret = dsa_port_vid_add(dp, vid, 0);
+ ret = dsa_port_vid_add(dp, vid, vlan_proto, 0);
if (ret)
return ret;
- ret = dsa_port_vid_add(dp->cpu_dp, vid, 0);
+ ret = dsa_port_vid_add(dp->cpu_dp, vid, ETH_P_8021Q, 0);
if (ret)
return ret;
@@ -1267,8 +1290,7 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
u16 vid)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
- struct bridge_vlan_info info;
- int ret;
+ u16 vlan_proto = ntohs(proto);
/* Check for a possible bridge VLAN entry now since there is no
* need to emulate the switchdev prepare + commit phase.
@@ -1277,19 +1299,14 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
if (dsa_port_skip_vlan_configuration(dp))
return 0;
- /* br_vlan_get_info() returns -EINVAL or -ENOENT if the
- * device, respectively the VID is not found, returning
- * 0 means success, which is a failure for us here.
- */
- ret = br_vlan_get_info(dp->bridge_dev, vid, &info);
- if (ret == 0)
+ if (dsa_slave_skip_vlan_configuration(dp, vlan_proto, vid))
return -EBUSY;
}
/* Do not deprogram the CPU port as it may be shared with other user
* ports which can be members of this VLAN as well.
*/
- return dsa_port_vid_del(dp, vid);
+ return dsa_port_vid_del(dp, vid, vlan_proto);
}
struct dsa_hw_port {
diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c
index 780b2a15ac9b..4c93988e61a3 100644
--- a/net/dsa/tag_8021q.c
+++ b/net/dsa/tag_8021q.c
@@ -152,9 +152,9 @@ static int dsa_8021q_vid_apply(struct dsa_switch *ds, int port, u16 vid,
struct dsa_port *dp = dsa_to_port(ds, port);
if (enabled)
- return dsa_port_vid_add(dp, vid, flags);
+ return dsa_port_vid_add(dp, vid, ETH_P_8021Q, flags);
- return dsa_port_vid_del(dp, vid);
+ return dsa_port_vid_del(dp, vid, ETH_P_8021Q);
}
/* RX VLAN tagging (left) and TX VLAN tagging (right) setup shown for a single
--
2.17.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v5 2/2] net: dsa: ocelot: Add support for QinQ Operation
2020-08-07 11:13 [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver hongbo.wang
2020-08-07 11:13 ` [PATCH v5 1/2] net: dsa: Add protocol support for 802.1AD when adding or deleting vlan for dsa switch port hongbo.wang
@ 2020-08-07 11:13 ` hongbo.wang
2020-08-08 0:24 ` [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver David Miller
2 siblings, 0 replies; 5+ messages in thread
From: hongbo.wang @ 2020-08-07 11:13 UTC (permalink / raw)
To: xiaoliang.yang_1, allan.nielsen, po.liu, claudiu.manoil,
alexandru.marginean, vladimir.oltean, leoyang.li, mingkai.hu,
andrew, f.fainelli, vivien.didelot, davem, jiri, idosch, kuba,
vinicius.gomes, nikolay, roopa, netdev, linux-kernel,
horatiu.vultur, alexandre.belloni, UNGLinuxDriver, ivecera
Cc: hongbo.wang
From: "hongbo.wang" <hongbo.wang@nxp.com>
This feature can be test in the following case:
Customer <-----> swp0 <-----> swp1 <-----> ISP
Customer will send and receive packets with single VLAN tag(CTAG),
ISP will send and receive packets with double VLAN tag(STAG and CTAG).
This refers to "4.3.3 Provider Bridges and Q-in-Q Operation" in
VSC99599_1_00_TS.pdf.
The related test commands:
1.
devlink dev param set pci/0000:00:00.5 name qinq_port_bitmap \
value 2 cmode runtime
ip link add dev br0 type bridge vlan_protocol 802.1ad
ip link set dev swp0 master br0
ip link set dev swp1 master br0
2.
ip link set dev br0 type bridge vlan_filtering 1
bridge vlan add dev swp0 vid 100 pvid
bridge vlan add dev swp1 vid 100
Result:
Customer(tpid:8100 vid:111) -> swp0 -> swp1 -> ISP(STAG \
tpid:88A8 vid:100, CTAG tpid:8100 vid:111)
3.
bridge vlan del dev swp0 vid 1 pvid
bridge vlan add dev swp0 vid 100 pvid untagged
Result:
ISP(tpid:88A8 vid:100 tpid:8100 vid:222) -> swp1 -> swp0 ->\
Customer(tpid:8100 vid:222)
Signed-off-by: hongbo.wang <hongbo.wang@nxp.com>
---
drivers/net/dsa/ocelot/felix.c | 124 +++++++++++++++++++++++++++++
drivers/net/ethernet/mscc/ocelot.c | 40 ++++++++--
include/soc/mscc/ocelot.h | 4 +
3 files changed, 162 insertions(+), 6 deletions(-)
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index c69d9592a2b7..f9d50af4be65 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -147,9 +147,26 @@ static void felix_vlan_add(struct dsa_switch *ds, int port,
vid, port, err);
return;
}
+
+ if (vlan->proto == ETH_P_8021AD) {
+ if (!ocelot->qinq_enable) {
+ ocelot->qinq_enable = true;
+ kref_init(&ocelot->qinq_refcount);
+ } else {
+ kref_get(&ocelot->qinq_refcount);
+ }
+ }
}
}
+static void felix_vlan_qinq_release(struct kref *ref)
+{
+ struct ocelot *ocelot;
+
+ ocelot = container_of(ref, struct ocelot, qinq_refcount);
+ ocelot->qinq_enable = false;
+}
+
static int felix_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
@@ -164,7 +181,11 @@ static int felix_vlan_del(struct dsa_switch *ds, int port,
vid, port, err);
return err;
}
+
+ if (ocelot->qinq_enable && vlan->proto == ETH_P_8021AD)
+ kref_put(&ocelot->qinq_refcount, felix_vlan_qinq_release);
}
+
return 0;
}
@@ -172,9 +193,13 @@ static int felix_port_enable(struct dsa_switch *ds, int port,
struct phy_device *phy)
{
struct ocelot *ocelot = ds->priv;
+ struct net_device *slave;
ocelot_port_enable(ocelot, port, phy);
+ slave = dsa_to_port(ds, port)->slave;
+ slave->features |= NETIF_F_HW_VLAN_STAG_FILTER;
+
return 0;
}
@@ -568,6 +593,97 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {
.enable = ocelot_ptp_enable,
};
+static int felix_qinq_port_bitmap_get(struct dsa_switch *ds, u32 *bitmap)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct ocelot_port *ocelot_port;
+ int port;
+
+ *bitmap = 0;
+ for (port = 0; port < ds->num_ports; port++) {
+ ocelot_port = ocelot->ports[port];
+ if (ocelot_port->qinq_mode)
+ *bitmap |= 0x01 << port;
+ }
+
+ return 0;
+}
+
+static int felix_qinq_port_bitmap_set(struct dsa_switch *ds, u32 bitmap)
+{
+ struct ocelot *ocelot = ds->priv;
+ struct ocelot_port *ocelot_port;
+ int port;
+
+ for (port = 0; port < ds->num_ports; port++) {
+ ocelot_port = ocelot->ports[port];
+ if (bitmap & (0x01 << port))
+ ocelot_port->qinq_mode = true;
+ else
+ ocelot_port->qinq_mode = false;
+ }
+
+ return 0;
+}
+
+enum felix_devlink_param_id {
+ FELIX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
+ FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP,
+};
+
+static int felix_devlink_param_get(struct dsa_switch *ds, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ int err;
+
+ switch (id) {
+ case FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP:
+ err = felix_qinq_port_bitmap_get(ds, &ctx->val.vu32);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int felix_devlink_param_set(struct dsa_switch *ds, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ int err;
+
+ switch (id) {
+ case FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP:
+ err = felix_qinq_port_bitmap_set(ds, ctx->val.vu32);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static const struct devlink_param felix_devlink_params[] = {
+ DSA_DEVLINK_PARAM_DRIVER(FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP,
+ "qinq_port_bitmap",
+ DEVLINK_PARAM_TYPE_U32,
+ BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
+};
+
+static int felix_setup_devlink_params(struct dsa_switch *ds)
+{
+ return dsa_devlink_params_register(ds, felix_devlink_params,
+ ARRAY_SIZE(felix_devlink_params));
+}
+
+static void felix_teardown_devlink_params(struct dsa_switch *ds)
+{
+ dsa_devlink_params_unregister(ds, felix_devlink_params,
+ ARRAY_SIZE(felix_devlink_params));
+}
+
/* Hardware initialization done here so that we can allocate structures with
* devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing
* us to allocate structures twice (leak memory) and map PCI memory twice
@@ -632,6 +748,10 @@ static int felix_setup(struct dsa_switch *ds)
*/
ds->pcs_poll = true;
+ err = felix_setup_devlink_params(ds);
+ if (err < 0)
+ return err;
+
return 0;
}
@@ -643,6 +763,8 @@ static void felix_teardown(struct dsa_switch *ds)
if (felix->info->mdio_bus_free)
felix->info->mdio_bus_free(ocelot);
+ felix_teardown_devlink_params(ds);
+
ocelot_deinit_timestamp(ocelot);
/* stop workqueue thread */
ocelot_deinit(ocelot);
@@ -817,6 +939,8 @@ const struct dsa_switch_ops felix_switch_ops = {
.cls_flower_del = felix_cls_flower_del,
.cls_flower_stats = felix_cls_flower_stats,
.port_setup_tc = felix_port_setup_tc,
+ .devlink_param_get = felix_devlink_param_get,
+ .devlink_param_set = felix_devlink_param_set,
};
static int __init felix_init(void)
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 867c680f5917..073c08989e21 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -143,6 +143,8 @@ static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
u16 vid)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
+ u32 port_tpid = 0;
+ u32 tag_tpid = 0;
u32 val = 0;
if (ocelot_port->vid != vid) {
@@ -156,8 +158,14 @@ static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
ocelot_port->vid = vid;
}
- ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(vid),
- REW_PORT_VLAN_CFG_PORT_VID_M,
+ if (ocelot->qinq_enable && ocelot_port->qinq_mode)
+ port_tpid = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021AD);
+ else
+ port_tpid = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q);
+
+ ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(vid) | port_tpid,
+ REW_PORT_VLAN_CFG_PORT_VID_M |
+ REW_PORT_VLAN_CFG_PORT_TPID_M,
REW_PORT_VLAN_CFG, port);
if (ocelot_port->vlan_aware && !ocelot_port->vid)
@@ -180,12 +188,19 @@ static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
else
/* Tag all frames */
val = REW_TAG_CFG_TAG_CFG(3);
+
+ if (ocelot->qinq_enable && ocelot_port->qinq_mode)
+ tag_tpid = REW_TAG_CFG_TAG_TPID_CFG(1);
+ else
+ tag_tpid = REW_TAG_CFG_TAG_TPID_CFG(0);
} else {
/* Port tagging disabled. */
val = REW_TAG_CFG_TAG_CFG(0);
+ tag_tpid = REW_TAG_CFG_TAG_TPID_CFG(0);
}
- ocelot_rmw_gix(ocelot, val,
- REW_TAG_CFG_TAG_CFG_M,
+
+ ocelot_rmw_gix(ocelot, val | tag_tpid,
+ REW_TAG_CFG_TAG_CFG_M | REW_TAG_CFG_TAG_TPID_CFG_M,
REW_TAG_CFG, port);
return 0;
@@ -204,6 +219,15 @@ void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1);
else
val = 0;
+
+ /* if switch is enabled for QinQ, the port for LAN should set
+ * VLAN_CFG.VLAN_POP_CNT=0 && VLAN_CFG.VLAN_AWARE_ENA=0.
+ * the port for MAN should set VLAN_CFG.VLAN_POP_CNT=1 &&
+ * VLAN_CFG.VLAN_AWARE_ENA=1. referring to 4.3.3 in VSC9959_1_00_TS.pdf
+ */
+ if (ocelot->qinq_enable && !ocelot_port->qinq_mode)
+ val = 0;
+
ocelot_rmw_gix(ocelot, val,
ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M,
@@ -217,10 +241,14 @@ EXPORT_SYMBOL(ocelot_port_vlan_filtering);
static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, u16 pvid)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
+ u32 tag_type = 0;
+
+ if (ocelot->qinq_enable && ocelot_port->qinq_mode)
+ tag_type = ANA_PORT_VLAN_CFG_VLAN_TAG_TYPE;
ocelot_rmw_gix(ocelot,
- ANA_PORT_VLAN_CFG_VLAN_VID(pvid),
- ANA_PORT_VLAN_CFG_VLAN_VID_M,
+ ANA_PORT_VLAN_CFG_VLAN_VID(pvid) | tag_type,
+ ANA_PORT_VLAN_CFG_VLAN_VID_M | tag_type,
ANA_PORT_VLAN_CFG, port);
ocelot_port->pvid = pvid;
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index da369b12005f..8d0f9f9ec0b2 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -556,6 +556,7 @@ struct ocelot_port {
struct regmap *target;
bool vlan_aware;
+ bool qinq_mode;
/* Ingress default VLAN (pvid) */
u16 pvid;
@@ -632,6 +633,9 @@ struct ocelot {
/* Protects the PTP clock */
spinlock_t ptp_clock_lock;
struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM];
+
+ bool qinq_enable;
+ struct kref qinq_refcount;
};
struct ocelot_policer {
--
2.17.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v5 1/2] net: dsa: Add protocol support for 802.1AD when adding or deleting vlan for dsa switch port
2020-08-07 11:13 ` [PATCH v5 1/2] net: dsa: Add protocol support for 802.1AD when adding or deleting vlan for dsa switch port hongbo.wang
@ 2020-08-07 11:25 ` Nikolay Aleksandrov
0 siblings, 0 replies; 5+ messages in thread
From: Nikolay Aleksandrov @ 2020-08-07 11:25 UTC (permalink / raw)
To: hongbo.wang, xiaoliang.yang_1, allan.nielsen, po.liu,
claudiu.manoil, alexandru.marginean, vladimir.oltean, leoyang.li,
mingkai.hu, andrew, f.fainelli, vivien.didelot, davem, jiri,
idosch, kuba, vinicius.gomes, roopa, netdev, linux-kernel,
horatiu.vultur, alexandre.belloni, UNGLinuxDriver, ivecera
On 07/08/2020 14:13, hongbo.wang@nxp.com wrote:
> From: "hongbo.wang" <hongbo.wang@nxp.com>
>
> the following command will be supported:
>
> Set bridge's vlan protocol:
> ip link set br0 type bridge vlan_protocol 802.1ad
> Add VLAN:
> ip link add link swp1 name swp1.100 type vlan protocol 802.1ad id 100
> Delete VLAN:
> ip link del link swp1 name swp1.100
>
> Signed-off-by: hongbo.wang <hongbo.wang@nxp.com>
> ---
> include/net/switchdev.h | 1 +
> net/bridge/br_switchdev.c | 22 ++++++++++++++++
> net/dsa/dsa_priv.h | 4 +--
> net/dsa/port.c | 6 +++--
> net/dsa/slave.c | 53 ++++++++++++++++++++++++++-------------
> net/dsa/tag_8021q.c | 4 +--
> 6 files changed, 66 insertions(+), 24 deletions(-)
>
Hi,
Please put the bridge changes in a separate patch with proper description.
Reviewers would easily miss these bridge changes. Also I believe net-next
is currently closed and that's where these patches should be targeted (i.e.
have net-next after PATCH in the subject). Few more comments below.
Thanks,
Nik
> diff --git a/include/net/switchdev.h b/include/net/switchdev.h
> index ff2246914301..7594ea82879f 100644
> --- a/include/net/switchdev.h
> +++ b/include/net/switchdev.h
> @@ -97,6 +97,7 @@ struct switchdev_obj_port_vlan {
> u16 flags;
> u16 vid_begin;
> u16 vid_end;
> + u16 proto;
> };
>
> #define SWITCHDEV_OBJ_PORT_VLAN(OBJ) \
> diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c
> index 015209bf44aa..bcfa00d6d5eb 100644
> --- a/net/bridge/br_switchdev.c
> +++ b/net/bridge/br_switchdev.c
> @@ -146,6 +146,26 @@ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
> }
> }
>
> +static u16 br_switchdev_get_bridge_vlan_proto(struct net_device *dev)
const
> +{
> + u16 vlan_proto = ETH_P_8021Q;
> + struct net_device *br = NULL;
> + struct net_bridge_port *p;
> +
> + if (netif_is_bridge_master(dev)) {
> + br = dev;
> + } else if (netif_is_bridge_port(dev)) {
You can use br_port_get_rtnl_rcu() and just check if p is not NULL.
But in general these helpers are used only on bridge devices, I don't think you
can reach them with a device that's not either a bridge or a port. So you can just
check if it's a bridge master else it's a port.
> + p = br_port_get_rcu(dev);
> + if (p && p->br)
No need to check for p->br, it always exists.
> + br = p->br->dev;
> + }
> +
> + if (br)
> + br_vlan_get_proto(br, &vlan_proto);
> +
> + return vlan_proto;
> +}
> +
> int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
> struct netlink_ext_ack *extack)
> {
> @@ -157,6 +177,7 @@ int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
> .vid_end = vid,
> };
>
> + v.proto = br_switchdev_get_bridge_vlan_proto(dev);
> return switchdev_port_obj_add(dev, &v.obj, extack);
> }
>
> @@ -169,5 +190,6 @@ int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
> .vid_end = vid,
> };
>
> + v.proto = br_switchdev_get_bridge_vlan_proto(dev);
> return switchdev_port_obj_del(dev, &v.obj);
> }
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver
2020-08-07 11:13 [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver hongbo.wang
2020-08-07 11:13 ` [PATCH v5 1/2] net: dsa: Add protocol support for 802.1AD when adding or deleting vlan for dsa switch port hongbo.wang
2020-08-07 11:13 ` [PATCH v5 2/2] net: dsa: ocelot: Add support for QinQ Operation hongbo.wang
@ 2020-08-08 0:24 ` David Miller
2 siblings, 0 replies; 5+ messages in thread
From: David Miller @ 2020-08-08 0:24 UTC (permalink / raw)
To: hongbo.wang
Cc: xiaoliang.yang_1, allan.nielsen, po.liu, claudiu.manoil,
alexandru.marginean, vladimir.oltean, leoyang.li, mingkai.hu,
andrew, f.fainelli, vivien.didelot, jiri, idosch, kuba,
vinicius.gomes, nikolay, roopa, netdev, linux-kernel,
horatiu.vultur, alexandre.belloni, UNGLinuxDriver, ivecera
From: hongbo.wang@nxp.com
Date: Fri, 7 Aug 2020 19:13:47 +0800
> From: "hongbo.wang" <hongbo.wang@nxp.com>
>
> 1. the patch 0001* is for setting single port into 802.1AD(QinQ) mode,
> before this patch, the function dsa_slave_vlan_rx_add_vid didn't pass
> the parameter "proto" to next port level, so switch's port can't get
> parameter "proto"
> after applying this patch, the following command can be supported:
> ip link set br0 type bridge vlan_protocol 802.1ad
> ip link add link swp1 name swp1.100 type vlan protocol 802.1ad id 100
>
> 2. the patch 0002* is for setting QinQ related registers in ocelot
> switch driver, after applying this patch, the switch(VSC99599)'s port can
> enable or disable QinQ mode.
>
> 3. Version log
> v5:
> a. add devlink to enable qinq_mode of ocelot's single port
> b. modify br_switchdev_port_vlan_add to pass bridge's vlan_proto to port driver
> c. enable NETIF_F_HW_VLAN_STAG_FILTER in ocelot driver
> v4:
> a. modify slave.c to support "ip set br0 type bridge vlan_protocol 802.1ad"
> b. modify ocelot.c, if enable QinQ, set VLAN_AWARE_ENA and VLAN_POP_CNT per
> port when vlan_filter=1
> v3: combine two patches to one post
Please defer new feature changes, like this, until the net-next tree is open
again. It is closed right now.
Thank you.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-08-08 0:24 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-07 11:13 [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver hongbo.wang
2020-08-07 11:13 ` [PATCH v5 1/2] net: dsa: Add protocol support for 802.1AD when adding or deleting vlan for dsa switch port hongbo.wang
2020-08-07 11:25 ` Nikolay Aleksandrov
2020-08-07 11:13 ` [PATCH v5 2/2] net: dsa: ocelot: Add support for QinQ Operation hongbo.wang
2020-08-08 0:24 ` [PATCH v5 0/2] Add 802.1AD protocol support for dsa switch and ocelot driver David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).