Skip to content

Commit 2291982

Browse files
vladimirolteanPaolo Abeni
authored andcommitted
net: dpaa2-eth: serialize changes to priv->mac with a mutex
The dpaa2 architecture permits dynamic connections between objects on the fsl-mc bus, specifically between a DPNI object (represented by a struct net_device) and a DPMAC object (represented by a struct phylink). The DPNI driver is notified when those connections are created/broken through the dpni_irq0_handler_thread() method. To ensure that ethtool operations, as well as netdev up/down operations serialize with the connection/disconnection of the DPNI with a DPMAC, dpni_irq0_handler_thread() takes the rtnl_lock() to block those other operations from taking place. There is code called by dpaa2_mac_connect() which wants to acquire the rtnl_mutex once again, see phylink_create() -> phylink_register_sfp() -> sfp_bus_add_upstream() -> rtnl_lock(). So the strategy doesn't quite work out, even though it's fairly simple. Create a different strategy, where all code paths in the dpaa2-eth driver access priv->mac only while they are holding priv->mac_lock. The phylink instance is not created or connected to the PHY under the priv->mac_lock, but only assigned to priv->mac then. This will eliminate the reliance on the rtnl_mutex. Add lockdep annotations and put comments where holding the lock is not necessary, and priv->mac can be dereferenced freely. Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Ioana Ciornei <[email protected]> Tested-by: Ioana Ciornei <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent 55f90a4 commit 2291982

File tree

3 files changed

+91
-16
lines changed

3 files changed

+91
-16
lines changed

drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,8 +2147,11 @@ static int dpaa2_eth_link_state_update(struct dpaa2_eth_priv *priv)
21472147

21482148
/* When we manage the MAC/PHY using phylink there is no need
21492149
* to manually update the netif_carrier.
2150+
* We can avoid locking because we are called from the "link changed"
2151+
* IRQ handler, which is the same as the "endpoint changed" IRQ handler
2152+
* (the writer to priv->mac), so we cannot race with it.
21502153
*/
2151-
if (dpaa2_eth_is_type_phy(priv))
2154+
if (dpaa2_mac_is_type_phy(priv->mac))
21522155
goto out;
21532156

21542157
/* Chech link state; speed / duplex changes are not treated yet */
@@ -2179,6 +2182,8 @@ static int dpaa2_eth_open(struct net_device *net_dev)
21792182

21802183
dpaa2_eth_seed_pools(priv);
21812184

