Commit 9e855b1f authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'fix-rtnl_mutex-deadlock-with-dpaa2-and-sfp-modules'

Vladimir Oltean says:

====================
Fix rtnl_mutex deadlock with DPAA2 and SFP modules

This patch set deliberately targets net-next and lacks Fixes: tags due
to caution on my part.

While testing some SFP modules on the Solidrun Honeycomb LX2K platform,
I noticed that rebooting causes a deadlock:

============================================
WARNING: possible recursive locking detected
6.1.0-rc5-07010-ga9b9500ffaac-dirty #656 Not tainted
--------------------------------------------
systemd-shutdow/1 is trying to acquire lock:
ffffa62db6cf42f0 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock+0x1c/0x30

but task is already holding lock:
ffffa62db6cf42f0 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock+0x1c/0x30

other info that might help us debug this:
 Possible unsafe locking scenario:

       CPU0
       ----
  lock(rtnl_mutex);
  lock(rtnl_mutex);

 *** DEADLOCK ***

 May be due to missing lock nesting notation

6 locks held by systemd-shutdow/1:
 #0: ffffa62db6863c70 (system_transition_mutex){+.+.}-{4:4}, at: __do_sys_reboot+0xd4/0x260
 #1: ffff2f2b0176f100 (&dev->mutex){....}-{4:4}, at: device_shutdown+0xf4/0x260
 #2: ffff2f2b017be900 (&dev->mutex){....}-{4:4}, at: device_shutdown+0x104/0x260
 #3: ffff2f2b017680f0 (&dev->mutex){....}-{4:4}, at: device_release_driver_internal+0x40/0x260
 #4: ffff2f2b0e1608f0 (&dev->mutex){....}-{4:4}, at: device_release_driver_internal+0x40/0x260
 #5: ffffa62db6cf42f0 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock+0x1c/0x30

stack backtrace:
CPU: 6 PID: 1 Comm: systemd-shutdow Not tainted 6.1.0-rc5-07010-ga9b9500ffaac-dirty #656
Hardware name: SolidRun LX2160A Honeycomb (DT)
Call trace:
 lock_acquire+0x68/0x84
 __mutex_lock+0x98/0x460
 mutex_lock_nested+0x2c/0x40
 rtnl_lock+0x1c/0x30
 sfp_bus_del_upstream+0x1c/0xac
 phylink_destroy+0x1c/0x50
 dpaa2_mac_disconnect+0x28/0x70
 dpaa2_eth_remove+0x1dc/0x1f0
 fsl_mc_driver_remove+0x24/0x60
 device_remove+0x70/0x80
 device_release_driver_internal+0x1f0/0x260
 device_links_unbind_consumers+0xe0/0x110
 device_release_driver_internal+0x138/0x260
 device_release_driver+0x18/0x24
 bus_remove_device+0x12c/0x13c
 device_del+0x16c/0x424
 fsl_mc_device_remove+0x28/0x40
 __fsl_mc_device_remove+0x10/0x20
 device_for_each_child+0x5c/0xac
 dprc_remove+0x94/0xb4
 fsl_mc_driver_remove+0x24/0x60
 device_remove+0x70/0x80
 device_release_driver_internal+0x1f0/0x260
 device_release_driver+0x18/0x24
 bus_remove_device+0x12c/0x13c
 device_del+0x16c/0x424
 fsl_mc_bus_remove+0x8c/0x10c
 fsl_mc_bus_shutdown+0x10/0x20
 platform_shutdown+0x24/0x3c
 device_shutdown+0x15c/0x260
 kernel_restart+0x40/0xa4
 __do_sys_reboot+0x1e4/0x260
 __arm64_sys_reboot+0x24/0x30

But fixing this appears to be not so simple. The patch set represents my
attempt to address it.

In short, the problem is that dpaa2_mac_connect() and dpaa2_mac_disconnect()
call 2 phylink functions in a row, one takes rtnl_lock() itself -
phylink_create(), and one which requires rtnl_lock() to be held by the
caller - phylink_fwnode_phy_connect(). The existing approach in the
drivers is too simple. We take rtnl_lock() when calling dpaa2_mac_connect(),
which is what results in the deadlock.

Fixing just that creates another problem. The drivers make use of
rtnl_lock() for serializing with other code paths too. I think I've
found all those code paths, and established other mechanisms for
serializing with them.
====================

