Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: spacemit: Make stats_lock softirq-safe

While most of the statistics functions (emac_get_stats64() and such) are
called with softirqs enabled, emac_stats_timer() is, as its name
suggests, also called from a timer, i.e. called in softirq context.

All of these take stats_lock. Therefore, make stats_lock softirq-safe by
changing spin_lock() into spin_lock_bh() for the functions that get
statistics.

Also, instead of directly calling emac_stats_timer() in emac_up() and
emac_resume(), set the timer to trigger instead, so that
emac_stats_timer() is only called from the timer. It will keep using
spin_lock().

This fixes a lockdep warning, and potential deadlock when stats_timer is
triggered in the middle of getting statistics.

Fixes: bfec6d7f2001 ("net: spacemit: Add K1 Ethernet MAC")
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Closes: https://lore.kernel.org/all/a52c0cf5-0444-41aa-b061-a0a1d72b02fe@samsung.com/
Signed-off-by: Vivian Wang <wangruikang@iscas.ac.cn>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://patch.msgid.link/20250919-k1-ethernet-fix-lock-v1-1-c8b700aa4954@iscas.ac.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Vivian Wang and committed by
Jakub Kicinski
35626012 4b1eb833

+15 -15
+15 -15
drivers/net/ethernet/spacemit/k1_emac.c
··· 135 135 bool flow_control_autoneg; 136 136 u8 flow_control; 137 137 138 - /* Hold while touching hardware statistics */ 138 + /* Softirq-safe, hold while touching hardware statistics */ 139 139 spinlock_t stats_lock; 140 140 }; 141 141 ··· 1239 1239 /* This is the only software counter */ 1240 1240 storage->tx_dropped = emac_get_stat_tx_drops(priv); 1241 1241 1242 - spin_lock(&priv->stats_lock); 1242 + spin_lock_bh(&priv->stats_lock); 1243 1243 1244 1244 emac_stats_update(priv); 1245 1245 ··· 1261 1261 storage->rx_missed_errors = rx_stats->stats.rx_drp_fifo_full_pkts; 1262 1262 storage->rx_missed_errors += rx_stats->stats.rx_truncate_fifo_full_pkts; 1263 1263 1264 - spin_unlock(&priv->stats_lock); 1264 + spin_unlock_bh(&priv->stats_lock); 1265 1265 } 1266 1266 1267 1267 static void emac_get_rmon_stats(struct net_device *dev, ··· 1275 1275 1276 1276 *ranges = emac_rmon_hist_ranges; 1277 1277 1278 - spin_lock(&priv->stats_lock); 1278 + spin_lock_bh(&priv->stats_lock); 1279 1279 1280 1280 emac_stats_update(priv); 1281 1281 ··· 1294 1294 rmon_stats->hist[5] = rx_stats->stats.rx_1024_1518_pkts; 1295 1295 rmon_stats->hist[6] = rx_stats->stats.rx_1519_plus_pkts; 1296 1296 1297 - spin_unlock(&priv->stats_lock); 1297 + spin_unlock_bh(&priv->stats_lock); 1298 1298 } 1299 1299 1300 1300 static void emac_get_eth_mac_stats(struct net_device *dev, ··· 1307 1307 tx_stats = &priv->tx_stats; 1308 1308 rx_stats = &priv->rx_stats; 1309 1309 1310 - spin_lock(&priv->stats_lock); 1310 + spin_lock_bh(&priv->stats_lock); 1311 1311 1312 1312 emac_stats_update(priv); 1313 1313 ··· 1325 1325 mac_stats->FramesAbortedDueToXSColls = 1326 1326 tx_stats->stats.tx_excessclsn_pkts; 1327 1327 1328 - spin_unlock(&priv->stats_lock); 1328 + spin_unlock_bh(&priv->stats_lock); 1329 1329 } 1330 1330 1331 1331 static void emac_get_pause_stats(struct net_device *dev, ··· 1338 1338 tx_stats = &priv->tx_stats; 1339 1339 rx_stats = &priv->rx_stats; 1340 1340 1341 - spin_lock(&priv->stats_lock); 1341 + spin_lock_bh(&priv->stats_lock); 1342 1342 1343 1343 emac_stats_update(priv); 1344 1344 1345 1345 pause_stats->tx_pause_frames = tx_stats->stats.tx_pause_pkts; 1346 1346 pause_stats->rx_pause_frames = rx_stats->stats.rx_pause_pkts; 1347 1347 1348 - spin_unlock(&priv->stats_lock); 1348 + spin_unlock_bh(&priv->stats_lock); 1349 1349 } 1350 1350 1351 1351 /* Other statistics that are not derivable from standard statistics */ ··· 1393 1393 u64 *rx_stats = (u64 *)&priv->rx_stats; 1394 1394 int i; 1395 1395 1396 - spin_lock(&priv->stats_lock); 1396 + spin_lock_bh(&priv->stats_lock); 1397 1397 1398 1398 emac_stats_update(priv); 1399 1399 1400 1400 for (i = 0; i < ARRAY_SIZE(emac_ethtool_rx_stats); i++) 1401 1401 data[i] = rx_stats[emac_ethtool_rx_stats[i].offset]; 1402 1402 1403 - spin_unlock(&priv->stats_lock); 1403 + spin_unlock_bh(&priv->stats_lock); 1404 1404 } 1405 1405 1406 1406 static int emac_ethtool_get_regs_len(struct net_device *dev) ··· 1769 1769 1770 1770 netif_start_queue(ndev); 1771 1771 1772 - emac_stats_timer(&priv->stats_timer); 1772 + mod_timer(&priv->stats_timer, jiffies); 1773 1773 1774 1774 return 0; 1775 1775 ··· 1807 1807 1808 1808 /* Update and save current stats, see emac_stats_update() for usage */ 1809 1809 1810 - spin_lock(&priv->stats_lock); 1810 + spin_lock_bh(&priv->stats_lock); 1811 1811 1812 1812 emac_stats_update(priv); 1813 1813 1814 1814 priv->tx_stats_off = priv->tx_stats; 1815 1815 priv->rx_stats_off = priv->rx_stats; 1816 1816 1817 - spin_unlock(&priv->stats_lock); 1817 + spin_unlock_bh(&priv->stats_lock); 1818 1818 1819 1819 pm_runtime_put_sync(&pdev->dev); 1820 1820 return 0; ··· 2111 2111 2112 2112 netif_device_attach(ndev); 2113 2113 2114 - emac_stats_timer(&priv->stats_timer); 2114 + mod_timer(&priv->stats_timer, jiffies); 2115 2115 2116 2116 return 0; 2117 2117 }