2185+
mutex_lock(&priv->mac_lock);
2186+
21822187
if (!dpaa2_eth_is_type_phy(priv)) {
21832188
/* We'll only start the txqs when the link is actually ready;
21842189
* make sure we don't race against the link up notification,
@@ -2197,13 +2202,16 @@ static int dpaa2_eth_open(struct net_device *net_dev)
21972202

21982203
err = dpni_enable(priv->mc_io, 0, priv->mc_token);
21992204
if (err < 0) {
2205+
mutex_unlock(&priv->mac_lock);
22002206
netdev_err(net_dev, "dpni_enable() failed\n");
22012207
goto enable_err;
22022208
}
22032209

22042210
if (dpaa2_eth_is_type_phy(priv))
22052211
dpaa2_mac_start(priv->mac);
22062212

2213+
mutex_unlock(&priv->mac_lock);
2214+
22072215
return 0;
22082216

22092217
enable_err:
@@ -2275,13 +2283,17 @@ static int dpaa2_eth_stop(struct net_device *net_dev)
22752283
int dpni_enabled = 0;
22762284
int retries = 10;
22772285

2286+
mutex_lock(&priv->mac_lock);
2287+
22782288
if (dpaa2_eth_is_type_phy(priv)) {
22792289
dpaa2_mac_stop(priv->mac);
22802290
} else {
22812291
netif_tx_stop_all_queues(net_dev);
22822292
netif_carrier_off(net_dev);
22832293
}
22842294

2295+
mutex_unlock(&priv->mac_lock);
2296+
22852297
/* On dpni_disable(), the MC firmware will:
22862298
* - stop MAC Rx and wait for all Rx frames to be enqueued to software
22872299
* - cut off WRIOP dequeues from egress FQs and wait until transmission
@@ -2607,12 +2619,20 @@ static int dpaa2_eth_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
26072619
static int dpaa2_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
26082620
{
26092621
struct dpaa2_eth_priv *priv = netdev_priv(dev);
2622+
int err;
26102623

26112624
if (cmd == SIOCSHWTSTAMP)
26122625
return dpaa2_eth_ts_ioctl(dev, rq, cmd);
26132626

2614-
if (dpaa2_eth_is_type_phy(priv))
2615-
return phylink_mii_ioctl(priv->mac->phylink, rq, cmd);
2627+
mutex_lock(&priv->mac_lock);
2628+
2629+
if (dpaa2_eth_is_type_phy(priv)) {
2630+
err = phylink_mii_ioctl(priv->mac->phylink, rq, cmd);
2631+
mutex_unlock(&priv->mac_lock);
2632+
return err;
2633+
}
2634+
2635+
mutex_unlock(&priv->mac_lock);
26162636

26172637
return -EOPNOTSUPP;
26182638
}
@@ -4639,7 +4659,9 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv)
46394659
}
46404660
}
46414661

4662+
mutex_lock(&priv->mac_lock);
46424663
priv->mac = mac;
4664+
mutex_unlock(&priv->mac_lock);
46434665

46444666
return 0;
46454667

@@ -4652,9 +4674,12 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv)
46524674

46534675
static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv)
46544676
{
4655-
struct dpaa2_mac *mac = priv->mac;
4677+
struct dpaa2_mac *mac;
46564678

4679+
mutex_lock(&priv->mac_lock);
4680+
mac = priv->mac;
46574681
priv->mac = NULL;
4682+
mutex_unlock(&priv->mac_lock);
46584683

46594684
if (!mac)
46604685
return;
@@ -4673,6 +4698,7 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg)
46734698
struct fsl_mc_device *dpni_dev = to_fsl_mc_device(dev);
46744699
struct net_device *net_dev = dev_get_drvdata(dev);
46754700
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
4701+
bool had_mac;
46764702
int err;
46774703

46784704
err = dpni_get_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle,
@@ -4690,7 +4716,12 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg)
46904716
dpaa2_eth_update_tx_fqids(priv);
46914717

46924718
rtnl_lock();
4693-
if (dpaa2_eth_has_mac(priv))
4719+
/* We can avoid locking because the "endpoint changed" IRQ
4720+
* handler is the only one who changes priv->mac at runtime,
4721+
* so we are not racing with anyone.
4722+
*/
4723+
had_mac = !!priv->mac;
4724+
if (had_mac)
46944725
dpaa2_eth_disconnect_mac(priv);
46954726
else
46964727
dpaa2_eth_connect_mac(priv);
@@ -4792,6 +4823,8 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
47924823
priv->net_dev = net_dev;
47934824
SET_NETDEV_DEVLINK_PORT(net_dev, &priv->devlink_port);
47944825

4826+
mutex_init(&priv->mac_lock);
4827+
47954828
priv->iommu_domain = iommu_get_domain_for_dev(dev);
47964829

47974830
priv->tx_tstamp_type = HWTSTAMP_TX_OFF;

drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,8 @@ struct dpaa2_eth_priv {
615615
#endif
616616

617617
struct dpaa2_mac *mac;
618+
/* Serializes changes to priv->mac */
619+
struct mutex mac_lock;
618620
struct workqueue_struct *dpaa2_ptp_wq;
619621
struct work_struct tx_onestep_tstamp;
620622
struct sk_buff_head tx_skbs;
@@ -768,11 +770,15 @@ static inline unsigned int dpaa2_eth_rx_head_room(struct dpaa2_eth_priv *priv)
768770

769771
static inline bool dpaa2_eth_is_type_phy(struct dpaa2_eth_priv *priv)
770772
{
773+
lockdep_assert_held(&priv->mac_lock);
774+
771775
return dpaa2_mac_is_type_phy(priv->mac);
772776
}
773777

774778
static inline bool dpaa2_eth_has_mac(struct dpaa2_eth_priv *priv)
775779
{
780+
lockdep_assert_held(&priv->mac_lock);
781+
776782
return priv->mac ? true : false;
777783
}
778784

drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,22 +85,35 @@ static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
8585
static int dpaa2_eth_nway_reset(struct net_device *net_dev)
8686
{
8787
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
88+
int err = -EOPNOTSUPP;
89+
90+
mutex_lock(&priv->mac_lock);
8891

8992
if (dpaa2_eth_is_type_phy(priv))
90-
return phylink_ethtool_nway_reset(priv->mac->phylink);
93+
err = phylink_ethtool_nway_reset(priv->mac->phylink);
94+
95+
mutex_unlock(&priv->mac_lock);
9196

92-
return -EOPNOTSUPP;
97+
return err;
9398
}
9499

95100
static int
96101
dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
97102
struct ethtool_link_ksettings *link_settings)
98103
{
99104
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
105+
int err;
100106

101-
if (dpaa2_eth_is_type_phy(priv))
102-
return phylink_ethtool_ksettings_get(priv->mac->phylink,
103-
link_settings);
107+
mutex_lock(&priv->mac_lock);
108+
109+
if (dpaa2_eth_is_type_phy(priv)) {
110+
err = phylink_ethtool_ksettings_get(priv->mac->phylink,
111+
link_settings);
112+
mutex_unlock(&priv->mac_lock);
113+
return err;
114+
}
115+
116+
mutex_unlock(&priv->mac_lock);
104117

105118
link_settings->base.autoneg = AUTONEG_DISABLE;
106119
if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX))
@@ -115,11 +128,17 @@ dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
115128
const struct ethtool_link_ksettings *link_settings)
116129
{
117130
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
131+
int err = -EOPNOTSUPP;
118132

119-
if (!dpaa2_eth_is_type_phy(priv))
120-
return -EOPNOTSUPP;
133+
mutex_lock(&priv->mac_lock);
134+
135+
if (dpaa2_eth_is_type_phy(priv))
136+
err = phylink_ethtool_ksettings_set(priv->mac->phylink,
137+
link_settings);
121138

122-
return phylink_ethtool_ksettings_set(priv->mac->phylink, link_settings);
139+
mutex_unlock(&priv->mac_lock);
140+
141+
return err;
123142
}
124143