Link: https://lore.kernel.org/r/20221129141221.872653-1-vladimir.oltean@nxp.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 682f560b 87db82cb
...@@ -181,10 +181,13 @@ when necessary using the below listed API:: ...@@ -181,10 +181,13 @@ when necessary using the below listed API::
- int dpaa2_mac_connect(struct dpaa2_mac *mac); - int dpaa2_mac_connect(struct dpaa2_mac *mac);
- void dpaa2_mac_disconnect(struct dpaa2_mac *mac); - void dpaa2_mac_disconnect(struct dpaa2_mac *mac);
A phylink integration is necessary only when the partner DPMAC is not of TYPE_FIXED. A phylink integration is necessary only when the partner DPMAC is not of
One can check for this condition using the below API:: ``TYPE_FIXED``. This means it is either of ``TYPE_PHY``, or of
``TYPE_BACKPLANE`` (the difference being the two that in the ``TYPE_BACKPLANE``
mode, the MC firmware does not access the PCS registers). One can check for
this condition using the following helper::
- bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,struct fsl_mc_io *mc_io); - static inline bool dpaa2_mac_is_type_phy(struct dpaa2_mac *mac);
Before connection to a MAC, the caller must allocate and populate the Before connection to a MAC, the caller must allocate and populate the
dpaa2_mac structure with the associated net_device, a pointer to the MC portal dpaa2_mac structure with the associated net_device, a pointer to the MC portal
......
...@@ -2147,8 +2147,11 @@ static int dpaa2_eth_link_state_update(struct dpaa2_eth_priv *priv) ...@@ -2147,8 +2147,11 @@ static int dpaa2_eth_link_state_update(struct dpaa2_eth_priv *priv)
/* When we manage the MAC/PHY using phylink there is no need /* When we manage the MAC/PHY using phylink there is no need
* to manually update the netif_carrier. * to manually update the netif_carrier.
* We can avoid locking because we are called from the "link changed"
* IRQ handler, which is the same as the "endpoint changed" IRQ handler
* (the writer to priv->mac), so we cannot race with it.
*/ */
if (dpaa2_eth_is_type_phy(priv)) if (dpaa2_mac_is_type_phy(priv->mac))
goto out; goto out;
/* Chech link state; speed / duplex changes are not treated yet */ /* Chech link state; speed / duplex changes are not treated yet */
...@@ -2179,6 +2182,8 @@ static int dpaa2_eth_open(struct net_device *net_dev) ...@@ -2179,6 +2182,8 @@ static int dpaa2_eth_open(struct net_device *net_dev)
dpaa2_eth_seed_pools(priv); dpaa2_eth_seed_pools(priv);
mutex_lock(&priv->mac_lock);
if (!dpaa2_eth_is_type_phy(priv)) { if (!dpaa2_eth_is_type_phy(priv)) {
/* We'll only start the txqs when the link is actually ready; /* We'll only start the txqs when the link is actually ready;
* make sure we don't race against the link up notification, * make sure we don't race against the link up notification,
...@@ -2197,14 +2202,15 @@ static int dpaa2_eth_open(struct net_device *net_dev) ...@@ -2197,14 +2202,15 @@ static int dpaa2_eth_open(struct net_device *net_dev)
err = dpni_enable(priv->mc_io, 0, priv->mc_token); err = dpni_enable(priv->mc_io, 0, priv->mc_token);
if (err < 0) { if (err < 0) {
mutex_unlock(&priv->mac_lock);
netdev_err(net_dev, "dpni_enable() failed\n"); netdev_err(net_dev, "dpni_enable() failed\n");
goto enable_err; goto enable_err;
} }
if (dpaa2_eth_is_type_phy(priv)) { if (dpaa2_eth_is_type_phy(priv))
dpaa2_mac_start(priv->mac); dpaa2_mac_start(priv->mac);
phylink_start(priv->mac->phylink);
} mutex_unlock(&priv->mac_lock);
return 0; return 0;
...@@ -2277,14 +2283,17 @@ static int dpaa2_eth_stop(struct net_device *net_dev) ...@@ -2277,14 +2283,17 @@ static int dpaa2_eth_stop(struct net_device *net_dev)
int dpni_enabled = 0; int dpni_enabled = 0;
int retries = 10; int retries = 10;
mutex_lock(&priv->mac_lock);
if (dpaa2_eth_is_type_phy(priv)) { if (dpaa2_eth_is_type_phy(priv)) {
phylink_stop(priv->mac->phylink);
dpaa2_mac_stop(priv->mac); dpaa2_mac_stop(priv->mac);
} else { } else {
netif_tx_stop_all_queues(net_dev); netif_tx_stop_all_queues(net_dev);
netif_carrier_off(net_dev); netif_carrier_off(net_dev);
} }
mutex_unlock(&priv->mac_lock);
/* On dpni_disable(), the MC firmware will: /* On dpni_disable(), the MC firmware will:
* - stop MAC Rx and wait for all Rx frames to be enqueued to software * - stop MAC Rx and wait for all Rx frames to be enqueued to software
* - cut off WRIOP dequeues from egress FQs and wait until transmission * - cut off WRIOP dequeues from egress FQs and wait until transmission
...@@ -2610,12 +2619,20 @@ static int dpaa2_eth_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -2610,12 +2619,20 @@ static int dpaa2_eth_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int dpaa2_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int dpaa2_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{ {
struct dpaa2_eth_priv *priv = netdev_priv(dev); struct dpaa2_eth_priv *priv = netdev_priv(dev);
int err;
if (cmd == SIOCSHWTSTAMP) if (cmd == SIOCSHWTSTAMP)
return dpaa2_eth_ts_ioctl(dev, rq, cmd); return dpaa2_eth_ts_ioctl(dev, rq, cmd);
if (dpaa2_eth_is_type_phy(priv)) mutex_lock(&priv->mac_lock);
return phylink_mii_ioctl(priv->mac->phylink, rq, cmd);
if (dpaa2_eth_is_type_phy(priv)) {
err = phylink_mii_ioctl(priv->mac->phylink, rq, cmd);
mutex_unlock(&priv->mac_lock);
return err;
}
mutex_unlock(&priv->mac_lock);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -3791,7 +3808,7 @@ static int dpaa2_eth_setup_dpni(struct fsl_mc_device *ls_dev) ...@@ -3791,7 +3808,7 @@ static int dpaa2_eth_setup_dpni(struct fsl_mc_device *ls_dev)
dev_err(dev, "DPNI version %u.%u not supported, need >= %u.%u\n", dev_err(dev, "DPNI version %u.%u not supported, need >= %u.%u\n",
priv->dpni_ver_major, priv->dpni_ver_minor, priv->dpni_ver_major, priv->dpni_ver_minor,
DPNI_VER_MAJOR, DPNI_VER_MINOR); DPNI_VER_MAJOR, DPNI_VER_MINOR);
err = -ENOTSUPP; err = -EOPNOTSUPP;
goto close; goto close;
} }
...@@ -4627,9 +4644,8 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv) ...@@ -4627,9 +4644,8 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv)
err = dpaa2_mac_open(mac); err = dpaa2_mac_open(mac);
if (err) if (err)
goto err_free_mac; goto err_free_mac;
priv->mac = mac;
if (dpaa2_eth_is_type_phy(priv)) { if (dpaa2_mac_is_type_phy(mac)) {
err = dpaa2_mac_connect(mac); err = dpaa2_mac_connect(mac);
if (err) { if (err) {
if (err == -EPROBE_DEFER) if (err == -EPROBE_DEFER)
...@@ -4643,11 +4659,14 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv) ...@@ -4643,11 +4659,14 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv)
} }
} }
mutex_lock(&priv->mac_lock);
priv->mac = mac;
mutex_unlock(&priv->mac_lock);
return 0; return 0;
err_close_mac: err_close_mac:
dpaa2_mac_close(mac); dpaa2_mac_close(mac);
priv->mac = NULL;
err_free_mac: err_free_mac:
kfree(mac); kfree(mac);
return err; return err;
...@@ -4655,15 +4674,21 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv) ...@@ -4655,15 +4674,21 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv)
static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv) static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv)
{ {
if (dpaa2_eth_is_type_phy(priv)) struct dpaa2_mac *mac;
dpaa2_mac_disconnect(priv->mac);
if (!dpaa2_eth_has_mac(priv)) mutex_lock(&priv->mac_lock);
mac = priv->mac;
priv->mac = NULL;
mutex_unlock(&priv->mac_lock);
if (!mac)
return; return;
dpaa2_mac_close(priv->mac); if (dpaa2_mac_is_type_phy(mac))
kfree(priv->mac); dpaa2_mac_disconnect(mac);
priv->mac = NULL;
dpaa2_mac_close(mac);
kfree(mac);
} }
static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg)
...@@ -4673,6 +4698,7 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) ...@@ -4673,6 +4698,7 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg)
struct fsl_mc_device *dpni_dev = to_fsl_mc_device(dev); struct fsl_mc_device *dpni_dev = to_fsl_mc_device(dev);
struct net_device *net_dev = dev_get_drvdata(dev); struct net_device *net_dev = dev_get_drvdata(dev);
struct dpaa2_eth_priv *priv = netdev_priv(net_dev); struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
bool had_mac;
int err; int err;
err = dpni_get_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle, err = dpni_get_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle,
...@@ -4689,12 +4715,15 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) ...@@ -4689,12 +4715,15 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg)
dpaa2_eth_set_mac_addr(netdev_priv(net_dev)); dpaa2_eth_set_mac_addr(netdev_priv(net_dev));
dpaa2_eth_update_tx_fqids(priv); dpaa2_eth_update_tx_fqids(priv);
rtnl_lock(); /* We can avoid locking because the "endpoint changed" IRQ
if (dpaa2_eth_has_mac(priv)) * handler is the only one who changes priv->mac at runtime,
* so we are not racing with anyone.
*/
had_mac = !!priv->mac;
if (had_mac)
dpaa2_eth_disconnect_mac(priv); dpaa2_eth_disconnect_mac(priv);
else else
dpaa2_eth_connect_mac(priv); dpaa2_eth_connect_mac(priv);
rtnl_unlock();
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -4792,6 +4821,8 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) ...@@ -4792,6 +4821,8 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
priv->net_dev = net_dev; priv->net_dev = net_dev;
SET_NETDEV_DEVLINK_PORT(net_dev, &priv->devlink_port); SET_NETDEV_DEVLINK_PORT(net_dev, &priv->devlink_port);
mutex_init(&priv->mac_lock);
priv->iommu_domain = iommu_get_domain_for_dev(dev); priv->iommu_domain = iommu_get_domain_for_dev(dev);
priv->tx_tstamp_type = HWTSTAMP_TX_OFF; priv->tx_tstamp_type = HWTSTAMP_TX_OFF;
...@@ -4899,6 +4930,10 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) ...@@ -4899,6 +4930,10 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
} }
#endif #endif
err = dpaa2_eth_connect_mac(priv);
if (err)
goto err_connect_mac;
err = dpaa2_eth_setup_irqs(dpni_dev); err = dpaa2_eth_setup_irqs(dpni_dev);
if (err) { if (err) {
netdev_warn(net_dev, "Failed to set link interrupt, fall back to polling\n"); netdev_warn(net_dev, "Failed to set link interrupt, fall back to polling\n");
...@@ -4911,10 +4946,6 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) ...@@ -4911,10 +4946,6 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
priv->do_link_poll = true; priv->do_link_poll = true;
} }
err = dpaa2_eth_connect_mac(priv);
if (err)
goto err_connect_mac;
err = dpaa2_eth_dl_alloc(priv); err = dpaa2_eth_dl_alloc(priv);
if (err) if (err)
goto err_dl_register; goto err_dl_register;
...@@ -4948,13 +4979,13 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) ...@@ -4948,13 +4979,13 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
err_dl_trap_register: err_dl_trap_register:
dpaa2_eth_dl_free(priv); dpaa2_eth_dl_free(priv);
err_dl_register: err_dl_register:
dpaa2_eth_disconnect_mac(priv);
err_connect_mac:
if (priv->do_link_poll) if (priv->do_link_poll)
kthread_stop(priv->poll_thread); kthread_stop(priv->poll_thread);
else else
fsl_mc_free_irqs(dpni_dev); fsl_mc_free_irqs(dpni_dev);
err_poll_thread: err_poll_thread:
dpaa2_eth_disconnect_mac(priv);
err_connect_mac:
dpaa2_eth_free_rings(priv); dpaa2_eth_free_rings(priv);
err_alloc_rings: err_alloc_rings:
err_csum: err_csum:
...@@ -5002,9 +5033,6 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) ...@@ -5002,9 +5033,6 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
#endif #endif
unregister_netdev(net_dev); unregister_netdev(net_dev);
rtnl_lock();
dpaa2_eth_disconnect_mac(priv);
rtnl_unlock();
dpaa2_eth_dl_port_del(priv); dpaa2_eth_dl_port_del(priv);
dpaa2_eth_dl_traps_unregister(priv); dpaa2_eth_dl_traps_unregister(priv);
...@@ -5015,6 +5043,7 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) ...@@ -5015,6 +5043,7 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
else else
fsl_mc_free_irqs(ls_dev); fsl_mc_free_irqs(ls_dev);
dpaa2_eth_disconnect_mac(priv);
dpaa2_eth_free_rings(priv); dpaa2_eth_free_rings(priv);
free_percpu(priv->fd); free_percpu(priv->fd);
free_percpu(priv->sgt_cache); free_percpu(priv->sgt_cache);
......
...@@ -615,6 +615,8 @@ struct dpaa2_eth_priv { ...@@ -615,6 +615,8 @@ struct dpaa2_eth_priv {
#endif #endif
struct dpaa2_mac *mac; struct dpaa2_mac *mac;
/* Serializes changes to priv->mac */
struct mutex mac_lock;
struct workqueue_struct *dpaa2_ptp_wq; struct workqueue_struct *dpaa2_ptp_wq;
struct work_struct tx_onestep_tstamp; struct work_struct tx_onestep_tstamp;
struct sk_buff_head tx_skbs; struct sk_buff_head tx_skbs;
...@@ -768,16 +770,15 @@ static inline unsigned int dpaa2_eth_rx_head_room(struct dpaa2_eth_priv *priv) ...@@ -768,16 +770,15 @@ static inline unsigned int dpaa2_eth_rx_head_room(struct dpaa2_eth_priv *priv)
static inline bool dpaa2_eth_is_type_phy(struct dpaa2_eth_priv *priv) static inline bool dpaa2_eth_is_type_phy(struct dpaa2_eth_priv *priv)
{ {
if (priv->mac && lockdep_assert_held(&priv->mac_lock);
(priv->mac->attr.link_type == DPMAC_LINK_TYPE_PHY ||
priv->mac->attr.link_type == DPMAC_LINK_TYPE_BACKPLANE))
return true;
return false; return dpaa2_mac_is_type_phy(priv->mac);
} }
static inline bool dpaa2_eth_has_mac(struct dpaa2_eth_priv *priv) static inline bool dpaa2_eth_has_mac(struct dpaa2_eth_priv *priv)
{ {
lockdep_assert_held(&priv->mac_lock);
return priv->mac ? true : false; return priv->mac ? true : false;
} }
......
...@@ -85,11 +85,16 @@ static void dpaa2_eth_get_drvinfo(struct net_device *net_dev, ...@@ -85,11 +85,16 @@ static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
static int dpaa2_eth_nway_reset(struct net_device *net_dev) static int dpaa2_eth_nway_reset(struct net_device *net_dev)
{ {
struct dpaa2_eth_priv *priv = netdev_priv(net_dev); struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
int err = -EOPNOTSUPP;
mutex_lock(&priv->mac_lock);
if (dpaa2_eth_is_type_phy(priv)) if (dpaa2_eth_is_type_phy(priv))
return phylink_ethtool_nway_reset(priv->mac->phylink); err = phylink_ethtool_nway_reset(priv->mac->phylink);
mutex_unlock(&priv->mac_lock);
return -EOPNOTSUPP; return err;
} }
static int static int
...@@ -97,10 +102,18 @@ dpaa2_eth_get_link_ksettings(struct net_device *net_dev, ...@@ -97,10 +102,18 @@ dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
struct ethtool_link_ksettings *link_settings) struct ethtool_link_ksettings *link_settings)
{ {
struct dpaa2_eth_priv *priv = netdev_priv(net_dev); struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
int err;
if (dpaa2_eth_is_type_phy(priv)) mutex_lock(&priv->mac_lock);
return phylink_ethtool_ksettings_get(priv->mac->phylink,
link_settings); if (dpaa2_eth_is_type_phy(priv)) {
err = phylink_ethtool_ksettings_get(priv->mac->phylink,
link_settings);
mutex_unlock(&priv->mac_lock);
return err;
}
mutex_unlock(&priv->mac_lock);
link_settings->base.autoneg = AUTONEG_DISABLE; link_settings->base.autoneg = AUTONEG_DISABLE;
if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX)) if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX))
...@@ -115,11 +128,17 @@ dpaa2_eth_set_link_ksettings(struct net_device *net_dev, ...@@ -115,11 +128,17 @@ dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
const struct ethtool_link_ksettings *link_settings) const struct ethtool_link_ksettings *link_settings)
{ {
struct dpaa2_eth_priv *priv = netdev_priv(net_dev); struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
int err = -EOPNOTSUPP;
if (!dpaa2_eth_is_type_phy(priv)) mutex_lock(&priv->mac_lock);
return -ENOTSUPP;
return phylink_ethtool_ksettings_set(priv->mac->phylink, link_settings); if (dpaa2_eth_is_type_phy(priv))
err = phylink_ethtool_ksettings_set(priv->mac->phylink,
link_settings);
mutex_unlock(&priv->mac_lock);
return err;
} }
static void dpaa2_eth_get_pauseparam(struct net_device *net_dev, static void dpaa2_eth_get_pauseparam(struct net_device *net_dev,
...@@ -128,11 +147,16 @@ static void dpaa2_eth_get_pauseparam(struct net_device *net_dev, ...@@ -128,11 +147,16 @@ static void dpaa2_eth_get_pauseparam(struct net_device *net_dev,
struct dpaa2_eth_priv *priv = netdev_priv(net_dev); struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
u64 link_options = priv->link_state.options; u64 link_options = priv->link_state.options;
mutex_lock(&priv->mac_lock);
if (dpaa2_eth_is_type_phy(priv)) { if (dpaa2_eth_is_type_phy(priv)) {
phylink_ethtool_get_pauseparam(priv->mac->phylink, pause); phylink_ethtool_get_pauseparam(priv->mac->phylink, pause);
mutex_unlock(&priv->mac_lock);
return; return;
} }
mutex_unlock(&priv->mac_lock);
pause->rx_pause = dpaa2_eth_rx_pause_enabled(link_options); pause->rx_pause = dpaa2_eth_rx_pause_enabled(link_options);
pause->tx_pause = dpaa2_eth_tx_pause_enabled(link_options); pause->tx_pause = dpaa2_eth_tx_pause_enabled(link_options);
pause->autoneg = AUTONEG_DISABLE; pause->autoneg = AUTONEG_DISABLE;
...@@ -151,9 +175,17 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev, ...@@ -151,9 +175,17 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (dpaa2_eth_is_type_phy(priv)) mutex_lock(&priv->mac_lock);
return phylink_ethtool_set_pauseparam(priv->mac->phylink,
pause); if (dpaa2_eth_is_type_phy(priv)) {
err = phylink_ethtool_set_pauseparam(priv->mac->phylink,
pause);
mutex_unlock(&priv->mac_lock);
return err;
}
mutex_unlock(&priv->mac_lock);
if (pause->autoneg) if (pause->autoneg)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -185,7 +217,6 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev, ...@@ -185,7 +217,6 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev,
static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset, static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset,
u8 *data) u8 *data)
{ {
struct dpaa2_eth_priv *priv = netdev_priv(netdev);
u8 *p = data; u8 *p = data;
int i; int i;
...@@ -199,22 +230,17 @@ static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset, ...@@ -199,22 +230,17 @@ static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset,
strscpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN); strscpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
if (dpaa2_eth_has_mac(priv)) dpaa2_mac_get_strings(p);
dpaa2_mac_get_strings(p);
break; break;
} }
} }
static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset) static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset)
{ {
int num_ss_stats = DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS;
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
switch (sset) { switch (sset) {
case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */ case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */
if (dpaa2_eth_has_mac(priv)) return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS +
num_ss_stats += dpaa2_mac_get_sset_count(); dpaa2_mac_get_sset_count();
return num_ss_stats;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -315,8 +341,12 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, ...@@ -315,8 +341,12 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
} }
*(data + i++) = buf_cnt_total; *(data + i++) = buf_cnt_total;
mutex_lock(&priv->mac_lock);
if (dpaa2_eth_has_mac(priv)) if (dpaa2_eth_has_mac(priv))
dpaa2_mac_get_ethtool_stats(priv->mac, data + i); dpaa2_mac_get_ethtool_stats(priv->mac, data + i);
mutex_unlock(&priv->mac_lock);
} }
static int dpaa2_eth_prep_eth_rule(struct ethhdr *eth_value, struct ethhdr *eth_mask, static int dpaa2_eth_prep_eth_rule(struct ethhdr *eth_value, struct ethhdr *eth_mask,
......
...@@ -338,12 +338,20 @@ static void dpaa2_mac_set_supported_interfaces(struct dpaa2_mac *mac) ...@@ -338,12 +338,20 @@ static void dpaa2_mac_set_supported_interfaces(struct dpaa2_mac *mac)
void dpaa2_mac_start(struct dpaa2_mac *mac) void dpaa2_mac_start(struct dpaa2_mac *mac)
{ {
ASSERT_RTNL();
if (mac->serdes_phy) if (mac->serdes_phy)
phy_power_on(mac->serdes_phy); phy_power_on(mac->serdes_phy);
phylink_start(mac->phylink);
} }
void dpaa2_mac_stop(struct dpaa2_mac *mac) void dpaa2_mac_stop(struct dpaa2_mac *mac)
{ {
ASSERT_RTNL();
phylink_stop(mac->phylink);
if (mac->serdes_phy) if (mac->serdes_phy)
phy_power_off(mac->serdes_phy); phy_power_off(mac->serdes_phy);
} }
...@@ -422,7 +430,9 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac) ...@@ -422,7 +430,9 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
} }
mac->phylink = phylink; mac->phylink = phylink;
rtnl_lock();
err = phylink_fwnode_phy_connect(mac->phylink, dpmac_node, 0); err = phylink_fwnode_phy_connect(mac->phylink, dpmac_node, 0);
rtnl_unlock();
if (err) { if (err) {
netdev_err(net_dev, "phylink_fwnode_phy_connect() = %d\n", err); netdev_err(net_dev, "phylink_fwnode_phy_connect() = %d\n", err);
goto err_phylink_destroy; goto err_phylink_destroy;
...@@ -440,10 +450,10 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac) ...@@ -440,10 +450,10 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
void dpaa2_mac_disconnect(struct dpaa2_mac *mac) void dpaa2_mac_disconnect(struct dpaa2_mac *mac)
{ {
if (!mac->phylink) rtnl_lock();
return;
phylink_disconnect_phy(mac->phylink); phylink_disconnect_phy(mac->phylink);
rtnl_unlock();
phylink_destroy(mac->phylink); phylink_destroy(mac->phylink);
dpaa2_pcs_destroy(mac); dpaa2_pcs_destroy(mac);
of_phy_put(mac->serdes_phy); of_phy_put(mac->serdes_phy);
......
...@@ -30,8 +30,14 @@ struct dpaa2_mac { ...@@ -30,8 +30,14 @@ struct dpaa2_mac {
struct phy *serdes_phy; struct phy *serdes_phy;
}; };
bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev, static inline bool dpaa2_mac_is_type_phy(struct dpaa2_mac *mac)
struct fsl_mc_io *mc_io); {
if (!mac)
return false;
return mac->attr.link_type == DPMAC_LINK_TYPE_PHY ||
mac->attr.link_type == DPMAC_LINK_TYPE_BACKPLANE;
}
int dpaa2_mac_open(struct dpaa2_mac *mac); int dpaa2_mac_open(struct dpaa2_mac *mac);
......
...@@ -60,11 +60,18 @@ dpaa2_switch_get_link_ksettings(struct net_device *netdev, ...@@ -60,11 +60,18 @@ dpaa2_switch_get_link_ksettings(struct net_device *netdev,
{ {
struct ethsw_port_priv *port_priv = netdev_priv(netdev); struct ethsw_port_priv *port_priv = netdev_priv(netdev);
struct dpsw_link_state state = {0}; struct dpsw_link_state state = {0};
int err = 0; int err;
mutex_lock(&port_priv->mac_lock);
if (dpaa2_switch_port_is_type_phy(port_priv)) {
err = phylink_ethtool_ksettings_get(port_priv->mac->phylink,
link_ksettings);
mutex_unlock(&port_priv->mac_lock);
return err;
}
if (dpaa2_switch_port_is_type_phy(port_priv)) mutex_unlock(&port_priv->mac_lock);
return phylink_ethtool_ksettings_get(port_priv->mac->phylink,
link_ksettings);
err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0, err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
port_priv->ethsw_data->dpsw_handle, port_priv->ethsw_data->dpsw_handle,
...@@ -99,9 +106,16 @@ dpaa2_switch_set_link_ksettings(struct net_device *netdev, ...@@ -99,9 +106,16 @@ dpaa2_switch_set_link_ksettings(struct net_device *netdev,
bool if_running; bool if_running;
int err = 0, ret; int err = 0, ret;
if (dpaa2_switch_port_is_type_phy(port_priv)) mutex_lock(&port_priv->mac_lock);
return phylink_ethtool_ksettings_set(port_priv->mac->phylink,
link_ksettings); if (dpaa2_switch_port_is_type_phy(port_priv)) {
err = phylink_ethtool_ksettings_set(port_priv->mac->phylink,
link_ksettings);
mutex_unlock(&port_priv->mac_lock);
return err;
}
mutex_unlock(&port_priv->mac_lock);
/* Interface needs to be down to change link settings */ /* Interface needs to be down to change link settings */
if_running = netif_running(netdev); if_running = netif_running(netdev);
...@@ -145,14 +159,9 @@ dpaa2_switch_set_link_ksettings(struct net_device *netdev, ...@@ -145,14 +159,9 @@ dpaa2_switch_set_link_ksettings(struct net_device *netdev,
static int static int
dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset) dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset)
{ {
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
int num_ss_stats = DPAA2_SWITCH_NUM_COUNTERS;
switch (sset) { switch (sset) {
case ETH_SS_STATS: case ETH_SS_STATS:
if (port_priv->mac) return DPAA2_SWITCH_NUM_COUNTERS + dpaa2_mac_get_sset_count();
num_ss_stats += dpaa2_mac_get_sset_count();
return num_ss_stats;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -161,7 +170,6 @@ dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset) ...@@ -161,7 +170,6 @@ dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset)
static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev, static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev,
u32 stringset, u8 *data) u32 stringset, u8 *data)
{ {
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
u8 *p = data; u8 *p = data;
int i; int i;
...@@ -172,8 +180,7 @@ static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev, ...@@ -172,8 +180,7 @@ static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
if (port_priv->mac) dpaa2_mac_get_strings(p);
dpaa2_mac_get_strings(p);
break; break;
} }
} }
...@@ -196,8 +203,12 @@ static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev, ...@@ -196,8 +203,12 @@ static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev,
dpaa2_switch_ethtool_counters[i].name, err); dpaa2_switch_ethtool_counters[i].name, err);
} }
if (port_priv->mac) mutex_lock(&port_priv->mac_lock);
if (dpaa2_switch_port_has_mac(port_priv))
dpaa2_mac_get_ethtool_stats(port_priv->mac, data + i); dpaa2_mac_get_ethtool_stats(port_priv->mac, data + i);
mutex_unlock(&port_priv->mac_lock);
} }
const struct ethtool_ops dpaa2_switch_port_ethtool_ops = { const struct ethtool_ops dpaa2_switch_port_ethtool_ops = {
......
...@@ -602,8 +602,11 @@ static int dpaa2_switch_port_link_state_update(struct net_device *netdev) ...@@ -602,8 +602,11 @@ static int dpaa2_switch_port_link_state_update(struct net_device *netdev)
/* When we manage the MAC/PHY using phylink there is no need /* When we manage the MAC/PHY using phylink there is no need
* to manually update the netif_carrier. * to manually update the netif_carrier.
* We can avoid locking because we are called from the "link changed"
* IRQ handler, which is the same as the "endpoint changed" IRQ handler
* (the writer to port_priv->mac), so we cannot race with it.
*/ */
if (dpaa2_switch_port_is_type_phy(port_priv)) if (dpaa2_mac_is_type_phy(port_priv->mac))
return 0; return 0;
/* Interrupts are received even though no one issued an 'ifconfig up' /* Interrupts are received even though no one issued an 'ifconfig up'
...@@ -683,6 +686,8 @@ static int dpaa2_switch_port_open(struct net_device *netdev) ...@@ -683,6 +686,8 @@ static int dpaa2_switch_port_open(struct net_device *netdev)
struct ethsw_core *ethsw = port_priv->ethsw_data; struct ethsw_core *ethsw = port_priv->ethsw_data;
int err; int err;
mutex_lock(&port_priv->mac_lock);
if (!dpaa2_switch_port_is_type_phy(port_priv)) { if (!dpaa2_switch_port_is_type_phy(port_priv)) {
/* Explicitly set carrier off, otherwise /* Explicitly set carrier off, otherwise
* netif_carrier_ok() will return true and cause 'ip link show' * netif_carrier_ok() will return true and cause 'ip link show'
...@@ -696,16 +701,17 @@ static int dpaa2_switch_port_open(struct net_device *netdev) ...@@ -696,16 +701,17 @@ static int dpaa2_switch_port_open(struct net_device *netdev)
port_priv->ethsw_data->dpsw_handle, port_priv->ethsw_data->dpsw_handle,
port_priv->idx); port_priv->idx);
if (err) { if (err) {
mutex_unlock(&port_priv->mac_lock);
netdev_err(netdev, "dpsw_if_enable err %d\n", err); netdev_err(netdev, "dpsw_if_enable err %d\n", err);
return err; return err;
} }
dpaa2_switch_enable_ctrl_if_napi(ethsw); dpaa2_switch_enable_ctrl_if_napi(ethsw);
if (dpaa2_switch_port_is_type_phy(port_priv)) { if (dpaa2_switch_port_is_type_phy(port_priv))
dpaa2_mac_start(port_priv->mac); dpaa2_mac_start(port_priv->mac);
phylink_start(port_priv->mac->phylink);
} mutex_unlock(&port_priv->mac_lock);
return 0; return 0;
} }
...@@ -716,14 +722,17 @@ static int dpaa2_switch_port_stop(struct net_device *netdev) ...@@ -716,14 +722,17 @@ static int dpaa2_switch_port_stop(struct net_device *netdev)
struct ethsw_core *ethsw = port_priv->ethsw_data; struct ethsw_core *ethsw = port_priv->ethsw_data;
int err; int err;
mutex_lock(&port_priv->mac_lock);
if (dpaa2_switch_port_is_type_phy(port_priv)) { if (dpaa2_switch_port_is_type_phy(port_priv)) {
phylink_stop(port_priv->mac->phylink);
dpaa2_mac_stop(port_priv->mac); dpaa2_mac_stop(port_priv->mac);
} else { } else {
netif_tx_stop_all_queues(netdev); netif_tx_stop_all_queues(netdev);
netif_carrier_off(netdev); netif_carrier_off(netdev);
} }
mutex_unlock(&port_priv->mac_lock);
err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0,
port_priv->ethsw_data->dpsw_handle, port_priv->ethsw_data->dpsw_handle,
port_priv->idx); port_priv->idx);
...@@ -1452,9 +1461,8 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv) ...@@ -1452,9 +1461,8 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv)
err = dpaa2_mac_open(mac); err = dpaa2_mac_open(mac);
if (err) if (err)
goto err_free_mac; goto err_free_mac;
port_priv->mac = mac;
if (dpaa2_switch_port_is_type_phy(port_priv)) { if (dpaa2_mac_is_type_phy(mac)) {
err = dpaa2_mac_connect(mac); err = dpaa2_mac_connect(mac);
if (err) { if (err) {
netdev_err(port_priv->netdev, netdev_err(port_priv->netdev,
...@@ -1464,11 +1472,14 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv) ...@@ -1464,11 +1472,14 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv)
} }
} }
mutex_lock(&port_priv->mac_lock);
port_priv->mac = mac;
mutex_unlock(&port_priv->mac_lock);
return 0; return 0;
err_close_mac: err_close_mac:
dpaa2_mac_close(mac); dpaa2_mac_close(mac);
port_priv->mac = NULL;
err_free_mac: err_free_mac:
kfree(mac); kfree(mac);
return err; return err;
...@@ -1476,15 +1487,21 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv) ...@@ -1476,15 +1487,21 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv)
static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv) static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv)
{ {
if (dpaa2_switch_port_is_type_phy(port_priv)) struct dpaa2_mac *mac;
dpaa2_mac_disconnect(port_priv->mac);
mutex_lock(&port_priv->mac_lock);
mac = port_priv->mac;
port_priv->mac = NULL;
mutex_unlock(&port_priv->mac_lock);
if (!dpaa2_switch_port_has_mac(port_priv)) if (!mac)
return; return;
dpaa2_mac_close(port_priv->mac); if (dpaa2_mac_is_type_phy(mac))
kfree(port_priv->mac); dpaa2_mac_disconnect(mac);
port_priv->mac = NULL;
dpaa2_mac_close(mac);
kfree(mac);
} }
static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg) static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
...@@ -1494,6 +1511,7 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg) ...@@ -1494,6 +1511,7 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
struct ethsw_port_priv *port_priv; struct ethsw_port_priv *port_priv;
u32 status = ~0; u32 status = ~0;
int err, if_id; int err, if_id;
bool had_mac;
err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, &status); DPSW_IRQ_INDEX_IF, &status);
...@@ -1511,12 +1529,15 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg) ...@@ -1511,12 +1529,15 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
} }
if (status & DPSW_IRQ_EVENT_ENDPOINT_CHANGED) { if (status & DPSW_IRQ_EVENT_ENDPOINT_CHANGED) {
rtnl_lock(); /* We can avoid locking because the "endpoint changed" IRQ
if (dpaa2_switch_port_has_mac(port_priv)) * handler is the only one who changes priv->mac at runtime,
* so we are not racing with anyone.
*/
had_mac = !!port_priv->mac;
if (had_mac)
dpaa2_switch_port_disconnect_mac(port_priv); dpaa2_switch_port_disconnect_mac(port_priv);
else else
dpaa2_switch_port_connect_mac(port_priv); dpaa2_switch_port_connect_mac(port_priv);
rtnl_unlock();
} }
out: out:
...@@ -2934,9 +2955,7 @@ static void dpaa2_switch_remove_port(struct ethsw_core *ethsw, ...@@ -2934,9 +2955,7 @@ static void dpaa2_switch_remove_port(struct ethsw_core *ethsw,
{ {
struct ethsw_port_priv *port_priv = ethsw->ports[port_idx]; struct ethsw_port_priv *port_priv = ethsw->ports[port_idx];
rtnl_lock();
dpaa2_switch_port_disconnect_mac(port_priv); dpaa2_switch_port_disconnect_mac(port_priv);
rtnl_unlock();
free_netdev(port_priv->netdev); free_netdev(port_priv->netdev);
ethsw->ports[port_idx] = NULL; ethsw->ports[port_idx] = NULL;
} }
...@@ -3255,6 +3274,8 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw, ...@@ -3255,6 +3274,8 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
port_priv->netdev = port_netdev; port_priv->netdev = port_netdev;
port_priv->ethsw_data = ethsw; port_priv->ethsw_data = ethsw;
mutex_init(&port_priv->mac_lock);
port_priv->idx = port_idx; port_priv->idx = port_idx;
port_priv->stp_state = BR_STATE_FORWARDING; port_priv->stp_state = BR_STATE_FORWARDING;
......
...@@ -161,6 +161,8 @@ struct ethsw_port_priv { ...@@ -161,6 +161,8 @@ struct ethsw_port_priv {
struct dpaa2_switch_filter_block *filter_block; struct dpaa2_switch_filter_block *filter_block;
struct dpaa2_mac *mac; struct dpaa2_mac *mac;
/* Protects against changes to port_priv->mac */
struct mutex mac_lock;
}; };
/* Switch data */ /* Switch data */
...@@ -230,12 +232,7 @@ static inline bool dpaa2_switch_supports_cpu_traffic(struct ethsw_core *ethsw) ...@@ -230,12 +232,7 @@ static inline bool dpaa2_switch_supports_cpu_traffic(struct ethsw_core *ethsw)
static inline bool static inline bool
dpaa2_switch_port_is_type_phy(struct ethsw_port_priv *port_priv) dpaa2_switch_port_is_type_phy(struct ethsw_port_priv *port_priv)
{ {
if (port_priv->mac && return dpaa2_mac_is_type_phy(port_priv->mac);
(port_priv->mac->attr.link_type == DPMAC_LINK_TYPE_PHY ||
port_priv->mac->attr.link_type == DPMAC_LINK_TYPE_BACKPLANE))
return true;
return false;
} }
static inline bool dpaa2_switch_port_has_mac(struct ethsw_port_priv *port_priv) static inline bool dpaa2_switch_port_has_mac(struct ethsw_port_priv *port_priv)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment