[PATCH net-next 1/2] r8169: support RTL8106E

Subsystems: 8169 10/100/1000 gigabit ethernet driver, networking drivers, the rest

STALE5157d

18 messages, 4 authors, 2012-07-09 · open the first message on its own page

[PATCH net-next 1/2] r8169: support RTL8106E

From: Hayes Wang <hidden>
Date: 2012-06-29 10:33:53

From: hayes <redacted>

Support the new chip RTL8106E.

Signed-off-by: Hayes Wang <redacted>
---
 drivers/net/ethernet/realtek/r8169.c |   56 ++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index d7a04e0..7afc593 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -46,6 +46,7 @@
 #define FIRMWARE_8105E_1	"rtl_nic/rtl8105e-1.fw"
 #define FIRMWARE_8402_1		"rtl_nic/rtl8402-1.fw"
 #define FIRMWARE_8411_1		"rtl_nic/rtl8411-1.fw"
+#define FIRMWARE_8106E_1	"rtl_nic/rtl8106e-1.fw"
 
 #ifdef RTL8169_DEBUG
 #define assert(expr) \
@@ -141,6 +142,7 @@ enum mac_version {
 	RTL_GIGA_MAC_VER_36,
 	RTL_GIGA_MAC_VER_37,
 	RTL_GIGA_MAC_VER_38,
+	RTL_GIGA_MAC_VER_39,
 	RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -259,6 +261,9 @@ static const struct {
 	[RTL_GIGA_MAC_VER_38] =
 		_R("RTL8411",		RTL_TD_1, FIRMWARE_8411_1,
 							JUMBO_9K, false),
+	[RTL_GIGA_MAC_VER_39] =
+		_R("RTL8106e",		RTL_TD_1, FIRMWARE_8106E_1,
+							JUMBO_1K, true),
 };
 #undef _R
 
@@ -431,7 +436,9 @@ enum rtl8168_registers {
 	RDSAR1			= 0xd0,	/* 8168c only. Undocumented on 8168dp */
 	MISC			= 0xf0,	/* 8168e only. */
 #define TXPLA_RST			(1 << 29)
+#define DISABLE_LAN_EN			(1 << 23) /* Enable GPIO pin */
 #define PWM_EN				(1 << 22)
+#define EARLY_TALLY_EN			(1 << 16)
 };
 
 enum rtl_register_content {
@@ -794,6 +801,7 @@ MODULE_FIRMWARE(FIRMWARE_8168F_1);
 MODULE_FIRMWARE(FIRMWARE_8168F_2);
 MODULE_FIRMWARE(FIRMWARE_8402_1);
 MODULE_FIRMWARE(FIRMWARE_8411_1);
+MODULE_FIRMWARE(FIRMWARE_8106E_1);
 
 static void rtl_lock_work(struct rtl8169_private *tp)
 {
@@ -1933,6 +1941,8 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
 		{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },
 
 		/* 8101 family. */
+		{ 0x7cf00000, 0x44900000,	RTL_GIGA_MAC_VER_39 },
+		{ 0x7c800000, 0x44800000,	RTL_GIGA_MAC_VER_39 },
 		{ 0x7c800000, 0x44000000,	RTL_GIGA_MAC_VER_37 },
 		{ 0x7cf00000, 0x40b00000,	RTL_GIGA_MAC_VER_30 },
 		{ 0x7cf00000, 0x40a00000,	RTL_GIGA_MAC_VER_30 },
@@ -3273,6 +3283,30 @@ static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
 	rtl_writephy(tp, 0x1f, 0x0000);
 }
 
+static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	static const struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0004 },
+		{ 0x10, 0xc07f },
+		{ 0x19, 0x7030 },
+		{ 0x1f, 0x0000 }
+	};
+
+	/* Disable ALDPS before ram code */
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_writephy(tp, 0x18, 0x0310);
+	msleep(100);
+
+	rtl_apply_firmware(tp);
+
+	rtl_eri_write(ioaddr, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	rtl_eri_write(ioaddr, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+}
+
 static void rtl_hw_phy_config(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -3369,6 +3403,10 @@ static void rtl_hw_phy_config(struct net_device *dev)
 		rtl8411_hw_phy_config(tp);
 		break;
 
+	case RTL_GIGA_MAC_VER_39:
+		rtl8106e_hw_phy_config(tp);
+		break;
+
 	default:
 		break;
 	}
@@ -3608,6 +3646,7 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_34:
 	case RTL_GIGA_MAC_VER_37:
 	case RTL_GIGA_MAC_VER_38:
+	case RTL_GIGA_MAC_VER_39:
 		RTL_W32(RxConfig, RTL_R32(RxConfig) |
 			AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
 		break;
@@ -3830,6 +3869,7 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_29:
 	case RTL_GIGA_MAC_VER_30:
 	case RTL_GIGA_MAC_VER_37:
+	case RTL_GIGA_MAC_VER_39:
 		ops->down	= r810x_pll_power_down;
 		ops->up		= r810x_pll_power_up;
 		break;
@@ -5123,6 +5163,18 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp)
 		     ERIAR_EXGMAC);
 }
 
+static void rtl_hw_start_8106(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	/* Force LAN exit from ASPM if Rx/Tx are not idle */
+	RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
+
+	RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
+	RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
+	RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
+}
+
 static void rtl_hw_start_8101(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -5167,6 +5219,10 @@ static void rtl_hw_start_8101(struct net_device *dev)
 	case RTL_GIGA_MAC_VER_37:
 		rtl_hw_start_8402(tp);
 		break;
+
+	case RTL_GIGA_MAC_VER_39:
+		rtl_hw_start_8106(tp);
+		break;
 	}
 
 	RTL_W8(Cfg9346, Cfg9346_Lock);
-- 
1.7.10.2

[PATCH net-next 2/2] r8169: support RTL8168G

From: Hayes Wang <hidden>
Date: 2012-06-29 10:33:51

From: hayes <redacted>

Support the new chip RTL8168G.

Signed-off-by: Hayes Wang <redacted>
---
 drivers/net/ethernet/realtek/r8169.c |  344 +++++++++++++++++++++++++++++++++-
 1 file changed, 343 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 7afc593..fda4432 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -47,6 +47,7 @@
 #define FIRMWARE_8402_1		"rtl_nic/rtl8402-1.fw"
 #define FIRMWARE_8411_1		"rtl_nic/rtl8411-1.fw"
 #define FIRMWARE_8106E_1	"rtl_nic/rtl8106e-1.fw"
+#define FIRMWARE_8168G_1	"rtl_nic/rtl8168g-1.fw"
 
 #ifdef RTL8169_DEBUG
 #define assert(expr) \
