Commit 3c7f44fa authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Paolo Abeni

net: dpaa2-switch: serialize changes to priv->mac with a mutex

The dpaa2-switch driver uses a DPMAC in the same way as the dpaa2-eth
driver, so we need to duplicate the locking solution established by the
previous change to the switch driver as well.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarIoana Ciornei <ioana.ciornei@nxp.com>
Tested-by: default avatarIoana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 2291982e
...@@ -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)) if (dpaa2_switch_port_is_type_phy(port_priv)) {
return phylink_ethtool_ksettings_get(port_priv->mac->phylink, err = phylink_ethtool_ksettings_get(port_priv->mac->phylink,
link_ksettings); link_ksettings);
mutex_unlock(&port_priv->mac_lock);
return err;
}
mutex_unlock(&port_priv->mac_lock);
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,
if (dpaa2_switch_port_is_type_phy(port_priv)) {
err = phylink_ethtool_ksettings_set(port_priv->mac->phylink,
link_ksettings); 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);
...@@ -189,8 +203,12 @@ static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev, ...@@ -189,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);
} }
mutex_lock(&port_priv->mac_lock);
if (dpaa2_switch_port_has_mac(port_priv)) 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,6 +701,7 @@ static int dpaa2_switch_port_open(struct net_device *netdev) ...@@ -696,6 +701,7 @@ 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;
} }
...@@ -705,6 +711,8 @@ static int dpaa2_switch_port_open(struct net_device *netdev) ...@@ -705,6 +711,8 @@ static int dpaa2_switch_port_open(struct net_device *netdev)
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);
mutex_unlock(&port_priv->mac_lock);
return 0; return 0;
} }
...@@ -714,6 +722,8 @@ static int dpaa2_switch_port_stop(struct net_device *netdev) ...@@ -714,6 +722,8 @@ 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)) {
dpaa2_mac_stop(port_priv->mac); dpaa2_mac_stop(port_priv->mac);
} else { } else {
...@@ -721,6 +731,8 @@ static int dpaa2_switch_port_stop(struct net_device *netdev) ...@@ -721,6 +731,8 @@ static int dpaa2_switch_port_stop(struct net_device *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);
...@@ -1460,7 +1472,9 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv) ...@@ -1460,7 +1472,9 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv)
} }
} }
mutex_lock(&port_priv->mac_lock);
port_priv->mac = mac; port_priv->mac = mac;
mutex_unlock(&port_priv->mac_lock);
return 0; return 0;
...@@ -1473,9 +1487,12 @@ static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv) ...@@ -1473,9 +1487,12 @@ 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)
{ {
struct dpaa2_mac *mac = port_priv->mac; struct dpaa2_mac *mac;
mutex_lock(&port_priv->mac_lock);
mac = port_priv->mac;
port_priv->mac = NULL; port_priv->mac = NULL;
mutex_unlock(&port_priv->mac_lock);
if (!mac) if (!mac)
return; return;
...@@ -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);
...@@ -1512,7 +1530,12 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg) ...@@ -1512,7 +1530,12 @@ 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(); rtnl_lock();
if (dpaa2_switch_port_has_mac(port_priv)) /* We can avoid locking because the "endpoint changed" IRQ
* 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);
...@@ -3255,6 +3278,8 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw, ...@@ -3255,6 +3278,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 */
......
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