From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2022-01-05 23:11:36
These patches contain miscellaneous work that makes the DSA init code
path symmetric with the teardown path, and some additional patches
carried by Ansuel Smith for his register access over Ethernet work, but
those patches can be applied as-is too.
https://patchwork.kernel.org/project/netdevbpf/patch/20211214224409.5770-3-ansuelsmth@gmail.com/
Vladimir Oltean (6):
net: dsa: reorder PHY initialization with MTU setup in slave.c
net: dsa: merge rtnl_lock sections in dsa_slave_create
net: dsa: stop updating master MTU from master.c
net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown}
net: dsa: first set up shared ports, then non-shared ports
net: dsa: setup master before ports
net/dsa/dsa2.c | 69 ++++++++++++++++++++++++++++++++++++------------
net/dsa/master.c | 29 +++-----------------
net/dsa/slave.c | 12 ++++-----
3 files changed, 60 insertions(+), 50 deletions(-)
--
2.25.1
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2022-01-05 23:11:37
In dsa_slave_create() there are 2 sections that take rtnl_lock():
MTU change and netdev registration. They are separated by PHY
initialization.
There isn't any strict ordering requirement except for the fact that
netdev registration should be last. Therefore, we can perform the MTU
change a bit later, after the PHY setup. A future change will then be
able to merge the two rtnl_lock sections into one.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
net/dsa/slave.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
@@ -2011,13 +2011,6 @@ int dsa_slave_create(struct dsa_port *port)port->slave=slave_dev;dsa_slave_setup_tagger(slave_dev);-rtnl_lock();-ret=dsa_slave_change_mtu(slave_dev,ETH_DATA_LEN);-rtnl_unlock();-if(ret&&ret!=-EOPNOTSUPP)-dev_warn(ds->dev,"nonfatal error %d setting MTU to %d on port %d\n",-ret,ETH_DATA_LEN,port->index);-netif_carrier_off(slave_dev);ret=dsa_slave_phy_setup(slave_dev);
@@ -2028,6 +2021,13 @@ int dsa_slave_create(struct dsa_port *port)gotoout_gcells;}+rtnl_lock();+ret=dsa_slave_change_mtu(slave_dev,ETH_DATA_LEN);+rtnl_unlock();+if(ret&&ret!=-EOPNOTSUPP)+dev_warn(ds->dev,"nonfatal error %d setting MTU to %d on port %d\n",+ret,ETH_DATA_LEN,port->index);+rtnl_lock();ret=register_netdevice(slave_dev);
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2022-01-05 23:11:39
Currently dsa_slave_create() has two sequences of rtnl_lock/rtnl_unlock
in a row. Remove the rtnl_unlock() and rtnl_lock() in between, such that
the operation can execute slighly faster.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
net/dsa/slave.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
@@ -2022,14 +2022,12 @@ int dsa_slave_create(struct dsa_port *port)}rtnl_lock();+ret=dsa_slave_change_mtu(slave_dev,ETH_DATA_LEN);-rtnl_unlock();if(ret&&ret!=-EOPNOTSUPP)dev_warn(ds->dev,"nonfatal error %d setting MTU to %d on port %d\n",ret,ETH_DATA_LEN,port->index);-rtnl_lock();-ret=register_netdevice(slave_dev);if(ret){netdev_err(master,"error %d registering interface %s\n",
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2022-01-05 23:11:40
At present there are two paths for changing the MTU of the DSA master.
The first is:
dsa_tree_setup
-> dsa_tree_setup_ports
-> dsa_port_setup
-> dsa_slave_create
-> dsa_slave_change_mtu
-> dev_set_mtu(master)
The second is:
dsa_tree_setup
-> dsa_tree_setup_master
-> dsa_master_setup
-> dev_set_mtu(dev)
So the dev_set_mtu() call from dsa_master_setup() has been effectively
superseded by the dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN) that is
done from dsa_slave_create() for each user port. The later function also
updates the master MTU according to the largest user port MTU from the
tree. Therefore, updating the master MTU through a separate code path
isn't needed.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
---
net/dsa/master.c | 25 +------------------------
1 file changed, 1 insertion(+), 24 deletions(-)
@@ -330,28 +330,13 @@ static const struct attribute_group dsa_group = {.attrs=dsa_slave_attrs,};-staticvoiddsa_master_reset_mtu(structnet_device*dev)-{-interr;--rtnl_lock();-err=dev_set_mtu(dev,ETH_DATA_LEN);-if(err)-netdev_dbg(dev,-"Unable to reset MTU to exclude DSA overheads\n");-rtnl_unlock();-}-staticstructlock_class_keydsa_master_addr_list_lock_key;intdsa_master_setup(structnet_device*dev,structdsa_port*cpu_dp){-conststructdsa_device_ops*tag_ops=cpu_dp->tag_ops;structdsa_switch*ds=cpu_dp->ds;structdevice_link*consumer_link;-intmtu,ret;--mtu=ETH_DATA_LEN+dsa_tag_protocol_overhead(tag_ops);+intret;/* The DSA master must use SET_NETDEV_DEV for this to work. */consumer_link=device_link_add(ds->dev,dev->dev.parent,
@@ -361,13 +346,6 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)"Failed to create a device link to DSA switch %s\n",dev_name(ds->dev));-rtnl_lock();-ret=dev_set_mtu(dev,mtu);-rtnl_unlock();-if(ret)-netdev_warn(dev,"error %d setting MTU to %d to include DSA overhead\n",-ret,mtu);-/* If we use a tagging format that doesn't have an ethertype*field,makesurethatallpacketsfromthispointonget*senttothetagformat'sreceivefunction.
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2022-01-05 23:11:44
DSA needs to simulate master tracking events when a binding is first
with a DSA master established and torn down, in order to give drivers
the simplifying guarantee that ->master_state_change calls are made
only when the master's readiness state to pass traffic changes.
master_state_change() provide a operational bool that DSA driver can use
to understand if DSA master is operational or not.
To avoid races, we need to block the reception of
NETDEV_UP/NETDEV_CHANGE/NETDEV_GOING_DOWN events in the netdev notifier
chain while we are changing the master's dev->dsa_ptr (this changes what
netdev_uses_dsa(dev) reports).
The dsa_master_setup() and dsa_master_teardown() functions optionally
require the rtnl_mutex to be held, if the tagger needs the master to be
promiscuous, these functions call dev_set_promiscuity(). Move the
rtnl_lock() from that function and make it top-level.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
---
net/dsa/dsa2.c | 8 ++++++++
net/dsa/master.c | 4 ++--
2 files changed, 10 insertions(+), 2 deletions(-)
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2022-01-05 23:11:47
After commit a57d8c217aad ("net: dsa: flush switchdev workqueue before
tearing down CPU/DSA ports"), the port setup and teardown procedure
became asymmetric.
The fact of the matter is that user ports need the shared ports to be up
before they can be used for CPU-initiated termination. And since we
register net devices for the user ports, those won't be functional until
we also call the setup for the shared (CPU, DSA) ports. But we may do
that later, depending on the port numbering scheme of the hardware we
are dealing with.
It just makes sense that all shared ports are brought up before any user
port is. I can't pinpoint any issue due to the current behavior, but
let's change it nonetheless, for consistency's sake.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
net/dsa/dsa2.c | 50 +++++++++++++++++++++++++++++++++++++-------------
1 file changed, 37 insertions(+), 13 deletions(-)
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2022-01-05 23:11:49
It is said that as soon as a network interface is registered, all its
resources should have already been prepared, so that it is available for
sending and receiving traffic. One of the resources needed by a DSA
slave interface is the master.
dsa_tree_setup
-> dsa_tree_setup_ports
-> dsa_port_setup
-> dsa_slave_create
-> register_netdevice
-> dsa_tree_setup_master
-> dsa_master_setup
-> sets up master->dsa_ptr, which enables reception
Therefore, there is a short period of time after register_netdevice()
during which the master isn't prepared to pass traffic to the DSA layer
(master->dsa_ptr is checked by eth_type_trans). Same thing during
unregistration, there is a time frame in which packets might be missed.
Note that this change opens us to another race: dsa_master_find_slave()
will get invoked potentially earlier than the slave creation, and later
than the slave deletion. Since dp->slave starts off as a NULL pointer,
the earlier calls aren't a problem, but the later calls are. To avoid
use-after-free, we should zeroize dp->slave before calling
dsa_slave_destroy().
In practice I cannot really test real life improvements brought by this
change, since in my systems, netdevice creation races with PHY autoneg
which takes a few seconds to complete, and that masks quite a few races.
Effects might be noticeable in a setup with fixed links all the way to
an external system.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
net/dsa/dsa2.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
In dsa_slave_create() there are 2 sections that take rtnl_lock():
MTU change and netdev registration. They are separated by PHY
initialization.
There isn't any strict ordering requirement except for the fact that
netdev registration should be last. Therefore, we can perform the MTU
change a bit later, after the PHY setup. A future change will then be
able to merge the two rtnl_lock sections into one.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Currently dsa_slave_create() has two sequences of rtnl_lock/rtnl_unlock
in a row. Remove the rtnl_unlock() and rtnl_lock() in between, such that
the operation can execute slighly faster.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Hello:
This series was applied to netdev/net-next.git (master)
by David S. Miller [off-list ref]:
On Thu, 6 Jan 2022 01:11:11 +0200 you wrote:
These patches contain miscellaneous work that makes the DSA init code
path symmetric with the teardown path, and some additional patches
carried by Ansuel Smith for his register access over Ethernet work, but
those patches can be applied as-is too.
https://patchwork.kernel.org/project/netdevbpf/patch/20211214224409.5770-3-ansuelsmth@gmail.com/
Vladimir Oltean (6):
net: dsa: reorder PHY initialization with MTU setup in slave.c
net: dsa: merge rtnl_lock sections in dsa_slave_create
net: dsa: stop updating master MTU from master.c
net: dsa: hold rtnl_mutex when calling dsa_master_{setup,teardown}
net: dsa: first set up shared ports, then non-shared ports
net: dsa: setup master before ports
[...]
From: Luiz Angelo Daros de Luca <luizluca@gmail.com> Date: 2022-03-31 05:54:04
Hi Vladimir,
I think I found an issue with this patch.
At present there are two paths for changing the MTU of the DSA master.
The first is:
dsa_tree_setup
-> dsa_tree_setup_ports
-> dsa_port_setup
-> dsa_slave_create
-> dsa_slave_change_mtu
-> dev_set_mtu(master)
The first code from dsa_slave_change_mtu() is:
if (!ds->ops->port_change_mtu)
return -EOPNOTSUPP;
So, when the switch does not implement ds->ops->port_change_mtu, the
master MTU will never be updated. This is the case for
drivers/net/dsa/realtek/rtl8365mb.c. Before this patch,
ops->port_change_mtu was optional. We either need to turn it into a
mandatory function (even if it is a no-op that fails when mtu is
different) or change the dsa_slave_change_mtu to only return
-EOPNOTSUPP when the new slave MTU differs from current slave MTU.
Regards,
Luiz
From: Vladimir Oltean <vladimir.oltean@nxp.com> Date: 2022-03-31 13:31:11
On Thu, Mar 31, 2022 at 02:53:46AM -0300, Luiz Angelo Daros de Luca wrote:
Hi Vladimir,
I think I found an issue with this patch.
quoted
At present there are two paths for changing the MTU of the DSA master.
The first is:
dsa_tree_setup
-> dsa_tree_setup_ports
-> dsa_port_setup
-> dsa_slave_create
-> dsa_slave_change_mtu
-> dev_set_mtu(master)
The first code from dsa_slave_change_mtu() is:
if (!ds->ops->port_change_mtu)
return -EOPNOTSUPP;
So, when the switch does not implement ds->ops->port_change_mtu, the
master MTU will never be updated. This is the case for
drivers/net/dsa/realtek/rtl8365mb.c. Before this patch,
ops->port_change_mtu was optional. We either need to turn it into a
mandatory function (even if it is a no-op that fails when mtu is
different) or change the dsa_slave_change_mtu to only return
-EOPNOTSUPP when the new slave MTU differs from current slave MTU.
Regards,
Luiz