@@ -143,6 +144,8 @@ enum mac_version {
 	RTL_GIGA_MAC_VER_37,
 	RTL_GIGA_MAC_VER_38,
 	RTL_GIGA_MAC_VER_39,
+	RTL_GIGA_MAC_VER_40,
+	RTL_GIGA_MAC_VER_41,
 	RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -264,6 +267,11 @@ static const struct {
 	[RTL_GIGA_MAC_VER_39] =
 		_R("RTL8106e",		RTL_TD_1, FIRMWARE_8106E_1,
 							JUMBO_1K, true),
+	[RTL_GIGA_MAC_VER_40] =
+		_R("RTL8168g/8111g",	RTL_TD_1, FIRMWARE_8168G_1,
+							JUMBO_9K, false),
+	[RTL_GIGA_MAC_VER_41] =
+		_R("RTL8168g/8111g",	RTL_TD_1, NULL, JUMBO_9K, false),
 };
 #undef _R
 
@@ -394,8 +402,11 @@ enum rtl8168_8101_registers {
 	TWSI			= 0xd2,
 	MCU			= 0xd3,
 #define	NOW_IS_OOB			(1 << 7)
+#define TX_EMPTY			(1 << 5)
+#define RX_EMPTY			(1 << 4)
 #define	EN_NDP				(1 << 3)
 #define	EN_OOB_RESET			(1 << 2)
+#define LINK_LIST_RDY			(1 << 1)
 	EFUSEAR			= 0xdc,
 #define	EFUSEAR_FLAG			0x80000000
 #define	EFUSEAR_WRITE_CMD		0x80000000
@@ -421,6 +432,7 @@ enum rtl8168_registers {
 #define ERIAR_MASK_SHIFT		12
 #define ERIAR_MASK_0001			(0x1 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_0011			(0x3 << ERIAR_MASK_SHIFT)
+#define ERIAR_MASK_0101			(0x5 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_1111			(0xf << ERIAR_MASK_SHIFT)
 	EPHY_RXER_NUM		= 0x7c,
 	OCPDR			= 0xb0,	/* OCP GPHY access */
@@ -433,11 +445,13 @@ enum rtl8168_registers {
 #define OCPAR_FLAG			0x80000000
 #define OCPAR_GPHY_WRITE_CMD		0x8000f060
 #define OCPAR_GPHY_READ_CMD		0x0000f060
+	GPHY_OCP		= 0xb8,
 	RDSAR1			= 0xd0,	/* 8168c only. Undocumented on 8168dp */
 	MISC			= 0xf0,	/* 8168e only. */
 #define TXPLA_RST			(1 << 29)
 #define DISABLE_LAN_EN			(1 << 23) /* Enable GPIO pin */
 #define PWM_EN				(1 << 22)
+#define RXDV_GATED_EN			(1 << 19)
 #define EARLY_TALLY_EN			(1 << 16)
 };
 
@@ -781,6 +795,8 @@ struct rtl8169_private {
 		} phy_action;
 	} *rtl_fw;
 #define RTL_FIRMWARE_UNKNOWN	ERR_PTR(-EAGAIN)
+
+	void (*write_fw)(struct rtl8169_private *, struct rtl_fw *);
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -802,6 +818,7 @@ MODULE_FIRMWARE(FIRMWARE_8168F_2);
 MODULE_FIRMWARE(FIRMWARE_8402_1);
 MODULE_FIRMWARE(FIRMWARE_8411_1);
 MODULE_FIRMWARE(FIRMWARE_8106E_1);
+MODULE_FIRMWARE(FIRMWARE_8168G_1);
 
 static void rtl_lock_work(struct rtl8169_private *tp)
 {
@@ -919,6 +936,99 @@ static int r8168dp_check_dash(struct rtl8169_private *tp)
 	return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
 }
 
+static void r8168_phy_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
+{
+	int i;
+
+	if (reg & 0xffff0001)
+		BUG();
+
+	RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
+
+	for (i = 0; i < 10; i++) {
+		udelay(25);
+		if (!(RTL_R32(GPHY_OCP) & OCPAR_FLAG))
+			break;
+	}
+}
+
+static u16 r8168_phy_ocp_read(void __iomem *ioaddr, u32 reg)
+{
+	int i;
+	u32 data;
+
+	if (reg & 0xffff0001)
+		BUG();
+
+	RTL_W32(GPHY_OCP, (reg << 15));
+
+	for (i = 0; i < 10; i++) {
+		udelay(25);
+		data = RTL_R32(GPHY_OCP);
+		if (data & OCPAR_FLAG)
+			break;
+	}
+
+	return (u16)(data & 0xffff);
+}
+
+static void rtl_w1w0_phy_ocp(void __iomem *ioaddr, int reg_addr, int p, int m)
+{
+	int val;
+
+	val = r8168_phy_ocp_read(ioaddr, reg_addr);
+	r8168_phy_ocp_write(ioaddr, reg_addr, (val | p) & ~m);
+}
+
+static void r8168_mac_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
+{
+	int i;
+
+	if (reg & 0xffff0001)
+		BUG();
+
+	RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
+
+	for (i = 0; i < 10; i++) {
+		udelay(25);
+		if (!(RTL_R32(OCPDR) & OCPAR_FLAG))
+			break;
+	}
+}
+
+static u16 r8168_mac_ocp_read(void __iomem *ioaddr, u32 reg)
+{
+	int i;
+	u32 data;
+
+	if (reg & 0xffff0001)
+		BUG();
+
+	RTL_W32(OCPDR, (reg << 15));
+
+	for (i = 0; i < 10; i++) {
+		udelay(25);
+		data = RTL_R32(OCPDR);
+		if (data & OCPAR_FLAG)
+			break;
+	}
+
+	return (u16)(data & 0xffff);
+}
+
+static void r8168g_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+{
+	if (reg_addr == 0x1f)
+		return;
+
+	r8168_phy_ocp_write(ioaddr, 0xa400 + reg_addr * 2, value);
+}
+
+static int r8168g_mdio_read(void __iomem *ioaddr, int reg_addr)
+{
+	return r8168_phy_ocp_read(ioaddr, 0xa400 + reg_addr * 2);
+}
+
 static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
 {
 	int i;
@@ -1902,6 +2012,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
 		u32 val;
 		int mac_version;
 	} mac_info[] = {
+		/* 8168G family. */
+		{ 0x7cf00000, 0x4c100000,	RTL_GIGA_MAC_VER_41 },
+		{ 0x7cf00000, 0x4c000000,	RTL_GIGA_MAC_VER_40 },
+
 		/* 8168F family. */
 		{ 0x7c800000, 0x48800000,	RTL_GIGA_MAC_VER_38 },
 		{ 0x7cf00000, 0x48100000,	RTL_GIGA_MAC_VER_36 },
@@ -2241,6 +2355,92 @@ static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
 	}
 }
 
+static void rtl_ocp_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
+{
+	struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 predata, count;
+	u32 base_addr;
+	size_t index;
+
+	predata = count = 0;
+	base_addr = 0xa400;
+
+	for (index = 0; index < pa->size; ) {
+		u32 action = le32_to_cpu(pa->code[index]);
+		u32 data = action & 0x0000ffff;
+		u32 regno = (action & 0x0fff0000) >> 16;
+
+		if (!action)
+			break;
+
+		switch(action & 0xf0000000) {
+		case PHY_READ:
+			predata = r8168_phy_ocp_read(ioaddr,
+					base_addr + (regno -16) * 2);
+			count++;
+			index++;
+			break;
+		case PHY_DATA_OR:
+			predata |= data;
+			index++;
+			break;
+		case PHY_DATA_AND:
+			predata &= data;
+			index++;
+			break;
+		case PHY_BJMPN:
+			index -= regno;
+			break;
+		case PHY_CLEAR_READCOUNT:
+			count = 0;
+			index++;
+			break;
+		case PHY_WRITE:
+			if (regno == 0x1f)
+				base_addr = data << 4;
+			else
+				r8168_phy_ocp_write(ioaddr,
+						base_addr + (regno - 0x10) * 2,
+						data);
+			index++;
+			break;
+		case PHY_READCOUNT_EQ_SKIP:
+			index += (count == data) ? 2 : 1;
+			break;
+		case PHY_COMP_EQ_SKIPN:
+			if (predata == data)
+				index += regno;
+			index++;
+			break;
+		case PHY_COMP_NEQ_SKIPN:
+			if (predata != data)
+				index += regno;
+			index++;
+			break;
+		case PHY_WRITE_PREVIOUS:
+			r8168_phy_ocp_write(ioaddr, base_addr + (regno -16) * 2,
+					    predata);
+			index++;
+			break;
+		case PHY_SKIPN:
+			index += regno + 1;
+			break;
+		case PHY_DELAY_MS:
+			mdelay(data);
+			index++;
+			break;
+
+		case PHY_READ_MAC_BYTE:
+		case PHY_WRITE_MAC_BYTE:
+		case PHY_WRITE_ERI_WORD:
+		case PHY_READ_EFUSE:
+		default:
+			BUG();
+		}
+	}
+}
+
 static void rtl_release_firmware(struct rtl8169_private *tp)
 {
 	if (!IS_ERR_OR_NULL(tp->rtl_fw)) {
@@ -2256,7 +2456,7 @@ static void rtl_apply_firmware(struct rtl8169_private *tp)
 
 	/* TODO: release firmware once rtl_phy_write_fw signals failures. */
 	if (!IS_ERR_OR_NULL(rtl_fw))
-		rtl_phy_write_fw(tp, rtl_fw);
+		tp->write_fw(tp, rtl_fw);
 }
 
 static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
@@ -3221,6 +3421,56 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
 	rtl_writephy(tp, 0x1f, 0x0000);
 }
 
+static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 mac_ocp_addr, i;
+	static const u16 mac_ocp_patch[] = {
+		0xE008, 0xE01B, 0xE01D, 0xE01F,
+		0xE021, 0xE023, 0xE025, 0xE027,
+		0x49D2 ,0xF10D, 0x766C, 0x49E2,
+		0xF00A, 0x1EC0, 0x8EE1, 0xC60A,
+		0x77C0, 0x4870, 0x9FC0, 0x1EA0,
+		0xC707, 0x8EE1, 0x9D6C, 0xC603,
+		0xBE00, 0xB416, 0x0076, 0xE86C,
+		0xC602, 0xBE00, 0x0000, 0xC602,
+		0xBE00, 0x0000, 0xC602, 0xBE00,
+		0x0000, 0xC602, 0xBE00, 0x0000,
+		0xC602, 0xBE00, 0x0000, 0xC602,
+		0xBE00, 0x0000, 0xC602, 0xBE00,
+		0x0000, 0x0000, 0x0000, 0x0000
+	};
+
+	/* patch code for GPHY reset */
+	mac_ocp_addr = 0xf800;
+	for (i = 0; mac_ocp_addr < 0xf868; i++) {
+		r8168_mac_ocp_write(ioaddr, mac_ocp_addr, mac_ocp_patch[i]);
+		mac_ocp_addr += 2;
+	}
+	r8168_mac_ocp_write(ioaddr, 0xfc26, 0x8000);
+	r8168_mac_ocp_write(ioaddr, 0xfc28, 0x0075);
+
+	rtl_apply_firmware(tp);
+
+	if (r8168_phy_ocp_read(ioaddr, 0xa460) & 0x0100)
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x0000, 0x8000);
+	else
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x8000, 0x0000);
+
+	if (r8168_phy_ocp_read(ioaddr, 0xa466) & 0x0100)
+		rtl_w1w0_phy_ocp(ioaddr, 0xc41a, 0x0002, 0x0000);
+	else
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x0000, 0x0002);
+
+	rtl_w1w0_phy_ocp(ioaddr, 0xa442, 0x000c, 0x0000);
+	rtl_w1w0_phy_ocp(ioaddr, 0xa4b2, 0x0004, 0x0000);
+
+	r8168_phy_ocp_write(ioaddr, 0xa436, 0x8012);
+	rtl_w1w0_phy_ocp(ioaddr, 0xa438, 0x8000, 0x0000);
+
+	rtl_w1w0_phy_ocp(ioaddr, 0xc422, 0x4000, 0x2000);
+}
+
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
 {
 	static const struct phy_reg phy_reg_init[] = {
@@ -3407,6 +3657,13 @@ static void rtl_hw_phy_config(struct net_device *dev)
 		rtl8106e_hw_phy_config(tp);
 		break;
 
+	case RTL_GIGA_MAC_VER_40:
+		rtl8168g_1_hw_phy_config(tp);
+		break;
+
+	case RTL_GIGA_MAC_VER_41:
+		break;
+
 	default:
 		break;
 	}
@@ -3621,15 +3878,24 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_27:
 		ops->write	= r8168dp_1_mdio_write;
 		ops->read	= r8168dp_1_mdio_read;
+		tp->write_fw	= rtl_phy_write_fw;
 		break;
 	case RTL_GIGA_MAC_VER_28:
 	case RTL_GIGA_MAC_VER_31:
 		ops->write	= r8168dp_2_mdio_write;
 		ops->read	= r8168dp_2_mdio_read;
+		tp->write_fw	= rtl_phy_write_fw;
+		break;
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
+		ops->write	= r8168g_mdio_write;
+		ops->read	= r8168g_mdio_read;
+		tp->write_fw	= rtl_ocp_write_fw;
 		break;
 	default:
 		ops->write	= r8169_mdio_write;
 		ops->read	= r8169_mdio_read;
+		tp->write_fw	= rtl_phy_write_fw;
 		break;
 	}
 }
@@ -3647,6 +3913,8 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_37:
 	case RTL_GIGA_MAC_VER_38:
 	case RTL_GIGA_MAC_VER_39:
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
 		RTL_W32(RxConfig, RTL_R32(RxConfig) |
 			AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
 		break;
@@ -3895,6 +4163,8 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_35:
 	case RTL_GIGA_MAC_VER_36:
 	case RTL_GIGA_MAC_VER_38:
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
 		ops->down	= r8168_pll_power_down;
 		ops->up		= r8168_pll_power_up;
 		break;
@@ -4183,6 +4453,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
 	           tp->mac_version == RTL_GIGA_MAC_VER_35 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_36 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_37 ||
+	           tp->mac_version == RTL_GIGA_MAC_VER_40 ||
+	           tp->mac_version == RTL_GIGA_MAC_VER_41 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_38) {
 		RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
 		while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
@@ -4921,6 +5193,28 @@ static void rtl_hw_start_8411(struct rtl8169_private *tp)
 		     ERIAR_EXGMAC);
 }
 
+static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	struct pci_dev *pdev = tp->pci_dev;
+
+	rtl_eri_write(ioaddr, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+	rtl_csi_access_enable_1(tp);
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+	RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
+	RTL_W8(MaxTxPacketSize, EarlySize);
+	rtl_eri_write(ioaddr, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+	rtl_w1w0_eri(ioaddr, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
+}
+
 static void rtl_hw_start_8168(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -5022,6 +5316,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
 		rtl_hw_start_8411(tp);
 		break;
 
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
+		rtl_hw_start_8168g_1(tp);
+		break;
+
 	default:
 		printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
 			dev->name, tp->mac_version);
@@ -6491,6 +6790,47 @@ static unsigned rtl_try_msi(struct rtl8169_private *tp,
 	return msi;
 }
 
+static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 tmp_data;
+
+	RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
+	while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
+		udelay(100);
+
+	while ((RTL_R8(MCU) & (TX_EMPTY | RX_EMPTY)) != (TX_EMPTY | RX_EMPTY))
+		udelay(100);
+
+	RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
+	msleep(1);
+	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
+
+	tmp_data = r8168_mac_ocp_read(ioaddr, 0xe8de);
+	tmp_data &= ~(1 << 14);
+	r8168_mac_ocp_write(ioaddr, 0xe8de, tmp_data);
+	while (!(RTL_R8(MCU) & LINK_LIST_RDY))
+		udelay(100);
+
+	tmp_data = r8168_mac_ocp_read(ioaddr, 0xe8de);
+	tmp_data |= (1 << 15);
+	r8168_mac_ocp_write(ioaddr, 0xe8de, tmp_data);
+	while (!(RTL_R8(MCU) & LINK_LIST_RDY))
+		udelay(100);
+}
+
+static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
+{
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
+		rtl_hw_init_8168g(tp);
+		break;
+	default:
+		break;
+	}
+}
+
 static int __devinit
 rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -6600,6 +6940,8 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	rtl_irq_disable(tp);
 
+	rtl_hw_initialize(tp);
+
 	rtl_hw_reset(tp);
 
 	rtl_ack_events(tp, 0xffff);
-- 
1.7.10.2

Re: [PATCH net-next 1/2] r8169: support RTL8106E

From: Francois Romieu <romieu@fr.zoreil.com>
Date: 2012-06-29 14:02:05

Hayes Wang [off-list ref] :
[...]
Support the new chip RTL8106E.
I'll give it a try this week end.

Thanks.

-- 
Ueimor

Re: [PATCH net-next 2/2] r8169: support RTL8168G

From: Francois Romieu <romieu@fr.zoreil.com>
Date: 2012-06-29 14:02:21

