Skip to content

Commit 0d5e2a8

Browse files
Doug Bergerdavem330
authored andcommitted
net: bcmgenet: synchronize UMAC_CMD access
The UMAC_CMD register is written from different execution contexts and has insufficient synchronization protections to prevent possible corruption. Of particular concern are the acceses from the phy_device delayed work context used by the adjust_link call and the BH context that may be used by the ndo_set_rx_mode call. A spinlock is added to the driver to protect contended register accesses (i.e. reg_lock) and it is used to synchronize accesses to UMAC_CMD. Fixes: 1c1008c ("net: bcmgenet: add main driver file") Cc: [email protected] Signed-off-by: Doug Berger <[email protected]> Acked-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2dbe5f1 commit 0d5e2a8

File tree

4 files changed

+23
-3
lines changed

4 files changed

+23
-3
lines changed

drivers/net/ethernet/broadcom/genet/bcmgenet.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2467,14 +2467,18 @@ static void umac_enable_set(struct bcmgenet_priv *priv, u32 mask, bool enable)
24672467
{
24682468
u32 reg;
24692469

2470+
spin_lock_bh(&priv->reg_lock);
24702471
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
2471-
if (reg & CMD_SW_RESET)
2472+
if (reg & CMD_SW_RESET) {
2473+
spin_unlock_bh(&priv->reg_lock);
24722474
return;
2475+
}
24732476
if (enable)
24742477
reg |= mask;
24752478
else
24762479
reg &= ~mask;
24772480
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
2481+
spin_unlock_bh(&priv->reg_lock);
24782482

24792483
/* UniMAC stops on a packet boundary, wait for a full-size packet
24802484
* to be processed
@@ -2490,8 +2494,10 @@ static void reset_umac(struct bcmgenet_priv *priv)
24902494
udelay(10);
24912495

24922496
/* issue soft reset and disable MAC while updating its registers */
2497+
spin_lock_bh(&priv->reg_lock);
24932498
bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD);
24942499
udelay(2);
2500+
spin_unlock_bh(&priv->reg_lock);
24952501
}
24962502

24972503
static void bcmgenet_intr_disable(struct bcmgenet_priv *priv)
@@ -3597,16 +3603,19 @@ static void bcmgenet_set_rx_mode(struct net_device *dev)
35973603
* 3. The number of filters needed exceeds the number filters
35983604
* supported by the hardware.
35993605
*/
3606+
spin_lock(&priv->reg_lock);
36003607
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
36013608
if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) ||
36023609
(nfilter > MAX_MDF_FILTER)) {
36033610
reg |= CMD_PROMISC;
36043611
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
3612+
spin_unlock(&priv->reg_lock);
36053613
bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
36063614
return;
36073615
} else {
36083616
reg &= ~CMD_PROMISC;
36093617
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
3618+
spin_unlock(&priv->reg_lock);
36103619
}
36113620

36123621
/* update MDF filter */
@@ -4005,6 +4014,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
40054014
goto err;
40064015
}
40074016

4017+
spin_lock_init(&priv->reg_lock);
40084018
spin_lock_init(&priv->lock);
40094019

40104020
/* Set default pause parameters */

drivers/net/ethernet/broadcom/genet/bcmgenet.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* SPDX-License-Identifier: GPL-2.0-only */
22
/*
3-
* Copyright (c) 2014-2020 Broadcom
3+
* Copyright (c) 2014-2024 Broadcom
44
*/
55

66
#ifndef __BCMGENET_H__
@@ -573,6 +573,8 @@ struct bcmgenet_rxnfc_rule {
573573
/* device context */
574574
struct bcmgenet_priv {
575575
void __iomem *base;
576+
/* reg_lock: lock to serialize access to shared registers */
577+
spinlock_t reg_lock;
576578
enum bcmgenet_version version;
577579
struct net_device *dev;
578580

drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
* Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
44
*
5-
* Copyright (c) 2014-2020 Broadcom
5+
* Copyright (c) 2014-2024 Broadcom
66
*/
77

88
#define pr_fmt(fmt) "bcmgenet_wol: " fmt
@@ -151,13 +151,15 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
151151
}
152152

153153
/* Can't suspend with WoL if MAC is still in reset */
154+
spin_lock_bh(&priv->reg_lock);
154155
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
155156
if (reg & CMD_SW_RESET)
156157
reg &= ~CMD_SW_RESET;
157158

158159
/* disable RX */
159160
reg &= ~CMD_RX_EN;
160161
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
162+
spin_unlock_bh(&priv->reg_lock);
161163
mdelay(10);
162164

163165
if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
@@ -203,13 +205,15 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
203205
}
204206

205207
/* Enable CRC forward */
208+
spin_lock_bh(&priv->reg_lock);
206209
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
207210
priv->crc_fwd_en = 1;
208211
reg |= CMD_CRC_FWD;
209212

210213
/* Receiver must be enabled for WOL MP detection */
211214
reg |= CMD_RX_EN;
212215
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
216+
spin_unlock_bh(&priv->reg_lock);
213217

214218
reg = UMAC_IRQ_MPD_R;
215219
if (hfb_enable)
@@ -256,7 +260,9 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
256260
}
257261

258262
/* Disable CRC Forward */
263+
spin_lock_bh(&priv->reg_lock);
259264
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
260265
reg &= ~CMD_CRC_FWD;
261266
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
267+
spin_unlock_bh(&priv->reg_lock);
262268
}

drivers/net/ethernet/broadcom/genet/bcmmii.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ static void bcmgenet_mac_config(struct net_device *dev)
7676
reg |= RGMII_LINK;
7777
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
7878

79+
spin_lock_bh(&priv->reg_lock);
7980
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
8081
reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
8182
CMD_HD_EN |
@@ -88,6 +89,7 @@ static void bcmgenet_mac_config(struct net_device *dev)
8889
reg |= CMD_TX_EN | CMD_RX_EN;
8990
}
9091
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
92+
spin_unlock_bh(&priv->reg_lock);
9193

9294
active = phy_init_eee(phydev, 0) >= 0;
9395
bcmgenet_eee_enable_set(dev,

0 commit comments

Comments
 (0)