r8169: use spinlock to protect mac ocp register access
authorHeiner Kallweit <hkallweit1@gmail.com>
Mon, 6 Mar 2023 21:23:15 +0000 (22:23 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 8 Mar 2023 09:30:41 +0000 (09:30 +0000)
For disabling ASPM during NAPI poll we'll have to access mac ocp
registers in atomic context. This could result in races because
a mac ocp read consists of a write to register OCPDR, followed
by a read from the same register. Therefore add a spinlock to
protect access to mac ocp registers.

Reviewed-by: Simon Horman <simon.horman@corigine.com>
Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Tested-by: Holger Hoffstätte <holger@applied-asynchrony.com>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/realtek/r8169_main.c

index 45147a1..259eac5 100644 (file)
@@ -613,6 +613,8 @@ struct rtl8169_private {
                struct work_struct work;
        } wk;
 
+       spinlock_t mac_ocp_lock;
+
        unsigned supports_gmii:1;
        unsigned aspm_manageable:1;
        dma_addr_t counters_phys_addr;
@@ -847,7 +849,7 @@ static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
                (RTL_R32(tp, GPHY_OCP) & 0xffff) : -ETIMEDOUT;
 }
 
-static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
+static void __r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
 {
        if (rtl_ocp_reg_failure(reg))
                return;
@@ -855,7 +857,16 @@ static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
        RTL_W32(tp, OCPDR, OCPAR_FLAG | (reg << 15) | data);
 }
 
-static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
+static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tp->mac_ocp_lock, flags);
+       __r8168_mac_ocp_write(tp, reg, data);
+       spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
+}
+
+static u16 __r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
 {
        if (rtl_ocp_reg_failure(reg))
                return 0;
@@ -865,12 +876,28 @@ static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
        return RTL_R32(tp, OCPDR);
 }
 
+static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
+{
+       unsigned long flags;
+       u16 val;
+
+       spin_lock_irqsave(&tp->mac_ocp_lock, flags);
+       val = __r8168_mac_ocp_read(tp, reg);
+       spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
+
+       return val;
+}
+
 static void r8168_mac_ocp_modify(struct rtl8169_private *tp, u32 reg, u16 mask,
                                 u16 set)
 {
-       u16 data = r8168_mac_ocp_read(tp, reg);
+       unsigned long flags;
+       u16 data;
 
-       r8168_mac_ocp_write(tp, reg, (data & ~mask) | set);
+       spin_lock_irqsave(&tp->mac_ocp_lock, flags);
+       data = __r8168_mac_ocp_read(tp, reg);
+       __r8168_mac_ocp_write(tp, reg, (data & ~mask) | set);
+       spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
 }
 
 /* Work around a hw issue with RTL8168g PHY, the quirk disables
@@ -5176,6 +5203,8 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        tp->eee_adv = -1;
        tp->ocp_base = OCP_STD_PHY_BASE;
 
+       spin_lock_init(&tp->mac_ocp_lock);
+
        dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev,
                                                   struct pcpu_sw_netstats);
        if (!dev->tstats)