Hayes Wang [off-list ref] :
[...]
quoted hunk
@@ -264,6 +267,11 @@ static const struct {
 	[RTL_GIGA_MAC_VER_39] =
 		_R("RTL8106e",		RTL_TD_1, FIRMWARE_8106E_1,
 							JUMBO_1K, true),
+	[RTL_GIGA_MAC_VER_40] =
+		_R("RTL8168g/8111g",	RTL_TD_1, FIRMWARE_8168G_1,
+							JUMBO_9K, false),
+	[RTL_GIGA_MAC_VER_41] =
+		_R("RTL8168g/8111g",	RTL_TD_1, NULL, JUMBO_9K, false),
You may explicitely state that jumbo operation requires no special action
by completing rtl_init_jumbo_ops.

(no checksuming with jumbo, sigh)

[...]
quoted hunk
 static void rtl_lock_work(struct rtl8169_private *tp)
 {
@@ -919,6 +936,99 @@ static int r8168dp_check_dash(struct rtl8169_private *tp)
 	return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
 }
 
+static void r8168_phy_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
+{
+	int i;
+
+	if (reg & 0xffff0001)
+		BUG();
The patch adds a lot of BUG(). BUG is terrible from a system or end user
viewpoint.

Were they only a devel helper or are they still supposed to be of use
in the future ? If the latter applies, why ?

[...]
+static u16 r8168_phy_ocp_read(void __iomem *ioaddr, u32 reg)
+{
+	int i;
+	u32 data;
+
+	if (reg & 0xffff0001)
+		BUG();
+
+	RTL_W32(GPHY_OCP, (reg << 15));
You can save on parenthesis here.

[...]
+static void r8168g_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+{
+	if (reg_addr == 0x1f)
+		return;
+
+	r8168_phy_ocp_write(ioaddr, 0xa400 + reg_addr * 2, value);
+}
+
+static int r8168g_mdio_read(void __iomem *ioaddr, int reg_addr)
+{
+	return r8168_phy_ocp_read(ioaddr, 0xa400 + reg_addr * 2);
+}
#define XYZ_{BASE/OFFSET}	0xa400 ?

[...]
quoted hunk
@@ -2241,6 +2355,92 @@ static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
 	}
 }
 
+static void rtl_ocp_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
+{
+	struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 predata, count;
+	u32 base_addr;
+	size_t index;
+
+	predata = count = 0;
+	base_addr = 0xa400;
+
+	for (index = 0; index < pa->size; ) {
+		u32 action = le32_to_cpu(pa->code[index]);
+		u32 data = action & 0x0000ffff;
+		u32 regno = (action & 0x0fff0000) >> 16;
+
+		if (!action)
+			break;
+
+		switch(action & 0xf0000000) {
+		case PHY_READ:
+			predata = r8168_phy_ocp_read(ioaddr,
+					base_addr + (regno -16) * 2);
+			count++;
+			index++;
+			break;
[duplicated code removed]
+		case PHY_WRITE:
+			if (regno == 0x1f)
+				base_addr = data << 4;
+			else
+				r8168_phy_ocp_write(ioaddr,
+						base_addr + (regno - 0x10) * 2,
+						data);
+			index++;
+			break;
[duplicated code removed]
+		case PHY_WRITE_PREVIOUS:
+			r8168_phy_ocp_write(ioaddr, base_addr + (regno -16) * 2,
+					    predata);
+			index++;
+			break;
I can't believe that the hardware people have designed something which
needs a different firmware write method, especially as it copies at lot
of code.

How did you come to the conclusion that it was not possible to hide this
stuff behind r8168g_mdio_{read / write} ?

I would not mind replacing the PHY_{READ/WRITE/WRITE_PREVIOUS} case with
chipset specific {READ/WRITE/WRITE_PREVIOUS} methods as long as the
semantic looks the same but going through a different (*write_fw) does not
trivially seem to be the best abstraction.

[...]
quoted hunk
@@ -3221,6 +3421,56 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
 	rtl_writephy(tp, 0x1f, 0x0000);
 }
 
+static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 mac_ocp_addr, i;
+	static const u16 mac_ocp_patch[] = {
+		0xE008, 0xE01B, 0xE01D, 0xE01F,
+		0xE021, 0xE023, 0xE025, 0xE027,
+		0x49D2 ,0xF10D, 0x766C, 0x49E2,
+		0xF00A, 0x1EC0, 0x8EE1, 0xC60A,
+		0x77C0, 0x4870, 0x9FC0, 0x1EA0,
+		0xC707, 0x8EE1, 0x9D6C, 0xC603,
+		0xBE00, 0xB416, 0x0076, 0xE86C,
+		0xC602, 0xBE00, 0x0000, 0xC602,
+		0xBE00, 0x0000, 0xC602, 0xBE00,
+		0x0000, 0xC602, 0xBE00, 0x0000,
+		0xC602, 0xBE00, 0x0000, 0xC602,
+		0xBE00, 0x0000, 0xC602, 0xBE00,
+		0x0000, 0x0000, 0x0000, 0x0000
Please s/\(.*\)/\L\1/
+	};
+
+	/* patch code for GPHY reset */
+	mac_ocp_addr = 0xf800;
+	for (i = 0; mac_ocp_addr < 0xf868; i++) {
+		r8168_mac_ocp_write(ioaddr, mac_ocp_addr, mac_ocp_patch[i]);
+		mac_ocp_addr += 2;
+	}
	for (i = 0; i < ARRAY_SIZE(mac_ocp_patch); i++)
		r8168_mac_ocp_write(ioaddr, 0xf800 + 2*i, mac_ocp_patch[i]);

The array must be correctly sized anyway. :o)

You may save a bit on the 'mac_ocp_patch' identifier and replace 0xf800 with
a #define.
+	r8168_mac_ocp_write(ioaddr, 0xfc26, 0x8000);
+	r8168_mac_ocp_write(ioaddr, 0xfc28, 0x0075);
+
+	rtl_apply_firmware(tp);
+
+	if (r8168_phy_ocp_read(ioaddr, 0xa460) & 0x0100)
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x0000, 0x8000);
+	else
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x8000, 0x0000);
+
+	if (r8168_phy_ocp_read(ioaddr, 0xa466) & 0x0100)
+		rtl_w1w0_phy_ocp(ioaddr, 0xc41a, 0x0002, 0x0000);
+	else
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x0000, 0x0002);
+
+	rtl_w1w0_phy_ocp(ioaddr, 0xa442, 0x000c, 0x0000);
+	rtl_w1w0_phy_ocp(ioaddr, 0xa4b2, 0x0004, 0x0000);
+
+	r8168_phy_ocp_write(ioaddr, 0xa436, 0x8012);
+	rtl_w1w0_phy_ocp(ioaddr, 0xa438, 0x8000, 0x0000);
+
+	rtl_w1w0_phy_ocp(ioaddr, 0xc422, 0x4000, 0x2000);
+}
Is there any chance for this part to be a bit more literate ?

[...]
quoted hunk
@@ -4921,6 +5193,28 @@ static void rtl_hw_start_8411(struct rtl8169_private *tp)
 		     ERIAR_EXGMAC);
 }
 
+static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	struct pci_dev *pdev = tp->pci_dev;
+
+	rtl_eri_write(ioaddr, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+	rtl_csi_access_enable_1(tp);
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+	RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
+	RTL_W8(MaxTxPacketSize, EarlySize);
+	rtl_eri_write(ioaddr, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+	rtl_w1w0_eri(ioaddr, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
+}
(ok, now it can be compared with similar functions)

[...]
quoted hunk
@@ -6491,6 +6790,47 @@ static unsigned rtl_try_msi(struct rtl8169_private *tp,
 	return msi;
 }
 
+static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 tmp_data;
+
+	RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
+	while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
+		udelay(100);
+
+	while ((RTL_R8(MCU) & (TX_EMPTY | RX_EMPTY)) != (TX_EMPTY | RX_EMPTY))
+		udelay(100);
#define RXTX_EMPTY	(TX_EMPTY | RX_EMPTY) ?
+
+	RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
+	msleep(1);
+	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
+
+	tmp_data = r8168_mac_ocp_read(ioaddr, 0xe8de);
+	tmp_data &= ~(1 << 14);
+	r8168_mac_ocp_write(ioaddr, 0xe8de, tmp_data);
+	while (!(RTL_R8(MCU) & LINK_LIST_RDY))
+		udelay(100);
+
+	tmp_data = r8168_mac_ocp_read(ioaddr, 0xe8de);
Same 0xe8de offset used twice. #define ?
+	tmp_data |= (1 << 15);
+	r8168_mac_ocp_write(ioaddr, 0xe8de, tmp_data);
+	while (!(RTL_R8(MCU) & LINK_LIST_RDY))
+		udelay(100);
+}
+
+static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
+{
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
+		rtl_hw_init_8168g(tp);
+		break;
+	default:
+		break;
+	}
+}
Why doesn't it belong to hw_start ?

Is it completely unneeded if the device requires a rtl8169_hw_reset,
resumes or such ?

Thanks.

-- 
Ueimor

RE: [PATCH net-next 2/2] r8169: support RTL8168G

From: hayeswang <hidden>
Date: 2012-07-02 07:28:25

