Commit 91c86435 authored by Heiner Kallweit's avatar Heiner Kallweit Committed by David S. Miller
Browse files

r8169: use spinlock to protect mac ocp register access



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: default avatarSimon Horman <simon.horman@corigine.com>
Tested-by: default avatarKai-Heng Feng <kai.heng.feng@canonical.com>
Tested-by: default avatarHolger Hoffstätte <holger@applied-asynchrony.com>
Signed-off-by: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8ca5a579
Loading
Loading
Loading
Loading
+33 −4
Original line number Diff line number Diff line
@@ -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)