1 From b2d6ebf2f92f8695c83fa6979f4ab579c588df76 Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Tue, 20 Jun 2023 07:57:38 +0200
4 Subject: [PATCH 4/4] net: dsa: qca8k: add support for port_change_master
6 Add support for port_change_master to permit assigning an alternative
7 CPU port if the switch have both CPU port connected or create a LAG on
8 both CPU port and assign the LAG as DSA master.
10 On port change master request, we check if the master is a LAG.
11 With LAG we compose the cpu_port_mask with the CPU port in the LAG, if
12 master is a simple dsa_port, we derive the index.
14 Finally we apply the new cpu_port_mask to the LOOKUP MEMBER to permit
15 the port to receive packet by the new CPU port setup for the port and we
16 refresh the CPU ports LOOKUP MEMBER configuration to reflect the new
19 port_lag_join/leave is updated to refresh the user ports if we detect
20 that the LAG is a DSA master and we have user port using it as a master.
22 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
24 drivers/net/dsa/qca/qca8k-8xxx.c | 116 ++++++++++++++++++++++++++++++-
25 1 file changed, 114 insertions(+), 2 deletions(-)
27 --- a/drivers/net/dsa/qca/qca8k-8xxx.c
28 +++ b/drivers/net/dsa/qca/qca8k-8xxx.c
29 @@ -1738,6 +1738,117 @@ qca8k_get_tag_protocol(struct dsa_switch
30 return DSA_TAG_PROTO_QCA;
33 +static int qca8k_port_change_master(struct dsa_switch *ds, int port,
34 + struct net_device *master,
35 + struct netlink_ext_ack *extack)
37 + struct dsa_switch_tree *dst = ds->dst;
38 + struct qca8k_priv *priv = ds->priv;
39 + u8 cpu_port_mask = 0;
40 + struct dsa_port *dp;
44 + /* With LAG of CPU port, compose the mask for port LOOKUP MEMBER */
45 + if (netif_is_lag_master(master)) {
46 + struct dsa_lag *lag;
49 + id = dsa_lag_id(dst, master);
50 + lag = dsa_lag_by_id(dst, id);
52 + dsa_lag_foreach_port(dp, dst, lag)
53 + if (dsa_port_is_cpu(dp))
54 + cpu_port_mask |= BIT(dp->index);
56 + dp = master->dsa_ptr;
57 + cpu_port_mask |= BIT(dp->index);
60 + /* Connect port to new cpu port */
61 + ret = regmap_read(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), &val);
65 + /* Reset connected CPU port in port LOOKUP MEMBER */
66 + val &= ~dsa_cpu_ports(ds);
67 + /* Assign the new CPU port in port LOOKUP MEMBER */
68 + val |= cpu_port_mask;
70 + ret = regmap_update_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
71 + QCA8K_PORT_LOOKUP_MEMBER,
76 + /* Refresh CPU port LOOKUP MEMBER with new port */
77 + dsa_tree_for_each_cpu_port(dp, ds->dst) {
78 + u32 reg = QCA8K_PORT_LOOKUP_CTRL(dp->index);
80 + /* If CPU port in mask assign port, else remove port */
81 + if (BIT(dp->index) & cpu_port_mask)
82 + ret = regmap_set_bits(priv->regmap, reg, BIT(port));
84 + ret = regmap_clear_bits(priv->regmap, reg, BIT(port));
93 +static int qca8k_port_lag_refresh_user_ports(struct dsa_switch *ds,
96 + struct net_device *lag_dev = lag.dev;
97 + struct dsa_port *dp;
100 + /* Ignore if LAG is not a DSA master */
101 + if (!netif_is_lag_master(lag_dev))
104 + dsa_switch_for_each_user_port(dp, ds) {
105 + /* Skip if assigned master is not the LAG */
106 + if (dsa_port_to_master(dp) != lag_dev)
109 + ret = qca8k_port_change_master(ds, dp->index,
118 +static int qca8xxx_port_lag_join(struct dsa_switch *ds, int port,
119 + struct dsa_lag lag,
120 + struct netdev_lag_upper_info *info,
121 + struct netlink_ext_ack *extack)
125 + ret = qca8k_port_lag_join(ds, port, lag, info, extack);
129 + return qca8k_port_lag_refresh_user_ports(ds, lag);
132 +static int qca8xxx_port_lag_leave(struct dsa_switch *ds, int port,
133 + struct dsa_lag lag)
137 + ret = qca8k_port_lag_leave(ds, port, lag);
141 + return qca8k_port_lag_refresh_user_ports(ds, lag);
145 qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
147 @@ -2024,8 +2135,9 @@ static const struct dsa_switch_ops qca8k
148 .phylink_mac_link_down = qca8k_phylink_mac_link_down,
149 .phylink_mac_link_up = qca8k_phylink_mac_link_up,
150 .get_phy_flags = qca8k_get_phy_flags,
151 - .port_lag_join = qca8k_port_lag_join,
152 - .port_lag_leave = qca8k_port_lag_leave,
153 + .port_lag_join = qca8xxx_port_lag_join,
154 + .port_lag_leave = qca8xxx_port_lag_leave,
155 + .port_change_master = qca8k_port_change_master,
156 .master_state_change = qca8k_master_change,
157 .connect_tag_protocol = qca8k_connect_tag_protocol,