[...]
quoted
+static void r8168_phy_ocp_write(void __iomem *ioaddr, u32 
reg, u32 data)
quoted
+{
+	int i;
+
+	if (reg & 0xffff0001)
+		BUG();
The patch adds a lot of BUG(). BUG is terrible from a system 
or end user
viewpoint.

Were they only a devel helper or are they still supposed to be of use
in the future ? If the latter applies, why ?
I think if the reg is invalid, there must be something wrong. The code should
have bug, and I should notice develper or someone using the code. I would
replace them with showing messages.

[...]
quoted
+static void rtl_ocp_write_fw(struct rtl8169_private *tp, 
struct rtl_fw *rtl_fw)
quoted
+{
+	struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 predata, count;
+	u32 base_addr;
+	size_t index;
+
+	predata = count = 0;
+	base_addr = 0xa400;
+
+	for (index = 0; index < pa->size; ) {
+		u32 action = le32_to_cpu(pa->code[index]);
+		u32 data = action & 0x0000ffff;
+		u32 regno = (action & 0x0fff0000) >> 16;
+
+		if (!action)
+			break;
+
+		switch(action & 0xf0000000) {
+		case PHY_READ:
+			predata = r8168_phy_ocp_read(ioaddr,
+					base_addr + (regno -16) * 2);
+			count++;
+			index++;
+			break;
[duplicated code removed]
quoted
+		case PHY_WRITE:
+			if (regno == 0x1f)
+				base_addr = data << 4;
+			else
+				r8168_phy_ocp_write(ioaddr,
+						base_addr + 
(regno - 0x10) * 2,
quoted
+						data);
+			index++;
+			break;
[duplicated code removed]
quoted
+		case PHY_WRITE_PREVIOUS:
+			r8168_phy_ocp_write(ioaddr, base_addr + 
(regno -16) * 2,
quoted
+					    predata);
+			index++;
+			break;
I can't believe that the hardware people have designed something which
needs a different firmware write method, especially as it 
copies at lot
of code.

How did you come to the conclusion that it was not possible 
to hide this
stuff behind r8168g_mdio_{read / write} ?

I would not mind replacing the 
PHY_{READ/WRITE/WRITE_PREVIOUS} case with
chipset specific {READ/WRITE/WRITE_PREVIOUS} methods as long as the
semantic looks the same but going through a different 
(*write_fw) does not
trivially seem to be the best abstraction.
The difficulty is how to deal with the base_addr. Although it should not happen,
the base_addr may be modify if two threads access phy at the same time.  I would
replace the method by saving the base_addr with a global variable. Then, the
r8168g_mdio functions could deal with both of the firmware and phy settings.

[...]
quoted
+static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
+{
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
+		rtl_hw_init_8168g(tp);
+		break;
+	default:
+		break;
+	}
+}
Why doesn't it belong to hw_start ?
According to the initialization process from our hardware, there are something
needed to do before reset. Maybe this considers the rebooting from the other OS
or hwardware behavior.  I don't sure if it is safe, to let them belong to
hw_start.
Is it completely unneeded if the device requires a rtl8169_hw_reset,
resumes or such ?
By the information from our hardware, these are the initial settings and only
need be done once. 

Best Regards,
Hayes

[PATCH v2 net-next 1/2] r8169: support RTL8106E

From: Hayes Wang <hidden>
Date: 2012-07-02 09:22:50

Support the new chip RTL8106E.

Signed-off-by: Hayes Wang <redacted>
---
 drivers/net/ethernet/realtek/r8169.c |   56 ++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index d7a04e0..7afc593 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -46,6 +46,7 @@
 #define FIRMWARE_8105E_1	"rtl_nic/rtl8105e-1.fw"
 #define FIRMWARE_8402_1		"rtl_nic/rtl8402-1.fw"
 #define FIRMWARE_8411_1		"rtl_nic/rtl8411-1.fw"
+#define FIRMWARE_8106E_1	"rtl_nic/rtl8106e-1.fw"
 
 #ifdef RTL8169_DEBUG
 #define assert(expr) \
@@ -141,6 +142,7 @@ enum mac_version {
 	RTL_GIGA_MAC_VER_36,
 	RTL_GIGA_MAC_VER_37,
 	RTL_GIGA_MAC_VER_38,
+	RTL_GIGA_MAC_VER_39,
 	RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -259,6 +261,9 @@ static const struct {
 	[RTL_GIGA_MAC_VER_38] =
 		_R("RTL8411",		RTL_TD_1, FIRMWARE_8411_1,
 							JUMBO_9K, false),
+	[RTL_GIGA_MAC_VER_39] =
+		_R("RTL8106e",		RTL_TD_1, FIRMWARE_8106E_1,
+							JUMBO_1K, true),
 };
 #undef _R
 
@@ -431,7 +436,9 @@ enum rtl8168_registers {
 	RDSAR1			= 0xd0,	/* 8168c only. Undocumented on 8168dp */
 	MISC			= 0xf0,	/* 8168e only. */
 #define TXPLA_RST			(1 << 29)
+#define DISABLE_LAN_EN			(1 << 23) /* Enable GPIO pin */
 #define PWM_EN				(1 << 22)
+#define EARLY_TALLY_EN			(1 << 16)
 };
 
 enum rtl_register_content {
@@ -794,6 +801,7 @@ MODULE_FIRMWARE(FIRMWARE_8168F_1);
 MODULE_FIRMWARE(FIRMWARE_8168F_2);
 MODULE_FIRMWARE(FIRMWARE_8402_1);
 MODULE_FIRMWARE(FIRMWARE_8411_1);
+MODULE_FIRMWARE(FIRMWARE_8106E_1);
 
 static void rtl_lock_work(struct rtl8169_private *tp)
 {
@@ -1933,6 +1941,8 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
 		{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },
 
 		/* 8101 family. */
+		{ 0x7cf00000, 0x44900000,	RTL_GIGA_MAC_VER_39 },
+		{ 0x7c800000, 0x44800000,	RTL_GIGA_MAC_VER_39 },
 		{ 0x7c800000, 0x44000000,	RTL_GIGA_MAC_VER_37 },
 		{ 0x7cf00000, 0x40b00000,	RTL_GIGA_MAC_VER_30 },
 		{ 0x7cf00000, 0x40a00000,	RTL_GIGA_MAC_VER_30 },
@@ -3273,6 +3283,30 @@ static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
 	rtl_writephy(tp, 0x1f, 0x0000);
 }
 
+static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	static const struct phy_reg phy_reg_init[] = {
+		{ 0x1f, 0x0004 },
+		{ 0x10, 0xc07f },
+		{ 0x19, 0x7030 },
+		{ 0x1f, 0x0000 }
+	};
+
+	/* Disable ALDPS before ram code */
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_writephy(tp, 0x18, 0x0310);
+	msleep(100);
+
+	rtl_apply_firmware(tp);
+
+	rtl_eri_write(ioaddr, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	rtl_eri_write(ioaddr, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+}
+
 static void rtl_hw_phy_config(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -3369,6 +3403,10 @@ static void rtl_hw_phy_config(struct net_device *dev)
 		rtl8411_hw_phy_config(tp);
 		break;
 
+	case RTL_GIGA_MAC_VER_39:
+		rtl8106e_hw_phy_config(tp);
+		break;
+
 	default:
 		break;
 	}
@@ -3608,6 +3646,7 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_34:
 	case RTL_GIGA_MAC_VER_37:
 	case RTL_GIGA_MAC_VER_38:
+	case RTL_GIGA_MAC_VER_39:
 		RTL_W32(RxConfig, RTL_R32(RxConfig) |
 			AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
 		break;
@@ -3830,6 +3869,7 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_29:
 	case RTL_GIGA_MAC_VER_30:
 	case RTL_GIGA_MAC_VER_37:
+	case RTL_GIGA_MAC_VER_39:
 		ops->down	= r810x_pll_power_down;
 		ops->up		= r810x_pll_power_up;
 		break;
@@ -5123,6 +5163,18 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp)
 		     ERIAR_EXGMAC);
 }
 
+static void rtl_hw_start_8106(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	/* Force LAN exit from ASPM if Rx/Tx are not idle */
+	RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
+
+	RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
+	RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
+	RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
+}
+
 static void rtl_hw_start_8101(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -5167,6 +5219,10 @@ static void rtl_hw_start_8101(struct net_device *dev)
 	case RTL_GIGA_MAC_VER_37:
 		rtl_hw_start_8402(tp);
 		break;
+
+	case RTL_GIGA_MAC_VER_39:
+		rtl_hw_start_8106(tp);
+		break;
 	}
 
 	RTL_W8(Cfg9346, Cfg9346_Lock);
-- 
1.7.10.2

[PATCH v2 net-next 2/2] r8169: support RTL8168G

From: Hayes Wang <hidden>
Date: 2012-07-02 09:22:50

Support the new chip RTL8168G.
For RTL8111G, the settings of phy and firmware are replaced with ocp functions.
The r8168g_mdio_{write / read} would redirect the relative settings to suitable
opc functions. However, a global variable ocp_base is needed to calculate the
real address of ocp functions. rtl_writephy(tp, 0x1f, xxxx) means the changing
of ocp_base.

Signed-off-by: Hayes Wang <redacted>
---
 drivers/net/ethernet/realtek/r8169.c |  308 ++++++++++++++++++++++++++++++++--
 1 file changed, 296 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 7afc593..0cf8626 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -47,6 +47,7 @@
 #define FIRMWARE_8402_1		"rtl_nic/rtl8402-1.fw"
 #define FIRMWARE_8411_1		"rtl_nic/rtl8411-1.fw"
 #define FIRMWARE_8106E_1	"rtl_nic/rtl8106e-1.fw"
+#define FIRMWARE_8168G_1	"rtl_nic/rtl8168g-1.fw"
 
 #ifdef RTL8169_DEBUG
 #define assert(expr) \
@@ -143,6 +144,8 @@ enum mac_version {
 	RTL_GIGA_MAC_VER_37,
 	RTL_GIGA_MAC_VER_38,
 	RTL_GIGA_MAC_VER_39,
+	RTL_GIGA_MAC_VER_40,
+	RTL_GIGA_MAC_VER_41,
 	RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -264,6 +267,11 @@ static const struct {
 	[RTL_GIGA_MAC_VER_39] =
 		_R("RTL8106e",		RTL_TD_1, FIRMWARE_8106E_1,
 							JUMBO_1K, true),
+	[RTL_GIGA_MAC_VER_40] =
+		_R("RTL8168g/8111g",	RTL_TD_1, FIRMWARE_8168G_1,
+							JUMBO_9K, false),
+	[RTL_GIGA_MAC_VER_41] =
+		_R("RTL8168g/8111g",	RTL_TD_1, NULL, JUMBO_9K, false),
 };
 #undef _R
 
@@ -394,8 +402,12 @@ enum rtl8168_8101_registers {
 	TWSI			= 0xd2,
 	MCU			= 0xd3,
 #define	NOW_IS_OOB			(1 << 7)
+#define TX_EMPTY			(1 << 5)
+#define RX_EMPTY			(1 << 4)
+#define RXTX_EMPTY			(TX_EMPTY | RX_EMPTY)
 #define	EN_NDP				(1 << 3)
 #define	EN_OOB_RESET			(1 << 2)
+#define LINK_LIST_RDY			(1 << 1)
 	EFUSEAR			= 0xdc,
 #define	EFUSEAR_FLAG			0x80000000
 #define	EFUSEAR_WRITE_CMD		0x80000000
@@ -421,6 +433,7 @@ enum rtl8168_registers {
 #define ERIAR_MASK_SHIFT		12
 #define ERIAR_MASK_0001			(0x1 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_0011			(0x3 << ERIAR_MASK_SHIFT)
+#define ERIAR_MASK_0101			(0x5 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_1111			(0xf << ERIAR_MASK_SHIFT)
 	EPHY_RXER_NUM		= 0x7c,
 	OCPDR			= 0xb0,	/* OCP GPHY access */
@@ -433,11 +446,13 @@ enum rtl8168_registers {
 #define OCPAR_FLAG			0x80000000
 #define OCPAR_GPHY_WRITE_CMD		0x8000f060
 #define OCPAR_GPHY_READ_CMD		0x0000f060
+	GPHY_OCP		= 0xb8,
 	RDSAR1			= 0xd0,	/* 8168c only. Undocumented on 8168dp */
 	MISC			= 0xf0,	/* 8168e only. */
 #define TXPLA_RST			(1 << 29)
 #define DISABLE_LAN_EN			(1 << 23) /* Enable GPIO pin */
 #define PWM_EN				(1 << 22)
+#define RXDV_GATED_EN			(1 << 19)
 #define EARLY_TALLY_EN			(1 << 16)
 };
 
@@ -728,8 +743,8 @@ struct rtl8169_private {
 	u16 event_slow;
 
 	struct mdio_ops {
-		void (*write)(void __iomem *, int, int);
-		int (*read)(void __iomem *, int);
+		void (*write)(struct rtl8169_private *, int, int);
+		int (*read)(struct rtl8169_private *, int);
 	} mdio_ops;
 
 	struct pll_power_ops {
@@ -781,6 +796,8 @@ struct rtl8169_private {
 		} phy_action;
 	} *rtl_fw;
 #define RTL_FIRMWARE_UNKNOWN	ERR_PTR(-EAGAIN)
+
+	u32 ocp_base;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -802,6 +819,7 @@ MODULE_FIRMWARE(FIRMWARE_8168F_2);
 MODULE_FIRMWARE(FIRMWARE_8402_1);
 MODULE_FIRMWARE(FIRMWARE_8411_1);
 MODULE_FIRMWARE(FIRMWARE_8106E_1);
+MODULE_FIRMWARE(FIRMWARE_8168G_1);
 
 static void rtl_lock_work(struct rtl8169_private *tp)
 {
@@ -919,9 +937,125 @@ static int r8168dp_check_dash(struct rtl8169_private *tp)
 	return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
 }
 
-static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+static void r8168_phy_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
+{
+	int i;
+
+	if (reg & 0xffff0001) {
+		printk(KERN_ERR "Invalid ocp reg %x!\n", reg);
+		return;
+	}
+
+	RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
+
+	for (i = 0; i < 10; i++) {
+		udelay(25);
+		if (!(RTL_R32(GPHY_OCP) & OCPAR_FLAG))
+			break;
+	}
+}
+
+static u16 r8168_phy_ocp_read(void __iomem *ioaddr, u32 reg)
+{
+	int i;
+	u32 data;
+
+	if (reg & 0xffff0001) {
+		printk(KERN_ERR "Invalid ocp reg %x!\n", reg);
+		return 0;
+	}
+
+	RTL_W32(GPHY_OCP, reg << 15);
+
+	for (i = 0; i < 10; i++) {
+		udelay(25);
+		data = RTL_R32(GPHY_OCP);
+		if (data & OCPAR_FLAG)
+			break;
+	}
+
+	return (u16)(data & 0xffff);
+}
+
+static void rtl_w1w0_phy_ocp(void __iomem *ioaddr, int reg_addr, int p, int m)
+{
+	int val;
+
+	val = r8168_phy_ocp_read(ioaddr, reg_addr);
+	r8168_phy_ocp_write(ioaddr, reg_addr, (val | p) & ~m);
+}
+
+static void r8168_mac_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
+{
+	int i;
+
+	if (reg & 0xffff0001)
+		BUG();
+
+	RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
+
+	for (i = 0; i < 10; i++) {
+		udelay(25);
+		if (!(RTL_R32(OCPDR) & OCPAR_FLAG))
+			break;
+	}
+}
+
+static u16 r8168_mac_ocp_read(void __iomem *ioaddr, u32 reg)
+{
+	int i;
+	u32 data;
+
+	if (reg & 0xffff0001)
+		BUG();
+
+	RTL_W32(OCPDR, (reg << 15));
+
+	for (i = 0; i < 10; i++) {
+		udelay(25);
+		data = RTL_R32(OCPDR);
+		if (data & OCPAR_FLAG)
+			break;
+	}
+
+	return (u16)(data & 0xffff);
+}
+
+#define OCP_STD_PHY_BASE	0xa400
+
+static
+void r8168g_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	if (reg_addr == 0x1f) {
+		if (reg_addr == 0)
+			tp->ocp_base = OCP_STD_PHY_BASE;
+		else
+			tp->ocp_base = value << 4;
+
+		return;
+	} else if (tp->ocp_base != OCP_STD_PHY_BASE)
+		reg_addr -= 0x10;
+
+	r8168_phy_ocp_write(ioaddr, tp->ocp_base + reg_addr * 2, value);
+}
+
+static int r8168g_mdio_read(struct rtl8169_private *tp, int reg_addr)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	if (tp->ocp_base != OCP_STD_PHY_BASE)
+		reg_addr -= 0x10;
+
+	return r8168_phy_ocp_read(ioaddr, tp->ocp_base + reg_addr * 2);
+}
+
+static
+void r8169_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
 {
 	int i;
+	void __iomem *ioaddr = tp->mmio_addr;
 
 	RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
 
@@ -941,9 +1075,10 @@ static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
 	udelay(20);
 }
 
-static int r8169_mdio_read(void __iomem *ioaddr, int reg_addr)
+static int r8169_mdio_read(struct rtl8169_private *tp, int reg_addr)
 {
 	int i, value = -1;
+	void __iomem *ioaddr = tp->mmio_addr;
 
 	RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
 
@@ -983,15 +1118,19 @@ static void r8168dp_1_mdio_access(void __iomem *ioaddr, int reg_addr, u32 data)
 	}
 }
 
-static void r8168dp_1_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+static
+void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
 {
+	void __iomem *ioaddr = tp->mmio_addr;
+
 	r8168dp_1_mdio_access(ioaddr, reg_addr, OCPDR_WRITE_CMD |
 		(value & OCPDR_DATA_MASK));
 }
 
-static int r8168dp_1_mdio_read(void __iomem *ioaddr, int reg_addr)
+static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg_addr)
 {
 	int i;
+	void __iomem *ioaddr = tp->mmio_addr;
 
 	r8168dp_1_mdio_access(ioaddr, reg_addr, OCPDR_READ_CMD);
 
@@ -1020,22 +1159,26 @@ static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
 	RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
 }
 
-static void r8168dp_2_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+static
+void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
 {
+	void __iomem *ioaddr = tp->mmio_addr;
+
 	r8168dp_2_mdio_start(ioaddr);
 
-	r8169_mdio_write(ioaddr, reg_addr, value);
+	r8169_mdio_write(tp, reg_addr, value);
 
 	r8168dp_2_mdio_stop(ioaddr);
 }
 
-static int r8168dp_2_mdio_read(void __iomem *ioaddr, int reg_addr)
+static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg_addr)
 {
 	int value;
+	void __iomem *ioaddr = tp->mmio_addr;
 
 	r8168dp_2_mdio_start(ioaddr);
 
-	value = r8169_mdio_read(ioaddr, reg_addr);
+	value = r8169_mdio_read(tp, reg_addr);
 
 	r8168dp_2_mdio_stop(ioaddr);
 
@@ -1044,12 +1187,12 @@ static int r8168dp_2_mdio_read(void __iomem *ioaddr, int reg_addr)
 
 static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
 {
-	tp->mdio_ops.write(tp->mmio_addr, location, val);
+	tp->mdio_ops.write(tp, location, val);
 }
 
 static int rtl_readphy(struct rtl8169_private *tp, int location)
 {
-	return tp->mdio_ops.read(tp->mmio_addr, location);
+	return tp->mdio_ops.read(tp, location);
 }
 
 static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
@@ -1902,6 +2045,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
 		u32 val;
 		int mac_version;
 	} mac_info[] = {
+		/* 8168G family. */
+		{ 0x7cf00000, 0x4c100000,	RTL_GIGA_MAC_VER_41 },
+		{ 0x7cf00000, 0x4c000000,	RTL_GIGA_MAC_VER_40 },
+
 		/* 8168F family. */
 		{ 0x7c800000, 0x48800000,	RTL_GIGA_MAC_VER_38 },
 		{ 0x7cf00000, 0x48100000,	RTL_GIGA_MAC_VER_36 },
@@ -3221,6 +3368,53 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
 	rtl_writephy(tp, 0x1f, 0x0000);
 }
 
+static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 i;
+	static const u16 mac_ocp_patch[] = {
+		0xe008, 0xe01b, 0xe01d, 0xe01f,
+		0xe021, 0xe023, 0xe025, 0xe027,
+		0x49d2 ,0xf10d, 0x766c, 0x49e2,
+		0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
+		0x77c0, 0x4870, 0x9fc0, 0x1ea0,
+		0xc707, 0x8ee1, 0x9d6c, 0xc603,
+		0xbe00, 0xb416, 0x0076, 0xe86c,
+		0xc602, 0xbe00, 0x0000, 0xc602,
+		0xbe00, 0x0000, 0xc602, 0xbe00,
+		0x0000, 0xc602, 0xbe00, 0x0000,
+		0xc602, 0xbe00, 0x0000, 0xc602,
+		0xbe00, 0x0000, 0xc602, 0xbe00,
+		0x0000, 0x0000, 0x0000, 0x0000
+	};
+
+	/* patch code for GPHY reset */
+	for (i = 0; ARRAY_SIZE(mac_ocp_patch); i++)
+		r8168_mac_ocp_write(ioaddr, 0xf800 + 2*i, mac_ocp_patch[i]);
+	r8168_mac_ocp_write(ioaddr, 0xfc26, 0x8000);
+	r8168_mac_ocp_write(ioaddr, 0xfc28, 0x0075);
+
+	rtl_apply_firmware(tp);
+
+	if (r8168_phy_ocp_read(ioaddr, 0xa460) & 0x0100)
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x0000, 0x8000);
+	else
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x8000, 0x0000);
+
+	if (r8168_phy_ocp_read(ioaddr, 0xa466) & 0x0100)
+		rtl_w1w0_phy_ocp(ioaddr, 0xc41a, 0x0002, 0x0000);
+	else
+		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x0000, 0x0002);
+
+	rtl_w1w0_phy_ocp(ioaddr, 0xa442, 0x000c, 0x0000);
+	rtl_w1w0_phy_ocp(ioaddr, 0xa4b2, 0x0004, 0x0000);
+
+	r8168_phy_ocp_write(ioaddr, 0xa436, 0x8012);
+	rtl_w1w0_phy_ocp(ioaddr, 0xa438, 0x8000, 0x0000);
+
+	rtl_w1w0_phy_ocp(ioaddr, 0xc422, 0x4000, 0x2000);
+}
+
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
 {
 	static const struct phy_reg phy_reg_init[] = {
@@ -3407,6 +3601,13 @@ static void rtl_hw_phy_config(struct net_device *dev)
 		rtl8106e_hw_phy_config(tp);
 		break;
 
+	case RTL_GIGA_MAC_VER_40:
+		rtl8168g_1_hw_phy_config(tp);
+		break;
+
+	case RTL_GIGA_MAC_VER_41:
+		break;
+
 	default:
 		break;
 	}
@@ -3627,6 +3828,11 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
 		ops->write	= r8168dp_2_mdio_write;
 		ops->read	= r8168dp_2_mdio_read;
 		break;
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
+		ops->write	= r8168g_mdio_write;
+		ops->read	= r8168g_mdio_read;
+		break;
 	default:
 		ops->write	= r8169_mdio_write;
 		ops->read	= r8169_mdio_read;
@@ -3647,6 +3853,8 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_37:
 	case RTL_GIGA_MAC_VER_38:
 	case RTL_GIGA_MAC_VER_39:
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
 		RTL_W32(RxConfig, RTL_R32(RxConfig) |
 			AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
 		break;
@@ -3895,6 +4103,8 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_35:
 	case RTL_GIGA_MAC_VER_36:
 	case RTL_GIGA_MAC_VER_38:
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
 		ops->down	= r8168_pll_power_down;
 		ops->up		= r8168_pll_power_up;
 		break;
@@ -4091,6 +4301,8 @@ static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
 	 * No action needed for jumbo frames with 8169.
 	 * No jumbo for 810x at all.
 	 */
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
 	default:
 		ops->disable	= NULL;
 		ops->enable	= NULL;
@@ -4183,6 +4395,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
 	           tp->mac_version == RTL_GIGA_MAC_VER_35 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_36 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_37 ||
+	           tp->mac_version == RTL_GIGA_MAC_VER_40 ||
+	           tp->mac_version == RTL_GIGA_MAC_VER_41 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_38) {
 		RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
 		while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
@@ -4921,6 +5135,28 @@ static void rtl_hw_start_8411(struct rtl8169_private *tp)
 		     ERIAR_EXGMAC);
 }
 
