1
0
mirror of https://git.openwrt.org/openwrt/openwrt.git synced 2024-10-19 05:58:53 +02:00

generic: 6.1: backport patch for multi CPU port support on QCA8K

Backport pending patch for multi CPU port support on QCA8K. 6.1 already
supports all the requiredt code to change a DSA master port so only this
patch fixing the driver is required.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
Christian Marangi 2023-06-20 08:41:32 +02:00
parent a62b1544d1
commit 500dbaefd2
No known key found for this signature in database
GPG Key ID: AC001D09ADBFEAD7
3 changed files with 281 additions and 0 deletions

@ -0,0 +1,86 @@
From 3b4329230db8750bea7a56ef07f07cbbf5fc6c5a Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 4 Jul 2023 22:50:12 +0200
Subject: [PATCH 19/20] net: dsa: qca8k: implement lag_fdb_add/del ops
Implement lag_fdb_add/del ops to correctly support using LAG interface.
Qca8k switch supports declaring fdb entry for link aggregation by simply
setting the DES_PORT bits to all the LAG member.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 2 ++
drivers/net/dsa/qca/qca8k-common.c | 48 ++++++++++++++++++++++++++++++
drivers/net/dsa/qca/qca8k.h | 6 ++++
3 files changed, 56 insertions(+)
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1993,6 +1993,8 @@ static const struct dsa_switch_ops qca8k
.port_fdb_add = qca8k_port_fdb_add,
.port_fdb_del = qca8k_port_fdb_del,
.port_fdb_dump = qca8k_port_fdb_dump,
+ .lag_fdb_add = qca8k_lag_fdb_add,
+ .lag_fdb_del = qca8k_lag_fdb_del,
.port_mdb_add = qca8k_port_mdb_add,
.port_mdb_del = qca8k_port_mdb_del,
.port_mirror_add = qca8k_port_mirror_add,
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -1215,6 +1215,42 @@ int qca8k_port_lag_leave(struct dsa_swit
return qca8k_lag_refresh_portmap(ds, port, lag, true);
}
+int qca8k_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag,
+ const unsigned char *addr, u16 vid,
+ struct dsa_db db)
+{
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+ struct dsa_port *dp;
+ u16 port_mask = 0;
+
+ /* Set the vid to the port vlan id if no vid is set */
+ if (!vid)
+ vid = QCA8K_PORT_VID_DEF;
+
+ dsa_lag_foreach_port(dp, ds->dst, &lag)
+ port_mask |= BIT(dp->index);
+
+ return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
+}
+
+int qca8k_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag,
+ const unsigned char *addr, u16 vid,
+ struct dsa_db db)
+{
+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+ struct dsa_port *dp;
+ u16 port_mask = 0;
+
+ /* Set the vid to the port vlan id if no vid is set */
+ if (!vid)
+ vid = QCA8K_PORT_VID_DEF;
+
+ dsa_lag_foreach_port(dp, ds->dst, &lag)
+ port_mask |= BIT(dp->index);
+
+ return qca8k_fdb_del(priv, addr, port_mask, vid);
+}
+
int qca8k_read_switch_id(struct qca8k_priv *priv)
{
u32 val;
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -590,5 +590,11 @@ int qca8k_port_lag_join(struct dsa_switc
struct netlink_ext_ack *extack);
int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
struct dsa_lag lag);
+int qca8k_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag,
+ const unsigned char *addr, u16 vid,
+ struct dsa_db db);
+int qca8k_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag,
+ const unsigned char *addr, u16 vid,
+ struct dsa_db db);
#endif /* __QCA8K_H */

@ -0,0 +1,37 @@
From b954d61d9ecfa64450fc178586719dc2a95b92a7 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 20 Jun 2023 21:48:24 +0200
Subject: [PATCH 3/4] net: dsa: qca8k: enable flooding to both CPU port
To permit a multi-CPU setup, flood all unknown frames to all CPU ports.
Each CPU port should have correct LOOKUP MEMBER configuration to
prevent receiving duplicate packets from user ports.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1882,15 +1882,12 @@ qca8k_setup(struct dsa_switch *ds)
}
}
- /* Forward all unknown frames to CPU port for Linux processing
- * Notice that in multi-cpu config only one port should be set
- * for igmp, unknown, multicast and broadcast packet
- */
+ /* Forward all unknown frames to CPU port for Linux processing */
ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) |
- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) |
- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) |
- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port)));
+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, dsa_cpu_ports(ds)) |
+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, dsa_cpu_ports(ds)) |
+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, dsa_cpu_ports(ds)) |
+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, dsa_cpu_ports(ds)));
if (ret)
return ret;

