mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
r8169: use spinlock to protect mac ocp register access
[ Upstream commit 91c8643578 ]
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>
Stable-dep-of: 5e864d90b208 ("r8169: skip DASH fw status checks when DASH is disabled")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
095cfa2d9b
commit
a33b7cb184
@@ -615,6 +615,8 @@ struct rtl8169_private {
|
|||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
} wk;
|
} wk;
|
||||||
|
|
||||||
|
spinlock_t mac_ocp_lock;
|
||||||
|
|
||||||
unsigned supports_gmii:1;
|
unsigned supports_gmii:1;
|
||||||
unsigned aspm_manageable:1;
|
unsigned aspm_manageable:1;
|
||||||
unsigned dash_enabled:1;
|
unsigned dash_enabled:1;
|
||||||
@@ -850,7 +852,7 @@ static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
|
|||||||
(RTL_R32(tp, GPHY_OCP) & 0xffff) : -ETIMEDOUT;
|
(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))
|
if (rtl_ocp_reg_failure(reg))
|
||||||
return;
|
return;
|
||||||
@@ -858,7 +860,16 @@ static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
|
|||||||
RTL_W32(tp, OCPDR, OCPAR_FLAG | (reg << 15) | 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))
|
if (rtl_ocp_reg_failure(reg))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -868,12 +879,28 @@ static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
|
|||||||
return RTL_R32(tp, OCPDR);
|
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,
|
static void r8168_mac_ocp_modify(struct rtl8169_private *tp, u32 reg, u16 mask,
|
||||||
u16 set)
|
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
|
/* Work around a hw issue with RTL8168g PHY, the quirk disables
|
||||||
@@ -5232,6 +5259,8 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
tp->eee_adv = -1;
|
tp->eee_adv = -1;
|
||||||
tp->ocp_base = OCP_STD_PHY_BASE;
|
tp->ocp_base = OCP_STD_PHY_BASE;
|
||||||
|
|
||||||
|
spin_lock_init(&tp->mac_ocp_lock);
|
||||||
|
|
||||||
dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev,
|
dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev,
|
||||||
struct pcpu_sw_netstats);
|
struct pcpu_sw_netstats);
|
||||||
if (!dev->tstats)
|
if (!dev->tstats)
|
||||||
|
|||||||
Reference in New Issue
Block a user