+static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	struct pci_dev *pdev = tp->pci_dev;
+
+	rtl_eri_write(ioaddr, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+	rtl_csi_access_enable_1(tp);
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+	RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
+	RTL_W8(MaxTxPacketSize, EarlySize);
+	rtl_eri_write(ioaddr, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+	rtl_w1w0_eri(ioaddr, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
+}
+
 static void rtl_hw_start_8168(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -5022,6 +5258,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
 		rtl_hw_start_8411(tp);
 		break;
 
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
+		rtl_hw_start_8168g_1(tp);
+		break;
+
 	default:
 		printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
 			dev->name, tp->mac_version);
@@ -6491,6 +6732,47 @@ static unsigned rtl_try_msi(struct rtl8169_private *tp,
 	return msi;
 }
 
+static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	u32 tmp_data;
+
+	RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
+	while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
+		udelay(100);
+
+	while ((RTL_R8(MCU) & RXTX_EMPTY) != RXTX_EMPTY)
+		udelay(100);
+
+	RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
+	msleep(1);
+	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
+
+	tmp_data = r8168_mac_ocp_read(ioaddr, 0xe8de);
+	tmp_data &= ~(1 << 14);
+	r8168_mac_ocp_write(ioaddr, 0xe8de, tmp_data);
+	while (!(RTL_R8(MCU) & LINK_LIST_RDY))
+		udelay(100);
+
+	tmp_data = r8168_mac_ocp_read(ioaddr, 0xe8de);
+	tmp_data |= (1 << 15);
+	r8168_mac_ocp_write(ioaddr, 0xe8de, tmp_data);
+	while (!(RTL_R8(MCU) & LINK_LIST_RDY))
+		udelay(100);
+}
+
+static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
+{
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_40:
+	case RTL_GIGA_MAC_VER_41:
+		rtl_hw_init_8168g(tp);
+		break;
+	default:
+		break;
+	}
+}
+
 static int __devinit
 rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -6600,6 +6882,8 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	rtl_irq_disable(tp);
 
+	rtl_hw_initialize(tp);
+
 	rtl_hw_reset(tp);
 
 	rtl_ack_events(tp, 0xffff);
-- 
1.7.10.2

Re: [PATCH v2 net-next 1/2] r8169: support RTL8106E

From: Francois Romieu <romieu@fr.zoreil.com>
Date: 2012-07-03 11:12:26

Hayes Wang [off-list ref] :
Support the new chip RTL8106E.

Signed-off-by: Hayes Wang <redacted>
Almost-Acked-by: Francois Romieu [off-list ref]

Simple bidirectional traffic worked fine (rsync + wget + ping) both
with and without tx checksumming offload.

Wol g or u worked as well. Link was ok and traffic flowing after a
suspend to ram.

No problem with module removal / insertion / device up / traffic loop.
+#define FIRMWARE_8106E_1	"rtl_nic/rtl8106e-1.fw"
I did not notice it. Was it submitted ?

It was obviously not required for testing :o)
quoted hunk
@@ -1933,6 +1941,8 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
 		{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },
 
 		/* 8101 family. */
+		{ 0x7cf00000, 0x44900000,	RTL_GIGA_MAC_VER_39 },
+		{ 0x7c800000, 0x44800000,	RTL_GIGA_MAC_VER_39 },
 		{ 0x7c800000, 0x44000000,	RTL_GIGA_MAC_VER_37 },
 		{ 0x7cf00000, 0x40b00000,	RTL_GIGA_MAC_VER_30 },
 		{ 0x7cf00000, 0x40a00000,	RTL_GIGA_MAC_VER_30 },
Realtek's 1.022.00 8101 driver only maps { 0x7c800000; 0x44800000 } to
a generic device - if at all - and it maps { 0x7cf00000; 0x44800000 }
to a different chipset (namely CFG_METHOD_15 where RTL_GIGA_MAC_VER_39
is CFG_METHOD_16).

Why should both drivers diverge ?

-- 
Ueimor

RE: [PATCH v2 net-next 1/2] r8169: support RTL8106E

From: hayeswang <hidden>
Date: 2012-07-04 09:02:29

Francois Romieu [mailto:romieu@fr.zoreil.com] 
[...]
quoted
+#define FIRMWARE_8106E_1	"rtl_nic/rtl8106e-1.fw"
I did not notice it. Was it submitted ?
I don't submit it yet.
It was obviously not required for testing :o)
quoted
@@ -1933,6 +1941,8 @@ static void 
rtl8169_get_mac_version(struct rtl8169_private *tp,
quoted
 		{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },
 
 		/* 8101 family. */
+		{ 0x7cf00000, 0x44900000,	RTL_GIGA_MAC_VER_39 },
+		{ 0x7c800000, 0x44800000,	RTL_GIGA_MAC_VER_39 },
 		{ 0x7c800000, 0x44000000,	RTL_GIGA_MAC_VER_37 },
 		{ 0x7cf00000, 0x40b00000,	RTL_GIGA_MAC_VER_30 },
 		{ 0x7cf00000, 0x40a00000,	RTL_GIGA_MAC_VER_30 },
Realtek's 1.022.00 8101 driver only maps { 0x7c800000; 0x44800000 } to
a generic device - if at all - and it maps { 0x7cf00000; 0x44800000 }
to a different chipset (namely CFG_METHOD_15 where RTL_GIGA_MAC_VER_39
is CFG_METHOD_16).

Why should both drivers diverge ?
Our PMs say only 0x44900000 would have mass production. Besides, you could use
the same setting for both of them. 

Best Regards,
Hayes

Re: [PATCH v2 net-next 2/2] r8169: support RTL8168G

From: Francois Romieu <romieu@fr.zoreil.com>
Date: 2012-07-04 22:16:30

Hayes Wang [off-list ref] :
Support the new chip RTL8168G.
[...]

Any objection against merging it with the patch below ?

- more BUG() avoidance
- save Joe P. some work
- remove useless parenthesis
- fix r8168g_mdio_write (if (reg_addr == 0x1f) { if (reg_addr == 0) snafu)
  -> Please check this one.
- long declarations before short ones
- avoid unbounded loops
- use a descriptive name for the 0xe8de value in rtl_hw_init_8168g.
  -> Please suggest something better than "PLOP"
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 0cf8626..c37aed9 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -937,14 +937,22 @@ static int r8168dp_check_dash(struct rtl8169_private *tp)
 	return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
 }
 
-static void r8168_phy_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
+static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg)
 {
+	if (reg & 0xffff0001) {
+		netif_err(tp, drv, tp->dev, "Invalid ocp reg %x!\n", reg);
+		return true;
+	}
+	return false;
+}
+
+static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
 	int i;
 