@ -0,0 +1,158 @@
From b2d6ebf2f92f8695c83fa6979f4ab579c588df76 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 20 Jun 2023 07:57:38 +0200
Subject: [PATCH 4/4] net: dsa: qca8k: add support for port_change_master
Add support for port_change_master to permit assigning an alternative
CPU port if the switch have both CPU port connected or create a LAG on
both CPU port and assign the LAG as DSA master.
On port change master request, we check if the master is a LAG.
With LAG we compose the cpu_port_mask with the CPU port in the LAG, if
master is a simple dsa_port, we derive the index.
Finally we apply the new cpu_port_mask to the LOOKUP MEMBER to permit
the port to receive packet by the new CPU port setup for the port and we
refresh the CPU ports LOOKUP MEMBER configuration to reflect the new
user port state.
port_lag_join/leave is updated to refresh the user ports if we detect
that the LAG is a DSA master and we have user port using it as a master.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 116 ++++++++++++++++++++++++++++++-
1 file changed, 114 insertions(+), 2 deletions(-)
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1719,6 +1719,117 @@ qca8k_get_tag_protocol(struct dsa_switch
return DSA_TAG_PROTO_QCA;
}
+static int qca8k_port_change_master(struct dsa_switch *ds, int port,
+ struct net_device *master,
+ struct netlink_ext_ack *extack)
+{
+ struct dsa_switch_tree *dst = ds->dst;
+ struct qca8k_priv *priv = ds->priv;
+ u8 cpu_port_mask = 0;
+ struct dsa_port *dp;
+ u32 val;
+ int ret;
+
+ /* With LAG of CPU port, compose the mask for port LOOKUP MEMBER */
+ if (netif_is_lag_master(master)) {
+ struct dsa_lag *lag;
+ int id;
+
+ id = dsa_lag_id(dst, master);
+ lag = dsa_lag_by_id(dst, id);
+
+ dsa_lag_foreach_port(dp, dst, lag)
+ if (dsa_port_is_cpu(dp))
+ cpu_port_mask |= BIT(dp->index);
+ } else {
+ dp = master->dsa_ptr;
+ cpu_port_mask |= BIT(dp->index);
+ }
+
+ /* Connect port to new cpu port */
+ ret = regmap_read(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), &val);
+ if (ret)
+ return ret;
+
+ /* Reset connected CPU port in port LOOKUP MEMBER */
+ val &= ~dsa_cpu_ports(ds);
+ /* Assign the new CPU port in port LOOKUP MEMBER */
+ val |= cpu_port_mask;
+
+ ret = regmap_update_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_MEMBER,
+ val);
+ if (ret)
+ return ret;
+
+ /* Refresh CPU port LOOKUP MEMBER with new port */
+ dsa_tree_for_each_cpu_port(dp, ds->dst) {
+ u32 reg = QCA8K_PORT_LOOKUP_CTRL(dp->index);
+
+ /* If CPU port in mask assign port, else remove port */
+ if (BIT(dp->index) & cpu_port_mask)
+ ret = regmap_set_bits(priv->regmap, reg, BIT(port));
+ else
+ ret = regmap_clear_bits(priv->regmap, reg, BIT(port));
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qca8k_port_lag_refresh_user_ports(struct dsa_switch *ds,
+ struct dsa_lag lag)
+{
+ struct net_device *lag_dev = lag.dev;
+ struct dsa_port *dp;
+ int ret;
+
+ /* Ignore if LAG is not a DSA master */
+ if (!netif_is_lag_master(lag_dev))
+ return 0;
+
+ dsa_switch_for_each_user_port(dp, ds) {
+ /* Skip if assigned master is not the LAG */
+ if (dsa_port_to_master(dp) != lag_dev)
+ continue;
+
+ ret = qca8k_port_change_master(ds, dp->index,
+ lag_dev, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qca8xxx_port_lag_join(struct dsa_switch *ds, int port,
+ struct dsa_lag lag,
+ struct netdev_lag_upper_info *info,
+ struct netlink_ext_ack *extack)
+{
+ int ret;
+
+ ret = qca8k_port_lag_join(ds, port, lag, info, extack);
+ if (ret)
+ return ret;
+
+ return qca8k_port_lag_refresh_user_ports(ds, lag);
+}
+
+static int qca8xxx_port_lag_leave(struct dsa_switch *ds, int port,
+ struct dsa_lag lag)
+{
+ int ret;
+
+ ret = qca8k_port_lag_leave(ds, port, lag);
+ if (ret)
+ return ret;
+
+ return qca8k_port_lag_refresh_user_ports(ds, lag);
+}
+
static void
qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
bool operational)
@@ -2005,8 +2116,9 @@ static const struct dsa_switch_ops qca8k
.phylink_mac_link_down = qca8k_phylink_mac_link_down,
.phylink_mac_link_up = qca8k_phylink_mac_link_up,
.get_phy_flags = qca8k_get_phy_flags,
- .port_lag_join = qca8k_port_lag_join,
- .port_lag_leave = qca8k_port_lag_leave,
+ .port_lag_join = qca8xxx_port_lag_join,
+ .port_lag_leave = qca8xxx_port_lag_leave,
+ .port_change_master = qca8k_port_change_master,
.master_state_change = qca8k_master_change,
.connect_tag_protocol = qca8k_connect_tag_protocol,
};