--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
-@@ -383,6 +383,13 @@ static int at803x_aneg_done(struct phy_d
+@@ -404,6 +404,13 @@ static int at803x_aneg_done(struct phy_d
if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) {
phydev_warn(phydev, "803x_aneg_done: SGMII link is not ok\n");
aneg_done = 0;
--- /dev/null
+From 9d5ef190e5615a7b63af89f88c4106a5bc127974 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 5 Feb 2021 15:37:10 +0200
+Subject: [PATCH] net: dsa: automatically bring up DSA master when opening user
+ port
+
+DSA wants the master interface to be open before the user port is due to
+historical reasons. The promiscuity of interfaces that are down used to
+have issues, as referenced Lennert Buytenhek in commit df02c6ff2e39
+("dsa: fix master interface allmulti/promisc handling").
+
+The bugfix mentioned there, commit b6c40d68ff64 ("net: only invoke
+dev->change_rx_flags when device is UP"), was basically a "don't do
+that" approach to working around the promiscuity while down issue.
+
+Further work done by Vlad Yasevich in commit d2615bf45069 ("net: core:
+Always propagate flag changes to interfaces") has resolved the
+underlying issue, and it is strictly up to the DSA and 8021q drivers
+now, it is no longer mandated by the networking core that the master
+interface must be up when changing its promiscuity.
+
+From DSA's point of view, deciding to error out in dsa_slave_open
+because the master isn't up is
+(a) a bad user experience and
+(b) knocking at an open door.
+Even if there still was an issue with promiscuity while down, DSA could
+still just open the master and avoid it.
+
+Doing it this way has the additional benefit that user space can now
+remove DSA-specific workarounds, like systemd-networkd with BindCarrier:
+https://github.com/systemd/systemd/issues/7478
+
+And we can finally remove one of the 2 bullets in the "Common pitfalls
+using DSA setups" chapter.
+
+Tested with two cascaded DSA switches:
+
+$ ip link set sw0p2 up
+fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode
+fsl_enetc 0000:00:00.2 eno2: Link is Up - 1Gbps/Full - flow control rx/tx
+mscc_felix 0000:00:00.5 swp0: configuring for fixed/sgmii link mode
+mscc_felix 0000:00:00.5 swp0: Link is Up - 1Gbps/Full - flow control off
+8021q: adding VLAN 0 to HW filter on device swp0
+sja1105 spi2.0 sw0p2: configuring for phy/rgmii-id link mode
+IPv6: ADDRCONF(NETDEV_CHANGE): eno2: link becomes ready
+IPv6: ADDRCONF(NETDEV_CHANGE): swp0: link becomes ready
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ Documentation/networking/dsa/dsa.rst | 4 ----
+ net/dsa/slave.c | 7 +++++--
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+--- a/Documentation/networking/dsa/dsa.rst
++++ b/Documentation/networking/dsa/dsa.rst
+@@ -273,10 +273,6 @@ will not make us go through the switch t
+ the Ethernet switch on the other end, expecting a tag will typically drop this
+ frame.
+
+-Slave network devices check that the master network device is UP before allowing
+-you to administratively bring UP these slave network devices. A common
+-configuration mistake is forgetting to bring UP the master network device first.
+-
+ Interactions with other subsystems
+ ==================================
+
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -68,8 +68,11 @@ static int dsa_slave_open(struct net_dev
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+ int err;
+
+- if (!(master->flags & IFF_UP))
+- return -ENETDOWN;
++ err = dev_open(master, NULL);
++ if (err < 0) {
++ netdev_err(dev, "failed to open master %s\n", master->name);
++ goto out;
++ }
+
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
+ err = dev_uc_add(master, dev->dev_addr);
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -2111,7 +2111,9 @@ static void dsa_slave_switchdev_event_wo
+@@ -2114,7 +2114,9 @@ static void dsa_slave_switchdev_event_wo
err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
if (err) {
break;
}
fdb_info->offloaded = true;
-@@ -2126,9 +2128,11 @@ static void dsa_slave_switchdev_event_wo
+@@ -2129,9 +2131,11 @@ static void dsa_slave_switchdev_event_wo
err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
if (err) {
struct sk_buff * (*xmit)(struct sk_buff *skb,
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -2086,76 +2086,66 @@ static int dsa_slave_netdevice_event(str
+@@ -2089,76 +2089,66 @@ static int dsa_slave_netdevice_event(str
return NOTIFY_DONE;
}
}
/* Called under rcu_read_lock() */
-@@ -2163,7 +2153,9 @@ static int dsa_slave_switchdev_event(str
+@@ -2166,7 +2156,9 @@ static int dsa_slave_switchdev_event(str
unsigned long event, void *ptr)
{
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
int err;
if (event == SWITCHDEV_PORT_ATTR_SET) {
-@@ -2176,20 +2168,32 @@ static int dsa_slave_switchdev_event(str
+@@ -2179,20 +2171,32 @@ static int dsa_slave_switchdev_event(str
if (!dsa_slave_dev_check(dev))
return NOTIFY_DONE;
dev_hold(dev);
break;
default:
-@@ -2199,10 +2203,6 @@ static int dsa_slave_switchdev_event(str
+@@ -2202,10 +2206,6 @@ static int dsa_slave_switchdev_event(str
dsa_schedule_work(&switchdev_work->work);
return NOTIFY_OK;
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -2158,31 +2158,29 @@ static int dsa_slave_switchdev_event(str
+@@ -2161,31 +2161,29 @@ static int dsa_slave_switchdev_event(str
struct dsa_port *dp;
int err;
fdb_info = ptr;
if (!fdb_info->added_by_user) {
-@@ -2195,13 +2193,12 @@ static int dsa_slave_switchdev_event(str
+@@ -2198,13 +2196,12 @@ static int dsa_slave_switchdev_event(str
switchdev_work->vid = fdb_info->vid;
dev_hold(dev);
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -2171,6 +2171,9 @@ static int dsa_slave_switchdev_event(str
+@@ -2174,6 +2174,9 @@ static int dsa_slave_switchdev_event(str
dp = dsa_slave_to_port(dev);
*/
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -2148,6 +2148,28 @@ static void dsa_slave_switchdev_event_wo
+@@ -2151,6 +2151,28 @@ static void dsa_slave_switchdev_event_wo
dev_put(dp->slave);
}
/* Called under rcu_read_lock() */
static int dsa_slave_switchdev_event(struct notifier_block *unused,
unsigned long event, void *ptr)
-@@ -2166,10 +2188,37 @@ static int dsa_slave_switchdev_event(str
+@@ -2169,10 +2191,37 @@ static int dsa_slave_switchdev_event(str
return notifier_from_errno(err);
case SWITCHDEV_FDB_ADD_TO_DEVICE:
case SWITCHDEV_FDB_DEL_TO_DEVICE:
if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del)
return NOTIFY_DONE;
-@@ -2184,18 +2233,13 @@ static int dsa_slave_switchdev_event(str
+@@ -2187,18 +2236,13 @@ static int dsa_slave_switchdev_event(str
switchdev_work->port = dp->index;
switchdev_work->event = event;
--- /dev/null
+From 9d5ef190e5615a7b63af89f88c4106a5bc127974 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 5 Feb 2021 15:37:10 +0200
+Subject: [PATCH] net: dsa: automatically bring up DSA master when opening user
+ port
+
+DSA wants the master interface to be open before the user port is due to
+historical reasons. The promiscuity of interfaces that are down used to
+have issues, as referenced Lennert Buytenhek in commit df02c6ff2e39
+("dsa: fix master interface allmulti/promisc handling").
+
+The bugfix mentioned there, commit b6c40d68ff64 ("net: only invoke
+dev->change_rx_flags when device is UP"), was basically a "don't do
+that" approach to working around the promiscuity while down issue.
+
+Further work done by Vlad Yasevich in commit d2615bf45069 ("net: core:
+Always propagate flag changes to interfaces") has resolved the
+underlying issue, and it is strictly up to the DSA and 8021q drivers
+now, it is no longer mandated by the networking core that the master
+interface must be up when changing its promiscuity.
+
+From DSA's point of view, deciding to error out in dsa_slave_open
+because the master isn't up is
+(a) a bad user experience and
+(b) knocking at an open door.
+Even if there still was an issue with promiscuity while down, DSA could
+still just open the master and avoid it.
+
+Doing it this way has the additional benefit that user space can now
+remove DSA-specific workarounds, like systemd-networkd with BindCarrier:
+https://github.com/systemd/systemd/issues/7478
+
+And we can finally remove one of the 2 bullets in the "Common pitfalls
+using DSA setups" chapter.
+
+Tested with two cascaded DSA switches:
+
+$ ip link set sw0p2 up
+fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode
+fsl_enetc 0000:00:00.2 eno2: Link is Up - 1Gbps/Full - flow control rx/tx
+mscc_felix 0000:00:00.5 swp0: configuring for fixed/sgmii link mode
+mscc_felix 0000:00:00.5 swp0: Link is Up - 1Gbps/Full - flow control off
+8021q: adding VLAN 0 to HW filter on device swp0
+sja1105 spi2.0 sw0p2: configuring for phy/rgmii-id link mode
+IPv6: ADDRCONF(NETDEV_CHANGE): eno2: link becomes ready
+IPv6: ADDRCONF(NETDEV_CHANGE): swp0: link becomes ready
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ Documentation/networking/dsa/dsa.rst | 4 ----
+ net/dsa/slave.c | 7 +++++--
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+--- a/Documentation/networking/dsa/dsa.rst
++++ b/Documentation/networking/dsa/dsa.rst
+@@ -273,10 +273,6 @@ will not make us go through the switch t
+ the Ethernet switch on the other end, expecting a tag will typically drop this
+ frame.
+
+-Slave network devices check that the master network device is UP before allowing
+-you to administratively bring UP these slave network devices. A common
+-configuration mistake is forgetting to bring UP the master network device first.
+-
+ Interactions with other subsystems
+ ==================================
+
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -70,8 +70,11 @@ static int dsa_slave_open(struct net_dev
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+ int err;
+
+- if (!(master->flags & IFF_UP))
+- return -ENETDOWN;
++ err = dev_open(master, NULL);
++ if (err < 0) {
++ netdev_err(dev, "failed to open master %s\n", master->name);
++ goto out;
++ }
+
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
+ err = dev_uc_add(master, dev->dev_addr);
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -1592,7 +1592,9 @@ static void dsa_slave_switchdev_event_wo
+@@ -1595,7 +1595,9 @@ static void dsa_slave_switchdev_event_wo
err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
if (err) {
break;
}
fdb_info->offloaded = true;
-@@ -1607,9 +1609,11 @@ static void dsa_slave_switchdev_event_wo
+@@ -1610,9 +1612,11 @@ static void dsa_slave_switchdev_event_wo
err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
if (err) {
struct sk_buff * (*xmit)(struct sk_buff *skb,
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -1567,76 +1567,66 @@ static int dsa_slave_netdevice_event(str
+@@ -1570,76 +1570,66 @@ static int dsa_slave_netdevice_event(str
return NOTIFY_DONE;
}
}
/* Called under rcu_read_lock() */
-@@ -1644,7 +1634,9 @@ static int dsa_slave_switchdev_event(str
+@@ -1647,7 +1637,9 @@ static int dsa_slave_switchdev_event(str
unsigned long event, void *ptr)
{
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
int err;
if (event == SWITCHDEV_PORT_ATTR_SET) {
-@@ -1657,20 +1649,32 @@ static int dsa_slave_switchdev_event(str
+@@ -1660,20 +1652,32 @@ static int dsa_slave_switchdev_event(str
if (!dsa_slave_dev_check(dev))
return NOTIFY_DONE;
dev_hold(dev);
break;
default:
-@@ -1680,10 +1684,6 @@ static int dsa_slave_switchdev_event(str
+@@ -1683,10 +1687,6 @@ static int dsa_slave_switchdev_event(str
dsa_schedule_work(&switchdev_work->work);
return NOTIFY_OK;
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -1639,31 +1639,29 @@ static int dsa_slave_switchdev_event(str
+@@ -1642,31 +1642,29 @@ static int dsa_slave_switchdev_event(str
struct dsa_port *dp;
int err;
fdb_info = ptr;
if (!fdb_info->added_by_user) {
-@@ -1676,13 +1674,12 @@ static int dsa_slave_switchdev_event(str
+@@ -1679,13 +1677,12 @@ static int dsa_slave_switchdev_event(str
switchdev_work->vid = fdb_info->vid;
dev_hold(dev);
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -1652,6 +1652,9 @@ static int dsa_slave_switchdev_event(str
+@@ -1655,6 +1655,9 @@ static int dsa_slave_switchdev_event(str
dp = dsa_slave_to_port(dev);
*/
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -1629,6 +1629,25 @@ static void dsa_slave_switchdev_event_wo
+@@ -1632,6 +1632,25 @@ static void dsa_slave_switchdev_event_wo
dev_put(dp->slave);
}
/* Called under rcu_read_lock() */
static int dsa_slave_switchdev_event(struct notifier_block *unused,
unsigned long event, void *ptr)
-@@ -1647,10 +1666,37 @@ static int dsa_slave_switchdev_event(str
+@@ -1650,10 +1669,37 @@ static int dsa_slave_switchdev_event(str
return notifier_from_errno(err);
case SWITCHDEV_FDB_ADD_TO_DEVICE:
case SWITCHDEV_FDB_DEL_TO_DEVICE:
if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del)
return NOTIFY_DONE;
-@@ -1665,18 +1711,13 @@ static int dsa_slave_switchdev_event(str
+@@ -1668,18 +1714,13 @@ static int dsa_slave_switchdev_event(str
switchdev_work->port = dp->index;
switchdev_work->event = event;
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -2191,10 +2191,12 @@ static int dsa_slave_switchdev_event(str
+@@ -2194,10 +2194,12 @@ static int dsa_slave_switchdev_event(str
fdb_info = ptr;
if (dsa_slave_dev_check(dev)) {
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -2205,7 +2205,11 @@ static int dsa_slave_switchdev_event(str
+@@ -2208,7 +2208,11 @@ static int dsa_slave_switchdev_event(str
struct net_device *br_dev;
struct dsa_slave_priv *p;
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -2198,9 +2198,12 @@ static int dsa_slave_switchdev_event(str
+@@ -2201,9 +2201,12 @@ static int dsa_slave_switchdev_event(str
else if (!fdb_info->added_by_user)
return NOTIFY_OK;
} else {
*/
struct net_device *br_dev;
struct dsa_slave_priv *p;
-@@ -2222,7 +2225,8 @@ static int dsa_slave_switchdev_event(str
+@@ -2225,7 +2228,8 @@ static int dsa_slave_switchdev_event(str
dp = p->dp->cpu_dp;
#define AT803X_PHY_ID_MASK 0xffffffef
+#define AT8032_PHY_ID_MASK 0xffffffff
- MODULE_DESCRIPTION("Atheros 803x PHY driver");
- MODULE_AUTHOR("Matus Ujhelyi");
-@@ -314,7 +316,7 @@ static int at803x_config_intr(struct phy
+ #define AT803X_PAGE_FIBER 0
+ #define AT803X_PAGE_COPPER 1
+@@ -357,7 +359,7 @@ static int at803x_config_intr(struct phy
static void at803x_link_change_notify(struct phy_device *phydev)
{
/*
* signalled. This is necessary to circumvent a hardware bug that
* occurs when the cable is unplugged while TX packets are pending
* in the FIFO. In such cases, the FIFO enters an error mode it
-@@ -471,6 +473,24 @@ static struct phy_driver at803x_driver[]
+@@ -516,6 +518,24 @@ static struct phy_driver at803x_driver[]
.aneg_done = at803x_aneg_done,
.ack_interrupt = &at803x_ack_interrupt,
.config_intr = &at803x_config_intr,
} };
module_phy_driver(at803x_driver);
-@@ -478,6 +498,7 @@ module_phy_driver(at803x_driver);
+@@ -523,6 +543,7 @@ module_phy_driver(at803x_driver);
static struct mdio_device_id __maybe_unused atheros_tbl[] = {
{ ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
{ ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
#include "dsa_priv.h"
-@@ -1223,6 +1227,27 @@ static struct devlink_port *dsa_slave_ge
+@@ -1226,6 +1230,27 @@ static struct devlink_port *dsa_slave_ge
return dp->ds->devlink ? &dp->devlink_port : NULL;
}
static const struct net_device_ops dsa_slave_netdev_ops = {
.ndo_open = dsa_slave_open,
.ndo_stop = dsa_slave_close,
-@@ -1247,6 +1272,9 @@ static const struct net_device_ops dsa_s
+@@ -1250,6 +1275,9 @@ static const struct net_device_ops dsa_s
.ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,
.ndo_get_devlink_port = dsa_slave_get_devlink_port,
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -1697,10 +1697,12 @@ static int dsa_slave_switchdev_event(str
+@@ -1700,10 +1700,12 @@ static int dsa_slave_switchdev_event(str
fdb_info = ptr;
if (dsa_slave_dev_check(dev)) {
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -1711,7 +1711,11 @@ static int dsa_slave_switchdev_event(str
+@@ -1714,7 +1714,11 @@ static int dsa_slave_switchdev_event(str
struct net_device *br_dev;
struct dsa_slave_priv *p;
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
-@@ -1704,9 +1704,12 @@ static int dsa_slave_switchdev_event(str
+@@ -1707,9 +1707,12 @@ static int dsa_slave_switchdev_event(str
else if (!fdb_info->added_by_user)
return NOTIFY_OK;
} else {
*/
struct net_device *br_dev;
struct dsa_slave_priv *p;
-@@ -1728,7 +1731,8 @@ static int dsa_slave_switchdev_event(str
+@@ -1731,7 +1734,8 @@ static int dsa_slave_switchdev_event(str
dp = p->dp->cpu_dp;