-	if (reg & 0xffff0001) {
-		printk(KERN_ERR "Invalid ocp reg %x!\n", reg);
+	if (rtl_ocp_reg_failure(tp, reg))
 		return;
-	}
 
 	RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
 
@@ -955,15 +963,14 @@ static void r8168_phy_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
 	}
 }
 
-static u16 r8168_phy_ocp_read(void __iomem *ioaddr, u32 reg)
+static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
 {
-	int i;
+	void __iomem *ioaddr = tp->mmio_addr;
 	u32 data;
+	int i;
 
-	if (reg & 0xffff0001) {
-		printk(KERN_ERR "Invalid ocp reg %x!\n", reg);
+	if (rtl_ocp_reg_failure(tp, reg))
 		return 0;
-	}
 
 	RTL_W32(GPHY_OCP, reg << 15);
 
@@ -977,20 +984,21 @@ static u16 r8168_phy_ocp_read(void __iomem *ioaddr, u32 reg)
 	return (u16)(data & 0xffff);
 }
 
-static void rtl_w1w0_phy_ocp(void __iomem *ioaddr, int reg_addr, int p, int m)
+static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
 {
 	int val;
 
-	val = r8168_phy_ocp_read(ioaddr, reg_addr);
-	r8168_phy_ocp_write(ioaddr, reg_addr, (val | p) & ~m);
+	val = r8168_phy_ocp_read(tp, reg);
+	r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
 }
 
-static void r8168_mac_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
+static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
 {
+	void __iomem *ioaddr = tp->mmio_addr;
 	int i;
 
-	if (reg & 0xffff0001)
-		BUG();
+	if (rtl_ocp_reg_failure(tp, reg))
+		return;
 
 	RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
 
@@ -1001,15 +1009,16 @@ static void r8168_mac_ocp_write(void __iomem *ioaddr, u32 reg, u32 data)
 	}
 }
 
-static u16 r8168_mac_ocp_read(void __iomem *ioaddr, u32 reg)
+static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
 {
-	int i;
+	void __iomem *ioaddr = tp->mmio_addr;
 	u32 data;
+	int i;
 
-	if (reg & 0xffff0001)
-		BUG();
+	if (rtl_ocp_reg_failure(tp, reg))
+		return 0;
 
-	RTL_W32(OCPDR, (reg << 15));
+	RTL_W32(OCPDR, reg << 15);
 
 	for (i = 0; i < 10; i++) {
 		udelay(25);
@@ -1023,39 +1032,32 @@ static u16 r8168_mac_ocp_read(void __iomem *ioaddr, u32 reg)
 
 #define OCP_STD_PHY_BASE	0xa400
 
-static
-void r8168g_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
+static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
 {
-	void __iomem *ioaddr = tp->mmio_addr;
-
-	if (reg_addr == 0x1f) {
-		if (reg_addr == 0)
-			tp->ocp_base = OCP_STD_PHY_BASE;
-		else
-			tp->ocp_base = value << 4;
-
+	if (reg == 0x1f) {
+		tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
 		return;
-	} else if (tp->ocp_base != OCP_STD_PHY_BASE)
-		reg_addr -= 0x10;
+	}
+
+	if (tp->ocp_base != OCP_STD_PHY_BASE)
+		reg -= 0x10;
 
-	r8168_phy_ocp_write(ioaddr, tp->ocp_base + reg_addr * 2, value);
+	r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
 }
 
 static int r8168g_mdio_read(struct rtl8169_private *tp, int reg_addr)
 {
-	void __iomem *ioaddr = tp->mmio_addr;
-
 	if (tp->ocp_base != OCP_STD_PHY_BASE)
 		reg_addr -= 0x10;
 
-	return r8168_phy_ocp_read(ioaddr, tp->ocp_base + reg_addr * 2);
+	return r8168_phy_ocp_read(tp, tp->ocp_base + reg_addr * 2);
 }
 
 static
 void r8169_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
 {
-	int i;
 	void __iomem *ioaddr = tp->mmio_addr;
+	int i;
 
 	RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
 
@@ -1077,8 +1079,8 @@ void r8169_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
 
 static int r8169_mdio_read(struct rtl8169_private *tp, int reg_addr)
 {
-	int i, value = -1;
 	void __iomem *ioaddr = tp->mmio_addr;
+	int i, value = -1;
 
 	RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
 
@@ -1129,8 +1131,8 @@ void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
 
 static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg_addr)
 {
-	int i;
 	void __iomem *ioaddr = tp->mmio_addr;
+	int i;
 
 	r8168dp_1_mdio_access(ioaddr, reg_addr, OCPDR_READ_CMD);
 
@@ -1159,26 +1161,25 @@ static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
 	RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
 }
 
-static
-void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
+static void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
 
 	r8168dp_2_mdio_start(ioaddr);
 
-	r8169_mdio_write(tp, reg_addr, value);
+	r8169_mdio_write(tp, reg, value);
 
 	r8168dp_2_mdio_stop(ioaddr);
 }
 
-static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg_addr)
+static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
 {
-	int value;
 	void __iomem *ioaddr = tp->mmio_addr;
+	int value;
 
 	r8168dp_2_mdio_start(ioaddr);
 
-	value = r8169_mdio_read(tp, reg_addr);
+	value = r8169_mdio_read(tp, reg);
 
 	r8168dp_2_mdio_stop(ioaddr);
 
@@ -3370,49 +3371,51 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
 
 static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
 {
-	void __iomem *ioaddr = tp->mmio_addr;
 	u32 i;
 	static const u16 mac_ocp_patch[] = {
 		0xe008, 0xe01b, 0xe01d, 0xe01f,
 		0xe021, 0xe023, 0xe025, 0xe027,
 		0x49d2 ,0xf10d, 0x766c, 0x49e2,
 		0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
+
 		0x77c0, 0x4870, 0x9fc0, 0x1ea0,
 		0xc707, 0x8ee1, 0x9d6c, 0xc603,
 		0xbe00, 0xb416, 0x0076, 0xe86c,
 		0xc602, 0xbe00, 0x0000, 0xc602,
+
 		0xbe00, 0x0000, 0xc602, 0xbe00,
 		0x0000, 0xc602, 0xbe00, 0x0000,
 		0xc602, 0xbe00, 0x0000, 0xc602,
 		0xbe00, 0x0000, 0xc602, 0xbe00,
+
 		0x0000, 0x0000, 0x0000, 0x0000
 	};
 
 	/* patch code for GPHY reset */
 	for (i = 0; ARRAY_SIZE(mac_ocp_patch); i++)
-		r8168_mac_ocp_write(ioaddr, 0xf800 + 2*i, mac_ocp_patch[i]);
-	r8168_mac_ocp_write(ioaddr, 0xfc26, 0x8000);
-	r8168_mac_ocp_write(ioaddr, 0xfc28, 0x0075);
+		r8168_mac_ocp_write(tp, 0xf800 + 2*i, mac_ocp_patch[i]);
+	r8168_mac_ocp_write(tp, 0xfc26, 0x8000);
+	r8168_mac_ocp_write(tp, 0xfc28, 0x0075);
 
 	rtl_apply_firmware(tp);
 
-	if (r8168_phy_ocp_read(ioaddr, 0xa460) & 0x0100)
-		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x0000, 0x8000);
+	if (r8168_phy_ocp_read(tp, 0xa460) & 0x0100)
+		rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x8000);
 	else
-		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x8000, 0x0000);
+		rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x8000, 0x0000);
 
-	if (r8168_phy_ocp_read(ioaddr, 0xa466) & 0x0100)
-		rtl_w1w0_phy_ocp(ioaddr, 0xc41a, 0x0002, 0x0000);
+	if (r8168_phy_ocp_read(tp, 0xa466) & 0x0100)
+		rtl_w1w0_phy_ocp(tp, 0xc41a, 0x0002, 0x0000);
 	else
-		rtl_w1w0_phy_ocp(ioaddr, 0xbcc4, 0x0000, 0x0002);
+		rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x0002);
 
-	rtl_w1w0_phy_ocp(ioaddr, 0xa442, 0x000c, 0x0000);
-	rtl_w1w0_phy_ocp(ioaddr, 0xa4b2, 0x0004, 0x0000);
+	rtl_w1w0_phy_ocp(tp, 0xa442, 0x000c, 0x0000);
+	rtl_w1w0_phy_ocp(tp, 0xa4b2, 0x0004, 0x0000);
 
-	r8168_phy_ocp_write(ioaddr, 0xa436, 0x8012);
-	rtl_w1w0_phy_ocp(ioaddr, 0xa438, 0x8000, 0x0000);
+	r8168_phy_ocp_write(tp, 0xa436, 0x8012);
+	rtl_w1w0_phy_ocp(tp, 0xa438, 0x8000, 0x0000);
 
