mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-27 12:57:53 +00:00
r8169: use spinlock to protect mac ocp register access
[ Upstream commit91c8643578
] 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:5e864d90b2
("r8169: skip DASH fw status checks when DASH is disabled") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
095cfa2d9b
commit
a33b7cb184
1 changed files with 33 additions and 4 deletions
|
@ -615,6 +615,8 @@ struct rtl8169_private {
|
|||
struct work_struct work;
|
||||
} wk;
|
||||
|
||||
spinlock_t mac_ocp_lock;
|
||||
|
||||
unsigned supports_gmii:1;
|
||||
unsigned aspm_manageable: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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -868,12 +879,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
|
||||
|
@ -5232,6 +5259,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)
|
||||
|
|
Loading…
Reference in a new issue