125144
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,
128147
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
129148
u64 link_options = priv->link_state.options;
130149

150+
mutex_lock(&priv->mac_lock);
151+
131152
if (dpaa2_eth_is_type_phy(priv)) {
132153
phylink_ethtool_get_pauseparam(priv->mac->phylink, pause);
154+
mutex_unlock(&priv->mac_lock);
133155
return;
134156
}
135157

158+
mutex_unlock(&priv->mac_lock);
159+
136160
pause->rx_pause = dpaa2_eth_rx_pause_enabled(link_options);
137161
pause->tx_pause = dpaa2_eth_tx_pause_enabled(link_options);
138162
pause->autoneg = AUTONEG_DISABLE;
@@ -151,9 +175,17 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev,
151175
return -EOPNOTSUPP;
152176
}
153177

154-
if (dpaa2_eth_is_type_phy(priv))
155-
return phylink_ethtool_set_pauseparam(priv->mac->phylink,
156-
pause);
178+
mutex_lock(&priv->mac_lock);
179+
180+
if (dpaa2_eth_is_type_phy(priv)) {
181+
err = phylink_ethtool_set_pauseparam(priv->mac->phylink,
182+
pause);
183+
mutex_unlock(&priv->mac_lock);
184+
return err;
185+
}
186+
187+
mutex_unlock(&priv->mac_lock);
188+
157189
if (pause->autoneg)
158190
return -EOPNOTSUPP;
159191

@@ -309,8 +341,12 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
309341
}
310342
*(data + i++) = buf_cnt_total;
311343

344+
mutex_lock(&priv->mac_lock);
345+
312346
if (dpaa2_eth_has_mac(priv))
313347
dpaa2_mac_get_ethtool_stats(priv->mac, data + i);
348+
349+
mutex_unlock(&priv->mac_lock);
314350
}
315351

316352
static int dpaa2_eth_prep_eth_rule(struct ethhdr *eth_value, struct ethhdr *eth_mask,

0 commit comments

Comments
 (0)