-	rtl_w1w0_phy_ocp(ioaddr, 0xc422, 0x4000, 0x2000);
+	rtl_w1w0_phy_ocp(tp, 0xc422, 0x4000, 0x2000);
 }
 
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
@@ -5144,16 +5147,24 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
 	rtl_eri_write(ioaddr, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
 	rtl_eri_write(ioaddr, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
 	rtl_eri_write(ioaddr, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+
 	rtl_csi_access_enable_1(tp);
+
 	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
 	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
 	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+
 	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
 	RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
 	RTL_W8(MaxTxPacketSize, EarlySize);
+
 	rtl_eri_write(ioaddr, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
 	rtl_eri_write(ioaddr, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+
+	/* Adjust EEE LED frequency */
 	RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+
 	rtl_w1w0_eri(ioaddr, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
 }
 
@@ -6732,33 +6743,56 @@ static unsigned rtl_try_msi(struct rtl8169_private *tp,
 	return msi;
 }
 
+#define	RTL_LOOP_MAX	10000
+
+static void rtl_mcu_wait_list_ready(void __iomem *ioaddr)
+{
+	int i;
+
+	for (i = 0; i < RTL_LOOP_MAX; i++) {
+		if (RTL_R8(MCU) & LINK_LIST_RDY)
+			return;
+		udelay(100);
+	}
+}
+
+#define PLOP		0xe8de
+
 static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	u32 tmp_data;
+	u32 data;
+	int i;
 
 	RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
-	while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
+
+	for (i = 0; i < RTL_LOOP_MAX; i++) {
+		if (RTL_R32(TxConfig) & TXCFG_EMPTY)
+			break;
 		udelay(100);
+	}
 
-	while ((RTL_R8(MCU) & RXTX_EMPTY) != RXTX_EMPTY)
+	for (i = 0; i < RTL_LOOP_MAX; i++) {
+		if ((RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY)
+			break;
 		udelay(100);
+	}
 
 	RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
 	msleep(1);
 	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
 
-	tmp_data = r8168_mac_ocp_read(ioaddr, 0xe8de);
-	tmp_data &= ~(1 << 14);
-	r8168_mac_ocp_write(ioaddr, 0xe8de, tmp_data);
-	while (!(RTL_R8(MCU) & LINK_LIST_RDY))
-		udelay(100);
+	data = r8168_mac_ocp_read(ioaddr, PLOP);
+	data &= ~(1 << 14);
+	r8168_mac_ocp_write(ioaddr, PLOP, data);
 
-	tmp_data = r8168_mac_ocp_read(ioaddr, 0xe8de);
-	tmp_data |= (1 << 15);
-	r8168_mac_ocp_write(ioaddr, 0xe8de, tmp_data);
-	while (!(RTL_R8(MCU) & LINK_LIST_RDY))
-		udelay(100);
+	rtl_mcu_wait_list_ready(ioaddr);
+
+	data = r8168_mac_ocp_read(ioaddr, PLOP);
+	data |= (1 << 15);
+	r8168_mac_ocp_write(ioaddr, PLOP, data);
+
+	rtl_mcu_wait_list_ready(ioaddr);
 }
 
 static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)

Re: [PATCH v2 net-next 2/2] r8169: support RTL8168G

From: Joe Perches <joe@perches.com>
Date: 2012-07-05 00:51:51

On Thu, 2012-07-05 at 00:04 +0200, Francois Romieu wrote:
Hayes Wang [off-list ref] :
quoted
Support the new chip RTL8168G.
- save Joe P. some work
Thanks.  Just a trivial thing below:

[]
quoted hunk
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
[]
+#define	RTL_LOOP_MAX	10000
+
+static void rtl_mcu_wait_list_ready(void __iomem *ioaddr)
+{
+	int i;
+
+	for (i = 0; i < RTL_LOOP_MAX; i++) {
+		if (RTL_R8(MCU) & LINK_LIST_RDY)
+			return;
+		udelay(100);
+	}
+}
This pattern is used a couple more times.
There's no failure handling either.

Maybe use a macro with RTL_R8/32, register and test?
Maybe the delays could be tuned out a bit better.
Maybe a continuous read or a less frequent read
might be better.
 static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
 {
[]
+	for (i = 0; i < RTL_LOOP_MAX; i++) {
+		if (RTL_R32(TxConfig) & TXCFG_EMPTY)
+			break;
 		udelay(100);
+	}
pattern
+	for (i = 0; i < RTL_LOOP_MAX; i++) {
+		if ((RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY)
+			break;
 		udelay(100);
+	}
pattern

RE: [PATCH v2 net-next 2/2] r8169: support RTL8168G

From: hayeswang <hidden>
Date: 2012-07-06 07:57:21

Francois Romieu [romieu@fr.zoreil.com]
[...]
Any objection against merging it with the patch below ?

- more BUG() avoidance
- save Joe P. some work
- remove useless parenthesis
- fix r8168g_mdio_write (if (reg_addr == 0x1f) { if (reg_addr == 0) snafu)
  -> Please check this one.
That is fine.
- long declarations before short ones
- avoid unbounded loops
- use a descriptive name for the 0xe8de value in rtl_hw_init_8168g.
  -> Please suggest something better than "PLOP"
I have no idea about naming 0xe8de. Our hardware engineers don't release any
datasheet about it. It seems to be related with oob settings. 

Re: [PATCH v2 net-next 2/2] r8169: support RTL8168G

From: Francois Romieu <romieu@fr.zoreil.com>
Date: 2012-07-06 15:31:46

hayeswang [off-list ref] :
Francois Romieu [romieu@fr.zoreil.com]
[...]
quoted
- fix r8168g_mdio_write (if (reg_addr == 0x1f) { if (reg_addr == 0) snafu)
  -> Please check this one.
That is fine.
Thanks, I'll merge your patch and feed both drivers to davem.

-- 
Ueimor

Re: [PATCH v2 net-next 2/2] r8169: support RTL8168G

From: Francois Romieu <romieu@fr.zoreil.com>
Date: 2012-07-06 15:32:31

Joe Perches [off-list ref] :
[...]
This pattern is used a couple more times.
There's no failure handling either.
I can do something for the initialize path. Other than that it's mostly
deeply burried hardware failure so I'd rather concentrate a bit on 
current problem reports.

This series already took me a bit further than expected (see below).
Maybe use a macro with RTL_R8/32, register and test?
Here is what I came up with. Completely untested. Attached patches #1 and
#2 should  be applied on top of the previous patch beforehand.

[PATCH 3/3] r8169: abstract out loop conditions.

Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
---
 drivers/net/ethernet/realtek/r8169.c |  460 +++++++++++++++++-----------------
 1 file changed, 225 insertions(+), 235 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 0759c76..4f350fc 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -844,47 +844,113 @@ static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
 	}
 }
 
+struct rtl_cond {
+	bool (*check)(struct rtl8169_private *);
+	const char *msg;
+};
+
+static void rtl_udelay(unsigned int d)
+{
+	udelay(d);
+}
+
+static bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c,
+			  void (*delay)(unsigned int), unsigned int d, int n,
+			  bool high)
+{
+	int i;
+
+	for (i = 0; i < n; i++) {
+		delay(d);
+		if (c->check(tp) == high)
+			return true;
+	}
+	netif_err(tp, drv, tp->dev, c->msg);
+	return false;
+}
+
+static bool rtl_udelay_loop_wait_high(struct rtl8169_private *tp,
+				      const struct rtl_cond *c,
+				      unsigned int d, int n)
+{
+	return rtl_loop_wait(tp, c, rtl_udelay, d, n, true);
+}
+
+static bool rtl_udelay_loop_wait_low(struct rtl8169_private *tp,
+				     const struct rtl_cond *c,
+				     unsigned int d, int n)
+{
+	return rtl_loop_wait(tp, c, rtl_udelay, d, n, false);
+}
+
+static bool rtl_msleep_loop_wait_high(struct rtl8169_private *tp,
+				      const struct rtl_cond *c,
+				      unsigned int d, int n)
+{
+	return rtl_loop_wait(tp, c, msleep, d, n, true);
+}
+
+static bool rtl_msleep_loop_wait_low(struct rtl8169_private *tp,
+				     const struct rtl_cond *c,
+				     unsigned int d, int n)
+{
+	return rtl_loop_wait(tp, c, msleep, d, n, false);
+}
+
+#define DECLARE_RTL_COND(name) \
+static bool name ## _check(struct rtl8169_private *);	\
+							\
+static const struct rtl_cond name = {			\
+	.check	= name ## _check,			\
+	.msg	= #name					\
+};							\
+							\
+static bool name ## _check(struct rtl8169_private *tp)
+
+DECLARE_RTL_COND(rtl_ocpar_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(OCPAR) & OCPAR_FLAG;
+}
+
 static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
 	RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
-	for (i = 0; i < 20; i++) {
-		udelay(100);
-		if (RTL_R32(OCPAR) & OCPAR_FLAG)
-			break;
-	}
-	return RTL_R32(OCPDR);
+
+	return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ?
+		RTL_R32(OCPDR) : ~0;
 }
 
 static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
 	RTL_W32(OCPDR, data);
 	RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
-	for (i = 0; i < 20; i++) {
-		udelay(100);
-		if ((RTL_R32(OCPAR) & OCPAR_FLAG) == 0)
-			break;
-	}
+
+	rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20);
+}
+
+DECLARE_RTL_COND(rtl_eriar_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(ERIAR) & ERIAR_FLAG;
 }
 
 static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
 	RTL_W8(ERIDR, cmd);
 	RTL_W32(ERIAR, 0x800010e8);
 	msleep(2);
-	for (i = 0; i < 5; i++) {
-		udelay(100);
-		if (!(RTL_R32(ERIAR) & ERIAR_FLAG))
-			break;
-	}
+
+	if (!rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 5))
+		return;
 
 	ocp_write(tp, 0x1, 0x30, 0x00000001);
 }
@@ -898,36 +964,27 @@ static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
 	return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
 }
 
-static void rtl8168_driver_start(struct rtl8169_private *tp)
+DECLARE_RTL_COND(rtl_ocp_read_cond)
 {
 	u16 reg;
-	int i;
-
-	rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
 
 	reg = rtl8168_get_ocp_reg(tp);
 
-	for (i = 0; i < 10; i++) {
-		msleep(10);
-		if (ocp_read(tp, 0x0f, reg) & 0x00000800)
-			break;
-	}
+	return ocp_read(tp, 0x0f, reg) & 0x00000800;
 }
 
-static void rtl8168_driver_stop(struct rtl8169_private *tp)
+static void rtl8168_driver_start(struct rtl8169_private *tp)
 {
-	u16 reg;
-	int i;
+	rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
 
-	rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
+	rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10);
+}
 
-	reg = rtl8168_get_ocp_reg(tp);
+static void rtl8168_driver_stop(struct rtl8169_private *tp)
+{
+	rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
 
-	for (i = 0; i < 10; i++) {
-		msleep(10);
-		if ((ocp_read(tp, 0x0f, reg) & 0x00000800) == 0)
-			break;
-	}
+	rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10);
 }
 
 static int r8168dp_check_dash(struct rtl8169_private *tp)
@@ -946,42 +1003,36 @@ static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg)
 	return false;
 }
 
+DECLARE_RTL_COND(rtl_ocp_gphy_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(GPHY_OCP) & OCPAR_FLAG;
+}
+
 static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
 	if (rtl_ocp_reg_failure(tp, reg))
 		return;
 
 	RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
 
-	for (i = 0; i < 10; i++) {
-		udelay(25);
-		if (!(RTL_R32(GPHY_OCP) & OCPAR_FLAG))
-			break;
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
 }
 
 static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	u32 data;
-	int i;
 
 	if (rtl_ocp_reg_failure(tp, reg))
 		return 0;
 
 	RTL_W32(GPHY_OCP, reg << 15);
 
-	for (i = 0; i < 10; i++) {
-		udelay(25);
-		data = RTL_R32(GPHY_OCP);
-		if (data & OCPAR_FLAG)
-			break;
-	}
-
-	return (u16)(data & 0xffff);
+	return rtl_udelay_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
+		(RTL_R32(GPHY_OCP) & 0xffff) : ~0;
 }
 
 static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
@@ -992,42 +1043,36 @@ static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
 	r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
 }
 
+DECLARE_RTL_COND(rtl_ocpdr_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(OCPDR) & OCPAR_FLAG;
+}
+
 static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
 	if (rtl_ocp_reg_failure(tp, reg))
 		return;
 
 	RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
 
-	for (i = 0; i < 10; i++) {
-		udelay(25);
-		if (!(RTL_R32(OCPDR) & OCPAR_FLAG))
-			break;
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_ocpdr_cond, 25, 10);
 }
 
 static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	u32 data;
-	int i;
 
 	if (rtl_ocp_reg_failure(tp, reg))
 		return 0;
 
 	RTL_W32(OCPDR, reg << 15);
 
-	for (i = 0; i < 10; i++) {
-		udelay(25);
-		data = RTL_R32(OCPDR);
-		if (data & OCPAR_FLAG)
-			break;
-	}
-
-	return (u16)(data & 0xffff);
+	return rtl_udelay_loop_wait_high(tp, &rtl_ocpdr_cond, 25, 10) ?
+		RTL_R32(OCPDR) : ~0;
 }
 
 #define OCP_STD_PHY_BASE	0xa400
@@ -1053,23 +1098,22 @@ static int r8168g_mdio_read(struct rtl8169_private *tp, int reg_addr)
 	return r8168_phy_ocp_read(tp, tp->ocp_base + reg_addr * 2);
 }
 
+DECLARE_RTL_COND(rtl_phyar_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(PHYAR) & 0x80000000;
+}
+
 static
 void r8169_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
 	RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
 
