From: Vladimir Oltean <olteanv@gmail.com>
To: Christian Marangi <ansuelsmth@gmail.com>
Cc: Andrew Lunn <andrew@lunn.ch>,
Florian Fainelli <f.fainelli@gmail.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [net-next PATCH] net: dsa: qca8k: add support for port_change_master
Date: Tue, 20 Jun 2023 23:12:27 +0300 [thread overview]
Message-ID: <20230620201227.7sdb3zmwutwtmt2e@skbuf> (raw)
In-Reply-To: <20230620063747.19175-1-ansuelsmth@gmail.com> <20230620063747.19175-1-ansuelsmth@gmail.com>
Hi Christian,
On Tue, Jun 20, 2023 at 08:37:47AM +0200, Christian Marangi wrote:
> 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 reenable the target port previously disabled.
>
> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
> ---
> drivers/net/dsa/qca/qca8k-8xxx.c | 54 ++++++++++++++++++++++++++++++++
> drivers/net/dsa/qca/qca8k.h | 1 +
> 2 files changed, 55 insertions(+)
>
> diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
> index dee7b6579916..435b69c1c552 100644
> --- a/drivers/net/dsa/qca/qca8k-8xxx.c
> +++ b/drivers/net/dsa/qca/qca8k-8xxx.c
> @@ -1713,6 +1713,59 @@ qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
> 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 qca8k_priv *priv = ds->priv;
> + u32 val, cpu_port_mask = 0;
> + struct dsa_port *dp;
> + int ret;
> +
> + /* With LAG of CPU port, compose the mask for LOOKUP MEMBER */
> + if (netif_is_lag_master(master)) {
> + struct dsa_lag *lag;
> + int id;
> +
> + id = dsa_lag_id(ds->dst, master);
> + lag = dsa_lag_by_id(ds->dst, id);
> +
> + dsa_lag_foreach_port(dp, ds->dst, lag)
I think you use ds->dst often enough that you could assign it to its own
local variable.
> + if (dsa_port_is_cpu(dp))
> + cpu_port_mask |= BIT(dp->index);
> + } else {
> + dp = dsa_port_from_netdev(master);
dsa_port_from_netdev() is implemented by calling:
static inline struct dsa_port *dsa_slave_to_port(const struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
return p->dp;
}
The "struct net_device *master" does not have a netdev_priv() of the
type "struct dsa_slave_priv *". So, this function does not do what you
want, but instead it messes through the guts of an unrelated private
structure, treating whatever it finds at offset 16 as a pointer, and
dereferincing that as a struct dsa_port *. I'm surprised it didn't
crash, to be frank.
To find the cpu_dp behind the master, you need to dereference
master->dsa_ptr (for which we don't have a helper).
> + cpu_port_mask |= BIT(dp->index);
> + }
> +
> + /* Disable port */
> + qca8k_port_set_status(priv, port, 0);
> +
> + /* Connect it to new cpu port */
> + ret = qca8k_read(priv, QCA8K_PORT_LOOKUP_CTRL(port), &val);
> + if (ret)
> + return ret;
> +
> + /* Reset connected CPU port in LOOKUP MEMBER */
> + val &= QCA8K_PORT_LOOKUP_USER_MEMBER;
val &= GENMASK(5, 1) practically has the effect of unsetting BIT(0) and BIT(6).
I suppose those are the 2 possible CPU ports? If so, then use ~dsa_cpu_ports(ds),
it's more readable at least for me as a fallback maintainer.
> + /* Assign the new CPU port in LOOKUP MEMBER */
> + val |= cpu_port_mask;
> +
> + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
> + QCA8K_PORT_LOOKUP_MEMBER,
> + val);
> + if (ret)
> + return ret;
> +
> + /* Fast Age the port to flush FDB table */
> + qca8k_port_fast_age(ds, port);
Why do you have to fast age the (user) port?
> +
> + /* Reenable port */
> + qca8k_port_set_status(priv, port, 1);
or disable/enable it, for that matter?
> +
> + return 0;
> +}
> +
> static void
> qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
> bool operational)
> @@ -1996,6 +2049,7 @@ static const struct dsa_switch_ops qca8k_switch_ops = {
> .get_phy_flags = qca8k_get_phy_flags,
> .port_lag_join = qca8k_port_lag_join,
> .port_lag_leave = qca8k_port_lag_leave,
> + .port_change_master = qca8k_port_change_master,
From my notes in commit eca70102cfb1 ("net: dsa: felix: add support for
changing DSA master"), I recall this:
When we change the DSA master to a LAG device, DSA guarantees us that
the LAG has at least one lower interface as a physical DSA master.
But DSA masters can come and go as lowers of that LAG, and
ds->ops->port_change_master() will not get called, because the DSA
master is still the same (the LAG). So we need to hook into the
ds->ops->port_lag_{join,leave} calls on the CPU ports and update the
logical port ID of the LAG that user ports are assigned to.
Otherwise said:
$ ip link add bond0 type bond mode balance-xor && ip link set bond0 up
$ ip link set eth0 down && ip link set eth0 master bond0 # .port_change_master() gets called
$ ip link set eth1 down && ip link set eth1 master bond0 # .port_change_master() does not get called
$ ip link set eth0 nomaster # .port_change_master() does not get called
Unless something has changed, I believe that you need to handle these as well,
and update the QCA8K_PORT_LOOKUP_MEMBER field. In the case above, your
CPU port association would remain towards eth0, but the bond's lower interface
is eth1.
> .master_state_change = qca8k_master_change,
> .connect_tag_protocol = qca8k_connect_tag_protocol,
> };
> diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
> index c5cc8a172d65..424f851db881 100644
> --- a/drivers/net/dsa/qca/qca8k.h
> +++ b/drivers/net/dsa/qca/qca8k.h
> @@ -250,6 +250,7 @@
> #define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8)
> #define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0)
> #define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc)
> +#define QCA8K_PORT_LOOKUP_USER_MEMBER GENMASK(5, 1)
> #define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0)
> #define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8)
> #define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x)
> --
> 2.40.1
>
next prev parent reply other threads:[~2023-06-20 20:12 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-20 6:37 [net-next PATCH] net: dsa: qca8k: add support for port_change_master Christian Marangi
2023-06-20 11:22 ` Christian Marangi
2023-06-20 20:12 ` Vladimir Oltean [this message]
2023-06-20 13:04 ` Christian Marangi
2023-06-21 10:25 ` Vladimir Oltean
2023-06-20 18:52 ` Christian Marangi
2023-06-21 12:17 ` Vladimir Oltean
2023-06-21 4:08 ` Christian Marangi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230620201227.7sdb3zmwutwtmt2e@skbuf \
--to=olteanv@gmail.com \
--cc=andrew@lunn.ch \
--cc=ansuelsmth@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=f.fainelli@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.