-	for (i = 20; i > 0; i--) {
-		/*
-		 * Check if the RTL8169 has completed writing to the specified
-		 * MII register.
-		 */
-		if (!(RTL_R32(PHYAR) & 0x80000000))
-			break;
-		udelay(25);
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
+
 	/*
 	 * According to hardware specs a 20us delay is required after write
 	 * complete indication, but before sending next command.
@@ -1080,21 +1124,13 @@ void r8169_mdio_write(struct rtl8169_private *tp, int reg_addr, int value)
 static int r8169_mdio_read(struct rtl8169_private *tp, int reg_addr)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i, value = -1;
+	int value;
 
 	RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
 
-	for (i = 20; i > 0; i--) {
-		/*
-		 * Check if the RTL8169 has completed retrieving data from
-		 * the specified MII register.
-		 */
-		if (RTL_R32(PHYAR) & 0x80000000) {
-			value = RTL_R32(PHYAR) & 0xffff;
-			break;
-		}
-		udelay(25);
-	}
+	value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
+		RTL_R32(PHYAR) & 0xffff : ~0;
+
 	/*
 	 * According to hardware specs a 20us delay is required after read
 	 * complete indication, but before sending next command.
@@ -1107,17 +1143,12 @@ static int r8169_mdio_read(struct rtl8169_private *tp, int reg_addr)
 static void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
 	RTL_W32(OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
 	RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
 	RTL_W32(EPHY_RXER_NUM, 0);
 
-	for (i = 0; i < 100; i++) {
-		mdelay(1);
-		if (!(RTL_R32(OCPAR) & OCPAR_FLAG))
-			break;
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100);
 }
 
 static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
@@ -1129,7 +1160,6 @@ static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
 static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg_addr)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
 	r8168dp_1_mdio_access(tp, reg_addr, OCPDR_READ_CMD);
 
@@ -1137,13 +1167,8 @@ static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg_addr)
 	RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
 	RTL_W32(EPHY_RXER_NUM, 0);
 
-	for (i = 0; i < 100; i++) {
-		mdelay(1);
-		if (RTL_R32(OCPAR) & OCPAR_FLAG)
-			break;
-	}
-
-	return RTL_R32(OCPDR) & OCPDR_DATA_MASK;
+	return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
+		RTL_R32(OCPDR) & OCPDR_DATA_MASK : ~0;
 }
 
 #define R8168DP_1_MDIO_ACCESS_BIT	0x00020000
@@ -1221,74 +1246,55 @@ static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
 	return rtl_readphy(tp, location);
 }
 
+DECLARE_RTL_COND(rtl_ephyar_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(EPHYAR) & EPHYAR_FLAG;
+}
+
 static void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	unsigned int i;
 
 	RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
 		(reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
 
-	for (i = 0; i < 100; i++) {
-		if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
-			break;
-		udelay(10);
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100);
+
+	udelay(10);
 }
 
 static u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	u16 value = 0xffff;
-	unsigned int i;
 
 	RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
 
-	for (i = 0; i < 100; i++) {
-		if (RTL_R32(EPHYAR) & EPHYAR_FLAG) {
-			value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK;
-			break;
-		}
-		udelay(10);
-	}
-
-	return value;
+	return rtl_udelay_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ?
+		RTL_R32(EPHYAR) & EPHYAR_DATA_MASK : ~0;
 }
 
 static void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
 			  u32 val, int type)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	unsigned int i;
 
 	BUG_ON((addr & 3) || (mask == 0));
 	RTL_W32(ERIDR, val);
 	RTL_W32(ERIAR, ERIAR_WRITE_CMD | type | mask | addr);
 
-	for (i = 0; i < 100; i++) {
-		if (!(RTL_R32(ERIAR) & ERIAR_FLAG))
-			break;
-		udelay(100);
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
 }
 
 static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, int type)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	u32 value = ~0x00;
-	unsigned int i;
 
 	RTL_W32(ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr);
 
-	for (i = 0; i < 100; i++) {
-		if (RTL_R32(ERIAR) & ERIAR_FLAG) {
-			value = RTL_R32(ERIDR);
-			break;
-		}
-		udelay(100);
-	}
-
-	return value;
+	return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
+		RTL_R32(ERIDR) : ~0;
 }
 
 static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p,
@@ -1315,23 +1321,21 @@ static void rtl_write_exgmac_batch(struct rtl8169_private *tp,
 	}
 }
 
+DECLARE_RTL_COND(rtl_efusear_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(EFUSEAR) & EFUSEAR_FLAG;
+}
+
 static u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	u8 value = 0xff;
-	unsigned int i;
 
 	RTL_W32(EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
 
-	for (i = 0; i < 300; i++) {
-		if (RTL_R32(EFUSEAR) & EFUSEAR_FLAG) {
-			value = RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK;
-			break;
-		}
-		udelay(100);
-	}
-
-	return value;
+	return rtl_udelay_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ?
+		RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
 }
 
 static u16 rtl_get_events(struct rtl8169_private *tp)
@@ -1938,6 +1942,13 @@ static int rtl8169_get_sset_count(struct net_device *dev, int sset)
 	}
 }
 
+DECLARE_RTL_COND(rtl_counters_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(CounterAddrLow) & CounterDump;
+}
+
 static void rtl8169_update_counters(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -1946,7 +1957,6 @@ static void rtl8169_update_counters(struct net_device *dev)
 	struct rtl8169_counters *counters;
 	dma_addr_t paddr;
 	u32 cmd;
-	int wait = 1000;
 
 	/*
 	 * Some chips are unable to dump tally counters when the receiver
@@ -1964,13 +1974,8 @@ static void rtl8169_update_counters(struct net_device *dev)
 	RTL_W32(CounterAddrLow, cmd);
 	RTL_W32(CounterAddrLow, cmd | CounterDump);
 
-	while (wait--) {
-		if ((RTL_R32(CounterAddrLow) & CounterDump) == 0) {
-			memcpy(&tp->counters, counters, sizeof(*counters));
-			break;
-		}
-		udelay(10);
-	}
+	if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
+		memcpy(&tp->counters, counters, sizeof(*counters));
 
 	RTL_W32(CounterAddrLow, 0);
 	RTL_W32(CounterAddrHigh, 0);
@@ -3662,18 +3667,16 @@ static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
 	free_netdev(dev);
 }
 
+DECLARE_RTL_COND(rtl_phy_reset_cond)
+{
+	return tp->phy_reset_pending(tp);
+}
+
 static void rtl8169_phy_reset(struct net_device *dev,
 			      struct rtl8169_private *tp)
 {
-	unsigned int i;
-
 	tp->phy_reset_enable(tp);
-	for (i = 0; i < 100; i++) {
-		if (!tp->phy_reset_pending(tp))
-			return;
-		msleep(1);
-	}
-	netif_err(tp, link, dev, "PHY reset failed\n");
+	rtl_msleep_loop_wait_low(tp, &rtl_phy_reset_cond, 1, 100);
 }
 
 static bool rtl_tbi_enabled(struct rtl8169_private *tp)
@@ -4307,20 +4310,20 @@ static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
 	}
 }
 
+DECLARE_RTL_COND(rtl_chipcmd_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R8(ChipCmd) & CmdReset;
+}
+
 static void rtl_hw_reset(struct rtl8169_private *tp)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	int i;
 
-	/* Soft reset the chip. */
 	RTL_W8(ChipCmd, CmdReset);
 
-	/* Check that the chip has finished the reset. */
-	for (i = 0; i < 100; i++) {
-		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
-			break;
-		udelay(100);
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
 }
 
 static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
@@ -4374,6 +4377,20 @@ static void rtl_rx_close(struct rtl8169_private *tp)
 	RTL_W32(RxConfig, RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK);
 }
 
+DECLARE_RTL_COND(rtl_npq_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R8(TxPoll) & NPQ;
+}
+
+DECLARE_RTL_COND(rtl_txcfg_empty_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(TxConfig) & TXCFG_EMPTY;
+}
+
 static void rtl8169_hw_reset(struct rtl8169_private *tp)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
@@ -4386,8 +4403,7 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
 	if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
 	    tp->mac_version == RTL_GIGA_MAC_VER_28 ||
 	    tp->mac_version == RTL_GIGA_MAC_VER_31) {
-		while (RTL_R8(TxPoll) & NPQ)
-			udelay(20);
+		rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
 	} else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_35 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_36 ||
@@ -4396,8 +4412,7 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
 	           tp->mac_version == RTL_GIGA_MAC_VER_41 ||
 	           tp->mac_version == RTL_GIGA_MAC_VER_38) {
 		RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
-		while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
-			udelay(100);
+		rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
 	} else {
 		RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
 		udelay(100);
@@ -4608,7 +4623,7 @@ static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
 
 static u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
 {
-	return tp->csi_ops.read ? tp->csi_ops.read(tp, addr) :~0;
+	return tp->csi_ops.read ? tp->csi_ops.read(tp, addr) : ~0;
 }
 
 static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits)
@@ -4629,77 +4644,56 @@ static void rtl_csi_access_enable_2(struct rtl8169_private *tp)
 	rtl_csi_access_enable(tp, 0x27000000);
 }
 
+DECLARE_RTL_COND(rtl_csiar_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	return RTL_R32(CSIAR) & CSIAR_FLAG;
+}
+
 static void r8169_csi_write(struct rtl8169_private *tp, int addr, int value)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	unsigned int i;
 
 	RTL_W32(CSIDR, value);
 	RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
 		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
 
-	for (i = 0; i < 100; i++) {
-		if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
-			break;
-		udelay(10);
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
 }
 
 static u32 r8169_csi_read(struct rtl8169_private *tp, int addr)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	u32 value = ~0x00;
-	unsigned int i;
 
 	RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
 		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
 
-	for (i = 0; i < 100; i++) {
-		if (RTL_R32(CSIAR) & CSIAR_FLAG) {
-			value = RTL_R32(CSIDR);
-			break;
-		}
-		udelay(10);
-	}
-
-	return value;
+	return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
+		RTL_R32(CSIDR) : ~0;
 }
 
 static void r8402_csi_write(struct rtl8169_private *tp, int addr, int value)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	unsigned int i;
 
 	RTL_W32(CSIDR, value);
 	RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
 		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT |
 		CSIAR_FUNC_NIC);
 
-	for (i = 0; i < 100; i++) {
-		if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
-			break;
-		udelay(10);
-	}
+	rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
 }
 
 static u32 r8402_csi_read(struct rtl8169_private *tp, int addr)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
-	u32 value = ~0x00;
-	unsigned int i;
 
 	RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC |
 		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
 
-	for (i = 0; i < 100; i++) {
-		if (RTL_R32(CSIAR) & CSIAR_FLAG) {
-			value = RTL_R32(CSIDR);
-			break;
-		}
-		udelay(10);
-	}
-
-	return value;
+	return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
+		RTL_R32(CSIDR) : ~0;
 }
 
 static void __devinit rtl_init_csi_ops(struct rtl8169_private *tp)
@@ -6731,17 +6725,18 @@ static unsigned rtl_try_msi(struct rtl8169_private *tp,
 	return msi;
 }
 
-#define	RTL_LOOP_MAX	10000
+DECLARE_RTL_COND(rtl_link_list_ready_cond)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
 
-static void rtl_mcu_wait_list_ready(void __iomem *ioaddr)
+	return RTL_R8(MCU) & LINK_LIST_RDY;
+}
+
+DECLARE_RTL_COND(rtl_rxtx_empty_cond)
 {
-	int i;
+	void __iomem *ioaddr = tp->mmio_addr;
 
-	for (i = 0; i < RTL_LOOP_MAX; i++) {
-		if (RTL_R8(MCU) & LINK_LIST_RDY)
-			return;
-		udelay(100);
-	}
+	return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY;
 }
 
 #define PLOP		0xe8de
@@ -6750,21 +6745,14 @@ static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
 	u32 data;
-	int i;
 
 	RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
 
-	for (i = 0; i < RTL_LOOP_MAX; i++) {
-		if (RTL_R32(TxConfig) & TXCFG_EMPTY)
-			break;
-		udelay(100);
-	}
+	if (!rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42))
+		return;
 
-	for (i = 0; i < RTL_LOOP_MAX; i++) {
-		if ((RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY)
-			break;
-		udelay(100);
-	}
+	if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42))
+		return;
 
 	RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
 	msleep(1);
@@ -6774,13 +6762,15 @@ static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
 	data &= ~(1 << 14);
 	r8168_mac_ocp_write(ioaddr, PLOP, data);
 
-	rtl_mcu_wait_list_ready(ioaddr);
+	if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
+		return;
 
 	data = r8168_mac_ocp_read(ioaddr, PLOP);
 	data |= (1 << 15);
 	r8168_mac_ocp_write(ioaddr, PLOP, data);
 
-	rtl_mcu_wait_list_ready(ioaddr);
+	if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
+		return;
 }
 
 static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
-- 
1.7.10.4

Re: [PATCH v2 net-next 2/2] r8169: support RTL8168G

From: Joe Perches <joe@perches.com>
Date: 2012-07-06 15:37:59

On Fri, 2012-07-06 at 17:20 +0200, Francois Romieu wrote:
Joe Perches [off-list ref] :
[...]
quoted
This pattern is used a couple more times.
There's no failure handling either.
I can do something for the initialize path. Other than that it's mostly
deeply burried hardware failure so I'd rather concentrate a bit on 
current problem reports.

This series already took me a bit further than expected (see below).
Allez Francois.

When you take up a suggestion, you really go with it.

Re: [PATCH net-next 1/2] r8169: support RTL8106E

From: David Miller <davem@davemloft.net>
Date: 2012-07-09 06:48:59

Francois, what would you like me to do with these two patches?  I
haven't seen full ACKs from you yet.

Thanks.

Re: [PATCH net-next 1/2] r8169: support RTL8106E

From: Francois Romieu <romieu@fr.zoreil.com>
Date: 2012-07-09 10:24:13

David Miller [off-list ref] :
Francois, what would you like me to do with these two patches?  I
haven't seen full ACKs from you yet.
You have two options:
- You can apply the first (8106) patch. I tested it. I'm ok with Hayes point.
  Consider it Acked.
- You wait for a pull request with both patches + the incremental bits for
  the second one. Some of the incremental bits are needed in the original
  patch itself while some make more sense before the patch itself.
  ETA: this evening or tomorrow morning at worst.

If you go for the first option, I'll simply skip the first patch and
apply again. It's the same work for me.

-- 
Ueimor

Re: [PATCH net-next 1/2] r8169: support RTL8106E

From: David Miller <davem@davemloft.net>
Date: 2012-07-09 21:10:58

From: Francois Romieu <romieu@fr.zoreil.com>
Date: Mon, 9 Jul 2012 12:12:15 +0200
David Miller [off-list ref] :
quoted
Francois, what would you like me to do with these two patches?  I
haven't seen full ACKs from you yet.
You have two options:
- You can apply the first (8106) patch. I tested it. I'm ok with Hayes point.
  Consider it Acked.
- You wait for a pull request with both patches + the incremental bits for
  the second one. Some of the incremental bits are needed in the original
  patch itself while some make more sense before the patch itself.
  ETA: this evening or tomorrow morning at worst.

If you go for the first option, I'll simply skip the first patch and
apply again. It's the same work for me.
I'll simply wait for your pull request, thank you.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help