162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * r8169.c: RealTek 8169/8168/8101 ethernet driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
662306a36Sopenharmony_ci * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
762306a36Sopenharmony_ci * Copyright (c) a lot of people too. Please respect their work.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * See MAINTAINERS file for support contact information.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/pci.h>
1462306a36Sopenharmony_ci#include <linux/netdevice.h>
1562306a36Sopenharmony_ci#include <linux/etherdevice.h>
1662306a36Sopenharmony_ci#include <linux/clk.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/ethtool.h>
1962306a36Sopenharmony_ci#include <linux/phy.h>
2062306a36Sopenharmony_ci#include <linux/if_vlan.h>
2162306a36Sopenharmony_ci#include <linux/in.h>
2262306a36Sopenharmony_ci#include <linux/io.h>
2362306a36Sopenharmony_ci#include <linux/ip.h>
2462306a36Sopenharmony_ci#include <linux/tcp.h>
2562306a36Sopenharmony_ci#include <linux/interrupt.h>
2662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2862306a36Sopenharmony_ci#include <linux/bitfield.h>
2962306a36Sopenharmony_ci#include <linux/prefetch.h>
3062306a36Sopenharmony_ci#include <linux/ipv6.h>
3162306a36Sopenharmony_ci#include <asm/unaligned.h>
3262306a36Sopenharmony_ci#include <net/ip6_checksum.h>
3362306a36Sopenharmony_ci#include <net/netdev_queues.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include "r8169.h"
3662306a36Sopenharmony_ci#include "r8169_firmware.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define FIRMWARE_8168D_1	"rtl_nic/rtl8168d-1.fw"
3962306a36Sopenharmony_ci#define FIRMWARE_8168D_2	"rtl_nic/rtl8168d-2.fw"
4062306a36Sopenharmony_ci#define FIRMWARE_8168E_1	"rtl_nic/rtl8168e-1.fw"
4162306a36Sopenharmony_ci#define FIRMWARE_8168E_2	"rtl_nic/rtl8168e-2.fw"
4262306a36Sopenharmony_ci#define FIRMWARE_8168E_3	"rtl_nic/rtl8168e-3.fw"
4362306a36Sopenharmony_ci#define FIRMWARE_8168F_1	"rtl_nic/rtl8168f-1.fw"
4462306a36Sopenharmony_ci#define FIRMWARE_8168F_2	"rtl_nic/rtl8168f-2.fw"
4562306a36Sopenharmony_ci#define FIRMWARE_8105E_1	"rtl_nic/rtl8105e-1.fw"
4662306a36Sopenharmony_ci#define FIRMWARE_8402_1		"rtl_nic/rtl8402-1.fw"
4762306a36Sopenharmony_ci#define FIRMWARE_8411_1		"rtl_nic/rtl8411-1.fw"
4862306a36Sopenharmony_ci#define FIRMWARE_8411_2		"rtl_nic/rtl8411-2.fw"
4962306a36Sopenharmony_ci#define FIRMWARE_8106E_1	"rtl_nic/rtl8106e-1.fw"
5062306a36Sopenharmony_ci#define FIRMWARE_8106E_2	"rtl_nic/rtl8106e-2.fw"
5162306a36Sopenharmony_ci#define FIRMWARE_8168G_2	"rtl_nic/rtl8168g-2.fw"
5262306a36Sopenharmony_ci#define FIRMWARE_8168G_3	"rtl_nic/rtl8168g-3.fw"
5362306a36Sopenharmony_ci#define FIRMWARE_8168H_2	"rtl_nic/rtl8168h-2.fw"
5462306a36Sopenharmony_ci#define FIRMWARE_8168FP_3	"rtl_nic/rtl8168fp-3.fw"
5562306a36Sopenharmony_ci#define FIRMWARE_8107E_2	"rtl_nic/rtl8107e-2.fw"
5662306a36Sopenharmony_ci#define FIRMWARE_8125A_3	"rtl_nic/rtl8125a-3.fw"
5762306a36Sopenharmony_ci#define FIRMWARE_8125B_2	"rtl_nic/rtl8125b-2.fw"
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
6062306a36Sopenharmony_ci   The RTL chips use a 64 element hash table based on the Ethernet CRC. */
6162306a36Sopenharmony_ci#define	MC_FILTER_LIMIT	32
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define TX_DMA_BURST	7	/* Maximum PCI burst, '7' is unlimited */
6462306a36Sopenharmony_ci#define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define R8169_REGS_SIZE		256
6762306a36Sopenharmony_ci#define R8169_RX_BUF_SIZE	(SZ_16K - 1)
6862306a36Sopenharmony_ci#define NUM_TX_DESC	256	/* Number of Tx descriptor registers */
6962306a36Sopenharmony_ci#define NUM_RX_DESC	256	/* Number of Rx descriptor registers */
7062306a36Sopenharmony_ci#define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
7162306a36Sopenharmony_ci#define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
7262306a36Sopenharmony_ci#define R8169_TX_STOP_THRS	(MAX_SKB_FRAGS + 1)
7362306a36Sopenharmony_ci#define R8169_TX_START_THRS	(2 * R8169_TX_STOP_THRS)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define OCP_STD_PHY_BASE	0xa400
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define RTL_CFG_NO_GBIT	1
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* write/read MMIO register */
8062306a36Sopenharmony_ci#define RTL_W8(tp, reg, val8)	writeb((val8), tp->mmio_addr + (reg))
8162306a36Sopenharmony_ci#define RTL_W16(tp, reg, val16)	writew((val16), tp->mmio_addr + (reg))
8262306a36Sopenharmony_ci#define RTL_W32(tp, reg, val32)	writel((val32), tp->mmio_addr + (reg))
8362306a36Sopenharmony_ci#define RTL_R8(tp, reg)		readb(tp->mmio_addr + (reg))
8462306a36Sopenharmony_ci#define RTL_R16(tp, reg)		readw(tp->mmio_addr + (reg))
8562306a36Sopenharmony_ci#define RTL_R32(tp, reg)		readl(tp->mmio_addr + (reg))
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#define JUMBO_4K	(4 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
8862306a36Sopenharmony_ci#define JUMBO_6K	(6 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
8962306a36Sopenharmony_ci#define JUMBO_7K	(7 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
9062306a36Sopenharmony_ci#define JUMBO_9K	(9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic const struct {
9362306a36Sopenharmony_ci	const char *name;
9462306a36Sopenharmony_ci	const char *fw_name;
9562306a36Sopenharmony_ci} rtl_chip_infos[] = {
9662306a36Sopenharmony_ci	/* PCI devices. */
9762306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_02] = {"RTL8169s"				},
9862306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_03] = {"RTL8110s"				},
9962306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_04] = {"RTL8169sb/8110sb"			},
10062306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_05] = {"RTL8169sc/8110sc"			},
10162306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_06] = {"RTL8169sc/8110sc"			},
10262306a36Sopenharmony_ci	/* PCI-E devices. */
10362306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_07] = {"RTL8102e"				},
10462306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_08] = {"RTL8102e"				},
10562306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e"			},
10662306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e"			},
10762306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_11] = {"RTL8168b/8111b"			},
10862306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_14] = {"RTL8401"				},
10962306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b"			},
11062306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp"			},
11162306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_19] = {"RTL8168c/8111c"			},
11262306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_20] = {"RTL8168c/8111c"			},
11362306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_21] = {"RTL8168c/8111c"			},
11462306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_22] = {"RTL8168c/8111c"			},
11562306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_23] = {"RTL8168cp/8111cp"			},
11662306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_24] = {"RTL8168cp/8111cp"			},
11762306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_25] = {"RTL8168d/8111d",	FIRMWARE_8168D_1},
11862306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_26] = {"RTL8168d/8111d",	FIRMWARE_8168D_2},
11962306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_28] = {"RTL8168dp/8111dp"			},
12062306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_29] = {"RTL8105e",		FIRMWARE_8105E_1},
12162306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_30] = {"RTL8105e",		FIRMWARE_8105E_1},
12262306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_31] = {"RTL8168dp/8111dp"			},
12362306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_32] = {"RTL8168e/8111e",	FIRMWARE_8168E_1},
12462306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_33] = {"RTL8168e/8111e",	FIRMWARE_8168E_2},
12562306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_34] = {"RTL8168evl/8111evl",	FIRMWARE_8168E_3},
12662306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_35] = {"RTL8168f/8111f",	FIRMWARE_8168F_1},
12762306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_36] = {"RTL8168f/8111f",	FIRMWARE_8168F_2},
12862306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_37] = {"RTL8402",		FIRMWARE_8402_1 },
12962306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_38] = {"RTL8411",		FIRMWARE_8411_1 },
13062306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_39] = {"RTL8106e",		FIRMWARE_8106E_1},
13162306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_40] = {"RTL8168g/8111g",	FIRMWARE_8168G_2},
13262306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_42] = {"RTL8168gu/8111gu",	FIRMWARE_8168G_3},
13362306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_43] = {"RTL8106eus",		FIRMWARE_8106E_2},
13462306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_44] = {"RTL8411b",		FIRMWARE_8411_2 },
13562306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_46] = {"RTL8168h/8111h",	FIRMWARE_8168H_2},
13662306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_48] = {"RTL8107e",		FIRMWARE_8107E_2},
13762306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep"			},
13862306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_52] = {"RTL8168fp/RTL8117",  FIRMWARE_8168FP_3},
13962306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_53] = {"RTL8168fp/RTL8117",			},
14062306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_61] = {"RTL8125A",		FIRMWARE_8125A_3},
14162306a36Sopenharmony_ci	/* reserve 62 for CFG_METHOD_4 in the vendor driver */
14262306a36Sopenharmony_ci	[RTL_GIGA_MAC_VER_63] = {"RTL8125B",		FIRMWARE_8125B_2},
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic const struct pci_device_id rtl8169_pci_tbl[] = {
14662306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x2502) },
14762306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x2600) },
14862306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x8129) },
14962306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x8136), RTL_CFG_NO_GBIT },
15062306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x8161) },
15162306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x8162) },
15262306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x8167) },
15362306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x8168) },
15462306a36Sopenharmony_ci	{ PCI_VDEVICE(NCUBE,	0x8168) },
15562306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x8169) },
15662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_DLINK,	0x4300,
15762306a36Sopenharmony_ci		PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0 },
15862306a36Sopenharmony_ci	{ PCI_VDEVICE(DLINK,	0x4300) },
15962306a36Sopenharmony_ci	{ PCI_VDEVICE(DLINK,	0x4302) },
16062306a36Sopenharmony_ci	{ PCI_VDEVICE(AT,	0xc107) },
16162306a36Sopenharmony_ci	{ PCI_VDEVICE(USR,	0x0116) },
16262306a36Sopenharmony_ci	{ PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024 },
16362306a36Sopenharmony_ci	{ 0x0001, 0x8168, PCI_ANY_ID, 0x2410 },
16462306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x8125) },
16562306a36Sopenharmony_ci	{ PCI_VDEVICE(REALTEK,	0x3000) },
16662306a36Sopenharmony_ci	{}
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cienum rtl_registers {
17262306a36Sopenharmony_ci	MAC0		= 0,	/* Ethernet hardware address. */
17362306a36Sopenharmony_ci	MAC4		= 4,
17462306a36Sopenharmony_ci	MAR0		= 8,	/* Multicast filter. */
17562306a36Sopenharmony_ci	CounterAddrLow		= 0x10,
17662306a36Sopenharmony_ci	CounterAddrHigh		= 0x14,
17762306a36Sopenharmony_ci	TxDescStartAddrLow	= 0x20,
17862306a36Sopenharmony_ci	TxDescStartAddrHigh	= 0x24,
17962306a36Sopenharmony_ci	TxHDescStartAddrLow	= 0x28,
18062306a36Sopenharmony_ci	TxHDescStartAddrHigh	= 0x2c,
18162306a36Sopenharmony_ci	FLASH		= 0x30,
18262306a36Sopenharmony_ci	ERSR		= 0x36,
18362306a36Sopenharmony_ci	ChipCmd		= 0x37,
18462306a36Sopenharmony_ci	TxPoll		= 0x38,
18562306a36Sopenharmony_ci	IntrMask	= 0x3c,
18662306a36Sopenharmony_ci	IntrStatus	= 0x3e,
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	TxConfig	= 0x40,
18962306a36Sopenharmony_ci#define	TXCFG_AUTO_FIFO			(1 << 7)	/* 8111e-vl */
19062306a36Sopenharmony_ci#define	TXCFG_EMPTY			(1 << 11)	/* 8111e-vl */
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	RxConfig	= 0x44,
19362306a36Sopenharmony_ci#define	RX128_INT_EN			(1 << 15)	/* 8111c and later */
19462306a36Sopenharmony_ci#define	RX_MULTI_EN			(1 << 14)	/* 8111c only */
19562306a36Sopenharmony_ci#define	RXCFG_FIFO_SHIFT		13
19662306a36Sopenharmony_ci					/* No threshold before first PCI xfer */
19762306a36Sopenharmony_ci#define	RX_FIFO_THRESH			(7 << RXCFG_FIFO_SHIFT)
19862306a36Sopenharmony_ci#define	RX_EARLY_OFF			(1 << 11)
19962306a36Sopenharmony_ci#define	RX_PAUSE_SLOT_ON		(1 << 11)	/* 8125b and later */
20062306a36Sopenharmony_ci#define	RXCFG_DMA_SHIFT			8
20162306a36Sopenharmony_ci					/* Unlimited maximum PCI burst. */
20262306a36Sopenharmony_ci#define	RX_DMA_BURST			(7 << RXCFG_DMA_SHIFT)
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	Cfg9346		= 0x50,
20562306a36Sopenharmony_ci	Config0		= 0x51,
20662306a36Sopenharmony_ci	Config1		= 0x52,
20762306a36Sopenharmony_ci	Config2		= 0x53,
20862306a36Sopenharmony_ci#define PME_SIGNAL			(1 << 5)	/* 8168c and later */
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	Config3		= 0x54,
21162306a36Sopenharmony_ci	Config4		= 0x55,
21262306a36Sopenharmony_ci	Config5		= 0x56,
21362306a36Sopenharmony_ci	PHYAR		= 0x60,
21462306a36Sopenharmony_ci	PHYstatus	= 0x6c,
21562306a36Sopenharmony_ci	RxMaxSize	= 0xda,
21662306a36Sopenharmony_ci	CPlusCmd	= 0xe0,
21762306a36Sopenharmony_ci	IntrMitigate	= 0xe2,
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci#define RTL_COALESCE_TX_USECS	GENMASK(15, 12)
22062306a36Sopenharmony_ci#define RTL_COALESCE_TX_FRAMES	GENMASK(11, 8)
22162306a36Sopenharmony_ci#define RTL_COALESCE_RX_USECS	GENMASK(7, 4)
22262306a36Sopenharmony_ci#define RTL_COALESCE_RX_FRAMES	GENMASK(3, 0)
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci#define RTL_COALESCE_T_MAX	0x0fU
22562306a36Sopenharmony_ci#define RTL_COALESCE_FRAME_MAX	(RTL_COALESCE_T_MAX * 4)
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	RxDescAddrLow	= 0xe4,
22862306a36Sopenharmony_ci	RxDescAddrHigh	= 0xe8,
22962306a36Sopenharmony_ci	EarlyTxThres	= 0xec,	/* 8169. Unit of 32 bytes. */
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci#define NoEarlyTx	0x3f	/* Max value : no early transmit. */
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	MaxTxPacketSize	= 0xec,	/* 8101/8168. Unit of 128 bytes. */
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci#define TxPacketMax	(8064 >> 7)
23662306a36Sopenharmony_ci#define EarlySize	0x27
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	FuncEvent	= 0xf0,
23962306a36Sopenharmony_ci	FuncEventMask	= 0xf4,
24062306a36Sopenharmony_ci	FuncPresetState	= 0xf8,
24162306a36Sopenharmony_ci	IBCR0           = 0xf8,
24262306a36Sopenharmony_ci	IBCR2           = 0xf9,
24362306a36Sopenharmony_ci	IBIMR0          = 0xfa,
24462306a36Sopenharmony_ci	IBISR0          = 0xfb,
24562306a36Sopenharmony_ci	FuncForceEvent	= 0xfc,
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cienum rtl8168_8101_registers {
24962306a36Sopenharmony_ci	CSIDR			= 0x64,
25062306a36Sopenharmony_ci	CSIAR			= 0x68,
25162306a36Sopenharmony_ci#define	CSIAR_FLAG			0x80000000
25262306a36Sopenharmony_ci#define	CSIAR_WRITE_CMD			0x80000000
25362306a36Sopenharmony_ci#define	CSIAR_BYTE_ENABLE		0x0000f000
25462306a36Sopenharmony_ci#define	CSIAR_ADDR_MASK			0x00000fff
25562306a36Sopenharmony_ci	PMCH			= 0x6f,
25662306a36Sopenharmony_ci#define D3COLD_NO_PLL_DOWN		BIT(7)
25762306a36Sopenharmony_ci#define D3HOT_NO_PLL_DOWN		BIT(6)
25862306a36Sopenharmony_ci#define D3_NO_PLL_DOWN			(BIT(7) | BIT(6))
25962306a36Sopenharmony_ci	EPHYAR			= 0x80,
26062306a36Sopenharmony_ci#define	EPHYAR_FLAG			0x80000000
26162306a36Sopenharmony_ci#define	EPHYAR_WRITE_CMD		0x80000000
26262306a36Sopenharmony_ci#define	EPHYAR_REG_MASK			0x1f
26362306a36Sopenharmony_ci#define	EPHYAR_REG_SHIFT		16
26462306a36Sopenharmony_ci#define	EPHYAR_DATA_MASK		0xffff
26562306a36Sopenharmony_ci	DLLPR			= 0xd0,
26662306a36Sopenharmony_ci#define	PFM_EN				(1 << 6)
26762306a36Sopenharmony_ci#define	TX_10M_PS_EN			(1 << 7)
26862306a36Sopenharmony_ci	DBG_REG			= 0xd1,
26962306a36Sopenharmony_ci#define	FIX_NAK_1			(1 << 4)
27062306a36Sopenharmony_ci#define	FIX_NAK_2			(1 << 3)
27162306a36Sopenharmony_ci	TWSI			= 0xd2,
27262306a36Sopenharmony_ci	MCU			= 0xd3,
27362306a36Sopenharmony_ci#define	NOW_IS_OOB			(1 << 7)
27462306a36Sopenharmony_ci#define	TX_EMPTY			(1 << 5)
27562306a36Sopenharmony_ci#define	RX_EMPTY			(1 << 4)
27662306a36Sopenharmony_ci#define	RXTX_EMPTY			(TX_EMPTY | RX_EMPTY)
27762306a36Sopenharmony_ci#define	EN_NDP				(1 << 3)
27862306a36Sopenharmony_ci#define	EN_OOB_RESET			(1 << 2)
27962306a36Sopenharmony_ci#define	LINK_LIST_RDY			(1 << 1)
28062306a36Sopenharmony_ci	EFUSEAR			= 0xdc,
28162306a36Sopenharmony_ci#define	EFUSEAR_FLAG			0x80000000
28262306a36Sopenharmony_ci#define	EFUSEAR_WRITE_CMD		0x80000000
28362306a36Sopenharmony_ci#define	EFUSEAR_READ_CMD		0x00000000
28462306a36Sopenharmony_ci#define	EFUSEAR_REG_MASK		0x03ff
28562306a36Sopenharmony_ci#define	EFUSEAR_REG_SHIFT		8
28662306a36Sopenharmony_ci#define	EFUSEAR_DATA_MASK		0xff
28762306a36Sopenharmony_ci	MISC_1			= 0xf2,
28862306a36Sopenharmony_ci#define	PFM_D3COLD_EN			(1 << 6)
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cienum rtl8168_registers {
29262306a36Sopenharmony_ci	LED_FREQ		= 0x1a,
29362306a36Sopenharmony_ci	EEE_LED			= 0x1b,
29462306a36Sopenharmony_ci	ERIDR			= 0x70,
29562306a36Sopenharmony_ci	ERIAR			= 0x74,
29662306a36Sopenharmony_ci#define ERIAR_FLAG			0x80000000
29762306a36Sopenharmony_ci#define ERIAR_WRITE_CMD			0x80000000
29862306a36Sopenharmony_ci#define ERIAR_READ_CMD			0x00000000
29962306a36Sopenharmony_ci#define ERIAR_ADDR_BYTE_ALIGN		4
30062306a36Sopenharmony_ci#define ERIAR_TYPE_SHIFT		16
30162306a36Sopenharmony_ci#define ERIAR_EXGMAC			(0x00 << ERIAR_TYPE_SHIFT)
30262306a36Sopenharmony_ci#define ERIAR_MSIX			(0x01 << ERIAR_TYPE_SHIFT)
30362306a36Sopenharmony_ci#define ERIAR_ASF			(0x02 << ERIAR_TYPE_SHIFT)
30462306a36Sopenharmony_ci#define ERIAR_OOB			(0x02 << ERIAR_TYPE_SHIFT)
30562306a36Sopenharmony_ci#define ERIAR_MASK_SHIFT		12
30662306a36Sopenharmony_ci#define ERIAR_MASK_0001			(0x1 << ERIAR_MASK_SHIFT)
30762306a36Sopenharmony_ci#define ERIAR_MASK_0011			(0x3 << ERIAR_MASK_SHIFT)
30862306a36Sopenharmony_ci#define ERIAR_MASK_0100			(0x4 << ERIAR_MASK_SHIFT)
30962306a36Sopenharmony_ci#define ERIAR_MASK_0101			(0x5 << ERIAR_MASK_SHIFT)
31062306a36Sopenharmony_ci#define ERIAR_MASK_1111			(0xf << ERIAR_MASK_SHIFT)
31162306a36Sopenharmony_ci	EPHY_RXER_NUM		= 0x7c,
31262306a36Sopenharmony_ci	OCPDR			= 0xb0,	/* OCP GPHY access */
31362306a36Sopenharmony_ci#define OCPDR_WRITE_CMD			0x80000000
31462306a36Sopenharmony_ci#define OCPDR_READ_CMD			0x00000000
31562306a36Sopenharmony_ci#define OCPDR_REG_MASK			0x7f
31662306a36Sopenharmony_ci#define OCPDR_GPHY_REG_SHIFT		16
31762306a36Sopenharmony_ci#define OCPDR_DATA_MASK			0xffff
31862306a36Sopenharmony_ci	OCPAR			= 0xb4,
31962306a36Sopenharmony_ci#define OCPAR_FLAG			0x80000000
32062306a36Sopenharmony_ci#define OCPAR_GPHY_WRITE_CMD		0x8000f060
32162306a36Sopenharmony_ci#define OCPAR_GPHY_READ_CMD		0x0000f060
32262306a36Sopenharmony_ci	GPHY_OCP		= 0xb8,
32362306a36Sopenharmony_ci	RDSAR1			= 0xd0,	/* 8168c only. Undocumented on 8168dp */
32462306a36Sopenharmony_ci	MISC			= 0xf0,	/* 8168e only. */
32562306a36Sopenharmony_ci#define TXPLA_RST			(1 << 29)
32662306a36Sopenharmony_ci#define DISABLE_LAN_EN			(1 << 23) /* Enable GPIO pin */
32762306a36Sopenharmony_ci#define PWM_EN				(1 << 22)
32862306a36Sopenharmony_ci#define RXDV_GATED_EN			(1 << 19)
32962306a36Sopenharmony_ci#define EARLY_TALLY_EN			(1 << 16)
33062306a36Sopenharmony_ci};
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cienum rtl8125_registers {
33362306a36Sopenharmony_ci	IntrMask_8125		= 0x38,
33462306a36Sopenharmony_ci	IntrStatus_8125		= 0x3c,
33562306a36Sopenharmony_ci	TxPoll_8125		= 0x90,
33662306a36Sopenharmony_ci	MAC0_BKP		= 0x19e0,
33762306a36Sopenharmony_ci	EEE_TXIDLE_TIMER_8125	= 0x6048,
33862306a36Sopenharmony_ci};
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci#define RX_VLAN_INNER_8125	BIT(22)
34162306a36Sopenharmony_ci#define RX_VLAN_OUTER_8125	BIT(23)
34262306a36Sopenharmony_ci#define RX_VLAN_8125		(RX_VLAN_INNER_8125 | RX_VLAN_OUTER_8125)
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci#define RX_FETCH_DFLT_8125	(8 << 27)
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cienum rtl_register_content {
34762306a36Sopenharmony_ci	/* InterruptStatusBits */
34862306a36Sopenharmony_ci	SYSErr		= 0x8000,
34962306a36Sopenharmony_ci	PCSTimeout	= 0x4000,
35062306a36Sopenharmony_ci	SWInt		= 0x0100,
35162306a36Sopenharmony_ci	TxDescUnavail	= 0x0080,
35262306a36Sopenharmony_ci	RxFIFOOver	= 0x0040,
35362306a36Sopenharmony_ci	LinkChg		= 0x0020,
35462306a36Sopenharmony_ci	RxOverflow	= 0x0010,
35562306a36Sopenharmony_ci	TxErr		= 0x0008,
35662306a36Sopenharmony_ci	TxOK		= 0x0004,
35762306a36Sopenharmony_ci	RxErr		= 0x0002,
35862306a36Sopenharmony_ci	RxOK		= 0x0001,
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* RxStatusDesc */
36162306a36Sopenharmony_ci	RxRWT	= (1 << 22),
36262306a36Sopenharmony_ci	RxRES	= (1 << 21),
36362306a36Sopenharmony_ci	RxRUNT	= (1 << 20),
36462306a36Sopenharmony_ci	RxCRC	= (1 << 19),
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* ChipCmdBits */
36762306a36Sopenharmony_ci	StopReq		= 0x80,
36862306a36Sopenharmony_ci	CmdReset	= 0x10,
36962306a36Sopenharmony_ci	CmdRxEnb	= 0x08,
37062306a36Sopenharmony_ci	CmdTxEnb	= 0x04,
37162306a36Sopenharmony_ci	RxBufEmpty	= 0x01,
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* TXPoll register p.5 */
37462306a36Sopenharmony_ci	HPQ		= 0x80,		/* Poll cmd on the high prio queue */
37562306a36Sopenharmony_ci	NPQ		= 0x40,		/* Poll cmd on the low prio queue */
37662306a36Sopenharmony_ci	FSWInt		= 0x01,		/* Forced software interrupt */
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* Cfg9346Bits */
37962306a36Sopenharmony_ci	Cfg9346_Lock	= 0x00,
38062306a36Sopenharmony_ci	Cfg9346_Unlock	= 0xc0,
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* rx_mode_bits */
38362306a36Sopenharmony_ci	AcceptErr	= 0x20,
38462306a36Sopenharmony_ci	AcceptRunt	= 0x10,
38562306a36Sopenharmony_ci#define RX_CONFIG_ACCEPT_ERR_MASK	0x30
38662306a36Sopenharmony_ci	AcceptBroadcast	= 0x08,
38762306a36Sopenharmony_ci	AcceptMulticast	= 0x04,
38862306a36Sopenharmony_ci	AcceptMyPhys	= 0x02,
38962306a36Sopenharmony_ci	AcceptAllPhys	= 0x01,
39062306a36Sopenharmony_ci#define RX_CONFIG_ACCEPT_OK_MASK	0x0f
39162306a36Sopenharmony_ci#define RX_CONFIG_ACCEPT_MASK		0x3f
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* TxConfigBits */
39462306a36Sopenharmony_ci	TxInterFrameGapShift = 24,
39562306a36Sopenharmony_ci	TxDMAShift = 8,	/* DMA burst value (0-7) is shift this many bits */
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* Config1 register p.24 */
39862306a36Sopenharmony_ci	LEDS1		= (1 << 7),
39962306a36Sopenharmony_ci	LEDS0		= (1 << 6),
40062306a36Sopenharmony_ci	Speed_down	= (1 << 4),
40162306a36Sopenharmony_ci	MEMMAP		= (1 << 3),
40262306a36Sopenharmony_ci	IOMAP		= (1 << 2),
40362306a36Sopenharmony_ci	VPD		= (1 << 1),
40462306a36Sopenharmony_ci	PMEnable	= (1 << 0),	/* Power Management Enable */
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* Config2 register p. 25 */
40762306a36Sopenharmony_ci	ClkReqEn	= (1 << 7),	/* Clock Request Enable */
40862306a36Sopenharmony_ci	MSIEnable	= (1 << 5),	/* 8169 only. Reserved in the 8168. */
40962306a36Sopenharmony_ci	PCI_Clock_66MHz = 0x01,
41062306a36Sopenharmony_ci	PCI_Clock_33MHz = 0x00,
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* Config3 register p.25 */
41362306a36Sopenharmony_ci	MagicPacket	= (1 << 5),	/* Wake up when receives a Magic Packet */
41462306a36Sopenharmony_ci	LinkUp		= (1 << 4),	/* Wake up when the cable connection is re-established */
41562306a36Sopenharmony_ci	Jumbo_En0	= (1 << 2),	/* 8168 only. Reserved in the 8168b */
41662306a36Sopenharmony_ci	Rdy_to_L23	= (1 << 1),	/* L23 Enable */
41762306a36Sopenharmony_ci	Beacon_en	= (1 << 0),	/* 8168 only. Reserved in the 8168b */
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* Config4 register */
42062306a36Sopenharmony_ci	Jumbo_En1	= (1 << 1),	/* 8168 only. Reserved in the 8168b */
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* Config5 register p.27 */
42362306a36Sopenharmony_ci	BWF		= (1 << 6),	/* Accept Broadcast wakeup frame */
42462306a36Sopenharmony_ci	MWF		= (1 << 5),	/* Accept Multicast wakeup frame */
42562306a36Sopenharmony_ci	UWF		= (1 << 4),	/* Accept Unicast wakeup frame */
42662306a36Sopenharmony_ci	Spi_en		= (1 << 3),
42762306a36Sopenharmony_ci	LanWake		= (1 << 1),	/* LanWake enable/disable */
42862306a36Sopenharmony_ci	PMEStatus	= (1 << 0),	/* PME status can be reset by PCI RST# */
42962306a36Sopenharmony_ci	ASPM_en		= (1 << 0),	/* ASPM enable */
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/* CPlusCmd p.31 */
43262306a36Sopenharmony_ci	EnableBist	= (1 << 15),	// 8168 8101
43362306a36Sopenharmony_ci	Mac_dbgo_oe	= (1 << 14),	// 8168 8101
43462306a36Sopenharmony_ci	EnAnaPLL	= (1 << 14),	// 8169
43562306a36Sopenharmony_ci	Normal_mode	= (1 << 13),	// unused
43662306a36Sopenharmony_ci	Force_half_dup	= (1 << 12),	// 8168 8101
43762306a36Sopenharmony_ci	Force_rxflow_en	= (1 << 11),	// 8168 8101
43862306a36Sopenharmony_ci	Force_txflow_en	= (1 << 10),	// 8168 8101
43962306a36Sopenharmony_ci	Cxpl_dbg_sel	= (1 << 9),	// 8168 8101
44062306a36Sopenharmony_ci	ASF		= (1 << 8),	// 8168 8101
44162306a36Sopenharmony_ci	PktCntrDisable	= (1 << 7),	// 8168 8101
44262306a36Sopenharmony_ci	Mac_dbgo_sel	= 0x001c,	// 8168
44362306a36Sopenharmony_ci	RxVlan		= (1 << 6),
44462306a36Sopenharmony_ci	RxChkSum	= (1 << 5),
44562306a36Sopenharmony_ci	PCIDAC		= (1 << 4),
44662306a36Sopenharmony_ci	PCIMulRW	= (1 << 3),
44762306a36Sopenharmony_ci#define INTT_MASK	GENMASK(1, 0)
44862306a36Sopenharmony_ci#define CPCMD_MASK	(Normal_mode | RxVlan | RxChkSum | INTT_MASK)
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* rtl8169_PHYstatus */
45162306a36Sopenharmony_ci	TBI_Enable	= 0x80,
45262306a36Sopenharmony_ci	TxFlowCtrl	= 0x40,
45362306a36Sopenharmony_ci	RxFlowCtrl	= 0x20,
45462306a36Sopenharmony_ci	_1000bpsF	= 0x10,
45562306a36Sopenharmony_ci	_100bps		= 0x08,
45662306a36Sopenharmony_ci	_10bps		= 0x04,
45762306a36Sopenharmony_ci	LinkStatus	= 0x02,
45862306a36Sopenharmony_ci	FullDup		= 0x01,
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/* ResetCounterCommand */
46162306a36Sopenharmony_ci	CounterReset	= 0x1,
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* DumpCounterCommand */
46462306a36Sopenharmony_ci	CounterDump	= 0x8,
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* magic enable v2 */
46762306a36Sopenharmony_ci	MagicPacket_v2	= (1 << 16),	/* Wake up when receives a Magic Packet */
46862306a36Sopenharmony_ci};
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cienum rtl_desc_bit {
47162306a36Sopenharmony_ci	/* First doubleword. */
47262306a36Sopenharmony_ci	DescOwn		= (1 << 31), /* Descriptor is owned by NIC */
47362306a36Sopenharmony_ci	RingEnd		= (1 << 30), /* End of descriptor ring */
47462306a36Sopenharmony_ci	FirstFrag	= (1 << 29), /* First segment of a packet */
47562306a36Sopenharmony_ci	LastFrag	= (1 << 28), /* Final segment of a packet */
47662306a36Sopenharmony_ci};
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/* Generic case. */
47962306a36Sopenharmony_cienum rtl_tx_desc_bit {
48062306a36Sopenharmony_ci	/* First doubleword. */
48162306a36Sopenharmony_ci	TD_LSO		= (1 << 27),		/* Large Send Offload */
48262306a36Sopenharmony_ci#define TD_MSS_MAX			0x07ffu	/* MSS value */
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/* Second doubleword. */
48562306a36Sopenharmony_ci	TxVlanTag	= (1 << 17),		/* Add VLAN tag */
48662306a36Sopenharmony_ci};
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/* 8169, 8168b and 810x except 8102e. */
48962306a36Sopenharmony_cienum rtl_tx_desc_bit_0 {
49062306a36Sopenharmony_ci	/* First doubleword. */
49162306a36Sopenharmony_ci#define TD0_MSS_SHIFT			16	/* MSS position (11 bits) */
49262306a36Sopenharmony_ci	TD0_TCP_CS	= (1 << 16),		/* Calculate TCP/IP checksum */
49362306a36Sopenharmony_ci	TD0_UDP_CS	= (1 << 17),		/* Calculate UDP/IP checksum */
49462306a36Sopenharmony_ci	TD0_IP_CS	= (1 << 18),		/* Calculate IP checksum */
49562306a36Sopenharmony_ci};
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/* 8102e, 8168c and beyond. */
49862306a36Sopenharmony_cienum rtl_tx_desc_bit_1 {
49962306a36Sopenharmony_ci	/* First doubleword. */
50062306a36Sopenharmony_ci	TD1_GTSENV4	= (1 << 26),		/* Giant Send for IPv4 */
50162306a36Sopenharmony_ci	TD1_GTSENV6	= (1 << 25),		/* Giant Send for IPv6 */
50262306a36Sopenharmony_ci#define GTTCPHO_SHIFT			18
50362306a36Sopenharmony_ci#define GTTCPHO_MAX			0x7f
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* Second doubleword. */
50662306a36Sopenharmony_ci#define TCPHO_SHIFT			18
50762306a36Sopenharmony_ci#define TCPHO_MAX			0x3ff
50862306a36Sopenharmony_ci#define TD1_MSS_SHIFT			18	/* MSS position (11 bits) */
50962306a36Sopenharmony_ci	TD1_IPv6_CS	= (1 << 28),		/* Calculate IPv6 checksum */
51062306a36Sopenharmony_ci	TD1_IPv4_CS	= (1 << 29),		/* Calculate IPv4 checksum */
51162306a36Sopenharmony_ci	TD1_TCP_CS	= (1 << 30),		/* Calculate TCP/IP checksum */
51262306a36Sopenharmony_ci	TD1_UDP_CS	= (1 << 31),		/* Calculate UDP/IP checksum */
51362306a36Sopenharmony_ci};
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cienum rtl_rx_desc_bit {
51662306a36Sopenharmony_ci	/* Rx private */
51762306a36Sopenharmony_ci	PID1		= (1 << 18), /* Protocol ID bit 1/2 */
51862306a36Sopenharmony_ci	PID0		= (1 << 17), /* Protocol ID bit 0/2 */
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci#define RxProtoUDP	(PID1)
52162306a36Sopenharmony_ci#define RxProtoTCP	(PID0)
52262306a36Sopenharmony_ci#define RxProtoIP	(PID1 | PID0)
52362306a36Sopenharmony_ci#define RxProtoMask	RxProtoIP
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	IPFail		= (1 << 16), /* IP checksum failed */
52662306a36Sopenharmony_ci	UDPFail		= (1 << 15), /* UDP/IP checksum failed */
52762306a36Sopenharmony_ci	TCPFail		= (1 << 14), /* TCP/IP checksum failed */
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci#define RxCSFailMask	(IPFail | UDPFail | TCPFail)
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	RxVlanTag	= (1 << 16), /* VLAN tag available */
53262306a36Sopenharmony_ci};
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci#define RTL_GSO_MAX_SIZE_V1	32000
53562306a36Sopenharmony_ci#define RTL_GSO_MAX_SEGS_V1	24
53662306a36Sopenharmony_ci#define RTL_GSO_MAX_SIZE_V2	64000
53762306a36Sopenharmony_ci#define RTL_GSO_MAX_SEGS_V2	64
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistruct TxDesc {
54062306a36Sopenharmony_ci	__le32 opts1;
54162306a36Sopenharmony_ci	__le32 opts2;
54262306a36Sopenharmony_ci	__le64 addr;
54362306a36Sopenharmony_ci};
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistruct RxDesc {
54662306a36Sopenharmony_ci	__le32 opts1;
54762306a36Sopenharmony_ci	__le32 opts2;
54862306a36Sopenharmony_ci	__le64 addr;
54962306a36Sopenharmony_ci};
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistruct ring_info {
55262306a36Sopenharmony_ci	struct sk_buff	*skb;
55362306a36Sopenharmony_ci	u32		len;
55462306a36Sopenharmony_ci};
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistruct rtl8169_counters {
55762306a36Sopenharmony_ci	__le64	tx_packets;
55862306a36Sopenharmony_ci	__le64	rx_packets;
55962306a36Sopenharmony_ci	__le64	tx_errors;
56062306a36Sopenharmony_ci	__le32	rx_errors;
56162306a36Sopenharmony_ci	__le16	rx_missed;
56262306a36Sopenharmony_ci	__le16	align_errors;
56362306a36Sopenharmony_ci	__le32	tx_one_collision;
56462306a36Sopenharmony_ci	__le32	tx_multi_collision;
56562306a36Sopenharmony_ci	__le64	rx_unicast;
56662306a36Sopenharmony_ci	__le64	rx_broadcast;
56762306a36Sopenharmony_ci	__le32	rx_multicast;
56862306a36Sopenharmony_ci	__le16	tx_aborted;
56962306a36Sopenharmony_ci	__le16	tx_underun;
57062306a36Sopenharmony_ci};
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistruct rtl8169_tc_offsets {
57362306a36Sopenharmony_ci	bool	inited;
57462306a36Sopenharmony_ci	__le64	tx_errors;
57562306a36Sopenharmony_ci	__le32	tx_multi_collision;
57662306a36Sopenharmony_ci	__le16	tx_aborted;
57762306a36Sopenharmony_ci	__le16	rx_missed;
57862306a36Sopenharmony_ci};
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cienum rtl_flag {
58162306a36Sopenharmony_ci	RTL_FLAG_TASK_ENABLED = 0,
58262306a36Sopenharmony_ci	RTL_FLAG_TASK_RESET_PENDING,
58362306a36Sopenharmony_ci	RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE,
58462306a36Sopenharmony_ci	RTL_FLAG_TASK_TX_TIMEOUT,
58562306a36Sopenharmony_ci	RTL_FLAG_MAX
58662306a36Sopenharmony_ci};
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cienum rtl_dash_type {
58962306a36Sopenharmony_ci	RTL_DASH_NONE,
59062306a36Sopenharmony_ci	RTL_DASH_DP,
59162306a36Sopenharmony_ci	RTL_DASH_EP,
59262306a36Sopenharmony_ci};
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistruct rtl8169_private {
59562306a36Sopenharmony_ci	void __iomem *mmio_addr;	/* memory map physical address */
59662306a36Sopenharmony_ci	struct pci_dev *pci_dev;
59762306a36Sopenharmony_ci	struct net_device *dev;
59862306a36Sopenharmony_ci	struct phy_device *phydev;
59962306a36Sopenharmony_ci	struct napi_struct napi;
60062306a36Sopenharmony_ci	enum mac_version mac_version;
60162306a36Sopenharmony_ci	enum rtl_dash_type dash_type;
60262306a36Sopenharmony_ci	u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
60362306a36Sopenharmony_ci	u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
60462306a36Sopenharmony_ci	u32 dirty_tx;
60562306a36Sopenharmony_ci	struct TxDesc *TxDescArray;	/* 256-aligned Tx descriptor ring */
60662306a36Sopenharmony_ci	struct RxDesc *RxDescArray;	/* 256-aligned Rx descriptor ring */
60762306a36Sopenharmony_ci	dma_addr_t TxPhyAddr;
60862306a36Sopenharmony_ci	dma_addr_t RxPhyAddr;
60962306a36Sopenharmony_ci	struct page *Rx_databuff[NUM_RX_DESC];	/* Rx data buffers */
61062306a36Sopenharmony_ci	struct ring_info tx_skb[NUM_TX_DESC];	/* Tx data buffers */
61162306a36Sopenharmony_ci	u16 cp_cmd;
61262306a36Sopenharmony_ci	u32 irq_mask;
61362306a36Sopenharmony_ci	int irq;
61462306a36Sopenharmony_ci	struct clk *clk;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	struct {
61762306a36Sopenharmony_ci		DECLARE_BITMAP(flags, RTL_FLAG_MAX);
61862306a36Sopenharmony_ci		struct work_struct work;
61962306a36Sopenharmony_ci	} wk;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	raw_spinlock_t config25_lock;
62262306a36Sopenharmony_ci	raw_spinlock_t mac_ocp_lock;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	raw_spinlock_t cfg9346_usage_lock;
62562306a36Sopenharmony_ci	int cfg9346_usage_count;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	unsigned supports_gmii:1;
62862306a36Sopenharmony_ci	unsigned aspm_manageable:1;
62962306a36Sopenharmony_ci	unsigned dash_enabled:1;
63062306a36Sopenharmony_ci	dma_addr_t counters_phys_addr;
63162306a36Sopenharmony_ci	struct rtl8169_counters *counters;
63262306a36Sopenharmony_ci	struct rtl8169_tc_offsets tc_offset;
63362306a36Sopenharmony_ci	u32 saved_wolopts;
63462306a36Sopenharmony_ci	int eee_adv;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	const char *fw_name;
63762306a36Sopenharmony_ci	struct rtl_fw *rtl_fw;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	u32 ocp_base;
64062306a36Sopenharmony_ci};
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_citypedef void (*rtl_generic_fct)(struct rtl8169_private *tp);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ciMODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
64562306a36Sopenharmony_ciMODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
64662306a36Sopenharmony_ciMODULE_SOFTDEP("pre: realtek");
64762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
64862306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168D_1);
64962306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168D_2);
65062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168E_1);
65162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168E_2);
65262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168E_3);
65362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8105E_1);
65462306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168F_1);
65562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168F_2);
65662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8402_1);
65762306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8411_1);
65862306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8411_2);
65962306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8106E_1);
66062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8106E_2);
66162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168G_2);
66262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168G_3);
66362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168H_2);
66462306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168FP_3);
66562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8107E_2);
66662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8125A_3);
66762306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8125B_2);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic inline struct device *tp_to_dev(struct rtl8169_private *tp)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	return &tp->pci_dev->dev;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic void rtl_lock_config_regs(struct rtl8169_private *tp)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	unsigned long flags;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags);
67962306a36Sopenharmony_ci	if (!--tp->cfg9346_usage_count)
68062306a36Sopenharmony_ci		RTL_W8(tp, Cfg9346, Cfg9346_Lock);
68162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags);
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_cistatic void rtl_unlock_config_regs(struct rtl8169_private *tp)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	unsigned long flags;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags);
68962306a36Sopenharmony_ci	if (!tp->cfg9346_usage_count++)
69062306a36Sopenharmony_ci		RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
69162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags);
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic void rtl_pci_commit(struct rtl8169_private *tp)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	/* Read an arbitrary register to commit a preceding PCI write */
69762306a36Sopenharmony_ci	RTL_R8(tp, ChipCmd);
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	unsigned long flags;
70362306a36Sopenharmony_ci	u8 val;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	raw_spin_lock_irqsave(&tp->config25_lock, flags);
70662306a36Sopenharmony_ci	val = RTL_R8(tp, Config2);
70762306a36Sopenharmony_ci	RTL_W8(tp, Config2, (val & ~clear) | set);
70862306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	unsigned long flags;
71462306a36Sopenharmony_ci	u8 val;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	raw_spin_lock_irqsave(&tp->config25_lock, flags);
71762306a36Sopenharmony_ci	val = RTL_R8(tp, Config5);
71862306a36Sopenharmony_ci	RTL_W8(tp, Config5, (val & ~clear) | set);
71962306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic bool rtl_is_8125(struct rtl8169_private *tp)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	return tp->mac_version >= RTL_GIGA_MAC_VER_61;
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic bool rtl_is_8168evl_up(struct rtl8169_private *tp)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
73062306a36Sopenharmony_ci	       tp->mac_version != RTL_GIGA_MAC_VER_39 &&
73162306a36Sopenharmony_ci	       tp->mac_version <= RTL_GIGA_MAC_VER_53;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic bool rtl_supports_eee(struct rtl8169_private *tp)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
73762306a36Sopenharmony_ci	       tp->mac_version != RTL_GIGA_MAC_VER_37 &&
73862306a36Sopenharmony_ci	       tp->mac_version != RTL_GIGA_MAC_VER_39;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic void rtl_read_mac_from_reg(struct rtl8169_private *tp, u8 *mac, int reg)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	int i;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	for (i = 0; i < ETH_ALEN; i++)
74662306a36Sopenharmony_ci		mac[i] = RTL_R8(tp, reg + i);
74762306a36Sopenharmony_ci}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_cistruct rtl_cond {
75062306a36Sopenharmony_ci	bool (*check)(struct rtl8169_private *);
75162306a36Sopenharmony_ci	const char *msg;
75262306a36Sopenharmony_ci};
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_cistatic bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c,
75562306a36Sopenharmony_ci			  unsigned long usecs, int n, bool high)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	int i;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
76062306a36Sopenharmony_ci		if (c->check(tp) == high)
76162306a36Sopenharmony_ci			return true;
76262306a36Sopenharmony_ci		fsleep(usecs);
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	if (net_ratelimit())
76662306a36Sopenharmony_ci		netdev_err(tp->dev, "%s == %d (loop: %d, delay: %lu).\n",
76762306a36Sopenharmony_ci			   c->msg, !high, n, usecs);
76862306a36Sopenharmony_ci	return false;
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic bool rtl_loop_wait_high(struct rtl8169_private *tp,
77262306a36Sopenharmony_ci			       const struct rtl_cond *c,
77362306a36Sopenharmony_ci			       unsigned long d, int n)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	return rtl_loop_wait(tp, c, d, n, true);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic bool rtl_loop_wait_low(struct rtl8169_private *tp,
77962306a36Sopenharmony_ci			      const struct rtl_cond *c,
78062306a36Sopenharmony_ci			      unsigned long d, int n)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	return rtl_loop_wait(tp, c, d, n, false);
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci#define DECLARE_RTL_COND(name)				\
78662306a36Sopenharmony_cistatic bool name ## _check(struct rtl8169_private *);	\
78762306a36Sopenharmony_ci							\
78862306a36Sopenharmony_cistatic const struct rtl_cond name = {			\
78962306a36Sopenharmony_ci	.check	= name ## _check,			\
79062306a36Sopenharmony_ci	.msg	= #name					\
79162306a36Sopenharmony_ci};							\
79262306a36Sopenharmony_ci							\
79362306a36Sopenharmony_cistatic bool name ## _check(struct rtl8169_private *tp)
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	/* based on RTL8168FP_OOBMAC_BASE in vendor driver */
79862306a36Sopenharmony_ci	if (type == ERIAR_OOB &&
79962306a36Sopenharmony_ci	    (tp->mac_version == RTL_GIGA_MAC_VER_52 ||
80062306a36Sopenharmony_ci	     tp->mac_version == RTL_GIGA_MAC_VER_53))
80162306a36Sopenharmony_ci		*cmd |= 0xf70 << 18;
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_eriar_cond)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	return RTL_R32(tp, ERIAR) & ERIAR_FLAG;
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic void _rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
81062306a36Sopenharmony_ci			   u32 val, int type)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	u32 cmd = ERIAR_WRITE_CMD | type | mask | addr;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (WARN(addr & 3 || !mask, "addr: 0x%x, mask: 0x%08x\n", addr, mask))
81562306a36Sopenharmony_ci		return;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	RTL_W32(tp, ERIDR, val);
81862306a36Sopenharmony_ci	r8168fp_adjust_ocp_cmd(tp, &cmd, type);
81962306a36Sopenharmony_ci	RTL_W32(tp, ERIAR, cmd);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_cistatic void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
82562306a36Sopenharmony_ci			  u32 val)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	_rtl_eri_write(tp, addr, mask, val, ERIAR_EXGMAC);
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic u32 _rtl_eri_read(struct rtl8169_private *tp, int addr, int type)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	u32 cmd = ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	r8168fp_adjust_ocp_cmd(tp, &cmd, type);
83562306a36Sopenharmony_ci	RTL_W32(tp, ERIAR, cmd);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	return rtl_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
83862306a36Sopenharmony_ci		RTL_R32(tp, ERIDR) : ~0;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic u32 rtl_eri_read(struct rtl8169_private *tp, int addr)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	return _rtl_eri_read(tp, addr, ERIAR_EXGMAC);
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic void rtl_w0w1_eri(struct rtl8169_private *tp, int addr, u32 p, u32 m)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	u32 val = rtl_eri_read(tp, addr);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	rtl_eri_write(tp, addr, ERIAR_MASK_1111, (val & ~m) | p);
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic void rtl_eri_set_bits(struct rtl8169_private *tp, int addr, u32 p)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	rtl_w0w1_eri(tp, addr, p, 0);
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic void rtl_eri_clear_bits(struct rtl8169_private *tp, int addr, u32 m)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	rtl_w0w1_eri(tp, addr, 0, m);
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic bool rtl_ocp_reg_failure(u32 reg)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	return WARN_ONCE(reg & 0xffff0001, "Invalid ocp reg %x!\n", reg);
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_ocp_gphy_cond)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	return RTL_R32(tp, GPHY_OCP) & OCPAR_FLAG;
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cistatic void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci	if (rtl_ocp_reg_failure(reg))
87662306a36Sopenharmony_ci		return;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	RTL_W32(tp, GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	if (rtl_ocp_reg_failure(reg))
88662306a36Sopenharmony_ci		return 0;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	RTL_W32(tp, GPHY_OCP, reg << 15);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	return rtl_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
89162306a36Sopenharmony_ci		(RTL_R32(tp, GPHY_OCP) & 0xffff) : -ETIMEDOUT;
89262306a36Sopenharmony_ci}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_cistatic void __r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	if (rtl_ocp_reg_failure(reg))
89762306a36Sopenharmony_ci		return;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	RTL_W32(tp, OCPDR, OCPAR_FLAG | (reg << 15) | data);
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_cistatic void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	unsigned long flags;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags);
90762306a36Sopenharmony_ci	__r8168_mac_ocp_write(tp, reg, data);
90862306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic u16 __r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	if (rtl_ocp_reg_failure(reg))
91462306a36Sopenharmony_ci		return 0;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	RTL_W32(tp, OCPDR, reg << 15);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	return RTL_R32(tp, OCPDR);
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_cistatic u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	unsigned long flags;
92462306a36Sopenharmony_ci	u16 val;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags);
92762306a36Sopenharmony_ci	val = __r8168_mac_ocp_read(tp, reg);
92862306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	return val;
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_cistatic void r8168_mac_ocp_modify(struct rtl8169_private *tp, u32 reg, u16 mask,
93462306a36Sopenharmony_ci				 u16 set)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	unsigned long flags;
93762306a36Sopenharmony_ci	u16 data;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags);
94062306a36Sopenharmony_ci	data = __r8168_mac_ocp_read(tp, reg);
94162306a36Sopenharmony_ci	__r8168_mac_ocp_write(tp, reg, (data & ~mask) | set);
94262306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci/* Work around a hw issue with RTL8168g PHY, the quirk disables
94662306a36Sopenharmony_ci * PHY MCU interrupts before PHY power-down.
94762306a36Sopenharmony_ci */
94862306a36Sopenharmony_cistatic void rtl8168g_phy_suspend_quirk(struct rtl8169_private *tp, int value)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	switch (tp->mac_version) {
95162306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40:
95262306a36Sopenharmony_ci		if (value & BMCR_RESET || !(value & BMCR_PDOWN))
95362306a36Sopenharmony_ci			rtl_eri_set_bits(tp, 0x1a8, 0xfc000000);
95462306a36Sopenharmony_ci		else
95562306a36Sopenharmony_ci			rtl_eri_clear_bits(tp, 0x1a8, 0xfc000000);
95662306a36Sopenharmony_ci		break;
95762306a36Sopenharmony_ci	default:
95862306a36Sopenharmony_ci		break;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci};
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	if (reg == 0x1f) {
96562306a36Sopenharmony_ci		tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
96662306a36Sopenharmony_ci		return;
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (tp->ocp_base != OCP_STD_PHY_BASE)
97062306a36Sopenharmony_ci		reg -= 0x10;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMCR)
97362306a36Sopenharmony_ci		rtl8168g_phy_suspend_quirk(tp, value);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
97662306a36Sopenharmony_ci}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_cistatic int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
97962306a36Sopenharmony_ci{
98062306a36Sopenharmony_ci	if (reg == 0x1f)
98162306a36Sopenharmony_ci		return tp->ocp_base == OCP_STD_PHY_BASE ? 0 : tp->ocp_base >> 4;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	if (tp->ocp_base != OCP_STD_PHY_BASE)
98462306a36Sopenharmony_ci		reg -= 0x10;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	if (reg == 0x1f) {
99262306a36Sopenharmony_ci		tp->ocp_base = value << 4;
99362306a36Sopenharmony_ci		return;
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic int mac_mcu_read(struct rtl8169_private *tp, int reg)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	return r8168_mac_ocp_read(tp, tp->ocp_base + reg);
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_phyar_cond)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	return RTL_R32(tp, PHYAR) & 0x80000000;
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	RTL_W32(tp, PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff));
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
101462306a36Sopenharmony_ci	/*
101562306a36Sopenharmony_ci	 * According to hardware specs a 20us delay is required after write
101662306a36Sopenharmony_ci	 * complete indication, but before sending next command.
101762306a36Sopenharmony_ci	 */
101862306a36Sopenharmony_ci	udelay(20);
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic int r8169_mdio_read(struct rtl8169_private *tp, int reg)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	int value;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	RTL_W32(tp, PHYAR, 0x0 | (reg & 0x1f) << 16);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	value = rtl_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
102862306a36Sopenharmony_ci		RTL_R32(tp, PHYAR) & 0xffff : -ETIMEDOUT;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	/*
103162306a36Sopenharmony_ci	 * According to hardware specs a 20us delay is required after read
103262306a36Sopenharmony_ci	 * complete indication, but before sending next command.
103362306a36Sopenharmony_ci	 */
103462306a36Sopenharmony_ci	udelay(20);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	return value;
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_ocpar_cond)
104062306a36Sopenharmony_ci{
104162306a36Sopenharmony_ci	return RTL_R32(tp, OCPAR) & OCPAR_FLAG;
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci#define R8168DP_1_MDIO_ACCESS_BIT	0x00020000
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic void r8168dp_2_mdio_start(struct rtl8169_private *tp)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci	RTL_W32(tp, 0xd0, RTL_R32(tp, 0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_cistatic void r8168dp_2_mdio_stop(struct rtl8169_private *tp)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	RTL_W32(tp, 0xd0, RTL_R32(tp, 0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cistatic void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	r8168dp_2_mdio_start(tp);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	r8169_mdio_write(tp, reg, value);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	r8168dp_2_mdio_stop(tp);
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistatic int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	int value;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	/* Work around issue with chip reporting wrong PHY ID */
107062306a36Sopenharmony_ci	if (reg == MII_PHYSID2)
107162306a36Sopenharmony_ci		return 0xc912;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	r8168dp_2_mdio_start(tp);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	value = r8169_mdio_read(tp, reg);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	r8168dp_2_mdio_stop(tp);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	return value;
108062306a36Sopenharmony_ci}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic void rtl_writephy(struct rtl8169_private *tp, int location, int val)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	switch (tp->mac_version) {
108562306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_28:
108662306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_31:
108762306a36Sopenharmony_ci		r8168dp_2_mdio_write(tp, location, val);
108862306a36Sopenharmony_ci		break;
108962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
109062306a36Sopenharmony_ci		r8168g_mdio_write(tp, location, val);
109162306a36Sopenharmony_ci		break;
109262306a36Sopenharmony_ci	default:
109362306a36Sopenharmony_ci		r8169_mdio_write(tp, location, val);
109462306a36Sopenharmony_ci		break;
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_cistatic int rtl_readphy(struct rtl8169_private *tp, int location)
109962306a36Sopenharmony_ci{
110062306a36Sopenharmony_ci	switch (tp->mac_version) {
110162306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_28:
110262306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_31:
110362306a36Sopenharmony_ci		return r8168dp_2_mdio_read(tp, location);
110462306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
110562306a36Sopenharmony_ci		return r8168g_mdio_read(tp, location);
110662306a36Sopenharmony_ci	default:
110762306a36Sopenharmony_ci		return r8169_mdio_read(tp, location);
110862306a36Sopenharmony_ci	}
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_ephyar_cond)
111262306a36Sopenharmony_ci{
111362306a36Sopenharmony_ci	return RTL_R32(tp, EPHYAR) & EPHYAR_FLAG;
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	RTL_W32(tp, EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
111962306a36Sopenharmony_ci		(reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100);
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	udelay(10);
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	RTL_W32(tp, EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	return rtl_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ?
113162306a36Sopenharmony_ci		RTL_R32(tp, EPHYAR) & EPHYAR_DATA_MASK : ~0;
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic u32 r8168dp_ocp_read(struct rtl8169_private *tp, u16 reg)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	RTL_W32(tp, OCPAR, 0x0fu << 12 | (reg & 0x0fff));
113762306a36Sopenharmony_ci	return rtl_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ?
113862306a36Sopenharmony_ci		RTL_R32(tp, OCPDR) : ~0;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic u32 r8168ep_ocp_read(struct rtl8169_private *tp, u16 reg)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	return _rtl_eri_read(tp, reg, ERIAR_OOB);
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic void r8168dp_ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg,
114762306a36Sopenharmony_ci			      u32 data)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	RTL_W32(tp, OCPDR, data);
115062306a36Sopenharmony_ci	RTL_W32(tp, OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
115162306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20);
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_cistatic void r8168ep_ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg,
115562306a36Sopenharmony_ci			      u32 data)
115662306a36Sopenharmony_ci{
115762306a36Sopenharmony_ci	_rtl_eri_write(tp, reg, ((u32)mask & 0x0f) << ERIAR_MASK_SHIFT,
115862306a36Sopenharmony_ci		       data, ERIAR_OOB);
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic void r8168dp_oob_notify(struct rtl8169_private *tp, u8 cmd)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	rtl_eri_write(tp, 0xe8, ERIAR_MASK_0001, cmd);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	r8168dp_ocp_write(tp, 0x1, 0x30, 0x00000001);
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci#define OOB_CMD_RESET		0x00
116962306a36Sopenharmony_ci#define OOB_CMD_DRIVER_START	0x05
117062306a36Sopenharmony_ci#define OOB_CMD_DRIVER_STOP	0x06
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
117562306a36Sopenharmony_ci}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_dp_ocp_read_cond)
117862306a36Sopenharmony_ci{
117962306a36Sopenharmony_ci	u16 reg;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	reg = rtl8168_get_ocp_reg(tp);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	return r8168dp_ocp_read(tp, reg) & 0x00000800;
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_ep_ocp_read_cond)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	return r8168ep_ocp_read(tp, 0x124) & 0x00000001;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_ocp_tx_cond)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	return RTL_R8(tp, IBISR0) & 0x20;
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_cistatic void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
119762306a36Sopenharmony_ci{
119862306a36Sopenharmony_ci	RTL_W8(tp, IBCR2, RTL_R8(tp, IBCR2) & ~0x01);
119962306a36Sopenharmony_ci	rtl_loop_wait_high(tp, &rtl_ocp_tx_cond, 50000, 2000);
120062306a36Sopenharmony_ci	RTL_W8(tp, IBISR0, RTL_R8(tp, IBISR0) | 0x20);
120162306a36Sopenharmony_ci	RTL_W8(tp, IBCR0, RTL_R8(tp, IBCR0) & ~0x01);
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_cistatic void rtl8168dp_driver_start(struct rtl8169_private *tp)
120562306a36Sopenharmony_ci{
120662306a36Sopenharmony_ci	r8168dp_oob_notify(tp, OOB_CMD_DRIVER_START);
120762306a36Sopenharmony_ci	rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10);
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_cistatic void rtl8168ep_driver_start(struct rtl8169_private *tp)
121162306a36Sopenharmony_ci{
121262306a36Sopenharmony_ci	r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_START);
121362306a36Sopenharmony_ci	r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01);
121462306a36Sopenharmony_ci	rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic void rtl8168_driver_start(struct rtl8169_private *tp)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	if (tp->dash_type == RTL_DASH_DP)
122062306a36Sopenharmony_ci		rtl8168dp_driver_start(tp);
122162306a36Sopenharmony_ci	else
122262306a36Sopenharmony_ci		rtl8168ep_driver_start(tp);
122362306a36Sopenharmony_ci}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_cistatic void rtl8168dp_driver_stop(struct rtl8169_private *tp)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	r8168dp_oob_notify(tp, OOB_CMD_DRIVER_STOP);
122862306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10);
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_cistatic void rtl8168ep_driver_stop(struct rtl8169_private *tp)
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci	rtl8168ep_stop_cmac(tp);
123462306a36Sopenharmony_ci	r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP);
123562306a36Sopenharmony_ci	r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01);
123662306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10);
123762306a36Sopenharmony_ci}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_cistatic void rtl8168_driver_stop(struct rtl8169_private *tp)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	if (tp->dash_type == RTL_DASH_DP)
124262306a36Sopenharmony_ci		rtl8168dp_driver_stop(tp);
124362306a36Sopenharmony_ci	else
124462306a36Sopenharmony_ci		rtl8168ep_driver_stop(tp);
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_cistatic bool r8168dp_check_dash(struct rtl8169_private *tp)
124862306a36Sopenharmony_ci{
124962306a36Sopenharmony_ci	u16 reg = rtl8168_get_ocp_reg(tp);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	return r8168dp_ocp_read(tp, reg) & BIT(15);
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic bool r8168ep_check_dash(struct rtl8169_private *tp)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	return r8168ep_ocp_read(tp, 0x128) & BIT(0);
125762306a36Sopenharmony_ci}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_cistatic bool rtl_dash_is_enabled(struct rtl8169_private *tp)
126062306a36Sopenharmony_ci{
126162306a36Sopenharmony_ci	switch (tp->dash_type) {
126262306a36Sopenharmony_ci	case RTL_DASH_DP:
126362306a36Sopenharmony_ci		return r8168dp_check_dash(tp);
126462306a36Sopenharmony_ci	case RTL_DASH_EP:
126562306a36Sopenharmony_ci		return r8168ep_check_dash(tp);
126662306a36Sopenharmony_ci	default:
126762306a36Sopenharmony_ci		return false;
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	switch (tp->mac_version) {
127462306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_28:
127562306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_31:
127662306a36Sopenharmony_ci		return RTL_DASH_DP;
127762306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53:
127862306a36Sopenharmony_ci		return RTL_DASH_EP;
127962306a36Sopenharmony_ci	default:
128062306a36Sopenharmony_ci		return RTL_DASH_NONE;
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	switch (tp->mac_version) {
128762306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26:
128862306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30:
128962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37:
129062306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63:
129162306a36Sopenharmony_ci		if (enable)
129262306a36Sopenharmony_ci			RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN);
129362306a36Sopenharmony_ci		else
129462306a36Sopenharmony_ci			RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | D3_NO_PLL_DOWN);
129562306a36Sopenharmony_ci		break;
129662306a36Sopenharmony_ci	default:
129762306a36Sopenharmony_ci		break;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_cistatic void rtl_reset_packet_filter(struct rtl8169_private *tp)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	rtl_eri_clear_bits(tp, 0xdc, BIT(0));
130462306a36Sopenharmony_ci	rtl_eri_set_bits(tp, 0xdc, BIT(0));
130562306a36Sopenharmony_ci}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_efusear_cond)
130862306a36Sopenharmony_ci{
130962306a36Sopenharmony_ci	return RTL_R32(tp, EFUSEAR) & EFUSEAR_FLAG;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ciu8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	RTL_W32(tp, EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return rtl_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ?
131762306a36Sopenharmony_ci		RTL_R32(tp, EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic u32 rtl_get_events(struct rtl8169_private *tp)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	if (rtl_is_8125(tp))
132362306a36Sopenharmony_ci		return RTL_R32(tp, IntrStatus_8125);
132462306a36Sopenharmony_ci	else
132562306a36Sopenharmony_ci		return RTL_R16(tp, IntrStatus);
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_cistatic void rtl_ack_events(struct rtl8169_private *tp, u32 bits)
132962306a36Sopenharmony_ci{
133062306a36Sopenharmony_ci	if (rtl_is_8125(tp))
133162306a36Sopenharmony_ci		RTL_W32(tp, IntrStatus_8125, bits);
133262306a36Sopenharmony_ci	else
133362306a36Sopenharmony_ci		RTL_W16(tp, IntrStatus, bits);
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic void rtl_irq_disable(struct rtl8169_private *tp)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	if (rtl_is_8125(tp))
133962306a36Sopenharmony_ci		RTL_W32(tp, IntrMask_8125, 0);
134062306a36Sopenharmony_ci	else
134162306a36Sopenharmony_ci		RTL_W16(tp, IntrMask, 0);
134262306a36Sopenharmony_ci}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_cistatic void rtl_irq_enable(struct rtl8169_private *tp)
134562306a36Sopenharmony_ci{
134662306a36Sopenharmony_ci	if (rtl_is_8125(tp))
134762306a36Sopenharmony_ci		RTL_W32(tp, IntrMask_8125, tp->irq_mask);
134862306a36Sopenharmony_ci	else
134962306a36Sopenharmony_ci		RTL_W16(tp, IntrMask, tp->irq_mask);
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	rtl_irq_disable(tp);
135562306a36Sopenharmony_ci	rtl_ack_events(tp, 0xffffffff);
135662306a36Sopenharmony_ci	rtl_pci_commit(tp);
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic void rtl_link_chg_patch(struct rtl8169_private *tp)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	struct phy_device *phydev = tp->phydev;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
136462306a36Sopenharmony_ci	    tp->mac_version == RTL_GIGA_MAC_VER_38) {
136562306a36Sopenharmony_ci		if (phydev->speed == SPEED_1000) {
136662306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011);
136762306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);
136862306a36Sopenharmony_ci		} else if (phydev->speed == SPEED_100) {
136962306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f);
137062306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);
137162306a36Sopenharmony_ci		} else {
137262306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f);
137362306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f);
137462306a36Sopenharmony_ci		}
137562306a36Sopenharmony_ci		rtl_reset_packet_filter(tp);
137662306a36Sopenharmony_ci	} else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
137762306a36Sopenharmony_ci		   tp->mac_version == RTL_GIGA_MAC_VER_36) {
137862306a36Sopenharmony_ci		if (phydev->speed == SPEED_1000) {
137962306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011);
138062306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);
138162306a36Sopenharmony_ci		} else {
138262306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f);
138362306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f);
138462306a36Sopenharmony_ci		}
138562306a36Sopenharmony_ci	} else if (tp->mac_version == RTL_GIGA_MAC_VER_37) {
138662306a36Sopenharmony_ci		if (phydev->speed == SPEED_10) {
138762306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02);
138862306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060a);
138962306a36Sopenharmony_ci		} else {
139062306a36Sopenharmony_ci			rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000);
139162306a36Sopenharmony_ci		}
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_cistatic void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	wol->supported = WAKE_ANY;
140262306a36Sopenharmony_ci	wol->wolopts = tp->saved_wolopts;
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cistatic void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
140662306a36Sopenharmony_ci{
140762306a36Sopenharmony_ci	static const struct {
140862306a36Sopenharmony_ci		u32 opt;
140962306a36Sopenharmony_ci		u16 reg;
141062306a36Sopenharmony_ci		u8  mask;
141162306a36Sopenharmony_ci	} cfg[] = {
141262306a36Sopenharmony_ci		{ WAKE_PHY,   Config3, LinkUp },
141362306a36Sopenharmony_ci		{ WAKE_UCAST, Config5, UWF },
141462306a36Sopenharmony_ci		{ WAKE_BCAST, Config5, BWF },
141562306a36Sopenharmony_ci		{ WAKE_MCAST, Config5, MWF },
141662306a36Sopenharmony_ci		{ WAKE_ANY,   Config5, LanWake },
141762306a36Sopenharmony_ci		{ WAKE_MAGIC, Config3, MagicPacket }
141862306a36Sopenharmony_ci	};
141962306a36Sopenharmony_ci	unsigned int i, tmp = ARRAY_SIZE(cfg);
142062306a36Sopenharmony_ci	unsigned long flags;
142162306a36Sopenharmony_ci	u8 options;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	rtl_unlock_config_regs(tp);
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if (rtl_is_8168evl_up(tp)) {
142662306a36Sopenharmony_ci		tmp--;
142762306a36Sopenharmony_ci		if (wolopts & WAKE_MAGIC)
142862306a36Sopenharmony_ci			rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2);
142962306a36Sopenharmony_ci		else
143062306a36Sopenharmony_ci			rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2);
143162306a36Sopenharmony_ci	} else if (rtl_is_8125(tp)) {
143262306a36Sopenharmony_ci		tmp--;
143362306a36Sopenharmony_ci		if (wolopts & WAKE_MAGIC)
143462306a36Sopenharmony_ci			r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0));
143562306a36Sopenharmony_ci		else
143662306a36Sopenharmony_ci			r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0);
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&tp->config25_lock, flags);
144062306a36Sopenharmony_ci	for (i = 0; i < tmp; i++) {
144162306a36Sopenharmony_ci		options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask;
144262306a36Sopenharmony_ci		if (wolopts & cfg[i].opt)
144362306a36Sopenharmony_ci			options |= cfg[i].mask;
144462306a36Sopenharmony_ci		RTL_W8(tp, cfg[i].reg, options);
144562306a36Sopenharmony_ci	}
144662306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	switch (tp->mac_version) {
144962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
145062306a36Sopenharmony_ci		options = RTL_R8(tp, Config1) & ~PMEnable;
145162306a36Sopenharmony_ci		if (wolopts)
145262306a36Sopenharmony_ci			options |= PMEnable;
145362306a36Sopenharmony_ci		RTL_W8(tp, Config1, options);
145462306a36Sopenharmony_ci		break;
145562306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_34:
145662306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_37:
145762306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63:
145862306a36Sopenharmony_ci		if (wolopts)
145962306a36Sopenharmony_ci			rtl_mod_config2(tp, 0, PME_SIGNAL);
146062306a36Sopenharmony_ci		else
146162306a36Sopenharmony_ci			rtl_mod_config2(tp, PME_SIGNAL, 0);
146262306a36Sopenharmony_ci		break;
146362306a36Sopenharmony_ci	default:
146462306a36Sopenharmony_ci		break;
146562306a36Sopenharmony_ci	}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	rtl_lock_config_regs(tp);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	device_set_wakeup_enable(tp_to_dev(tp), wolopts);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	if (!tp->dash_enabled) {
147262306a36Sopenharmony_ci		rtl_set_d3_pll_down(tp, !wolopts);
147362306a36Sopenharmony_ci		tp->dev->wol_enabled = wolopts ? 1 : 0;
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_cistatic int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	if (wol->wolopts & ~WAKE_ANY)
148262306a36Sopenharmony_ci		return -EINVAL;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	tp->saved_wolopts = wol->wolopts;
148562306a36Sopenharmony_ci	__rtl8169_set_wol(tp, tp->saved_wolopts);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return 0;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cistatic void rtl8169_get_drvinfo(struct net_device *dev,
149162306a36Sopenharmony_ci				struct ethtool_drvinfo *info)
149262306a36Sopenharmony_ci{
149362306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
149462306a36Sopenharmony_ci	struct rtl_fw *rtl_fw = tp->rtl_fw;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
149762306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
149862306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
149962306a36Sopenharmony_ci	if (rtl_fw)
150062306a36Sopenharmony_ci		strscpy(info->fw_version, rtl_fw->version,
150162306a36Sopenharmony_ci			sizeof(info->fw_version));
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cistatic int rtl8169_get_regs_len(struct net_device *dev)
150562306a36Sopenharmony_ci{
150662306a36Sopenharmony_ci	return R8169_REGS_SIZE;
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_cistatic netdev_features_t rtl8169_fix_features(struct net_device *dev,
151062306a36Sopenharmony_ci	netdev_features_t features)
151162306a36Sopenharmony_ci{
151262306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	if (dev->mtu > TD_MSS_MAX)
151562306a36Sopenharmony_ci		features &= ~NETIF_F_ALL_TSO;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	if (dev->mtu > ETH_DATA_LEN &&
151862306a36Sopenharmony_ci	    tp->mac_version > RTL_GIGA_MAC_VER_06)
151962306a36Sopenharmony_ci		features &= ~(NETIF_F_CSUM_MASK | NETIF_F_ALL_TSO);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	return features;
152262306a36Sopenharmony_ci}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_cistatic void rtl_set_rx_config_features(struct rtl8169_private *tp,
152562306a36Sopenharmony_ci				       netdev_features_t features)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	u32 rx_config = RTL_R32(tp, RxConfig);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (features & NETIF_F_RXALL)
153062306a36Sopenharmony_ci		rx_config |= RX_CONFIG_ACCEPT_ERR_MASK;
153162306a36Sopenharmony_ci	else
153262306a36Sopenharmony_ci		rx_config &= ~RX_CONFIG_ACCEPT_ERR_MASK;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	if (rtl_is_8125(tp)) {
153562306a36Sopenharmony_ci		if (features & NETIF_F_HW_VLAN_CTAG_RX)
153662306a36Sopenharmony_ci			rx_config |= RX_VLAN_8125;
153762306a36Sopenharmony_ci		else
153862306a36Sopenharmony_ci			rx_config &= ~RX_VLAN_8125;
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	RTL_W32(tp, RxConfig, rx_config);
154262306a36Sopenharmony_ci}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_cistatic int rtl8169_set_features(struct net_device *dev,
154562306a36Sopenharmony_ci				netdev_features_t features)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	rtl_set_rx_config_features(tp, features);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	if (features & NETIF_F_RXCSUM)
155262306a36Sopenharmony_ci		tp->cp_cmd |= RxChkSum;
155362306a36Sopenharmony_ci	else
155462306a36Sopenharmony_ci		tp->cp_cmd &= ~RxChkSum;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	if (!rtl_is_8125(tp)) {
155762306a36Sopenharmony_ci		if (features & NETIF_F_HW_VLAN_CTAG_RX)
155862306a36Sopenharmony_ci			tp->cp_cmd |= RxVlan;
155962306a36Sopenharmony_ci		else
156062306a36Sopenharmony_ci			tp->cp_cmd &= ~RxVlan;
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	RTL_W16(tp, CPlusCmd, tp->cp_cmd);
156462306a36Sopenharmony_ci	rtl_pci_commit(tp);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	return 0;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	return (skb_vlan_tag_present(skb)) ?
157262306a36Sopenharmony_ci		TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00;
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
157662306a36Sopenharmony_ci{
157762306a36Sopenharmony_ci	u32 opts2 = le32_to_cpu(desc->opts2);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	if (opts2 & RxVlanTag)
158062306a36Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff));
158162306a36Sopenharmony_ci}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_cistatic void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
158462306a36Sopenharmony_ci			     void *p)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
158762306a36Sopenharmony_ci	u32 __iomem *data = tp->mmio_addr;
158862306a36Sopenharmony_ci	u32 *dw = p;
158962306a36Sopenharmony_ci	int i;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	for (i = 0; i < R8169_REGS_SIZE; i += 4)
159262306a36Sopenharmony_ci		memcpy_fromio(dw++, data++, 4);
159362306a36Sopenharmony_ci}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_cistatic const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
159662306a36Sopenharmony_ci	"tx_packets",
159762306a36Sopenharmony_ci	"rx_packets",
159862306a36Sopenharmony_ci	"tx_errors",
159962306a36Sopenharmony_ci	"rx_errors",
160062306a36Sopenharmony_ci	"rx_missed",
160162306a36Sopenharmony_ci	"align_errors",
160262306a36Sopenharmony_ci	"tx_single_collisions",
160362306a36Sopenharmony_ci	"tx_multi_collisions",
160462306a36Sopenharmony_ci	"unicast",
160562306a36Sopenharmony_ci	"broadcast",
160662306a36Sopenharmony_ci	"multicast",
160762306a36Sopenharmony_ci	"tx_aborted",
160862306a36Sopenharmony_ci	"tx_underrun",
160962306a36Sopenharmony_ci};
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_cistatic int rtl8169_get_sset_count(struct net_device *dev, int sset)
161262306a36Sopenharmony_ci{
161362306a36Sopenharmony_ci	switch (sset) {
161462306a36Sopenharmony_ci	case ETH_SS_STATS:
161562306a36Sopenharmony_ci		return ARRAY_SIZE(rtl8169_gstrings);
161662306a36Sopenharmony_ci	default:
161762306a36Sopenharmony_ci		return -EOPNOTSUPP;
161862306a36Sopenharmony_ci	}
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_counters_cond)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	return RTL_R32(tp, CounterAddrLow) & (CounterReset | CounterDump);
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_cistatic void rtl8169_do_counters(struct rtl8169_private *tp, u32 counter_cmd)
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	u32 cmd = lower_32_bits(tp->counters_phys_addr);
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	RTL_W32(tp, CounterAddrHigh, upper_32_bits(tp->counters_phys_addr));
163162306a36Sopenharmony_ci	rtl_pci_commit(tp);
163262306a36Sopenharmony_ci	RTL_W32(tp, CounterAddrLow, cmd);
163362306a36Sopenharmony_ci	RTL_W32(tp, CounterAddrLow, cmd | counter_cmd);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_counters_cond, 10, 1000);
163662306a36Sopenharmony_ci}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_cistatic void rtl8169_update_counters(struct rtl8169_private *tp)
163962306a36Sopenharmony_ci{
164062306a36Sopenharmony_ci	u8 val = RTL_R8(tp, ChipCmd);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	/*
164362306a36Sopenharmony_ci	 * Some chips are unable to dump tally counters when the receiver
164462306a36Sopenharmony_ci	 * is disabled. If 0xff chip may be in a PCI power-save state.
164562306a36Sopenharmony_ci	 */
164662306a36Sopenharmony_ci	if (val & CmdRxEnb && val != 0xff)
164762306a36Sopenharmony_ci		rtl8169_do_counters(tp, CounterDump);
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cistatic void rtl8169_init_counter_offsets(struct rtl8169_private *tp)
165162306a36Sopenharmony_ci{
165262306a36Sopenharmony_ci	struct rtl8169_counters *counters = tp->counters;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	/*
165562306a36Sopenharmony_ci	 * rtl8169_init_counter_offsets is called from rtl_open.  On chip
165662306a36Sopenharmony_ci	 * versions prior to RTL_GIGA_MAC_VER_19 the tally counters are only
165762306a36Sopenharmony_ci	 * reset by a power cycle, while the counter values collected by the
165862306a36Sopenharmony_ci	 * driver are reset at every driver unload/load cycle.
165962306a36Sopenharmony_ci	 *
166062306a36Sopenharmony_ci	 * To make sure the HW values returned by @get_stats64 match the SW
166162306a36Sopenharmony_ci	 * values, we collect the initial values at first open(*) and use them
166262306a36Sopenharmony_ci	 * as offsets to normalize the values returned by @get_stats64.
166362306a36Sopenharmony_ci	 *
166462306a36Sopenharmony_ci	 * (*) We can't call rtl8169_init_counter_offsets from rtl_init_one
166562306a36Sopenharmony_ci	 * for the reason stated in rtl8169_update_counters; CmdRxEnb is only
166662306a36Sopenharmony_ci	 * set at open time by rtl_hw_start.
166762306a36Sopenharmony_ci	 */
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if (tp->tc_offset.inited)
167062306a36Sopenharmony_ci		return;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	if (tp->mac_version >= RTL_GIGA_MAC_VER_19) {
167362306a36Sopenharmony_ci		rtl8169_do_counters(tp, CounterReset);
167462306a36Sopenharmony_ci	} else {
167562306a36Sopenharmony_ci		rtl8169_update_counters(tp);
167662306a36Sopenharmony_ci		tp->tc_offset.tx_errors = counters->tx_errors;
167762306a36Sopenharmony_ci		tp->tc_offset.tx_multi_collision = counters->tx_multi_collision;
167862306a36Sopenharmony_ci		tp->tc_offset.tx_aborted = counters->tx_aborted;
167962306a36Sopenharmony_ci		tp->tc_offset.rx_missed = counters->rx_missed;
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	tp->tc_offset.inited = true;
168362306a36Sopenharmony_ci}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_cistatic void rtl8169_get_ethtool_stats(struct net_device *dev,
168662306a36Sopenharmony_ci				      struct ethtool_stats *stats, u64 *data)
168762306a36Sopenharmony_ci{
168862306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
168962306a36Sopenharmony_ci	struct rtl8169_counters *counters;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	counters = tp->counters;
169262306a36Sopenharmony_ci	rtl8169_update_counters(tp);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	data[0] = le64_to_cpu(counters->tx_packets);
169562306a36Sopenharmony_ci	data[1] = le64_to_cpu(counters->rx_packets);
169662306a36Sopenharmony_ci	data[2] = le64_to_cpu(counters->tx_errors);
169762306a36Sopenharmony_ci	data[3] = le32_to_cpu(counters->rx_errors);
169862306a36Sopenharmony_ci	data[4] = le16_to_cpu(counters->rx_missed);
169962306a36Sopenharmony_ci	data[5] = le16_to_cpu(counters->align_errors);
170062306a36Sopenharmony_ci	data[6] = le32_to_cpu(counters->tx_one_collision);
170162306a36Sopenharmony_ci	data[7] = le32_to_cpu(counters->tx_multi_collision);
170262306a36Sopenharmony_ci	data[8] = le64_to_cpu(counters->rx_unicast);
170362306a36Sopenharmony_ci	data[9] = le64_to_cpu(counters->rx_broadcast);
170462306a36Sopenharmony_ci	data[10] = le32_to_cpu(counters->rx_multicast);
170562306a36Sopenharmony_ci	data[11] = le16_to_cpu(counters->tx_aborted);
170662306a36Sopenharmony_ci	data[12] = le16_to_cpu(counters->tx_underun);
170762306a36Sopenharmony_ci}
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_cistatic void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci	switch(stringset) {
171262306a36Sopenharmony_ci	case ETH_SS_STATS:
171362306a36Sopenharmony_ci		memcpy(data, rtl8169_gstrings, sizeof(rtl8169_gstrings));
171462306a36Sopenharmony_ci		break;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci/*
171962306a36Sopenharmony_ci * Interrupt coalescing
172062306a36Sopenharmony_ci *
172162306a36Sopenharmony_ci * > 1 - the availability of the IntrMitigate (0xe2) register through the
172262306a36Sopenharmony_ci * >     8169, 8168 and 810x line of chipsets
172362306a36Sopenharmony_ci *
172462306a36Sopenharmony_ci * 8169, 8168, and 8136(810x) serial chipsets support it.
172562306a36Sopenharmony_ci *
172662306a36Sopenharmony_ci * > 2 - the Tx timer unit at gigabit speed
172762306a36Sopenharmony_ci *
172862306a36Sopenharmony_ci * The unit of the timer depends on both the speed and the setting of CPlusCmd
172962306a36Sopenharmony_ci * (0xe0) bit 1 and bit 0.
173062306a36Sopenharmony_ci *
173162306a36Sopenharmony_ci * For 8169
173262306a36Sopenharmony_ci * bit[1:0] \ speed        1000M           100M            10M
173362306a36Sopenharmony_ci * 0 0                     320ns           2.56us          40.96us
173462306a36Sopenharmony_ci * 0 1                     2.56us          20.48us         327.7us
173562306a36Sopenharmony_ci * 1 0                     5.12us          40.96us         655.4us
173662306a36Sopenharmony_ci * 1 1                     10.24us         81.92us         1.31ms
173762306a36Sopenharmony_ci *
173862306a36Sopenharmony_ci * For the other
173962306a36Sopenharmony_ci * bit[1:0] \ speed        1000M           100M            10M
174062306a36Sopenharmony_ci * 0 0                     5us             2.56us          40.96us
174162306a36Sopenharmony_ci * 0 1                     40us            20.48us         327.7us
174262306a36Sopenharmony_ci * 1 0                     80us            40.96us         655.4us
174362306a36Sopenharmony_ci * 1 1                     160us           81.92us         1.31ms
174462306a36Sopenharmony_ci */
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci/* rx/tx scale factors for all CPlusCmd[0:1] cases */
174762306a36Sopenharmony_cistruct rtl_coalesce_info {
174862306a36Sopenharmony_ci	u32 speed;
174962306a36Sopenharmony_ci	u32 scale_nsecs[4];
175062306a36Sopenharmony_ci};
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci/* produce array with base delay *1, *8, *8*2, *8*2*2 */
175362306a36Sopenharmony_ci#define COALESCE_DELAY(d) { (d), 8 * (d), 16 * (d), 32 * (d) }
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_cistatic const struct rtl_coalesce_info rtl_coalesce_info_8169[] = {
175662306a36Sopenharmony_ci	{ SPEED_1000,	COALESCE_DELAY(320) },
175762306a36Sopenharmony_ci	{ SPEED_100,	COALESCE_DELAY(2560) },
175862306a36Sopenharmony_ci	{ SPEED_10,	COALESCE_DELAY(40960) },
175962306a36Sopenharmony_ci	{ 0 },
176062306a36Sopenharmony_ci};
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_cistatic const struct rtl_coalesce_info rtl_coalesce_info_8168_8136[] = {
176362306a36Sopenharmony_ci	{ SPEED_1000,	COALESCE_DELAY(5000) },
176462306a36Sopenharmony_ci	{ SPEED_100,	COALESCE_DELAY(2560) },
176562306a36Sopenharmony_ci	{ SPEED_10,	COALESCE_DELAY(40960) },
176662306a36Sopenharmony_ci	{ 0 },
176762306a36Sopenharmony_ci};
176862306a36Sopenharmony_ci#undef COALESCE_DELAY
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci/* get rx/tx scale vector corresponding to current speed */
177162306a36Sopenharmony_cistatic const struct rtl_coalesce_info *
177262306a36Sopenharmony_cirtl_coalesce_info(struct rtl8169_private *tp)
177362306a36Sopenharmony_ci{
177462306a36Sopenharmony_ci	const struct rtl_coalesce_info *ci;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
177762306a36Sopenharmony_ci		ci = rtl_coalesce_info_8169;
177862306a36Sopenharmony_ci	else
177962306a36Sopenharmony_ci		ci = rtl_coalesce_info_8168_8136;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	/* if speed is unknown assume highest one */
178262306a36Sopenharmony_ci	if (tp->phydev->speed == SPEED_UNKNOWN)
178362306a36Sopenharmony_ci		return ci;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	for (; ci->speed; ci++) {
178662306a36Sopenharmony_ci		if (tp->phydev->speed == ci->speed)
178762306a36Sopenharmony_ci			return ci;
178862306a36Sopenharmony_ci	}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	return ERR_PTR(-ELNRNG);
179162306a36Sopenharmony_ci}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_cistatic int rtl_get_coalesce(struct net_device *dev,
179462306a36Sopenharmony_ci			    struct ethtool_coalesce *ec,
179562306a36Sopenharmony_ci			    struct kernel_ethtool_coalesce *kernel_coal,
179662306a36Sopenharmony_ci			    struct netlink_ext_ack *extack)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
179962306a36Sopenharmony_ci	const struct rtl_coalesce_info *ci;
180062306a36Sopenharmony_ci	u32 scale, c_us, c_fr;
180162306a36Sopenharmony_ci	u16 intrmit;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	if (rtl_is_8125(tp))
180462306a36Sopenharmony_ci		return -EOPNOTSUPP;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	memset(ec, 0, sizeof(*ec));
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	/* get rx/tx scale corresponding to current speed and CPlusCmd[0:1] */
180962306a36Sopenharmony_ci	ci = rtl_coalesce_info(tp);
181062306a36Sopenharmony_ci	if (IS_ERR(ci))
181162306a36Sopenharmony_ci		return PTR_ERR(ci);
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	scale = ci->scale_nsecs[tp->cp_cmd & INTT_MASK];
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	intrmit = RTL_R16(tp, IntrMitigate);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	c_us = FIELD_GET(RTL_COALESCE_TX_USECS, intrmit);
181862306a36Sopenharmony_ci	ec->tx_coalesce_usecs = DIV_ROUND_UP(c_us * scale, 1000);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	c_fr = FIELD_GET(RTL_COALESCE_TX_FRAMES, intrmit);
182162306a36Sopenharmony_ci	/* ethtool_coalesce states usecs and max_frames must not both be 0 */
182262306a36Sopenharmony_ci	ec->tx_max_coalesced_frames = (c_us || c_fr) ? c_fr * 4 : 1;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	c_us = FIELD_GET(RTL_COALESCE_RX_USECS, intrmit);
182562306a36Sopenharmony_ci	ec->rx_coalesce_usecs = DIV_ROUND_UP(c_us * scale, 1000);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	c_fr = FIELD_GET(RTL_COALESCE_RX_FRAMES, intrmit);
182862306a36Sopenharmony_ci	ec->rx_max_coalesced_frames = (c_us || c_fr) ? c_fr * 4 : 1;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	return 0;
183162306a36Sopenharmony_ci}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci/* choose appropriate scale factor and CPlusCmd[0:1] for (speed, usec) */
183462306a36Sopenharmony_cistatic int rtl_coalesce_choose_scale(struct rtl8169_private *tp, u32 usec,
183562306a36Sopenharmony_ci				     u16 *cp01)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	const struct rtl_coalesce_info *ci;
183862306a36Sopenharmony_ci	u16 i;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	ci = rtl_coalesce_info(tp);
184162306a36Sopenharmony_ci	if (IS_ERR(ci))
184262306a36Sopenharmony_ci		return PTR_ERR(ci);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
184562306a36Sopenharmony_ci		if (usec <= ci->scale_nsecs[i] * RTL_COALESCE_T_MAX / 1000U) {
184662306a36Sopenharmony_ci			*cp01 = i;
184762306a36Sopenharmony_ci			return ci->scale_nsecs[i];
184862306a36Sopenharmony_ci		}
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	return -ERANGE;
185262306a36Sopenharmony_ci}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_cistatic int rtl_set_coalesce(struct net_device *dev,
185562306a36Sopenharmony_ci			    struct ethtool_coalesce *ec,
185662306a36Sopenharmony_ci			    struct kernel_ethtool_coalesce *kernel_coal,
185762306a36Sopenharmony_ci			    struct netlink_ext_ack *extack)
185862306a36Sopenharmony_ci{
185962306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
186062306a36Sopenharmony_ci	u32 tx_fr = ec->tx_max_coalesced_frames;
186162306a36Sopenharmony_ci	u32 rx_fr = ec->rx_max_coalesced_frames;
186262306a36Sopenharmony_ci	u32 coal_usec_max, units;
186362306a36Sopenharmony_ci	u16 w = 0, cp01 = 0;
186462306a36Sopenharmony_ci	int scale;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	if (rtl_is_8125(tp))
186762306a36Sopenharmony_ci		return -EOPNOTSUPP;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	if (rx_fr > RTL_COALESCE_FRAME_MAX || tx_fr > RTL_COALESCE_FRAME_MAX)
187062306a36Sopenharmony_ci		return -ERANGE;
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	coal_usec_max = max(ec->rx_coalesce_usecs, ec->tx_coalesce_usecs);
187362306a36Sopenharmony_ci	scale = rtl_coalesce_choose_scale(tp, coal_usec_max, &cp01);
187462306a36Sopenharmony_ci	if (scale < 0)
187562306a36Sopenharmony_ci		return scale;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	/* Accept max_frames=1 we returned in rtl_get_coalesce. Accept it
187862306a36Sopenharmony_ci	 * not only when usecs=0 because of e.g. the following scenario:
187962306a36Sopenharmony_ci	 *
188062306a36Sopenharmony_ci	 * - both rx_usecs=0 & rx_frames=0 in hardware (no delay on RX)
188162306a36Sopenharmony_ci	 * - rtl_get_coalesce returns rx_usecs=0, rx_frames=1
188262306a36Sopenharmony_ci	 * - then user does `ethtool -C eth0 rx-usecs 100`
188362306a36Sopenharmony_ci	 *
188462306a36Sopenharmony_ci	 * Since ethtool sends to kernel whole ethtool_coalesce settings,
188562306a36Sopenharmony_ci	 * if we want to ignore rx_frames then it has to be set to 0.
188662306a36Sopenharmony_ci	 */
188762306a36Sopenharmony_ci	if (rx_fr == 1)
188862306a36Sopenharmony_ci		rx_fr = 0;
188962306a36Sopenharmony_ci	if (tx_fr == 1)
189062306a36Sopenharmony_ci		tx_fr = 0;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	/* HW requires time limit to be set if frame limit is set */
189362306a36Sopenharmony_ci	if ((tx_fr && !ec->tx_coalesce_usecs) ||
189462306a36Sopenharmony_ci	    (rx_fr && !ec->rx_coalesce_usecs))
189562306a36Sopenharmony_ci		return -EINVAL;
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	w |= FIELD_PREP(RTL_COALESCE_TX_FRAMES, DIV_ROUND_UP(tx_fr, 4));
189862306a36Sopenharmony_ci	w |= FIELD_PREP(RTL_COALESCE_RX_FRAMES, DIV_ROUND_UP(rx_fr, 4));
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	units = DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000U, scale);
190162306a36Sopenharmony_ci	w |= FIELD_PREP(RTL_COALESCE_TX_USECS, units);
190262306a36Sopenharmony_ci	units = DIV_ROUND_UP(ec->rx_coalesce_usecs * 1000U, scale);
190362306a36Sopenharmony_ci	w |= FIELD_PREP(RTL_COALESCE_RX_USECS, units);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	RTL_W16(tp, IntrMitigate, w);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	/* Meaning of PktCntrDisable bit changed from RTL8168e-vl */
190862306a36Sopenharmony_ci	if (rtl_is_8168evl_up(tp)) {
190962306a36Sopenharmony_ci		if (!rx_fr && !tx_fr)
191062306a36Sopenharmony_ci			/* disable packet counter */
191162306a36Sopenharmony_ci			tp->cp_cmd |= PktCntrDisable;
191262306a36Sopenharmony_ci		else
191362306a36Sopenharmony_ci			tp->cp_cmd &= ~PktCntrDisable;
191462306a36Sopenharmony_ci	}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	tp->cp_cmd = (tp->cp_cmd & ~INTT_MASK) | cp01;
191762306a36Sopenharmony_ci	RTL_W16(tp, CPlusCmd, tp->cp_cmd);
191862306a36Sopenharmony_ci	rtl_pci_commit(tp);
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	return 0;
192162306a36Sopenharmony_ci}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_cistatic int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data)
192462306a36Sopenharmony_ci{
192562306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	if (!rtl_supports_eee(tp))
192862306a36Sopenharmony_ci		return -EOPNOTSUPP;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	return phy_ethtool_get_eee(tp->phydev, data);
193162306a36Sopenharmony_ci}
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_cistatic int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data)
193462306a36Sopenharmony_ci{
193562306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
193662306a36Sopenharmony_ci	int ret;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	if (!rtl_supports_eee(tp))
193962306a36Sopenharmony_ci		return -EOPNOTSUPP;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	ret = phy_ethtool_set_eee(tp->phydev, data);
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	if (!ret)
194462306a36Sopenharmony_ci		tp->eee_adv = phy_read_mmd(dev->phydev, MDIO_MMD_AN,
194562306a36Sopenharmony_ci					   MDIO_AN_EEE_ADV);
194662306a36Sopenharmony_ci	return ret;
194762306a36Sopenharmony_ci}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_cistatic void rtl8169_get_ringparam(struct net_device *dev,
195062306a36Sopenharmony_ci				  struct ethtool_ringparam *data,
195162306a36Sopenharmony_ci				  struct kernel_ethtool_ringparam *kernel_data,
195262306a36Sopenharmony_ci				  struct netlink_ext_ack *extack)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	data->rx_max_pending = NUM_RX_DESC;
195562306a36Sopenharmony_ci	data->rx_pending = NUM_RX_DESC;
195662306a36Sopenharmony_ci	data->tx_max_pending = NUM_TX_DESC;
195762306a36Sopenharmony_ci	data->tx_pending = NUM_TX_DESC;
195862306a36Sopenharmony_ci}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_cistatic void rtl8169_get_pauseparam(struct net_device *dev,
196162306a36Sopenharmony_ci				   struct ethtool_pauseparam *data)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
196462306a36Sopenharmony_ci	bool tx_pause, rx_pause;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	phy_get_pause(tp->phydev, &tx_pause, &rx_pause);
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	data->autoneg = tp->phydev->autoneg;
196962306a36Sopenharmony_ci	data->tx_pause = tx_pause ? 1 : 0;
197062306a36Sopenharmony_ci	data->rx_pause = rx_pause ? 1 : 0;
197162306a36Sopenharmony_ci}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_cistatic int rtl8169_set_pauseparam(struct net_device *dev,
197462306a36Sopenharmony_ci				  struct ethtool_pauseparam *data)
197562306a36Sopenharmony_ci{
197662306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	if (dev->mtu > ETH_DATA_LEN)
197962306a36Sopenharmony_ci		return -EOPNOTSUPP;
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	phy_set_asym_pause(tp->phydev, data->rx_pause, data->tx_pause);
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	return 0;
198462306a36Sopenharmony_ci}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_cistatic const struct ethtool_ops rtl8169_ethtool_ops = {
198762306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
198862306a36Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES,
198962306a36Sopenharmony_ci	.get_drvinfo		= rtl8169_get_drvinfo,
199062306a36Sopenharmony_ci	.get_regs_len		= rtl8169_get_regs_len,
199162306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
199262306a36Sopenharmony_ci	.get_coalesce		= rtl_get_coalesce,
199362306a36Sopenharmony_ci	.set_coalesce		= rtl_set_coalesce,
199462306a36Sopenharmony_ci	.get_regs		= rtl8169_get_regs,
199562306a36Sopenharmony_ci	.get_wol		= rtl8169_get_wol,
199662306a36Sopenharmony_ci	.set_wol		= rtl8169_set_wol,
199762306a36Sopenharmony_ci	.get_strings		= rtl8169_get_strings,
199862306a36Sopenharmony_ci	.get_sset_count		= rtl8169_get_sset_count,
199962306a36Sopenharmony_ci	.get_ethtool_stats	= rtl8169_get_ethtool_stats,
200062306a36Sopenharmony_ci	.get_ts_info		= ethtool_op_get_ts_info,
200162306a36Sopenharmony_ci	.nway_reset		= phy_ethtool_nway_reset,
200262306a36Sopenharmony_ci	.get_eee		= rtl8169_get_eee,
200362306a36Sopenharmony_ci	.set_eee		= rtl8169_set_eee,
200462306a36Sopenharmony_ci	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
200562306a36Sopenharmony_ci	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
200662306a36Sopenharmony_ci	.get_ringparam		= rtl8169_get_ringparam,
200762306a36Sopenharmony_ci	.get_pauseparam		= rtl8169_get_pauseparam,
200862306a36Sopenharmony_ci	.set_pauseparam		= rtl8169_set_pauseparam,
200962306a36Sopenharmony_ci};
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_cistatic void rtl_enable_eee(struct rtl8169_private *tp)
201262306a36Sopenharmony_ci{
201362306a36Sopenharmony_ci	struct phy_device *phydev = tp->phydev;
201462306a36Sopenharmony_ci	int adv;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	/* respect EEE advertisement the user may have set */
201762306a36Sopenharmony_ci	if (tp->eee_adv >= 0)
201862306a36Sopenharmony_ci		adv = tp->eee_adv;
201962306a36Sopenharmony_ci	else
202062306a36Sopenharmony_ci		adv = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	if (adv >= 0)
202362306a36Sopenharmony_ci		phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv);
202462306a36Sopenharmony_ci}
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_cistatic enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii)
202762306a36Sopenharmony_ci{
202862306a36Sopenharmony_ci	/*
202962306a36Sopenharmony_ci	 * The driver currently handles the 8168Bf and the 8168Be identically
203062306a36Sopenharmony_ci	 * but they can be identified more specifically through the test below
203162306a36Sopenharmony_ci	 * if needed:
203262306a36Sopenharmony_ci	 *
203362306a36Sopenharmony_ci	 * (RTL_R32(tp, TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
203462306a36Sopenharmony_ci	 *
203562306a36Sopenharmony_ci	 * Same thing for the 8101Eb and the 8101Ec:
203662306a36Sopenharmony_ci	 *
203762306a36Sopenharmony_ci	 * (RTL_R32(tp, TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
203862306a36Sopenharmony_ci	 */
203962306a36Sopenharmony_ci	static const struct rtl_mac_info {
204062306a36Sopenharmony_ci		u16 mask;
204162306a36Sopenharmony_ci		u16 val;
204262306a36Sopenharmony_ci		enum mac_version ver;
204362306a36Sopenharmony_ci	} mac_info[] = {
204462306a36Sopenharmony_ci		/* 8125B family. */
204562306a36Sopenharmony_ci		{ 0x7cf, 0x641,	RTL_GIGA_MAC_VER_63 },
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci		/* 8125A family. */
204862306a36Sopenharmony_ci		{ 0x7cf, 0x609,	RTL_GIGA_MAC_VER_61 },
204962306a36Sopenharmony_ci		/* It seems only XID 609 made it to the mass market.
205062306a36Sopenharmony_ci		 * { 0x7cf, 0x608,	RTL_GIGA_MAC_VER_60 },
205162306a36Sopenharmony_ci		 * { 0x7c8, 0x608,	RTL_GIGA_MAC_VER_61 },
205262306a36Sopenharmony_ci		 */
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci		/* RTL8117 */
205562306a36Sopenharmony_ci		{ 0x7cf, 0x54b,	RTL_GIGA_MAC_VER_53 },
205662306a36Sopenharmony_ci		{ 0x7cf, 0x54a,	RTL_GIGA_MAC_VER_52 },
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci		/* 8168EP family. */
205962306a36Sopenharmony_ci		{ 0x7cf, 0x502,	RTL_GIGA_MAC_VER_51 },
206062306a36Sopenharmony_ci		/* It seems this chip version never made it to
206162306a36Sopenharmony_ci		 * the wild. Let's disable detection.
206262306a36Sopenharmony_ci		 * { 0x7cf, 0x501,      RTL_GIGA_MAC_VER_50 },
206362306a36Sopenharmony_ci		 * { 0x7cf, 0x500,      RTL_GIGA_MAC_VER_49 },
206462306a36Sopenharmony_ci		 */
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci		/* 8168H family. */
206762306a36Sopenharmony_ci		{ 0x7cf, 0x541,	RTL_GIGA_MAC_VER_46 },
206862306a36Sopenharmony_ci		/* It seems this chip version never made it to
206962306a36Sopenharmony_ci		 * the wild. Let's disable detection.
207062306a36Sopenharmony_ci		 * { 0x7cf, 0x540,	RTL_GIGA_MAC_VER_45 },
207162306a36Sopenharmony_ci		 */
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci		/* 8168G family. */
207462306a36Sopenharmony_ci		{ 0x7cf, 0x5c8,	RTL_GIGA_MAC_VER_44 },
207562306a36Sopenharmony_ci		{ 0x7cf, 0x509,	RTL_GIGA_MAC_VER_42 },
207662306a36Sopenharmony_ci		/* It seems this chip version never made it to
207762306a36Sopenharmony_ci		 * the wild. Let's disable detection.
207862306a36Sopenharmony_ci		 * { 0x7cf, 0x4c1,	RTL_GIGA_MAC_VER_41 },
207962306a36Sopenharmony_ci		 */
208062306a36Sopenharmony_ci		{ 0x7cf, 0x4c0,	RTL_GIGA_MAC_VER_40 },
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci		/* 8168F family. */
208362306a36Sopenharmony_ci		{ 0x7c8, 0x488,	RTL_GIGA_MAC_VER_38 },
208462306a36Sopenharmony_ci		{ 0x7cf, 0x481,	RTL_GIGA_MAC_VER_36 },
208562306a36Sopenharmony_ci		{ 0x7cf, 0x480,	RTL_GIGA_MAC_VER_35 },
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci		/* 8168E family. */
208862306a36Sopenharmony_ci		{ 0x7c8, 0x2c8,	RTL_GIGA_MAC_VER_34 },
208962306a36Sopenharmony_ci		{ 0x7cf, 0x2c1,	RTL_GIGA_MAC_VER_32 },
209062306a36Sopenharmony_ci		{ 0x7c8, 0x2c0,	RTL_GIGA_MAC_VER_33 },
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci		/* 8168D family. */
209362306a36Sopenharmony_ci		{ 0x7cf, 0x281,	RTL_GIGA_MAC_VER_25 },
209462306a36Sopenharmony_ci		{ 0x7c8, 0x280,	RTL_GIGA_MAC_VER_26 },
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci		/* 8168DP family. */
209762306a36Sopenharmony_ci		/* It seems this early RTL8168dp version never made it to
209862306a36Sopenharmony_ci		 * the wild. Support has been removed.
209962306a36Sopenharmony_ci		 * { 0x7cf, 0x288,      RTL_GIGA_MAC_VER_27 },
210062306a36Sopenharmony_ci		 */
210162306a36Sopenharmony_ci		{ 0x7cf, 0x28a,	RTL_GIGA_MAC_VER_28 },
210262306a36Sopenharmony_ci		{ 0x7cf, 0x28b,	RTL_GIGA_MAC_VER_31 },
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci		/* 8168C family. */
210562306a36Sopenharmony_ci		{ 0x7cf, 0x3c9,	RTL_GIGA_MAC_VER_23 },
210662306a36Sopenharmony_ci		{ 0x7cf, 0x3c8,	RTL_GIGA_MAC_VER_18 },
210762306a36Sopenharmony_ci		{ 0x7c8, 0x3c8,	RTL_GIGA_MAC_VER_24 },
210862306a36Sopenharmony_ci		{ 0x7cf, 0x3c0,	RTL_GIGA_MAC_VER_19 },
210962306a36Sopenharmony_ci		{ 0x7cf, 0x3c2,	RTL_GIGA_MAC_VER_20 },
211062306a36Sopenharmony_ci		{ 0x7cf, 0x3c3,	RTL_GIGA_MAC_VER_21 },
211162306a36Sopenharmony_ci		{ 0x7c8, 0x3c0,	RTL_GIGA_MAC_VER_22 },
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci		/* 8168B family. */
211462306a36Sopenharmony_ci		{ 0x7c8, 0x380,	RTL_GIGA_MAC_VER_17 },
211562306a36Sopenharmony_ci		{ 0x7c8, 0x300,	RTL_GIGA_MAC_VER_11 },
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci		/* 8101 family. */
211862306a36Sopenharmony_ci		{ 0x7c8, 0x448,	RTL_GIGA_MAC_VER_39 },
211962306a36Sopenharmony_ci		{ 0x7c8, 0x440,	RTL_GIGA_MAC_VER_37 },
212062306a36Sopenharmony_ci		{ 0x7cf, 0x409,	RTL_GIGA_MAC_VER_29 },
212162306a36Sopenharmony_ci		{ 0x7c8, 0x408,	RTL_GIGA_MAC_VER_30 },
212262306a36Sopenharmony_ci		{ 0x7cf, 0x349,	RTL_GIGA_MAC_VER_08 },
212362306a36Sopenharmony_ci		{ 0x7cf, 0x249,	RTL_GIGA_MAC_VER_08 },
212462306a36Sopenharmony_ci		{ 0x7cf, 0x348,	RTL_GIGA_MAC_VER_07 },
212562306a36Sopenharmony_ci		{ 0x7cf, 0x248,	RTL_GIGA_MAC_VER_07 },
212662306a36Sopenharmony_ci		{ 0x7cf, 0x240,	RTL_GIGA_MAC_VER_14 },
212762306a36Sopenharmony_ci		{ 0x7c8, 0x348,	RTL_GIGA_MAC_VER_09 },
212862306a36Sopenharmony_ci		{ 0x7c8, 0x248,	RTL_GIGA_MAC_VER_09 },
212962306a36Sopenharmony_ci		{ 0x7c8, 0x340,	RTL_GIGA_MAC_VER_10 },
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci		/* 8110 family. */
213262306a36Sopenharmony_ci		{ 0xfc8, 0x980,	RTL_GIGA_MAC_VER_06 },
213362306a36Sopenharmony_ci		{ 0xfc8, 0x180,	RTL_GIGA_MAC_VER_05 },
213462306a36Sopenharmony_ci		{ 0xfc8, 0x100,	RTL_GIGA_MAC_VER_04 },
213562306a36Sopenharmony_ci		{ 0xfc8, 0x040,	RTL_GIGA_MAC_VER_03 },
213662306a36Sopenharmony_ci		{ 0xfc8, 0x008,	RTL_GIGA_MAC_VER_02 },
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci		/* Catch-all */
213962306a36Sopenharmony_ci		{ 0x000, 0x000,	RTL_GIGA_MAC_NONE   }
214062306a36Sopenharmony_ci	};
214162306a36Sopenharmony_ci	const struct rtl_mac_info *p = mac_info;
214262306a36Sopenharmony_ci	enum mac_version ver;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	while ((xid & p->mask) != p->val)
214562306a36Sopenharmony_ci		p++;
214662306a36Sopenharmony_ci	ver = p->ver;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	if (ver != RTL_GIGA_MAC_NONE && !gmii) {
214962306a36Sopenharmony_ci		if (ver == RTL_GIGA_MAC_VER_42)
215062306a36Sopenharmony_ci			ver = RTL_GIGA_MAC_VER_43;
215162306a36Sopenharmony_ci		else if (ver == RTL_GIGA_MAC_VER_46)
215262306a36Sopenharmony_ci			ver = RTL_GIGA_MAC_VER_48;
215362306a36Sopenharmony_ci	}
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	return ver;
215662306a36Sopenharmony_ci}
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_cistatic void rtl_release_firmware(struct rtl8169_private *tp)
215962306a36Sopenharmony_ci{
216062306a36Sopenharmony_ci	if (tp->rtl_fw) {
216162306a36Sopenharmony_ci		rtl_fw_release_firmware(tp->rtl_fw);
216262306a36Sopenharmony_ci		kfree(tp->rtl_fw);
216362306a36Sopenharmony_ci		tp->rtl_fw = NULL;
216462306a36Sopenharmony_ci	}
216562306a36Sopenharmony_ci}
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_civoid r8169_apply_firmware(struct rtl8169_private *tp)
216862306a36Sopenharmony_ci{
216962306a36Sopenharmony_ci	int val;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	/* TODO: release firmware if rtl_fw_write_firmware signals failure. */
217262306a36Sopenharmony_ci	if (tp->rtl_fw) {
217362306a36Sopenharmony_ci		rtl_fw_write_firmware(tp, tp->rtl_fw);
217462306a36Sopenharmony_ci		/* At least one firmware doesn't reset tp->ocp_base. */
217562306a36Sopenharmony_ci		tp->ocp_base = OCP_STD_PHY_BASE;
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci		/* PHY soft reset may still be in progress */
217862306a36Sopenharmony_ci		phy_read_poll_timeout(tp->phydev, MII_BMCR, val,
217962306a36Sopenharmony_ci				      !(val & BMCR_RESET),
218062306a36Sopenharmony_ci				      50000, 600000, true);
218162306a36Sopenharmony_ci	}
218262306a36Sopenharmony_ci}
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_cistatic void rtl8168_config_eee_mac(struct rtl8169_private *tp)
218562306a36Sopenharmony_ci{
218662306a36Sopenharmony_ci	/* Adjust EEE LED frequency */
218762306a36Sopenharmony_ci	if (tp->mac_version != RTL_GIGA_MAC_VER_38)
218862306a36Sopenharmony_ci		RTL_W8(tp, EEE_LED, RTL_R8(tp, EEE_LED) & ~0x07);
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	rtl_eri_set_bits(tp, 0x1b0, 0x0003);
219162306a36Sopenharmony_ci}
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_cistatic void rtl8125a_config_eee_mac(struct rtl8169_private *tp)
219462306a36Sopenharmony_ci{
219562306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0));
219662306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xeb62, 0, BIT(2) | BIT(1));
219762306a36Sopenharmony_ci}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_cistatic void rtl8125_set_eee_txidle_timer(struct rtl8169_private *tp)
220062306a36Sopenharmony_ci{
220162306a36Sopenharmony_ci	RTL_W16(tp, EEE_TXIDLE_TIMER_8125, tp->dev->mtu + ETH_HLEN + 0x20);
220262306a36Sopenharmony_ci}
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_cistatic void rtl8125b_config_eee_mac(struct rtl8169_private *tp)
220562306a36Sopenharmony_ci{
220662306a36Sopenharmony_ci	rtl8125_set_eee_txidle_timer(tp);
220762306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0));
220862306a36Sopenharmony_ci}
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_cistatic void rtl_rar_exgmac_set(struct rtl8169_private *tp, const u8 *addr)
221162306a36Sopenharmony_ci{
221262306a36Sopenharmony_ci	rtl_eri_write(tp, 0xe0, ERIAR_MASK_1111, get_unaligned_le32(addr));
221362306a36Sopenharmony_ci	rtl_eri_write(tp, 0xe4, ERIAR_MASK_1111, get_unaligned_le16(addr + 4));
221462306a36Sopenharmony_ci	rtl_eri_write(tp, 0xf0, ERIAR_MASK_1111, get_unaligned_le16(addr) << 16);
221562306a36Sopenharmony_ci	rtl_eri_write(tp, 0xf4, ERIAR_MASK_1111, get_unaligned_le32(addr + 2));
221662306a36Sopenharmony_ci}
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ciu16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp)
221962306a36Sopenharmony_ci{
222062306a36Sopenharmony_ci	u16 data1, data2, ioffset;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xdd02, 0x807d);
222362306a36Sopenharmony_ci	data1 = r8168_mac_ocp_read(tp, 0xdd02);
222462306a36Sopenharmony_ci	data2 = r8168_mac_ocp_read(tp, 0xdd00);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	ioffset = (data2 >> 1) & 0x7ff8;
222762306a36Sopenharmony_ci	ioffset |= data2 & 0x0007;
222862306a36Sopenharmony_ci	if (data1 & BIT(7))
222962306a36Sopenharmony_ci		ioffset |= BIT(15);
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	return ioffset;
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_cistatic void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
223562306a36Sopenharmony_ci{
223662306a36Sopenharmony_ci	set_bit(flag, tp->wk.flags);
223762306a36Sopenharmony_ci	schedule_work(&tp->wk.work);
223862306a36Sopenharmony_ci}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_cistatic void rtl8169_init_phy(struct rtl8169_private *tp)
224162306a36Sopenharmony_ci{
224262306a36Sopenharmony_ci	r8169_hw_phy_config(tp, tp->phydev, tp->mac_version);
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
224562306a36Sopenharmony_ci		pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
224662306a36Sopenharmony_ci		pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
224762306a36Sopenharmony_ci		/* set undocumented MAC Reg C+CR Offset 0x82h */
224862306a36Sopenharmony_ci		RTL_W8(tp, 0x82, 0x01);
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_05 &&
225262306a36Sopenharmony_ci	    tp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_GIGABYTE &&
225362306a36Sopenharmony_ci	    tp->pci_dev->subsystem_device == 0xe000)
225462306a36Sopenharmony_ci		phy_write_paged(tp->phydev, 0x0001, 0x10, 0xf01b);
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	/* We may have called phy_speed_down before */
225762306a36Sopenharmony_ci	phy_speed_up(tp->phydev);
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	if (rtl_supports_eee(tp))
226062306a36Sopenharmony_ci		rtl_enable_eee(tp);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	genphy_soft_reset(tp->phydev);
226362306a36Sopenharmony_ci}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_cistatic void rtl_rar_set(struct rtl8169_private *tp, const u8 *addr)
226662306a36Sopenharmony_ci{
226762306a36Sopenharmony_ci	rtl_unlock_config_regs(tp);
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	RTL_W32(tp, MAC4, get_unaligned_le16(addr + 4));
227062306a36Sopenharmony_ci	rtl_pci_commit(tp);
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	RTL_W32(tp, MAC0, get_unaligned_le32(addr));
227362306a36Sopenharmony_ci	rtl_pci_commit(tp);
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_34)
227662306a36Sopenharmony_ci		rtl_rar_exgmac_set(tp, addr);
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	rtl_lock_config_regs(tp);
227962306a36Sopenharmony_ci}
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_cistatic int rtl_set_mac_address(struct net_device *dev, void *p)
228262306a36Sopenharmony_ci{
228362306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
228462306a36Sopenharmony_ci	int ret;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	ret = eth_mac_addr(dev, p);
228762306a36Sopenharmony_ci	if (ret)
228862306a36Sopenharmony_ci		return ret;
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	rtl_rar_set(tp, dev->dev_addr);
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	return 0;
229362306a36Sopenharmony_ci}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_cistatic void rtl_init_rxcfg(struct rtl8169_private *tp)
229662306a36Sopenharmony_ci{
229762306a36Sopenharmony_ci	switch (tp->mac_version) {
229862306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
229962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_10 ... RTL_GIGA_MAC_VER_17:
230062306a36Sopenharmony_ci		RTL_W32(tp, RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
230162306a36Sopenharmony_ci		break;
230262306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24:
230362306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_36:
230462306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_38:
230562306a36Sopenharmony_ci		RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
230662306a36Sopenharmony_ci		break;
230762306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53:
230862306a36Sopenharmony_ci		RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
230962306a36Sopenharmony_ci		break;
231062306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_61:
231162306a36Sopenharmony_ci		RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST);
231262306a36Sopenharmony_ci		break;
231362306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_63:
231462306a36Sopenharmony_ci		RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
231562306a36Sopenharmony_ci			RX_PAUSE_SLOT_ON);
231662306a36Sopenharmony_ci		break;
231762306a36Sopenharmony_ci	default:
231862306a36Sopenharmony_ci		RTL_W32(tp, RxConfig, RX128_INT_EN | RX_DMA_BURST);
231962306a36Sopenharmony_ci		break;
232062306a36Sopenharmony_ci	}
232162306a36Sopenharmony_ci}
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_cistatic void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
232462306a36Sopenharmony_ci{
232562306a36Sopenharmony_ci	tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
232662306a36Sopenharmony_ci}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_cistatic void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
232962306a36Sopenharmony_ci{
233062306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
233162306a36Sopenharmony_ci	RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1);
233262306a36Sopenharmony_ci}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_cistatic void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
233562306a36Sopenharmony_ci{
233662306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
233762306a36Sopenharmony_ci	RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1);
233862306a36Sopenharmony_ci}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_cistatic void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
234162306a36Sopenharmony_ci{
234262306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
234362306a36Sopenharmony_ci}
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_cistatic void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
234662306a36Sopenharmony_ci{
234762306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_cistatic void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
235162306a36Sopenharmony_ci{
235262306a36Sopenharmony_ci	RTL_W8(tp, MaxTxPacketSize, 0x24);
235362306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
235462306a36Sopenharmony_ci	RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01);
235562306a36Sopenharmony_ci}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_cistatic void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	RTL_W8(tp, MaxTxPacketSize, 0x3f);
236062306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
236162306a36Sopenharmony_ci	RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01);
236262306a36Sopenharmony_ci}
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_cistatic void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
236562306a36Sopenharmony_ci{
236662306a36Sopenharmony_ci	RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0));
236762306a36Sopenharmony_ci}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_cistatic void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
237062306a36Sopenharmony_ci{
237162306a36Sopenharmony_ci	RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0));
237262306a36Sopenharmony_ci}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_cistatic void rtl_jumbo_config(struct rtl8169_private *tp)
237562306a36Sopenharmony_ci{
237662306a36Sopenharmony_ci	bool jumbo = tp->dev->mtu > ETH_DATA_LEN;
237762306a36Sopenharmony_ci	int readrq = 4096;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	rtl_unlock_config_regs(tp);
238062306a36Sopenharmony_ci	switch (tp->mac_version) {
238162306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_17:
238262306a36Sopenharmony_ci		if (jumbo) {
238362306a36Sopenharmony_ci			readrq = 512;
238462306a36Sopenharmony_ci			r8168b_1_hw_jumbo_enable(tp);
238562306a36Sopenharmony_ci		} else {
238662306a36Sopenharmony_ci			r8168b_1_hw_jumbo_disable(tp);
238762306a36Sopenharmony_ci		}
238862306a36Sopenharmony_ci		break;
238962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26:
239062306a36Sopenharmony_ci		if (jumbo) {
239162306a36Sopenharmony_ci			readrq = 512;
239262306a36Sopenharmony_ci			r8168c_hw_jumbo_enable(tp);
239362306a36Sopenharmony_ci		} else {
239462306a36Sopenharmony_ci			r8168c_hw_jumbo_disable(tp);
239562306a36Sopenharmony_ci		}
239662306a36Sopenharmony_ci		break;
239762306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_28:
239862306a36Sopenharmony_ci		if (jumbo)
239962306a36Sopenharmony_ci			r8168dp_hw_jumbo_enable(tp);
240062306a36Sopenharmony_ci		else
240162306a36Sopenharmony_ci			r8168dp_hw_jumbo_disable(tp);
240262306a36Sopenharmony_ci		break;
240362306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33:
240462306a36Sopenharmony_ci		if (jumbo)
240562306a36Sopenharmony_ci			r8168e_hw_jumbo_enable(tp);
240662306a36Sopenharmony_ci		else
240762306a36Sopenharmony_ci			r8168e_hw_jumbo_disable(tp);
240862306a36Sopenharmony_ci		break;
240962306a36Sopenharmony_ci	default:
241062306a36Sopenharmony_ci		break;
241162306a36Sopenharmony_ci	}
241262306a36Sopenharmony_ci	rtl_lock_config_regs(tp);
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	if (pci_is_pcie(tp->pci_dev) && tp->supports_gmii)
241562306a36Sopenharmony_ci		pcie_set_readrq(tp->pci_dev, readrq);
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	/* Chip doesn't support pause in jumbo mode */
241862306a36Sopenharmony_ci	if (jumbo) {
241962306a36Sopenharmony_ci		linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
242062306a36Sopenharmony_ci				   tp->phydev->advertising);
242162306a36Sopenharmony_ci		linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
242262306a36Sopenharmony_ci				   tp->phydev->advertising);
242362306a36Sopenharmony_ci		phy_start_aneg(tp->phydev);
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci}
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_chipcmd_cond)
242862306a36Sopenharmony_ci{
242962306a36Sopenharmony_ci	return RTL_R8(tp, ChipCmd) & CmdReset;
243062306a36Sopenharmony_ci}
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_cistatic void rtl_hw_reset(struct rtl8169_private *tp)
243362306a36Sopenharmony_ci{
243462306a36Sopenharmony_ci	RTL_W8(tp, ChipCmd, CmdReset);
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
243762306a36Sopenharmony_ci}
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_cistatic void rtl_request_firmware(struct rtl8169_private *tp)
244062306a36Sopenharmony_ci{
244162306a36Sopenharmony_ci	struct rtl_fw *rtl_fw;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	/* firmware loaded already or no firmware available */
244462306a36Sopenharmony_ci	if (tp->rtl_fw || !tp->fw_name)
244562306a36Sopenharmony_ci		return;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL);
244862306a36Sopenharmony_ci	if (!rtl_fw)
244962306a36Sopenharmony_ci		return;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	rtl_fw->phy_write = rtl_writephy;
245262306a36Sopenharmony_ci	rtl_fw->phy_read = rtl_readphy;
245362306a36Sopenharmony_ci	rtl_fw->mac_mcu_write = mac_mcu_write;
245462306a36Sopenharmony_ci	rtl_fw->mac_mcu_read = mac_mcu_read;
245562306a36Sopenharmony_ci	rtl_fw->fw_name = tp->fw_name;
245662306a36Sopenharmony_ci	rtl_fw->dev = tp_to_dev(tp);
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	if (rtl_fw_request_firmware(rtl_fw))
245962306a36Sopenharmony_ci		kfree(rtl_fw);
246062306a36Sopenharmony_ci	else
246162306a36Sopenharmony_ci		tp->rtl_fw = rtl_fw;
246262306a36Sopenharmony_ci}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_cistatic void rtl_rx_close(struct rtl8169_private *tp)
246562306a36Sopenharmony_ci{
246662306a36Sopenharmony_ci	RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) & ~RX_CONFIG_ACCEPT_MASK);
246762306a36Sopenharmony_ci}
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_npq_cond)
247062306a36Sopenharmony_ci{
247162306a36Sopenharmony_ci	return RTL_R8(tp, TxPoll) & NPQ;
247262306a36Sopenharmony_ci}
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_txcfg_empty_cond)
247562306a36Sopenharmony_ci{
247662306a36Sopenharmony_ci	return RTL_R32(tp, TxConfig) & TXCFG_EMPTY;
247762306a36Sopenharmony_ci}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_rxtx_empty_cond)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	return (RTL_R8(tp, MCU) & RXTX_EMPTY) == RXTX_EMPTY;
248262306a36Sopenharmony_ci}
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_rxtx_empty_cond_2)
248562306a36Sopenharmony_ci{
248662306a36Sopenharmony_ci	/* IntrMitigate has new functionality on RTL8125 */
248762306a36Sopenharmony_ci	return (RTL_R16(tp, IntrMitigate) & 0x0103) == 0x0103;
248862306a36Sopenharmony_ci}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_cistatic void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp)
249162306a36Sopenharmony_ci{
249262306a36Sopenharmony_ci	switch (tp->mac_version) {
249362306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53:
249462306a36Sopenharmony_ci		rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42);
249562306a36Sopenharmony_ci		rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
249662306a36Sopenharmony_ci		break;
249762306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61:
249862306a36Sopenharmony_ci		rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
249962306a36Sopenharmony_ci		break;
250062306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_63:
250162306a36Sopenharmony_ci		RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
250262306a36Sopenharmony_ci		rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42);
250362306a36Sopenharmony_ci		rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42);
250462306a36Sopenharmony_ci		break;
250562306a36Sopenharmony_ci	default:
250662306a36Sopenharmony_ci		break;
250762306a36Sopenharmony_ci	}
250862306a36Sopenharmony_ci}
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_cistatic void rtl_disable_rxdvgate(struct rtl8169_private *tp)
251162306a36Sopenharmony_ci{
251262306a36Sopenharmony_ci	RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN);
251362306a36Sopenharmony_ci}
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_cistatic void rtl_enable_rxdvgate(struct rtl8169_private *tp)
251662306a36Sopenharmony_ci{
251762306a36Sopenharmony_ci	RTL_W32(tp, MISC, RTL_R32(tp, MISC) | RXDV_GATED_EN);
251862306a36Sopenharmony_ci	fsleep(2000);
251962306a36Sopenharmony_ci	rtl_wait_txrx_fifo_empty(tp);
252062306a36Sopenharmony_ci}
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_cistatic void rtl_wol_enable_rx(struct rtl8169_private *tp)
252362306a36Sopenharmony_ci{
252462306a36Sopenharmony_ci	if (tp->mac_version >= RTL_GIGA_MAC_VER_25)
252562306a36Sopenharmony_ci		RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) |
252662306a36Sopenharmony_ci			AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	if (tp->mac_version >= RTL_GIGA_MAC_VER_40)
252962306a36Sopenharmony_ci		rtl_disable_rxdvgate(tp);
253062306a36Sopenharmony_ci}
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_cistatic void rtl_prepare_power_down(struct rtl8169_private *tp)
253362306a36Sopenharmony_ci{
253462306a36Sopenharmony_ci	if (tp->dash_enabled)
253562306a36Sopenharmony_ci		return;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
253862306a36Sopenharmony_ci	    tp->mac_version == RTL_GIGA_MAC_VER_33)
253962306a36Sopenharmony_ci		rtl_ephy_write(tp, 0x19, 0xff64);
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	if (device_may_wakeup(tp_to_dev(tp))) {
254262306a36Sopenharmony_ci		phy_speed_down(tp->phydev, false);
254362306a36Sopenharmony_ci		rtl_wol_enable_rx(tp);
254462306a36Sopenharmony_ci	}
254562306a36Sopenharmony_ci}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_cistatic void rtl_set_tx_config_registers(struct rtl8169_private *tp)
254862306a36Sopenharmony_ci{
254962306a36Sopenharmony_ci	u32 val = TX_DMA_BURST << TxDMAShift |
255062306a36Sopenharmony_ci		  InterFrameGap << TxInterFrameGapShift;
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci	if (rtl_is_8168evl_up(tp))
255362306a36Sopenharmony_ci		val |= TXCFG_AUTO_FIFO;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	RTL_W32(tp, TxConfig, val);
255662306a36Sopenharmony_ci}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_cistatic void rtl_set_rx_max_size(struct rtl8169_private *tp)
255962306a36Sopenharmony_ci{
256062306a36Sopenharmony_ci	/* Low hurts. Let's disable the filtering. */
256162306a36Sopenharmony_ci	RTL_W16(tp, RxMaxSize, R8169_RX_BUF_SIZE + 1);
256262306a36Sopenharmony_ci}
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_cistatic void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
256562306a36Sopenharmony_ci{
256662306a36Sopenharmony_ci	/*
256762306a36Sopenharmony_ci	 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
256862306a36Sopenharmony_ci	 * register to be written before TxDescAddrLow to work.
256962306a36Sopenharmony_ci	 * Switching from MMIO to I/O access fixes the issue as well.
257062306a36Sopenharmony_ci	 */
257162306a36Sopenharmony_ci	RTL_W32(tp, TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
257262306a36Sopenharmony_ci	RTL_W32(tp, TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
257362306a36Sopenharmony_ci	RTL_W32(tp, RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
257462306a36Sopenharmony_ci	RTL_W32(tp, RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
257562306a36Sopenharmony_ci}
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_cistatic void rtl8169_set_magic_reg(struct rtl8169_private *tp)
257862306a36Sopenharmony_ci{
257962306a36Sopenharmony_ci	u32 val;
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_05)
258262306a36Sopenharmony_ci		val = 0x000fff00;
258362306a36Sopenharmony_ci	else if (tp->mac_version == RTL_GIGA_MAC_VER_06)
258462306a36Sopenharmony_ci		val = 0x00ffff00;
258562306a36Sopenharmony_ci	else
258662306a36Sopenharmony_ci		return;
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	if (RTL_R8(tp, Config2) & PCI_Clock_66MHz)
258962306a36Sopenharmony_ci		val |= 0xff;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	RTL_W32(tp, 0x7c, val);
259262306a36Sopenharmony_ci}
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_cistatic void rtl_set_rx_mode(struct net_device *dev)
259562306a36Sopenharmony_ci{
259662306a36Sopenharmony_ci	u32 rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
259762306a36Sopenharmony_ci	/* Multicast hash filter */
259862306a36Sopenharmony_ci	u32 mc_filter[2] = { 0xffffffff, 0xffffffff };
259962306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
260062306a36Sopenharmony_ci	u32 tmp;
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
260362306a36Sopenharmony_ci		rx_mode |= AcceptAllPhys;
260462306a36Sopenharmony_ci	} else if (!(dev->flags & IFF_MULTICAST)) {
260562306a36Sopenharmony_ci		rx_mode &= ~AcceptMulticast;
260662306a36Sopenharmony_ci	} else if (netdev_mc_count(dev) > MC_FILTER_LIMIT ||
260762306a36Sopenharmony_ci		   dev->flags & IFF_ALLMULTI ||
260862306a36Sopenharmony_ci		   tp->mac_version == RTL_GIGA_MAC_VER_35) {
260962306a36Sopenharmony_ci		/* accept all multicasts */
261062306a36Sopenharmony_ci	} else if (netdev_mc_empty(dev)) {
261162306a36Sopenharmony_ci		rx_mode &= ~AcceptMulticast;
261262306a36Sopenharmony_ci	} else {
261362306a36Sopenharmony_ci		struct netdev_hw_addr *ha;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci		mc_filter[1] = mc_filter[0] = 0;
261662306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
261762306a36Sopenharmony_ci			u32 bit_nr = eth_hw_addr_crc(ha) >> 26;
261862306a36Sopenharmony_ci			mc_filter[bit_nr >> 5] |= BIT(bit_nr & 31);
261962306a36Sopenharmony_ci		}
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci		if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
262262306a36Sopenharmony_ci			tmp = mc_filter[0];
262362306a36Sopenharmony_ci			mc_filter[0] = swab32(mc_filter[1]);
262462306a36Sopenharmony_ci			mc_filter[1] = swab32(tmp);
262562306a36Sopenharmony_ci		}
262662306a36Sopenharmony_ci	}
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	RTL_W32(tp, MAR0 + 4, mc_filter[1]);
262962306a36Sopenharmony_ci	RTL_W32(tp, MAR0 + 0, mc_filter[0]);
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	tmp = RTL_R32(tp, RxConfig);
263262306a36Sopenharmony_ci	RTL_W32(tp, RxConfig, (tmp & ~RX_CONFIG_ACCEPT_OK_MASK) | rx_mode);
263362306a36Sopenharmony_ci}
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_csiar_cond)
263662306a36Sopenharmony_ci{
263762306a36Sopenharmony_ci	return RTL_R32(tp, CSIAR) & CSIAR_FLAG;
263862306a36Sopenharmony_ci}
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_cistatic void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
264162306a36Sopenharmony_ci{
264262306a36Sopenharmony_ci	u32 func = PCI_FUNC(tp->pci_dev->devfn);
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	RTL_W32(tp, CSIDR, value);
264562306a36Sopenharmony_ci	RTL_W32(tp, CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
264662306a36Sopenharmony_ci		CSIAR_BYTE_ENABLE | func << 16);
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
264962306a36Sopenharmony_ci}
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_cistatic u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
265262306a36Sopenharmony_ci{
265362306a36Sopenharmony_ci	u32 func = PCI_FUNC(tp->pci_dev->devfn);
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	RTL_W32(tp, CSIAR, (addr & CSIAR_ADDR_MASK) | func << 16 |
265662306a36Sopenharmony_ci		CSIAR_BYTE_ENABLE);
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	return rtl_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
265962306a36Sopenharmony_ci		RTL_R32(tp, CSIDR) : ~0;
266062306a36Sopenharmony_ci}
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_cistatic void rtl_set_aspm_entry_latency(struct rtl8169_private *tp, u8 val)
266362306a36Sopenharmony_ci{
266462306a36Sopenharmony_ci	struct pci_dev *pdev = tp->pci_dev;
266562306a36Sopenharmony_ci	u32 csi;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	/* According to Realtek the value at config space address 0x070f
266862306a36Sopenharmony_ci	 * controls the L0s/L1 entrance latency. We try standard ECAM access
266962306a36Sopenharmony_ci	 * first and if it fails fall back to CSI.
267062306a36Sopenharmony_ci	 * bit 0..2: L0: 0 = 1us, 1 = 2us .. 6 = 7us, 7 = 7us (no typo)
267162306a36Sopenharmony_ci	 * bit 3..5: L1: 0 = 1us, 1 = 2us .. 6 = 64us, 7 = 64us
267262306a36Sopenharmony_ci	 */
267362306a36Sopenharmony_ci	if (pdev->cfg_size > 0x070f &&
267462306a36Sopenharmony_ci	    pci_write_config_byte(pdev, 0x070f, val) == PCIBIOS_SUCCESSFUL)
267562306a36Sopenharmony_ci		return;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	netdev_notice_once(tp->dev,
267862306a36Sopenharmony_ci		"No native access to PCI extended config space, falling back to CSI\n");
267962306a36Sopenharmony_ci	csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff;
268062306a36Sopenharmony_ci	rtl_csi_write(tp, 0x070c, csi | val << 24);
268162306a36Sopenharmony_ci}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_cistatic void rtl_set_def_aspm_entry_latency(struct rtl8169_private *tp)
268462306a36Sopenharmony_ci{
268562306a36Sopenharmony_ci	/* L0 7us, L1 16us */
268662306a36Sopenharmony_ci	rtl_set_aspm_entry_latency(tp, 0x27);
268762306a36Sopenharmony_ci}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_cistruct ephy_info {
269062306a36Sopenharmony_ci	unsigned int offset;
269162306a36Sopenharmony_ci	u16 mask;
269262306a36Sopenharmony_ci	u16 bits;
269362306a36Sopenharmony_ci};
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_cistatic void __rtl_ephy_init(struct rtl8169_private *tp,
269662306a36Sopenharmony_ci			    const struct ephy_info *e, int len)
269762306a36Sopenharmony_ci{
269862306a36Sopenharmony_ci	u16 w;
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	while (len-- > 0) {
270162306a36Sopenharmony_ci		w = (rtl_ephy_read(tp, e->offset) & ~e->mask) | e->bits;
270262306a36Sopenharmony_ci		rtl_ephy_write(tp, e->offset, w);
270362306a36Sopenharmony_ci		e++;
270462306a36Sopenharmony_ci	}
270562306a36Sopenharmony_ci}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci#define rtl_ephy_init(tp, a) __rtl_ephy_init(tp, a, ARRAY_SIZE(a))
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_cistatic void rtl_disable_clock_request(struct rtl8169_private *tp)
271062306a36Sopenharmony_ci{
271162306a36Sopenharmony_ci	pcie_capability_clear_word(tp->pci_dev, PCI_EXP_LNKCTL,
271262306a36Sopenharmony_ci				   PCI_EXP_LNKCTL_CLKREQ_EN);
271362306a36Sopenharmony_ci}
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_cistatic void rtl_enable_clock_request(struct rtl8169_private *tp)
271662306a36Sopenharmony_ci{
271762306a36Sopenharmony_ci	pcie_capability_set_word(tp->pci_dev, PCI_EXP_LNKCTL,
271862306a36Sopenharmony_ci				 PCI_EXP_LNKCTL_CLKREQ_EN);
271962306a36Sopenharmony_ci}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_cistatic void rtl_pcie_state_l2l3_disable(struct rtl8169_private *tp)
272262306a36Sopenharmony_ci{
272362306a36Sopenharmony_ci	/* work around an issue when PCI reset occurs during L2/L3 state */
272462306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Rdy_to_L23);
272562306a36Sopenharmony_ci}
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_cistatic void rtl_enable_exit_l1(struct rtl8169_private *tp)
272862306a36Sopenharmony_ci{
272962306a36Sopenharmony_ci	/* Bits control which events trigger ASPM L1 exit:
273062306a36Sopenharmony_ci	 * Bit 12: rxdv
273162306a36Sopenharmony_ci	 * Bit 11: ltr_msg
273262306a36Sopenharmony_ci	 * Bit 10: txdma_poll
273362306a36Sopenharmony_ci	 * Bit  9: xadm
273462306a36Sopenharmony_ci	 * Bit  8: pktavi
273562306a36Sopenharmony_ci	 * Bit  7: txpla
273662306a36Sopenharmony_ci	 */
273762306a36Sopenharmony_ci	switch (tp->mac_version) {
273862306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_36:
273962306a36Sopenharmony_ci		rtl_eri_set_bits(tp, 0xd4, 0x1f00);
274062306a36Sopenharmony_ci		break;
274162306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38:
274262306a36Sopenharmony_ci		rtl_eri_set_bits(tp, 0xd4, 0x0c00);
274362306a36Sopenharmony_ci		break;
274462306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
274562306a36Sopenharmony_ci		r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80);
274662306a36Sopenharmony_ci		break;
274762306a36Sopenharmony_ci	default:
274862306a36Sopenharmony_ci		break;
274962306a36Sopenharmony_ci	}
275062306a36Sopenharmony_ci}
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_cistatic void rtl_disable_exit_l1(struct rtl8169_private *tp)
275362306a36Sopenharmony_ci{
275462306a36Sopenharmony_ci	switch (tp->mac_version) {
275562306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:
275662306a36Sopenharmony_ci		rtl_eri_clear_bits(tp, 0xd4, 0x1f00);
275762306a36Sopenharmony_ci		break;
275862306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
275962306a36Sopenharmony_ci		r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0);
276062306a36Sopenharmony_ci		break;
276162306a36Sopenharmony_ci	default:
276262306a36Sopenharmony_ci		break;
276362306a36Sopenharmony_ci	}
276462306a36Sopenharmony_ci}
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_cistatic void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
276762306a36Sopenharmony_ci{
276862306a36Sopenharmony_ci	if (tp->mac_version < RTL_GIGA_MAC_VER_32)
276962306a36Sopenharmony_ci		return;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	/* Don't enable ASPM in the chip if OS can't control ASPM */
277262306a36Sopenharmony_ci	if (enable && tp->aspm_manageable) {
277362306a36Sopenharmony_ci		/* On these chip versions ASPM can even harm
277462306a36Sopenharmony_ci		 * bus communication of other PCI devices.
277562306a36Sopenharmony_ci		 */
277662306a36Sopenharmony_ci		if (tp->mac_version == RTL_GIGA_MAC_VER_42 ||
277762306a36Sopenharmony_ci		    tp->mac_version == RTL_GIGA_MAC_VER_43)
277862306a36Sopenharmony_ci			return;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci		rtl_mod_config5(tp, 0, ASPM_en);
278162306a36Sopenharmony_ci		rtl_mod_config2(tp, 0, ClkReqEn);
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci		switch (tp->mac_version) {
278462306a36Sopenharmony_ci		case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
278562306a36Sopenharmony_ci		case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63:
278662306a36Sopenharmony_ci			/* reset ephy tx/rx disable timer */
278762306a36Sopenharmony_ci			r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0);
278862306a36Sopenharmony_ci			/* chip can trigger L1.2 */
278962306a36Sopenharmony_ci			r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, BIT(2));
279062306a36Sopenharmony_ci			break;
279162306a36Sopenharmony_ci		default:
279262306a36Sopenharmony_ci			break;
279362306a36Sopenharmony_ci		}
279462306a36Sopenharmony_ci	} else {
279562306a36Sopenharmony_ci		switch (tp->mac_version) {
279662306a36Sopenharmony_ci		case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
279762306a36Sopenharmony_ci		case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63:
279862306a36Sopenharmony_ci			r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);
279962306a36Sopenharmony_ci			break;
280062306a36Sopenharmony_ci		default:
280162306a36Sopenharmony_ci			break;
280262306a36Sopenharmony_ci		}
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_ci		rtl_mod_config2(tp, ClkReqEn, 0);
280562306a36Sopenharmony_ci		rtl_mod_config5(tp, ASPM_en, 0);
280662306a36Sopenharmony_ci	}
280762306a36Sopenharmony_ci}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_cistatic void rtl_set_fifo_size(struct rtl8169_private *tp, u16 rx_stat,
281062306a36Sopenharmony_ci			      u16 tx_stat, u16 rx_dyn, u16 tx_dyn)
281162306a36Sopenharmony_ci{
281262306a36Sopenharmony_ci	/* Usage of dynamic vs. static FIFO is controlled by bit
281362306a36Sopenharmony_ci	 * TXCFG_AUTO_FIFO. Exact meaning of FIFO values isn't known.
281462306a36Sopenharmony_ci	 */
281562306a36Sopenharmony_ci	rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, (rx_stat << 16) | rx_dyn);
281662306a36Sopenharmony_ci	rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, (tx_stat << 16) | tx_dyn);
281762306a36Sopenharmony_ci}
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_cistatic void rtl8168g_set_pause_thresholds(struct rtl8169_private *tp,
282062306a36Sopenharmony_ci					  u8 low, u8 high)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	/* FIFO thresholds for pause flow control */
282362306a36Sopenharmony_ci	rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, low);
282462306a36Sopenharmony_ci	rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, high);
282562306a36Sopenharmony_ci}
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_cistatic void rtl_hw_start_8168b(struct rtl8169_private *tp)
282862306a36Sopenharmony_ci{
282962306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
283062306a36Sopenharmony_ci}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_cistatic void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
283362306a36Sopenharmony_ci{
283462306a36Sopenharmony_ci	RTL_W8(tp, Config1, RTL_R8(tp, Config1) | Speed_down);
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci	rtl_disable_clock_request(tp);
283962306a36Sopenharmony_ci}
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_cistatic void rtl_hw_start_8168cp_1(struct rtl8169_private *tp)
284262306a36Sopenharmony_ci{
284362306a36Sopenharmony_ci	static const struct ephy_info e_info_8168cp[] = {
284462306a36Sopenharmony_ci		{ 0x01, 0,	0x0001 },
284562306a36Sopenharmony_ci		{ 0x02, 0x0800,	0x1000 },
284662306a36Sopenharmony_ci		{ 0x03, 0,	0x0042 },
284762306a36Sopenharmony_ci		{ 0x06, 0x0080,	0x0000 },
284862306a36Sopenharmony_ci		{ 0x07, 0,	0x2000 }
284962306a36Sopenharmony_ci	};
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168cp);
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	__rtl_hw_start_8168cp(tp);
285662306a36Sopenharmony_ci}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_cistatic void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
285962306a36Sopenharmony_ci{
286062306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
286362306a36Sopenharmony_ci}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_cistatic void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
286662306a36Sopenharmony_ci{
286762306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	/* Magic. */
287262306a36Sopenharmony_ci	RTL_W8(tp, DBG_REG, 0x20);
287362306a36Sopenharmony_ci}
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_cistatic void rtl_hw_start_8168c_1(struct rtl8169_private *tp)
287662306a36Sopenharmony_ci{
287762306a36Sopenharmony_ci	static const struct ephy_info e_info_8168c_1[] = {
287862306a36Sopenharmony_ci		{ 0x02, 0x0800,	0x1000 },
287962306a36Sopenharmony_ci		{ 0x03, 0,	0x0002 },
288062306a36Sopenharmony_ci		{ 0x06, 0x0080,	0x0000 }
288162306a36Sopenharmony_ci	};
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	RTL_W8(tp, DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168c_1);
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	__rtl_hw_start_8168cp(tp);
289062306a36Sopenharmony_ci}
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_cistatic void rtl_hw_start_8168c_2(struct rtl8169_private *tp)
289362306a36Sopenharmony_ci{
289462306a36Sopenharmony_ci	static const struct ephy_info e_info_8168c_2[] = {
289562306a36Sopenharmony_ci		{ 0x01, 0,	0x0001 },
289662306a36Sopenharmony_ci		{ 0x03, 0x0400,	0x0020 }
289762306a36Sopenharmony_ci	};
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168c_2);
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	__rtl_hw_start_8168cp(tp);
290462306a36Sopenharmony_ci}
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_cistatic void rtl_hw_start_8168c_4(struct rtl8169_private *tp)
290762306a36Sopenharmony_ci{
290862306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	__rtl_hw_start_8168cp(tp);
291162306a36Sopenharmony_ci}
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_cistatic void rtl_hw_start_8168d(struct rtl8169_private *tp)
291462306a36Sopenharmony_ci{
291562306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	rtl_disable_clock_request(tp);
291862306a36Sopenharmony_ci}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_cistatic void rtl_hw_start_8168d_4(struct rtl8169_private *tp)
292162306a36Sopenharmony_ci{
292262306a36Sopenharmony_ci	static const struct ephy_info e_info_8168d_4[] = {
292362306a36Sopenharmony_ci		{ 0x0b, 0x0000,	0x0048 },
292462306a36Sopenharmony_ci		{ 0x19, 0x0020,	0x0050 },
292562306a36Sopenharmony_ci		{ 0x0c, 0x0100,	0x0020 },
292662306a36Sopenharmony_ci		{ 0x10, 0x0004,	0x0000 },
292762306a36Sopenharmony_ci	};
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168d_4);
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	rtl_enable_clock_request(tp);
293462306a36Sopenharmony_ci}
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_cistatic void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
293762306a36Sopenharmony_ci{
293862306a36Sopenharmony_ci	static const struct ephy_info e_info_8168e_1[] = {
293962306a36Sopenharmony_ci		{ 0x00, 0x0200,	0x0100 },
294062306a36Sopenharmony_ci		{ 0x00, 0x0000,	0x0004 },
294162306a36Sopenharmony_ci		{ 0x06, 0x0002,	0x0001 },
294262306a36Sopenharmony_ci		{ 0x06, 0x0000,	0x0030 },
294362306a36Sopenharmony_ci		{ 0x07, 0x0000,	0x2000 },
294462306a36Sopenharmony_ci		{ 0x00, 0x0000,	0x0020 },
294562306a36Sopenharmony_ci		{ 0x03, 0x5800,	0x2000 },
294662306a36Sopenharmony_ci		{ 0x03, 0x0000,	0x0001 },
294762306a36Sopenharmony_ci		{ 0x01, 0x0800,	0x1000 },
294862306a36Sopenharmony_ci		{ 0x07, 0x0000,	0x4000 },
294962306a36Sopenharmony_ci		{ 0x1e, 0x0000,	0x2000 },
295062306a36Sopenharmony_ci		{ 0x19, 0xffff,	0xfe6c },
295162306a36Sopenharmony_ci		{ 0x0a, 0x0000,	0x0040 }
295262306a36Sopenharmony_ci	};
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168e_1);
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	rtl_disable_clock_request(tp);
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	/* Reset tx FIFO pointer */
296162306a36Sopenharmony_ci	RTL_W32(tp, MISC, RTL_R32(tp, MISC) | TXPLA_RST);
296262306a36Sopenharmony_ci	RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~TXPLA_RST);
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	rtl_mod_config5(tp, Spi_en, 0);
296562306a36Sopenharmony_ci}
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_cistatic void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
296862306a36Sopenharmony_ci{
296962306a36Sopenharmony_ci	static const struct ephy_info e_info_8168e_2[] = {
297062306a36Sopenharmony_ci		{ 0x09, 0x0000,	0x0080 },
297162306a36Sopenharmony_ci		{ 0x19, 0x0000,	0x0224 },
297262306a36Sopenharmony_ci		{ 0x00, 0x0000,	0x0004 },
297362306a36Sopenharmony_ci		{ 0x0c, 0x3df0,	0x0200 },
297462306a36Sopenharmony_ci	};
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168e_2);
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
298162306a36Sopenharmony_ci	rtl_eri_write(tp, 0xb8, ERIAR_MASK_1111, 0x0000);
298262306a36Sopenharmony_ci	rtl_set_fifo_size(tp, 0x10, 0x10, 0x02, 0x06);
298362306a36Sopenharmony_ci	rtl_eri_set_bits(tp, 0x1d0, BIT(1));
298462306a36Sopenharmony_ci	rtl_reset_packet_filter(tp);
298562306a36Sopenharmony_ci	rtl_eri_set_bits(tp, 0x1b0, BIT(4));
298662306a36Sopenharmony_ci	rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050);
298762306a36Sopenharmony_ci	rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060);
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	rtl_disable_clock_request(tp);
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	rtl8168_config_eee_mac(tp);
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN);
299662306a36Sopenharmony_ci	RTL_W32(tp, MISC, RTL_R32(tp, MISC) | PWM_EN);
299762306a36Sopenharmony_ci	rtl_mod_config5(tp, Spi_en, 0);
299862306a36Sopenharmony_ci}
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_cistatic void rtl_hw_start_8168f(struct rtl8169_private *tp)
300162306a36Sopenharmony_ci{
300262306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
300562306a36Sopenharmony_ci	rtl_eri_write(tp, 0xb8, ERIAR_MASK_1111, 0x0000);
300662306a36Sopenharmony_ci	rtl_set_fifo_size(tp, 0x10, 0x10, 0x02, 0x06);
300762306a36Sopenharmony_ci	rtl_reset_packet_filter(tp);
300862306a36Sopenharmony_ci	rtl_eri_set_bits(tp, 0x1b0, BIT(4));
300962306a36Sopenharmony_ci	rtl_eri_set_bits(tp, 0x1d0, BIT(4) | BIT(1));
301062306a36Sopenharmony_ci	rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050);
301162306a36Sopenharmony_ci	rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060);
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	rtl_disable_clock_request(tp);
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci	RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
301662306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN);
301762306a36Sopenharmony_ci	RTL_W32(tp, MISC, RTL_R32(tp, MISC) | PWM_EN);
301862306a36Sopenharmony_ci	rtl_mod_config5(tp, Spi_en, 0);
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci	rtl8168_config_eee_mac(tp);
302162306a36Sopenharmony_ci}
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_cistatic void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
302462306a36Sopenharmony_ci{
302562306a36Sopenharmony_ci	static const struct ephy_info e_info_8168f_1[] = {
302662306a36Sopenharmony_ci		{ 0x06, 0x00c0,	0x0020 },
302762306a36Sopenharmony_ci		{ 0x08, 0x0001,	0x0002 },
302862306a36Sopenharmony_ci		{ 0x09, 0x0000,	0x0080 },
302962306a36Sopenharmony_ci		{ 0x19, 0x0000,	0x0224 },
303062306a36Sopenharmony_ci		{ 0x00, 0x0000,	0x0008 },
303162306a36Sopenharmony_ci		{ 0x0c, 0x3df0,	0x0200 },
303262306a36Sopenharmony_ci	};
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	rtl_hw_start_8168f(tp);
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168f_1);
303762306a36Sopenharmony_ci}
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_cistatic void rtl_hw_start_8411(struct rtl8169_private *tp)
304062306a36Sopenharmony_ci{
304162306a36Sopenharmony_ci	static const struct ephy_info e_info_8168f_1[] = {
304262306a36Sopenharmony_ci		{ 0x06, 0x00c0,	0x0020 },
304362306a36Sopenharmony_ci		{ 0x0f, 0xffff,	0x5200 },
304462306a36Sopenharmony_ci		{ 0x19, 0x0000,	0x0224 },
304562306a36Sopenharmony_ci		{ 0x00, 0x0000,	0x0008 },
304662306a36Sopenharmony_ci		{ 0x0c, 0x3df0,	0x0200 },
304762306a36Sopenharmony_ci	};
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	rtl_hw_start_8168f(tp);
305062306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168f_1);
305362306a36Sopenharmony_ci}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_cistatic void rtl_hw_start_8168g(struct rtl8169_private *tp)
305662306a36Sopenharmony_ci{
305762306a36Sopenharmony_ci	rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06);
305862306a36Sopenharmony_ci	rtl8168g_set_pause_thresholds(tp, 0x38, 0x48);
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	rtl_reset_packet_filter(tp);
306362306a36Sopenharmony_ci	rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f);
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	rtl_disable_rxdvgate(tp);
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_ci	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
306862306a36Sopenharmony_ci	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	rtl8168_config_eee_mac(tp);
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	rtl_w0w1_eri(tp, 0x2fc, 0x01, 0x06);
307362306a36Sopenharmony_ci	rtl_eri_clear_bits(tp, 0x1b0, BIT(12));
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
307662306a36Sopenharmony_ci}
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_cistatic void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
307962306a36Sopenharmony_ci{
308062306a36Sopenharmony_ci	static const struct ephy_info e_info_8168g_1[] = {
308162306a36Sopenharmony_ci		{ 0x00, 0x0008,	0x0000 },
308262306a36Sopenharmony_ci		{ 0x0c, 0x3ff0,	0x0820 },
308362306a36Sopenharmony_ci		{ 0x1e, 0x0000,	0x0001 },
308462306a36Sopenharmony_ci		{ 0x19, 0x8000,	0x0000 }
308562306a36Sopenharmony_ci	};
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	rtl_hw_start_8168g(tp);
308862306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168g_1);
308962306a36Sopenharmony_ci}
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_cistatic void rtl_hw_start_8168g_2(struct rtl8169_private *tp)
309262306a36Sopenharmony_ci{
309362306a36Sopenharmony_ci	static const struct ephy_info e_info_8168g_2[] = {
309462306a36Sopenharmony_ci		{ 0x00, 0x0008,	0x0000 },
309562306a36Sopenharmony_ci		{ 0x0c, 0x3ff0,	0x0820 },
309662306a36Sopenharmony_ci		{ 0x19, 0xffff,	0x7c00 },
309762306a36Sopenharmony_ci		{ 0x1e, 0xffff,	0x20eb },
309862306a36Sopenharmony_ci		{ 0x0d, 0xffff,	0x1666 },
309962306a36Sopenharmony_ci		{ 0x00, 0xffff,	0x10a3 },
310062306a36Sopenharmony_ci		{ 0x06, 0xffff,	0xf050 },
310162306a36Sopenharmony_ci		{ 0x04, 0x0000,	0x0010 },
310262306a36Sopenharmony_ci		{ 0x1d, 0x4000,	0x0000 },
310362306a36Sopenharmony_ci	};
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	rtl_hw_start_8168g(tp);
310662306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168g_2);
310762306a36Sopenharmony_ci}
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_cistatic void rtl_hw_start_8411_2(struct rtl8169_private *tp)
311062306a36Sopenharmony_ci{
311162306a36Sopenharmony_ci	static const struct ephy_info e_info_8411_2[] = {
311262306a36Sopenharmony_ci		{ 0x00, 0x0008,	0x0000 },
311362306a36Sopenharmony_ci		{ 0x0c, 0x37d0,	0x0820 },
311462306a36Sopenharmony_ci		{ 0x1e, 0x0000,	0x0001 },
311562306a36Sopenharmony_ci		{ 0x19, 0x8021,	0x0000 },
311662306a36Sopenharmony_ci		{ 0x1e, 0x0000,	0x2000 },
311762306a36Sopenharmony_ci		{ 0x0d, 0x0100,	0x0200 },
311862306a36Sopenharmony_ci		{ 0x00, 0x0000,	0x0080 },
311962306a36Sopenharmony_ci		{ 0x06, 0x0000,	0x0010 },
312062306a36Sopenharmony_ci		{ 0x04, 0x0000,	0x0010 },
312162306a36Sopenharmony_ci		{ 0x1d, 0x0000,	0x4000 },
312262306a36Sopenharmony_ci	};
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci	rtl_hw_start_8168g(tp);
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8411_2);
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	/* The following Realtek-provided magic fixes an issue with the RX unit
312962306a36Sopenharmony_ci	 * getting confused after the PHY having been powered-down.
313062306a36Sopenharmony_ci	 */
313162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC28, 0x0000);
313262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC2A, 0x0000);
313362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC2C, 0x0000);
313462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC2E, 0x0000);
313562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC30, 0x0000);
313662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC32, 0x0000);
313762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC34, 0x0000);
313862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC36, 0x0000);
313962306a36Sopenharmony_ci	mdelay(3);
314062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC26, 0x0000);
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF800, 0xE008);
314362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF802, 0xE00A);
314462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF804, 0xE00C);
314562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF806, 0xE00E);
314662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF808, 0xE027);
314762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF80A, 0xE04F);
314862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF80C, 0xE05E);
314962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF80E, 0xE065);
315062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF810, 0xC602);
315162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF812, 0xBE00);
315262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF814, 0x0000);
315362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF816, 0xC502);
315462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF818, 0xBD00);
315562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF81A, 0x074C);
315662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF81C, 0xC302);
315762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF81E, 0xBB00);
315862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF820, 0x080A);
315962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF822, 0x6420);
316062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF824, 0x48C2);
316162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF826, 0x8C20);
316262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF828, 0xC516);
316362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF82A, 0x64A4);
316462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF82C, 0x49C0);
316562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF82E, 0xF009);
316662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF830, 0x74A2);
316762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF832, 0x8CA5);
316862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF834, 0x74A0);
316962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF836, 0xC50E);
317062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF838, 0x9CA2);
317162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF83A, 0x1C11);
317262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0);
317362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF83E, 0xE006);
317462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF840, 0x74F8);
317562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF842, 0x48C4);
317662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF844, 0x8CF8);
317762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF846, 0xC404);
317862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF848, 0xBC00);
317962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF84A, 0xC403);
318062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF84C, 0xBC00);
318162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2);
318262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF850, 0x0C0A);
318362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF852, 0xE434);
318462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF854, 0xD3C0);
318562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF856, 0x49D9);
318662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF858, 0xF01F);
318762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF85A, 0xC526);
318862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF85C, 0x64A5);
318962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF85E, 0x1400);
319062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF860, 0xF007);
319162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF862, 0x0C01);
319262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF864, 0x8CA5);
319362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF866, 0x1C15);
319462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF868, 0xC51B);
319562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0);
319662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF86C, 0xE013);
319762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF86E, 0xC519);
319862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF870, 0x74A0);
319962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF872, 0x48C4);
320062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF874, 0x8CA0);
320162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF876, 0xC516);
320262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF878, 0x74A4);
320362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF87A, 0x48C8);
320462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF87C, 0x48CA);
320562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4);
320662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF880, 0xC512);
320762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF882, 0x1B00);
320862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF884, 0x9BA0);
320962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF886, 0x1B1C);
321062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF888, 0x483F);
321162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2);
321262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF88C, 0x1B04);
321362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF88E, 0xC508);
321462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF890, 0x9BA0);
321562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF892, 0xC505);
321662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF894, 0xBD00);
321762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF896, 0xC502);
321862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF898, 0xBD00);
321962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF89A, 0x0300);
322062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF89C, 0x051E);
322162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF89E, 0xE434);
322262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8A0, 0xE018);
322362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8A2, 0xE092);
322462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20);
322562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0);
322662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F);
322762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4);
322862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3);
322962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8AE, 0xF007);
323062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0);
323162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8B2, 0xF103);
323262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8B4, 0xC607);
323362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00);
323462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8B8, 0xC606);
323562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00);
323662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8BC, 0xC602);
323762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00);
323862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C);
323962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28);
324062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C);
324162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00);
324262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8C8, 0xC707);
324362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00);
324462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2);
324562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1);
324662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8D0, 0xC502);
324762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00);
324862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA);
324962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0);
325062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8D8, 0xC502);
325162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00);
325262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xF8DC, 0x0132);
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC26, 0x8000);
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC2A, 0x0743);
325762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC2C, 0x0801);
325862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC2E, 0x0BE9);
325962306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC30, 0x02FD);
326062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC32, 0x0C25);
326162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC34, 0x00A9);
326262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xFC36, 0x012D);
326362306a36Sopenharmony_ci}
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_cistatic void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
326662306a36Sopenharmony_ci{
326762306a36Sopenharmony_ci	static const struct ephy_info e_info_8168h_1[] = {
326862306a36Sopenharmony_ci		{ 0x1e, 0x0800,	0x0001 },
326962306a36Sopenharmony_ci		{ 0x1d, 0x0000,	0x0800 },
327062306a36Sopenharmony_ci		{ 0x05, 0xffff,	0x2089 },
327162306a36Sopenharmony_ci		{ 0x06, 0xffff,	0x5881 },
327262306a36Sopenharmony_ci		{ 0x04, 0xffff,	0x854a },
327362306a36Sopenharmony_ci		{ 0x01, 0xffff,	0x068b }
327462306a36Sopenharmony_ci	};
327562306a36Sopenharmony_ci	int rg_saw_cnt;
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168h_1);
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_ci	rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06);
328062306a36Sopenharmony_ci	rtl8168g_set_pause_thresholds(tp, 0x38, 0x48);
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	rtl_reset_packet_filter(tp);
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	rtl_eri_set_bits(tp, 0xdc, 0x001c);
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87);
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	rtl_disable_rxdvgate(tp);
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
329362306a36Sopenharmony_ci	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	rtl8168_config_eee_mac(tp);
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN);
329862306a36Sopenharmony_ci	RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN);
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN);
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci	rtl_eri_clear_bits(tp, 0x1b0, BIT(12));
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff;
330762306a36Sopenharmony_ci	if (rg_saw_cnt > 0) {
330862306a36Sopenharmony_ci		u16 sw_cnt_1ms_ini;
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_ci		sw_cnt_1ms_ini = 16000000/rg_saw_cnt;
331162306a36Sopenharmony_ci		sw_cnt_1ms_ini &= 0x0fff;
331262306a36Sopenharmony_ci		r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini);
331362306a36Sopenharmony_ci	}
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0070);
331662306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe052, 0x6000, 0x8008);
331762306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe0d6, 0x01ff, 0x017f);
331862306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xd420, 0x0fff, 0x047f);
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xe63e, 0x0001);
332162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xe63e, 0x0000);
332262306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc094, 0x0000);
332362306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
332462306a36Sopenharmony_ci}
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_cistatic void rtl_hw_start_8168ep(struct rtl8169_private *tp)
332762306a36Sopenharmony_ci{
332862306a36Sopenharmony_ci	rtl8168ep_stop_cmac(tp);
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci	rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06);
333162306a36Sopenharmony_ci	rtl8168g_set_pause_thresholds(tp, 0x2f, 0x5f);
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	rtl_reset_packet_filter(tp);
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87);
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	rtl_disable_rxdvgate(tp);
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
334262306a36Sopenharmony_ci	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci	rtl8168_config_eee_mac(tp);
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	rtl_w0w1_eri(tp, 0x2fc, 0x01, 0x06);
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN);
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
335162306a36Sopenharmony_ci}
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_cistatic void rtl_hw_start_8168ep_3(struct rtl8169_private *tp)
335462306a36Sopenharmony_ci{
335562306a36Sopenharmony_ci	static const struct ephy_info e_info_8168ep_3[] = {
335662306a36Sopenharmony_ci		{ 0x00, 0x0000,	0x0080 },
335762306a36Sopenharmony_ci		{ 0x0d, 0x0100,	0x0200 },
335862306a36Sopenharmony_ci		{ 0x19, 0x8021,	0x0000 },
335962306a36Sopenharmony_ci		{ 0x1e, 0x0000,	0x2000 },
336062306a36Sopenharmony_ci	};
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8168ep_3);
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	rtl_hw_start_8168ep(tp);
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN);
336762306a36Sopenharmony_ci	RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN);
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xd3e2, 0x0fff, 0x0271);
337062306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xd3e4, 0x00ff, 0x0000);
337162306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe860, 0x0000, 0x0080);
337262306a36Sopenharmony_ci}
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_cistatic void rtl_hw_start_8117(struct rtl8169_private *tp)
337562306a36Sopenharmony_ci{
337662306a36Sopenharmony_ci	static const struct ephy_info e_info_8117[] = {
337762306a36Sopenharmony_ci		{ 0x19, 0x0040,	0x1100 },
337862306a36Sopenharmony_ci		{ 0x59, 0x0040,	0x1100 },
337962306a36Sopenharmony_ci	};
338062306a36Sopenharmony_ci	int rg_saw_cnt;
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci	rtl8168ep_stop_cmac(tp);
338362306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8117);
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06);
338662306a36Sopenharmony_ci	rtl8168g_set_pause_thresholds(tp, 0x2f, 0x5f);
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci	rtl_reset_packet_filter(tp);
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	rtl_eri_set_bits(tp, 0xd4, 0x0010);
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci	rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87);
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci	rtl_disable_rxdvgate(tp);
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
339962306a36Sopenharmony_ci	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	rtl8168_config_eee_mac(tp);
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN);
340462306a36Sopenharmony_ci	RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN);
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN);
340762306a36Sopenharmony_ci
340862306a36Sopenharmony_ci	rtl_eri_clear_bits(tp, 0x1b0, BIT(12));
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff;
341362306a36Sopenharmony_ci	if (rg_saw_cnt > 0) {
341462306a36Sopenharmony_ci		u16 sw_cnt_1ms_ini;
341562306a36Sopenharmony_ci
341662306a36Sopenharmony_ci		sw_cnt_1ms_ini = (16000000 / rg_saw_cnt) & 0x0fff;
341762306a36Sopenharmony_ci		r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini);
341862306a36Sopenharmony_ci	}
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0070);
342162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xea80, 0x0003);
342262306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe052, 0x0000, 0x0009);
342362306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xd420, 0x0fff, 0x047f);
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xe63e, 0x0001);
342662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xe63e, 0x0000);
342762306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc094, 0x0000);
342862306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci	/* firmware is for MAC only */
343162306a36Sopenharmony_ci	r8169_apply_firmware(tp);
343262306a36Sopenharmony_ci}
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_cistatic void rtl_hw_start_8102e_1(struct rtl8169_private *tp)
343562306a36Sopenharmony_ci{
343662306a36Sopenharmony_ci	static const struct ephy_info e_info_8102e_1[] = {
343762306a36Sopenharmony_ci		{ 0x01,	0, 0x6e65 },
343862306a36Sopenharmony_ci		{ 0x02,	0, 0x091f },
343962306a36Sopenharmony_ci		{ 0x03,	0, 0xc2f9 },
344062306a36Sopenharmony_ci		{ 0x06,	0, 0xafb5 },
344162306a36Sopenharmony_ci		{ 0x07,	0, 0x0e00 },
344262306a36Sopenharmony_ci		{ 0x19,	0, 0xec80 },
344362306a36Sopenharmony_ci		{ 0x01,	0, 0x2e65 },
344462306a36Sopenharmony_ci		{ 0x01,	0, 0x6e65 }
344562306a36Sopenharmony_ci	};
344662306a36Sopenharmony_ci	u8 cfg1;
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci	RTL_W8(tp, DBG_REG, FIX_NAK_1);
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	RTL_W8(tp, Config1,
345362306a36Sopenharmony_ci	       LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
345462306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci	cfg1 = RTL_R8(tp, Config1);
345762306a36Sopenharmony_ci	if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
345862306a36Sopenharmony_ci		RTL_W8(tp, Config1, cfg1 & ~LEDS0);
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8102e_1);
346162306a36Sopenharmony_ci}
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_cistatic void rtl_hw_start_8102e_2(struct rtl8169_private *tp)
346462306a36Sopenharmony_ci{
346562306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	RTL_W8(tp, Config1, MEMMAP | IOMAP | VPD | PMEnable);
346862306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
346962306a36Sopenharmony_ci}
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_cistatic void rtl_hw_start_8102e_3(struct rtl8169_private *tp)
347262306a36Sopenharmony_ci{
347362306a36Sopenharmony_ci	rtl_hw_start_8102e_2(tp);
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	rtl_ephy_write(tp, 0x03, 0xc2f9);
347662306a36Sopenharmony_ci}
347762306a36Sopenharmony_ci
347862306a36Sopenharmony_cistatic void rtl_hw_start_8401(struct rtl8169_private *tp)
347962306a36Sopenharmony_ci{
348062306a36Sopenharmony_ci	static const struct ephy_info e_info_8401[] = {
348162306a36Sopenharmony_ci		{ 0x01,	0xffff, 0x6fe5 },
348262306a36Sopenharmony_ci		{ 0x03,	0xffff, 0x0599 },
348362306a36Sopenharmony_ci		{ 0x06,	0xffff, 0xaf25 },
348462306a36Sopenharmony_ci		{ 0x07,	0xffff, 0x8e68 },
348562306a36Sopenharmony_ci	};
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8401);
348862306a36Sopenharmony_ci	RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en);
348962306a36Sopenharmony_ci}
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_cistatic void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
349262306a36Sopenharmony_ci{
349362306a36Sopenharmony_ci	static const struct ephy_info e_info_8105e_1[] = {
349462306a36Sopenharmony_ci		{ 0x07,	0, 0x4000 },
349562306a36Sopenharmony_ci		{ 0x19,	0, 0x0200 },
349662306a36Sopenharmony_ci		{ 0x19,	0, 0x0020 },
349762306a36Sopenharmony_ci		{ 0x1e,	0, 0x2000 },
349862306a36Sopenharmony_ci		{ 0x03,	0, 0x0001 },
349962306a36Sopenharmony_ci		{ 0x19,	0, 0x0100 },
350062306a36Sopenharmony_ci		{ 0x19,	0, 0x0004 },
350162306a36Sopenharmony_ci		{ 0x0a,	0, 0x0020 }
350262306a36Sopenharmony_ci	};
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci	/* Force LAN exit from ASPM if Rx/Tx are not idle */
350562306a36Sopenharmony_ci	RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) | 0x002800);
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	/* Disable Early Tally Counter */
350862306a36Sopenharmony_ci	RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) & ~0x010000);
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_ci	RTL_W8(tp, MCU, RTL_R8(tp, MCU) | EN_NDP | EN_OOB_RESET);
351162306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN);
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8105e_1);
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
351662306a36Sopenharmony_ci}
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_cistatic void rtl_hw_start_8105e_2(struct rtl8169_private *tp)
351962306a36Sopenharmony_ci{
352062306a36Sopenharmony_ci	rtl_hw_start_8105e_1(tp);
352162306a36Sopenharmony_ci	rtl_ephy_write(tp, 0x1e, rtl_ephy_read(tp, 0x1e) | 0x8000);
352262306a36Sopenharmony_ci}
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_cistatic void rtl_hw_start_8402(struct rtl8169_private *tp)
352562306a36Sopenharmony_ci{
352662306a36Sopenharmony_ci	static const struct ephy_info e_info_8402[] = {
352762306a36Sopenharmony_ci		{ 0x19,	0xffff, 0xff64 },
352862306a36Sopenharmony_ci		{ 0x1e,	0, 0x4000 }
352962306a36Sopenharmony_ci	};
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
353262306a36Sopenharmony_ci
353362306a36Sopenharmony_ci	/* Force LAN exit from ASPM if Rx/Tx are not idle */
353462306a36Sopenharmony_ci	RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) | 0x002800);
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci	RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8402);
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci	rtl_set_fifo_size(tp, 0x00, 0x00, 0x02, 0x06);
354162306a36Sopenharmony_ci	rtl_reset_packet_filter(tp);
354262306a36Sopenharmony_ci	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000);
354362306a36Sopenharmony_ci	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000);
354462306a36Sopenharmony_ci	rtl_w0w1_eri(tp, 0x0d4, 0x0e00, 0xff00);
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	/* disable EEE */
354762306a36Sopenharmony_ci	rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000);
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
355062306a36Sopenharmony_ci}
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_cistatic void rtl_hw_start_8106(struct rtl8169_private *tp)
355362306a36Sopenharmony_ci{
355462306a36Sopenharmony_ci	/* Force LAN exit from ASPM if Rx/Tx are not idle */
355562306a36Sopenharmony_ci	RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) | 0x002800);
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci	RTL_W32(tp, MISC, (RTL_R32(tp, MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
355862306a36Sopenharmony_ci	RTL_W8(tp, MCU, RTL_R8(tp, MCU) | EN_NDP | EN_OOB_RESET);
355962306a36Sopenharmony_ci	RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN);
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	/* L0 7us, L1 32us - needed to avoid issues with link-up detection */
356262306a36Sopenharmony_ci	rtl_set_aspm_entry_latency(tp, 0x2f);
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000);
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_ci	/* disable EEE */
356762306a36Sopenharmony_ci	rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000);
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
357062306a36Sopenharmony_ci}
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_mac_ocp_e00e_cond)
357362306a36Sopenharmony_ci{
357462306a36Sopenharmony_ci	return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13);
357562306a36Sopenharmony_ci}
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_cistatic void rtl_hw_start_8125_common(struct rtl8169_private *tp)
357862306a36Sopenharmony_ci{
357962306a36Sopenharmony_ci	rtl_pcie_state_l2l3_disable(tp);
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci	RTL_W16(tp, 0x382, 0x221b);
358262306a36Sopenharmony_ci	RTL_W8(tp, 0x4500, 0);
358362306a36Sopenharmony_ci	RTL_W16(tp, 0x4800, 0);
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_ci	/* disable UPS */
358662306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000);
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci	RTL_W8(tp, Config1, RTL_R8(tp, Config1) & ~0x10);
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc140, 0xffff);
359162306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc142, 0xffff);
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xd3e2, 0x0fff, 0x03a9);
359462306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xd3e4, 0x00ff, 0x0000);
359562306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe860, 0x0000, 0x0080);
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci	/* disable new tx descriptor format */
359862306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000);
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_63)
360162306a36Sopenharmony_ci		r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200);
360262306a36Sopenharmony_ci	else
360362306a36Sopenharmony_ci		r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400);
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_63)
360662306a36Sopenharmony_ci		r8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0000);
360762306a36Sopenharmony_ci	else
360862306a36Sopenharmony_ci		r8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0020);
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xc0b4, 0x0000, 0x000c);
361162306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xeb6a, 0x00ff, 0x0033);
361262306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xeb50, 0x03e0, 0x0040);
361362306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030);
361462306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000);
361562306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001);
361662306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe0c0, 0x4f0f, 0x4403);
361762306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe052, 0x0080, 0x0068);
361862306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xd430, 0x0fff, 0x047f);
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000);
362162306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xeb54, 0x0000, 0x0001);
362262306a36Sopenharmony_ci	udelay(1);
362362306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xeb54, 0x0001, 0x0000);
362462306a36Sopenharmony_ci	RTL_W16(tp, 0x1880, RTL_R16(tp, 0x1880) & ~0x0030);
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xe098, 0xc302);
362762306a36Sopenharmony_ci
362862306a36Sopenharmony_ci	rtl_loop_wait_low(tp, &rtl_mac_ocp_e00e_cond, 1000, 10);
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_63)
363162306a36Sopenharmony_ci		rtl8125b_config_eee_mac(tp);
363262306a36Sopenharmony_ci	else
363362306a36Sopenharmony_ci		rtl8125a_config_eee_mac(tp);
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci	rtl_disable_rxdvgate(tp);
363662306a36Sopenharmony_ci}
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_cistatic void rtl_hw_start_8125a_2(struct rtl8169_private *tp)
363962306a36Sopenharmony_ci{
364062306a36Sopenharmony_ci	static const struct ephy_info e_info_8125a_2[] = {
364162306a36Sopenharmony_ci		{ 0x04, 0xffff, 0xd000 },
364262306a36Sopenharmony_ci		{ 0x0a, 0xffff, 0x8653 },
364362306a36Sopenharmony_ci		{ 0x23, 0xffff, 0xab66 },
364462306a36Sopenharmony_ci		{ 0x20, 0xffff, 0x9455 },
364562306a36Sopenharmony_ci		{ 0x21, 0xffff, 0x99ff },
364662306a36Sopenharmony_ci		{ 0x29, 0xffff, 0xfe04 },
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci		{ 0x44, 0xffff, 0xd000 },
364962306a36Sopenharmony_ci		{ 0x4a, 0xffff, 0x8653 },
365062306a36Sopenharmony_ci		{ 0x63, 0xffff, 0xab66 },
365162306a36Sopenharmony_ci		{ 0x60, 0xffff, 0x9455 },
365262306a36Sopenharmony_ci		{ 0x61, 0xffff, 0x99ff },
365362306a36Sopenharmony_ci		{ 0x69, 0xffff, 0xfe04 },
365462306a36Sopenharmony_ci	};
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
365762306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8125a_2);
365862306a36Sopenharmony_ci	rtl_hw_start_8125_common(tp);
365962306a36Sopenharmony_ci}
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_cistatic void rtl_hw_start_8125b(struct rtl8169_private *tp)
366262306a36Sopenharmony_ci{
366362306a36Sopenharmony_ci	static const struct ephy_info e_info_8125b[] = {
366462306a36Sopenharmony_ci		{ 0x0b, 0xffff, 0xa908 },
366562306a36Sopenharmony_ci		{ 0x1e, 0xffff, 0x20eb },
366662306a36Sopenharmony_ci		{ 0x4b, 0xffff, 0xa908 },
366762306a36Sopenharmony_ci		{ 0x5e, 0xffff, 0x20eb },
366862306a36Sopenharmony_ci		{ 0x22, 0x0030, 0x0020 },
366962306a36Sopenharmony_ci		{ 0x62, 0x0030, 0x0020 },
367062306a36Sopenharmony_ci	};
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci	rtl_set_def_aspm_entry_latency(tp);
367362306a36Sopenharmony_ci	rtl_ephy_init(tp, e_info_8125b);
367462306a36Sopenharmony_ci	rtl_hw_start_8125_common(tp);
367562306a36Sopenharmony_ci}
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_cistatic void rtl_hw_config(struct rtl8169_private *tp)
367862306a36Sopenharmony_ci{
367962306a36Sopenharmony_ci	static const rtl_generic_fct hw_configs[] = {
368062306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_07] = rtl_hw_start_8102e_1,
368162306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3,
368262306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2,
368362306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_10] = NULL,
368462306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b,
368562306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_14] = rtl_hw_start_8401,
368662306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b,
368762306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1,
368862306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_19] = rtl_hw_start_8168c_1,
368962306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_20] = rtl_hw_start_8168c_2,
369062306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_21] = rtl_hw_start_8168c_2,
369162306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_22] = rtl_hw_start_8168c_4,
369262306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_23] = rtl_hw_start_8168cp_2,
369362306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_24] = rtl_hw_start_8168cp_3,
369462306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_25] = rtl_hw_start_8168d,
369562306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_26] = rtl_hw_start_8168d,
369662306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_28] = rtl_hw_start_8168d_4,
369762306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_29] = rtl_hw_start_8105e_1,
369862306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_30] = rtl_hw_start_8105e_2,
369962306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_31] = rtl_hw_start_8168d,
370062306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_32] = rtl_hw_start_8168e_1,
370162306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_33] = rtl_hw_start_8168e_1,
370262306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_34] = rtl_hw_start_8168e_2,
370362306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_35] = rtl_hw_start_8168f_1,
370462306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_36] = rtl_hw_start_8168f_1,
370562306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_37] = rtl_hw_start_8402,
370662306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_38] = rtl_hw_start_8411,
370762306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_39] = rtl_hw_start_8106,
370862306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_40] = rtl_hw_start_8168g_1,
370962306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_42] = rtl_hw_start_8168g_2,
371062306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_43] = rtl_hw_start_8168g_2,
371162306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_44] = rtl_hw_start_8411_2,
371262306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_46] = rtl_hw_start_8168h_1,
371362306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_48] = rtl_hw_start_8168h_1,
371462306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_51] = rtl_hw_start_8168ep_3,
371562306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_52] = rtl_hw_start_8117,
371662306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117,
371762306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
371862306a36Sopenharmony_ci		[RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
371962306a36Sopenharmony_ci	};
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci	if (hw_configs[tp->mac_version])
372262306a36Sopenharmony_ci		hw_configs[tp->mac_version](tp);
372362306a36Sopenharmony_ci}
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_cistatic void rtl_hw_start_8125(struct rtl8169_private *tp)
372662306a36Sopenharmony_ci{
372762306a36Sopenharmony_ci	int i;
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	/* disable interrupt coalescing */
373062306a36Sopenharmony_ci	for (i = 0xa00; i < 0xb00; i += 4)
373162306a36Sopenharmony_ci		RTL_W32(tp, i, 0);
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	rtl_hw_config(tp);
373462306a36Sopenharmony_ci}
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_cistatic void rtl_hw_start_8168(struct rtl8169_private *tp)
373762306a36Sopenharmony_ci{
373862306a36Sopenharmony_ci	if (rtl_is_8168evl_up(tp))
373962306a36Sopenharmony_ci		RTL_W8(tp, MaxTxPacketSize, EarlySize);
374062306a36Sopenharmony_ci	else
374162306a36Sopenharmony_ci		RTL_W8(tp, MaxTxPacketSize, TxPacketMax);
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	rtl_hw_config(tp);
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	/* disable interrupt coalescing */
374662306a36Sopenharmony_ci	RTL_W16(tp, IntrMitigate, 0x0000);
374762306a36Sopenharmony_ci}
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_cistatic void rtl_hw_start_8169(struct rtl8169_private *tp)
375062306a36Sopenharmony_ci{
375162306a36Sopenharmony_ci	RTL_W8(tp, EarlyTxThres, NoEarlyTx);
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	tp->cp_cmd |= PCIMulRW;
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
375662306a36Sopenharmony_ci	    tp->mac_version == RTL_GIGA_MAC_VER_03)
375762306a36Sopenharmony_ci		tp->cp_cmd |= EnAnaPLL;
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci	RTL_W16(tp, CPlusCmd, tp->cp_cmd);
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci	rtl8169_set_magic_reg(tp);
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ci	/* disable interrupt coalescing */
376462306a36Sopenharmony_ci	RTL_W16(tp, IntrMitigate, 0x0000);
376562306a36Sopenharmony_ci}
376662306a36Sopenharmony_ci
376762306a36Sopenharmony_cistatic void rtl_hw_start(struct  rtl8169_private *tp)
376862306a36Sopenharmony_ci{
376962306a36Sopenharmony_ci	rtl_unlock_config_regs(tp);
377062306a36Sopenharmony_ci	/* disable aspm and clock request before ephy access */
377162306a36Sopenharmony_ci	rtl_hw_aspm_clkreq_enable(tp, false);
377262306a36Sopenharmony_ci	RTL_W16(tp, CPlusCmd, tp->cp_cmd);
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci	if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
377562306a36Sopenharmony_ci		rtl_hw_start_8169(tp);
377662306a36Sopenharmony_ci	else if (rtl_is_8125(tp))
377762306a36Sopenharmony_ci		rtl_hw_start_8125(tp);
377862306a36Sopenharmony_ci	else
377962306a36Sopenharmony_ci		rtl_hw_start_8168(tp);
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci	rtl_enable_exit_l1(tp);
378262306a36Sopenharmony_ci	rtl_hw_aspm_clkreq_enable(tp, true);
378362306a36Sopenharmony_ci	rtl_set_rx_max_size(tp);
378462306a36Sopenharmony_ci	rtl_set_rx_tx_desc_registers(tp);
378562306a36Sopenharmony_ci	rtl_lock_config_regs(tp);
378662306a36Sopenharmony_ci
378762306a36Sopenharmony_ci	rtl_jumbo_config(tp);
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci	/* Initially a 10 us delay. Turned it into a PCI commit. - FR */
379062306a36Sopenharmony_ci	rtl_pci_commit(tp);
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	RTL_W8(tp, ChipCmd, CmdTxEnb | CmdRxEnb);
379362306a36Sopenharmony_ci	rtl_init_rxcfg(tp);
379462306a36Sopenharmony_ci	rtl_set_tx_config_registers(tp);
379562306a36Sopenharmony_ci	rtl_set_rx_config_features(tp, tp->dev->features);
379662306a36Sopenharmony_ci	rtl_set_rx_mode(tp->dev);
379762306a36Sopenharmony_ci	rtl_irq_enable(tp);
379862306a36Sopenharmony_ci}
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_cistatic int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
380162306a36Sopenharmony_ci{
380262306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci	dev->mtu = new_mtu;
380562306a36Sopenharmony_ci	netdev_update_features(dev);
380662306a36Sopenharmony_ci	rtl_jumbo_config(tp);
380762306a36Sopenharmony_ci
380862306a36Sopenharmony_ci	switch (tp->mac_version) {
380962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_61:
381062306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_63:
381162306a36Sopenharmony_ci		rtl8125_set_eee_txidle_timer(tp);
381262306a36Sopenharmony_ci		break;
381362306a36Sopenharmony_ci	default:
381462306a36Sopenharmony_ci		break;
381562306a36Sopenharmony_ci	}
381662306a36Sopenharmony_ci
381762306a36Sopenharmony_ci	return 0;
381862306a36Sopenharmony_ci}
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_cistatic void rtl8169_mark_to_asic(struct RxDesc *desc)
382162306a36Sopenharmony_ci{
382262306a36Sopenharmony_ci	u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci	desc->opts2 = 0;
382562306a36Sopenharmony_ci	/* Force memory writes to complete before releasing descriptor */
382662306a36Sopenharmony_ci	dma_wmb();
382762306a36Sopenharmony_ci	WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE));
382862306a36Sopenharmony_ci}
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_cistatic struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
383162306a36Sopenharmony_ci					  struct RxDesc *desc)
383262306a36Sopenharmony_ci{
383362306a36Sopenharmony_ci	struct device *d = tp_to_dev(tp);
383462306a36Sopenharmony_ci	int node = dev_to_node(d);
383562306a36Sopenharmony_ci	dma_addr_t mapping;
383662306a36Sopenharmony_ci	struct page *data;
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci	data = alloc_pages_node(node, GFP_KERNEL, get_order(R8169_RX_BUF_SIZE));
383962306a36Sopenharmony_ci	if (!data)
384062306a36Sopenharmony_ci		return NULL;
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci	mapping = dma_map_page(d, data, 0, R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
384362306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(d, mapping))) {
384462306a36Sopenharmony_ci		netdev_err(tp->dev, "Failed to map RX DMA!\n");
384562306a36Sopenharmony_ci		__free_pages(data, get_order(R8169_RX_BUF_SIZE));
384662306a36Sopenharmony_ci		return NULL;
384762306a36Sopenharmony_ci	}
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_ci	desc->addr = cpu_to_le64(mapping);
385062306a36Sopenharmony_ci	rtl8169_mark_to_asic(desc);
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ci	return data;
385362306a36Sopenharmony_ci}
385462306a36Sopenharmony_ci
385562306a36Sopenharmony_cistatic void rtl8169_rx_clear(struct rtl8169_private *tp)
385662306a36Sopenharmony_ci{
385762306a36Sopenharmony_ci	int i;
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	for (i = 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) {
386062306a36Sopenharmony_ci		dma_unmap_page(tp_to_dev(tp),
386162306a36Sopenharmony_ci			       le64_to_cpu(tp->RxDescArray[i].addr),
386262306a36Sopenharmony_ci			       R8169_RX_BUF_SIZE, DMA_FROM_DEVICE);
386362306a36Sopenharmony_ci		__free_pages(tp->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
386462306a36Sopenharmony_ci		tp->Rx_databuff[i] = NULL;
386562306a36Sopenharmony_ci		tp->RxDescArray[i].addr = 0;
386662306a36Sopenharmony_ci		tp->RxDescArray[i].opts1 = 0;
386762306a36Sopenharmony_ci	}
386862306a36Sopenharmony_ci}
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_cistatic int rtl8169_rx_fill(struct rtl8169_private *tp)
387162306a36Sopenharmony_ci{
387262306a36Sopenharmony_ci	int i;
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_ci	for (i = 0; i < NUM_RX_DESC; i++) {
387562306a36Sopenharmony_ci		struct page *data;
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_ci		data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
387862306a36Sopenharmony_ci		if (!data) {
387962306a36Sopenharmony_ci			rtl8169_rx_clear(tp);
388062306a36Sopenharmony_ci			return -ENOMEM;
388162306a36Sopenharmony_ci		}
388262306a36Sopenharmony_ci		tp->Rx_databuff[i] = data;
388362306a36Sopenharmony_ci	}
388462306a36Sopenharmony_ci
388562306a36Sopenharmony_ci	/* mark as last descriptor in the ring */
388662306a36Sopenharmony_ci	tp->RxDescArray[NUM_RX_DESC - 1].opts1 |= cpu_to_le32(RingEnd);
388762306a36Sopenharmony_ci
388862306a36Sopenharmony_ci	return 0;
388962306a36Sopenharmony_ci}
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_cistatic int rtl8169_init_ring(struct rtl8169_private *tp)
389262306a36Sopenharmony_ci{
389362306a36Sopenharmony_ci	rtl8169_init_ring_indexes(tp);
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	memset(tp->tx_skb, 0, sizeof(tp->tx_skb));
389662306a36Sopenharmony_ci	memset(tp->Rx_databuff, 0, sizeof(tp->Rx_databuff));
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	return rtl8169_rx_fill(tp);
389962306a36Sopenharmony_ci}
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_cistatic void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int entry)
390262306a36Sopenharmony_ci{
390362306a36Sopenharmony_ci	struct ring_info *tx_skb = tp->tx_skb + entry;
390462306a36Sopenharmony_ci	struct TxDesc *desc = tp->TxDescArray + entry;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci	dma_unmap_single(tp_to_dev(tp), le64_to_cpu(desc->addr), tx_skb->len,
390762306a36Sopenharmony_ci			 DMA_TO_DEVICE);
390862306a36Sopenharmony_ci	memset(desc, 0, sizeof(*desc));
390962306a36Sopenharmony_ci	memset(tx_skb, 0, sizeof(*tx_skb));
391062306a36Sopenharmony_ci}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_cistatic void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
391362306a36Sopenharmony_ci				   unsigned int n)
391462306a36Sopenharmony_ci{
391562306a36Sopenharmony_ci	unsigned int i;
391662306a36Sopenharmony_ci
391762306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
391862306a36Sopenharmony_ci		unsigned int entry = (start + i) % NUM_TX_DESC;
391962306a36Sopenharmony_ci		struct ring_info *tx_skb = tp->tx_skb + entry;
392062306a36Sopenharmony_ci		unsigned int len = tx_skb->len;
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci		if (len) {
392362306a36Sopenharmony_ci			struct sk_buff *skb = tx_skb->skb;
392462306a36Sopenharmony_ci
392562306a36Sopenharmony_ci			rtl8169_unmap_tx_skb(tp, entry);
392662306a36Sopenharmony_ci			if (skb)
392762306a36Sopenharmony_ci				dev_consume_skb_any(skb);
392862306a36Sopenharmony_ci		}
392962306a36Sopenharmony_ci	}
393062306a36Sopenharmony_ci}
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_cistatic void rtl8169_tx_clear(struct rtl8169_private *tp)
393362306a36Sopenharmony_ci{
393462306a36Sopenharmony_ci	rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
393562306a36Sopenharmony_ci	netdev_reset_queue(tp->dev);
393662306a36Sopenharmony_ci}
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_cistatic void rtl8169_cleanup(struct rtl8169_private *tp)
393962306a36Sopenharmony_ci{
394062306a36Sopenharmony_ci	napi_disable(&tp->napi);
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci	/* Give a racing hard_start_xmit a few cycles to complete. */
394362306a36Sopenharmony_ci	synchronize_net();
394462306a36Sopenharmony_ci
394562306a36Sopenharmony_ci	/* Disable interrupts */
394662306a36Sopenharmony_ci	rtl8169_irq_mask_and_ack(tp);
394762306a36Sopenharmony_ci
394862306a36Sopenharmony_ci	rtl_rx_close(tp);
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_ci	switch (tp->mac_version) {
395162306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_28:
395262306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_31:
395362306a36Sopenharmony_ci		rtl_loop_wait_low(tp, &rtl_npq_cond, 20, 2000);
395462306a36Sopenharmony_ci		break;
395562306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38:
395662306a36Sopenharmony_ci		RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
395762306a36Sopenharmony_ci		rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
395862306a36Sopenharmony_ci		break;
395962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63:
396062306a36Sopenharmony_ci		rtl_enable_rxdvgate(tp);
396162306a36Sopenharmony_ci		fsleep(2000);
396262306a36Sopenharmony_ci		break;
396362306a36Sopenharmony_ci	default:
396462306a36Sopenharmony_ci		RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq);
396562306a36Sopenharmony_ci		fsleep(100);
396662306a36Sopenharmony_ci		break;
396762306a36Sopenharmony_ci	}
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_ci	rtl_hw_reset(tp);
397062306a36Sopenharmony_ci
397162306a36Sopenharmony_ci	rtl8169_tx_clear(tp);
397262306a36Sopenharmony_ci	rtl8169_init_ring_indexes(tp);
397362306a36Sopenharmony_ci}
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_cistatic void rtl_reset_work(struct rtl8169_private *tp)
397662306a36Sopenharmony_ci{
397762306a36Sopenharmony_ci	int i;
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci	netif_stop_queue(tp->dev);
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	rtl8169_cleanup(tp);
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci	for (i = 0; i < NUM_RX_DESC; i++)
398462306a36Sopenharmony_ci		rtl8169_mark_to_asic(tp->RxDescArray + i);
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci	napi_enable(&tp->napi);
398762306a36Sopenharmony_ci	rtl_hw_start(tp);
398862306a36Sopenharmony_ci}
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_cistatic void rtl8169_tx_timeout(struct net_device *dev, unsigned int txqueue)
399162306a36Sopenharmony_ci{
399262306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
399362306a36Sopenharmony_ci
399462306a36Sopenharmony_ci	rtl_schedule_task(tp, RTL_FLAG_TASK_TX_TIMEOUT);
399562306a36Sopenharmony_ci}
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_cistatic int rtl8169_tx_map(struct rtl8169_private *tp, const u32 *opts, u32 len,
399862306a36Sopenharmony_ci			  void *addr, unsigned int entry, bool desc_own)
399962306a36Sopenharmony_ci{
400062306a36Sopenharmony_ci	struct TxDesc *txd = tp->TxDescArray + entry;
400162306a36Sopenharmony_ci	struct device *d = tp_to_dev(tp);
400262306a36Sopenharmony_ci	dma_addr_t mapping;
400362306a36Sopenharmony_ci	u32 opts1;
400462306a36Sopenharmony_ci	int ret;
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci	mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
400762306a36Sopenharmony_ci	ret = dma_mapping_error(d, mapping);
400862306a36Sopenharmony_ci	if (unlikely(ret)) {
400962306a36Sopenharmony_ci		if (net_ratelimit())
401062306a36Sopenharmony_ci			netdev_err(tp->dev, "Failed to map TX data!\n");
401162306a36Sopenharmony_ci		return ret;
401262306a36Sopenharmony_ci	}
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_ci	txd->addr = cpu_to_le64(mapping);
401562306a36Sopenharmony_ci	txd->opts2 = cpu_to_le32(opts[1]);
401662306a36Sopenharmony_ci
401762306a36Sopenharmony_ci	opts1 = opts[0] | len;
401862306a36Sopenharmony_ci	if (entry == NUM_TX_DESC - 1)
401962306a36Sopenharmony_ci		opts1 |= RingEnd;
402062306a36Sopenharmony_ci	if (desc_own)
402162306a36Sopenharmony_ci		opts1 |= DescOwn;
402262306a36Sopenharmony_ci	txd->opts1 = cpu_to_le32(opts1);
402362306a36Sopenharmony_ci
402462306a36Sopenharmony_ci	tp->tx_skb[entry].len = len;
402562306a36Sopenharmony_ci
402662306a36Sopenharmony_ci	return 0;
402762306a36Sopenharmony_ci}
402862306a36Sopenharmony_ci
402962306a36Sopenharmony_cistatic int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
403062306a36Sopenharmony_ci			      const u32 *opts, unsigned int entry)
403162306a36Sopenharmony_ci{
403262306a36Sopenharmony_ci	struct skb_shared_info *info = skb_shinfo(skb);
403362306a36Sopenharmony_ci	unsigned int cur_frag;
403462306a36Sopenharmony_ci
403562306a36Sopenharmony_ci	for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
403662306a36Sopenharmony_ci		const skb_frag_t *frag = info->frags + cur_frag;
403762306a36Sopenharmony_ci		void *addr = skb_frag_address(frag);
403862306a36Sopenharmony_ci		u32 len = skb_frag_size(frag);
403962306a36Sopenharmony_ci
404062306a36Sopenharmony_ci		entry = (entry + 1) % NUM_TX_DESC;
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_ci		if (unlikely(rtl8169_tx_map(tp, opts, len, addr, entry, true)))
404362306a36Sopenharmony_ci			goto err_out;
404462306a36Sopenharmony_ci	}
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci	return 0;
404762306a36Sopenharmony_ci
404862306a36Sopenharmony_cierr_out:
404962306a36Sopenharmony_ci	rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
405062306a36Sopenharmony_ci	return -EIO;
405162306a36Sopenharmony_ci}
405262306a36Sopenharmony_ci
405362306a36Sopenharmony_cistatic bool rtl_skb_is_udp(struct sk_buff *skb)
405462306a36Sopenharmony_ci{
405562306a36Sopenharmony_ci	int no = skb_network_offset(skb);
405662306a36Sopenharmony_ci	struct ipv6hdr *i6h, _i6h;
405762306a36Sopenharmony_ci	struct iphdr *ih, _ih;
405862306a36Sopenharmony_ci
405962306a36Sopenharmony_ci	switch (vlan_get_protocol(skb)) {
406062306a36Sopenharmony_ci	case htons(ETH_P_IP):
406162306a36Sopenharmony_ci		ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih);
406262306a36Sopenharmony_ci		return ih && ih->protocol == IPPROTO_UDP;
406362306a36Sopenharmony_ci	case htons(ETH_P_IPV6):
406462306a36Sopenharmony_ci		i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h);
406562306a36Sopenharmony_ci		return i6h && i6h->nexthdr == IPPROTO_UDP;
406662306a36Sopenharmony_ci	default:
406762306a36Sopenharmony_ci		return false;
406862306a36Sopenharmony_ci	}
406962306a36Sopenharmony_ci}
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_ci#define RTL_MIN_PATCH_LEN	47
407262306a36Sopenharmony_ci
407362306a36Sopenharmony_ci/* see rtl8125_get_patch_pad_len() in r8125 vendor driver */
407462306a36Sopenharmony_cistatic unsigned int rtl8125_quirk_udp_padto(struct rtl8169_private *tp,
407562306a36Sopenharmony_ci					    struct sk_buff *skb)
407662306a36Sopenharmony_ci{
407762306a36Sopenharmony_ci	unsigned int padto = 0, len = skb->len;
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	if (rtl_is_8125(tp) && len < 128 + RTL_MIN_PATCH_LEN &&
408062306a36Sopenharmony_ci	    rtl_skb_is_udp(skb) && skb_transport_header_was_set(skb)) {
408162306a36Sopenharmony_ci		unsigned int trans_data_len = skb_tail_pointer(skb) -
408262306a36Sopenharmony_ci					      skb_transport_header(skb);
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_ci		if (trans_data_len >= offsetof(struct udphdr, len) &&
408562306a36Sopenharmony_ci		    trans_data_len < RTL_MIN_PATCH_LEN) {
408662306a36Sopenharmony_ci			u16 dest = ntohs(udp_hdr(skb)->dest);
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci			/* dest is a standard PTP port */
408962306a36Sopenharmony_ci			if (dest == 319 || dest == 320)
409062306a36Sopenharmony_ci				padto = len + RTL_MIN_PATCH_LEN - trans_data_len;
409162306a36Sopenharmony_ci		}
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_ci		if (trans_data_len < sizeof(struct udphdr))
409462306a36Sopenharmony_ci			padto = max_t(unsigned int, padto,
409562306a36Sopenharmony_ci				      len + sizeof(struct udphdr) - trans_data_len);
409662306a36Sopenharmony_ci	}
409762306a36Sopenharmony_ci
409862306a36Sopenharmony_ci	return padto;
409962306a36Sopenharmony_ci}
410062306a36Sopenharmony_ci
410162306a36Sopenharmony_cistatic unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp,
410262306a36Sopenharmony_ci					   struct sk_buff *skb)
410362306a36Sopenharmony_ci{
410462306a36Sopenharmony_ci	unsigned int padto;
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	padto = rtl8125_quirk_udp_padto(tp, skb);
410762306a36Sopenharmony_ci
410862306a36Sopenharmony_ci	switch (tp->mac_version) {
410962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_34:
411062306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_61:
411162306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_63:
411262306a36Sopenharmony_ci		padto = max_t(unsigned int, padto, ETH_ZLEN);
411362306a36Sopenharmony_ci		break;
411462306a36Sopenharmony_ci	default:
411562306a36Sopenharmony_ci		break;
411662306a36Sopenharmony_ci	}
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_ci	return padto;
411962306a36Sopenharmony_ci}
412062306a36Sopenharmony_ci
412162306a36Sopenharmony_cistatic void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
412262306a36Sopenharmony_ci{
412362306a36Sopenharmony_ci	u32 mss = skb_shinfo(skb)->gso_size;
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	if (mss) {
412662306a36Sopenharmony_ci		opts[0] |= TD_LSO;
412762306a36Sopenharmony_ci		opts[0] |= mss << TD0_MSS_SHIFT;
412862306a36Sopenharmony_ci	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
412962306a36Sopenharmony_ci		const struct iphdr *ip = ip_hdr(skb);
413062306a36Sopenharmony_ci
413162306a36Sopenharmony_ci		if (ip->protocol == IPPROTO_TCP)
413262306a36Sopenharmony_ci			opts[0] |= TD0_IP_CS | TD0_TCP_CS;
413362306a36Sopenharmony_ci		else if (ip->protocol == IPPROTO_UDP)
413462306a36Sopenharmony_ci			opts[0] |= TD0_IP_CS | TD0_UDP_CS;
413562306a36Sopenharmony_ci		else
413662306a36Sopenharmony_ci			WARN_ON_ONCE(1);
413762306a36Sopenharmony_ci	}
413862306a36Sopenharmony_ci}
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_cistatic bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
414162306a36Sopenharmony_ci				struct sk_buff *skb, u32 *opts)
414262306a36Sopenharmony_ci{
414362306a36Sopenharmony_ci	struct skb_shared_info *shinfo = skb_shinfo(skb);
414462306a36Sopenharmony_ci	u32 mss = shinfo->gso_size;
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_ci	if (mss) {
414762306a36Sopenharmony_ci		if (shinfo->gso_type & SKB_GSO_TCPV4) {
414862306a36Sopenharmony_ci			opts[0] |= TD1_GTSENV4;
414962306a36Sopenharmony_ci		} else if (shinfo->gso_type & SKB_GSO_TCPV6) {
415062306a36Sopenharmony_ci			if (skb_cow_head(skb, 0))
415162306a36Sopenharmony_ci				return false;
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci			tcp_v6_gso_csum_prep(skb);
415462306a36Sopenharmony_ci			opts[0] |= TD1_GTSENV6;
415562306a36Sopenharmony_ci		} else {
415662306a36Sopenharmony_ci			WARN_ON_ONCE(1);
415762306a36Sopenharmony_ci		}
415862306a36Sopenharmony_ci
415962306a36Sopenharmony_ci		opts[0] |= skb_transport_offset(skb) << GTTCPHO_SHIFT;
416062306a36Sopenharmony_ci		opts[1] |= mss << TD1_MSS_SHIFT;
416162306a36Sopenharmony_ci	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
416262306a36Sopenharmony_ci		u8 ip_protocol;
416362306a36Sopenharmony_ci
416462306a36Sopenharmony_ci		switch (vlan_get_protocol(skb)) {
416562306a36Sopenharmony_ci		case htons(ETH_P_IP):
416662306a36Sopenharmony_ci			opts[1] |= TD1_IPv4_CS;
416762306a36Sopenharmony_ci			ip_protocol = ip_hdr(skb)->protocol;
416862306a36Sopenharmony_ci			break;
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci		case htons(ETH_P_IPV6):
417162306a36Sopenharmony_ci			opts[1] |= TD1_IPv6_CS;
417262306a36Sopenharmony_ci			ip_protocol = ipv6_hdr(skb)->nexthdr;
417362306a36Sopenharmony_ci			break;
417462306a36Sopenharmony_ci
417562306a36Sopenharmony_ci		default:
417662306a36Sopenharmony_ci			ip_protocol = IPPROTO_RAW;
417762306a36Sopenharmony_ci			break;
417862306a36Sopenharmony_ci		}
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_ci		if (ip_protocol == IPPROTO_TCP)
418162306a36Sopenharmony_ci			opts[1] |= TD1_TCP_CS;
418262306a36Sopenharmony_ci		else if (ip_protocol == IPPROTO_UDP)
418362306a36Sopenharmony_ci			opts[1] |= TD1_UDP_CS;
418462306a36Sopenharmony_ci		else
418562306a36Sopenharmony_ci			WARN_ON_ONCE(1);
418662306a36Sopenharmony_ci
418762306a36Sopenharmony_ci		opts[1] |= skb_transport_offset(skb) << TCPHO_SHIFT;
418862306a36Sopenharmony_ci	} else {
418962306a36Sopenharmony_ci		unsigned int padto = rtl_quirk_packet_padto(tp, skb);
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_ci		/* skb_padto would free the skb on error */
419262306a36Sopenharmony_ci		return !__skb_put_padto(skb, padto, false);
419362306a36Sopenharmony_ci	}
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci	return true;
419662306a36Sopenharmony_ci}
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_cistatic unsigned int rtl_tx_slots_avail(struct rtl8169_private *tp)
419962306a36Sopenharmony_ci{
420062306a36Sopenharmony_ci	return READ_ONCE(tp->dirty_tx) + NUM_TX_DESC - READ_ONCE(tp->cur_tx);
420162306a36Sopenharmony_ci}
420262306a36Sopenharmony_ci
420362306a36Sopenharmony_ci/* Versions RTL8102e and from RTL8168c onwards support csum_v2 */
420462306a36Sopenharmony_cistatic bool rtl_chip_supports_csum_v2(struct rtl8169_private *tp)
420562306a36Sopenharmony_ci{
420662306a36Sopenharmony_ci	switch (tp->mac_version) {
420762306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
420862306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_10 ... RTL_GIGA_MAC_VER_17:
420962306a36Sopenharmony_ci		return false;
421062306a36Sopenharmony_ci	default:
421162306a36Sopenharmony_ci		return true;
421262306a36Sopenharmony_ci	}
421362306a36Sopenharmony_ci}
421462306a36Sopenharmony_ci
421562306a36Sopenharmony_cistatic void rtl8169_doorbell(struct rtl8169_private *tp)
421662306a36Sopenharmony_ci{
421762306a36Sopenharmony_ci	if (rtl_is_8125(tp))
421862306a36Sopenharmony_ci		RTL_W16(tp, TxPoll_8125, BIT(0));
421962306a36Sopenharmony_ci	else
422062306a36Sopenharmony_ci		RTL_W8(tp, TxPoll, NPQ);
422162306a36Sopenharmony_ci}
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_cistatic netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
422462306a36Sopenharmony_ci				      struct net_device *dev)
422562306a36Sopenharmony_ci{
422662306a36Sopenharmony_ci	unsigned int frags = skb_shinfo(skb)->nr_frags;
422762306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
422862306a36Sopenharmony_ci	unsigned int entry = tp->cur_tx % NUM_TX_DESC;
422962306a36Sopenharmony_ci	struct TxDesc *txd_first, *txd_last;
423062306a36Sopenharmony_ci	bool stop_queue, door_bell;
423162306a36Sopenharmony_ci	u32 opts[2];
423262306a36Sopenharmony_ci
423362306a36Sopenharmony_ci	if (unlikely(!rtl_tx_slots_avail(tp))) {
423462306a36Sopenharmony_ci		if (net_ratelimit())
423562306a36Sopenharmony_ci			netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
423662306a36Sopenharmony_ci		goto err_stop_0;
423762306a36Sopenharmony_ci	}
423862306a36Sopenharmony_ci
423962306a36Sopenharmony_ci	opts[1] = rtl8169_tx_vlan_tag(skb);
424062306a36Sopenharmony_ci	opts[0] = 0;
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	if (!rtl_chip_supports_csum_v2(tp))
424362306a36Sopenharmony_ci		rtl8169_tso_csum_v1(skb, opts);
424462306a36Sopenharmony_ci	else if (!rtl8169_tso_csum_v2(tp, skb, opts))
424562306a36Sopenharmony_ci		goto err_dma_0;
424662306a36Sopenharmony_ci
424762306a36Sopenharmony_ci	if (unlikely(rtl8169_tx_map(tp, opts, skb_headlen(skb), skb->data,
424862306a36Sopenharmony_ci				    entry, false)))
424962306a36Sopenharmony_ci		goto err_dma_0;
425062306a36Sopenharmony_ci
425162306a36Sopenharmony_ci	txd_first = tp->TxDescArray + entry;
425262306a36Sopenharmony_ci
425362306a36Sopenharmony_ci	if (frags) {
425462306a36Sopenharmony_ci		if (rtl8169_xmit_frags(tp, skb, opts, entry))
425562306a36Sopenharmony_ci			goto err_dma_1;
425662306a36Sopenharmony_ci		entry = (entry + frags) % NUM_TX_DESC;
425762306a36Sopenharmony_ci	}
425862306a36Sopenharmony_ci
425962306a36Sopenharmony_ci	txd_last = tp->TxDescArray + entry;
426062306a36Sopenharmony_ci	txd_last->opts1 |= cpu_to_le32(LastFrag);
426162306a36Sopenharmony_ci	tp->tx_skb[entry].skb = skb;
426262306a36Sopenharmony_ci
426362306a36Sopenharmony_ci	skb_tx_timestamp(skb);
426462306a36Sopenharmony_ci
426562306a36Sopenharmony_ci	/* Force memory writes to complete before releasing descriptor */
426662306a36Sopenharmony_ci	dma_wmb();
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_ci	door_bell = __netdev_sent_queue(dev, skb->len, netdev_xmit_more());
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_ci	txd_first->opts1 |= cpu_to_le32(DescOwn | FirstFrag);
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_ci	/* rtl_tx needs to see descriptor changes before updated tp->cur_tx */
427362306a36Sopenharmony_ci	smp_wmb();
427462306a36Sopenharmony_ci
427562306a36Sopenharmony_ci	WRITE_ONCE(tp->cur_tx, tp->cur_tx + frags + 1);
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	stop_queue = !netif_subqueue_maybe_stop(dev, 0, rtl_tx_slots_avail(tp),
427862306a36Sopenharmony_ci						R8169_TX_STOP_THRS,
427962306a36Sopenharmony_ci						R8169_TX_START_THRS);
428062306a36Sopenharmony_ci	if (door_bell || stop_queue)
428162306a36Sopenharmony_ci		rtl8169_doorbell(tp);
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	return NETDEV_TX_OK;
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_cierr_dma_1:
428662306a36Sopenharmony_ci	rtl8169_unmap_tx_skb(tp, entry);
428762306a36Sopenharmony_cierr_dma_0:
428862306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
428962306a36Sopenharmony_ci	dev->stats.tx_dropped++;
429062306a36Sopenharmony_ci	return NETDEV_TX_OK;
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_cierr_stop_0:
429362306a36Sopenharmony_ci	netif_stop_queue(dev);
429462306a36Sopenharmony_ci	dev->stats.tx_dropped++;
429562306a36Sopenharmony_ci	return NETDEV_TX_BUSY;
429662306a36Sopenharmony_ci}
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_cistatic unsigned int rtl_last_frag_len(struct sk_buff *skb)
429962306a36Sopenharmony_ci{
430062306a36Sopenharmony_ci	struct skb_shared_info *info = skb_shinfo(skb);
430162306a36Sopenharmony_ci	unsigned int nr_frags = info->nr_frags;
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci	if (!nr_frags)
430462306a36Sopenharmony_ci		return UINT_MAX;
430562306a36Sopenharmony_ci
430662306a36Sopenharmony_ci	return skb_frag_size(info->frags + nr_frags - 1);
430762306a36Sopenharmony_ci}
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_ci/* Workaround for hw issues with TSO on RTL8168evl */
431062306a36Sopenharmony_cistatic netdev_features_t rtl8168evl_fix_tso(struct sk_buff *skb,
431162306a36Sopenharmony_ci					    netdev_features_t features)
431262306a36Sopenharmony_ci{
431362306a36Sopenharmony_ci	/* IPv4 header has options field */
431462306a36Sopenharmony_ci	if (vlan_get_protocol(skb) == htons(ETH_P_IP) &&
431562306a36Sopenharmony_ci	    ip_hdrlen(skb) > sizeof(struct iphdr))
431662306a36Sopenharmony_ci		features &= ~NETIF_F_ALL_TSO;
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci	/* IPv4 TCP header has options field */
431962306a36Sopenharmony_ci	else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 &&
432062306a36Sopenharmony_ci		 tcp_hdrlen(skb) > sizeof(struct tcphdr))
432162306a36Sopenharmony_ci		features &= ~NETIF_F_ALL_TSO;
432262306a36Sopenharmony_ci
432362306a36Sopenharmony_ci	else if (rtl_last_frag_len(skb) <= 6)
432462306a36Sopenharmony_ci		features &= ~NETIF_F_ALL_TSO;
432562306a36Sopenharmony_ci
432662306a36Sopenharmony_ci	return features;
432762306a36Sopenharmony_ci}
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_cistatic netdev_features_t rtl8169_features_check(struct sk_buff *skb,
433062306a36Sopenharmony_ci						struct net_device *dev,
433162306a36Sopenharmony_ci						netdev_features_t features)
433262306a36Sopenharmony_ci{
433362306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
433462306a36Sopenharmony_ci
433562306a36Sopenharmony_ci	if (skb_is_gso(skb)) {
433662306a36Sopenharmony_ci		if (tp->mac_version == RTL_GIGA_MAC_VER_34)
433762306a36Sopenharmony_ci			features = rtl8168evl_fix_tso(skb, features);
433862306a36Sopenharmony_ci
433962306a36Sopenharmony_ci		if (skb_transport_offset(skb) > GTTCPHO_MAX &&
434062306a36Sopenharmony_ci		    rtl_chip_supports_csum_v2(tp))
434162306a36Sopenharmony_ci			features &= ~NETIF_F_ALL_TSO;
434262306a36Sopenharmony_ci	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
434362306a36Sopenharmony_ci		/* work around hw bug on some chip versions */
434462306a36Sopenharmony_ci		if (skb->len < ETH_ZLEN)
434562306a36Sopenharmony_ci			features &= ~NETIF_F_CSUM_MASK;
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_ci		if (rtl_quirk_packet_padto(tp, skb))
434862306a36Sopenharmony_ci			features &= ~NETIF_F_CSUM_MASK;
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci		if (skb_transport_offset(skb) > TCPHO_MAX &&
435162306a36Sopenharmony_ci		    rtl_chip_supports_csum_v2(tp))
435262306a36Sopenharmony_ci			features &= ~NETIF_F_CSUM_MASK;
435362306a36Sopenharmony_ci	}
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_ci	return vlan_features_check(skb, features);
435662306a36Sopenharmony_ci}
435762306a36Sopenharmony_ci
435862306a36Sopenharmony_cistatic void rtl8169_pcierr_interrupt(struct net_device *dev)
435962306a36Sopenharmony_ci{
436062306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
436162306a36Sopenharmony_ci	struct pci_dev *pdev = tp->pci_dev;
436262306a36Sopenharmony_ci	int pci_status_errs;
436362306a36Sopenharmony_ci	u16 pci_cmd;
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
436662306a36Sopenharmony_ci
436762306a36Sopenharmony_ci	pci_status_errs = pci_status_get_and_clear_errors(pdev);
436862306a36Sopenharmony_ci
436962306a36Sopenharmony_ci	if (net_ratelimit())
437062306a36Sopenharmony_ci		netdev_err(dev, "PCI error (cmd = 0x%04x, status_errs = 0x%04x)\n",
437162306a36Sopenharmony_ci			   pci_cmd, pci_status_errs);
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
437462306a36Sopenharmony_ci}
437562306a36Sopenharmony_ci
437662306a36Sopenharmony_cistatic void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
437762306a36Sopenharmony_ci		   int budget)
437862306a36Sopenharmony_ci{
437962306a36Sopenharmony_ci	unsigned int dirty_tx, bytes_compl = 0, pkts_compl = 0;
438062306a36Sopenharmony_ci	struct sk_buff *skb;
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci	dirty_tx = tp->dirty_tx;
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci	while (READ_ONCE(tp->cur_tx) != dirty_tx) {
438562306a36Sopenharmony_ci		unsigned int entry = dirty_tx % NUM_TX_DESC;
438662306a36Sopenharmony_ci		u32 status;
438762306a36Sopenharmony_ci
438862306a36Sopenharmony_ci		status = le32_to_cpu(READ_ONCE(tp->TxDescArray[entry].opts1));
438962306a36Sopenharmony_ci		if (status & DescOwn)
439062306a36Sopenharmony_ci			break;
439162306a36Sopenharmony_ci
439262306a36Sopenharmony_ci		skb = tp->tx_skb[entry].skb;
439362306a36Sopenharmony_ci		rtl8169_unmap_tx_skb(tp, entry);
439462306a36Sopenharmony_ci
439562306a36Sopenharmony_ci		if (skb) {
439662306a36Sopenharmony_ci			pkts_compl++;
439762306a36Sopenharmony_ci			bytes_compl += skb->len;
439862306a36Sopenharmony_ci			napi_consume_skb(skb, budget);
439962306a36Sopenharmony_ci		}
440062306a36Sopenharmony_ci		dirty_tx++;
440162306a36Sopenharmony_ci	}
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci	if (tp->dirty_tx != dirty_tx) {
440462306a36Sopenharmony_ci		dev_sw_netstats_tx_add(dev, pkts_compl, bytes_compl);
440562306a36Sopenharmony_ci		WRITE_ONCE(tp->dirty_tx, dirty_tx);
440662306a36Sopenharmony_ci
440762306a36Sopenharmony_ci		netif_subqueue_completed_wake(dev, 0, pkts_compl, bytes_compl,
440862306a36Sopenharmony_ci					      rtl_tx_slots_avail(tp),
440962306a36Sopenharmony_ci					      R8169_TX_START_THRS);
441062306a36Sopenharmony_ci		/*
441162306a36Sopenharmony_ci		 * 8168 hack: TxPoll requests are lost when the Tx packets are
441262306a36Sopenharmony_ci		 * too close. Let's kick an extra TxPoll request when a burst
441362306a36Sopenharmony_ci		 * of start_xmit activity is detected (if it is not detected,
441462306a36Sopenharmony_ci		 * it is slow enough). -- FR
441562306a36Sopenharmony_ci		 * If skb is NULL then we come here again once a tx irq is
441662306a36Sopenharmony_ci		 * triggered after the last fragment is marked transmitted.
441762306a36Sopenharmony_ci		 */
441862306a36Sopenharmony_ci		if (READ_ONCE(tp->cur_tx) != dirty_tx && skb)
441962306a36Sopenharmony_ci			rtl8169_doorbell(tp);
442062306a36Sopenharmony_ci	}
442162306a36Sopenharmony_ci}
442262306a36Sopenharmony_ci
442362306a36Sopenharmony_cistatic inline int rtl8169_fragmented_frame(u32 status)
442462306a36Sopenharmony_ci{
442562306a36Sopenharmony_ci	return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
442662306a36Sopenharmony_ci}
442762306a36Sopenharmony_ci
442862306a36Sopenharmony_cistatic inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
442962306a36Sopenharmony_ci{
443062306a36Sopenharmony_ci	u32 status = opts1 & (RxProtoMask | RxCSFailMask);
443162306a36Sopenharmony_ci
443262306a36Sopenharmony_ci	if (status == RxProtoTCP || status == RxProtoUDP)
443362306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
443462306a36Sopenharmony_ci	else
443562306a36Sopenharmony_ci		skb_checksum_none_assert(skb);
443662306a36Sopenharmony_ci}
443762306a36Sopenharmony_ci
443862306a36Sopenharmony_cistatic int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget)
443962306a36Sopenharmony_ci{
444062306a36Sopenharmony_ci	struct device *d = tp_to_dev(tp);
444162306a36Sopenharmony_ci	int count;
444262306a36Sopenharmony_ci
444362306a36Sopenharmony_ci	for (count = 0; count < budget; count++, tp->cur_rx++) {
444462306a36Sopenharmony_ci		unsigned int pkt_size, entry = tp->cur_rx % NUM_RX_DESC;
444562306a36Sopenharmony_ci		struct RxDesc *desc = tp->RxDescArray + entry;
444662306a36Sopenharmony_ci		struct sk_buff *skb;
444762306a36Sopenharmony_ci		const void *rx_buf;
444862306a36Sopenharmony_ci		dma_addr_t addr;
444962306a36Sopenharmony_ci		u32 status;
445062306a36Sopenharmony_ci
445162306a36Sopenharmony_ci		status = le32_to_cpu(READ_ONCE(desc->opts1));
445262306a36Sopenharmony_ci		if (status & DescOwn)
445362306a36Sopenharmony_ci			break;
445462306a36Sopenharmony_ci
445562306a36Sopenharmony_ci		/* This barrier is needed to keep us from reading
445662306a36Sopenharmony_ci		 * any other fields out of the Rx descriptor until
445762306a36Sopenharmony_ci		 * we know the status of DescOwn
445862306a36Sopenharmony_ci		 */
445962306a36Sopenharmony_ci		dma_rmb();
446062306a36Sopenharmony_ci
446162306a36Sopenharmony_ci		if (unlikely(status & RxRES)) {
446262306a36Sopenharmony_ci			if (net_ratelimit())
446362306a36Sopenharmony_ci				netdev_warn(dev, "Rx ERROR. status = %08x\n",
446462306a36Sopenharmony_ci					    status);
446562306a36Sopenharmony_ci			dev->stats.rx_errors++;
446662306a36Sopenharmony_ci			if (status & (RxRWT | RxRUNT))
446762306a36Sopenharmony_ci				dev->stats.rx_length_errors++;
446862306a36Sopenharmony_ci			if (status & RxCRC)
446962306a36Sopenharmony_ci				dev->stats.rx_crc_errors++;
447062306a36Sopenharmony_ci
447162306a36Sopenharmony_ci			if (!(dev->features & NETIF_F_RXALL))
447262306a36Sopenharmony_ci				goto release_descriptor;
447362306a36Sopenharmony_ci			else if (status & RxRWT || !(status & (RxRUNT | RxCRC)))
447462306a36Sopenharmony_ci				goto release_descriptor;
447562306a36Sopenharmony_ci		}
447662306a36Sopenharmony_ci
447762306a36Sopenharmony_ci		pkt_size = status & GENMASK(13, 0);
447862306a36Sopenharmony_ci		if (likely(!(dev->features & NETIF_F_RXFCS)))
447962306a36Sopenharmony_ci			pkt_size -= ETH_FCS_LEN;
448062306a36Sopenharmony_ci
448162306a36Sopenharmony_ci		/* The driver does not support incoming fragmented frames.
448262306a36Sopenharmony_ci		 * They are seen as a symptom of over-mtu sized frames.
448362306a36Sopenharmony_ci		 */
448462306a36Sopenharmony_ci		if (unlikely(rtl8169_fragmented_frame(status))) {
448562306a36Sopenharmony_ci			dev->stats.rx_dropped++;
448662306a36Sopenharmony_ci			dev->stats.rx_length_errors++;
448762306a36Sopenharmony_ci			goto release_descriptor;
448862306a36Sopenharmony_ci		}
448962306a36Sopenharmony_ci
449062306a36Sopenharmony_ci		skb = napi_alloc_skb(&tp->napi, pkt_size);
449162306a36Sopenharmony_ci		if (unlikely(!skb)) {
449262306a36Sopenharmony_ci			dev->stats.rx_dropped++;
449362306a36Sopenharmony_ci			goto release_descriptor;
449462306a36Sopenharmony_ci		}
449562306a36Sopenharmony_ci
449662306a36Sopenharmony_ci		addr = le64_to_cpu(desc->addr);
449762306a36Sopenharmony_ci		rx_buf = page_address(tp->Rx_databuff[entry]);
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_ci		dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
450062306a36Sopenharmony_ci		prefetch(rx_buf);
450162306a36Sopenharmony_ci		skb_copy_to_linear_data(skb, rx_buf, pkt_size);
450262306a36Sopenharmony_ci		skb->tail += pkt_size;
450362306a36Sopenharmony_ci		skb->len = pkt_size;
450462306a36Sopenharmony_ci		dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
450562306a36Sopenharmony_ci
450662306a36Sopenharmony_ci		rtl8169_rx_csum(skb, status);
450762306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, dev);
450862306a36Sopenharmony_ci
450962306a36Sopenharmony_ci		rtl8169_rx_vlan_tag(desc, skb);
451062306a36Sopenharmony_ci
451162306a36Sopenharmony_ci		if (skb->pkt_type == PACKET_MULTICAST)
451262306a36Sopenharmony_ci			dev->stats.multicast++;
451362306a36Sopenharmony_ci
451462306a36Sopenharmony_ci		napi_gro_receive(&tp->napi, skb);
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_ci		dev_sw_netstats_rx_add(dev, pkt_size);
451762306a36Sopenharmony_cirelease_descriptor:
451862306a36Sopenharmony_ci		rtl8169_mark_to_asic(desc);
451962306a36Sopenharmony_ci	}
452062306a36Sopenharmony_ci
452162306a36Sopenharmony_ci	return count;
452262306a36Sopenharmony_ci}
452362306a36Sopenharmony_ci
452462306a36Sopenharmony_cistatic irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
452562306a36Sopenharmony_ci{
452662306a36Sopenharmony_ci	struct rtl8169_private *tp = dev_instance;
452762306a36Sopenharmony_ci	u32 status = rtl_get_events(tp);
452862306a36Sopenharmony_ci
452962306a36Sopenharmony_ci	if ((status & 0xffff) == 0xffff || !(status & tp->irq_mask))
453062306a36Sopenharmony_ci		return IRQ_NONE;
453162306a36Sopenharmony_ci
453262306a36Sopenharmony_ci	if (unlikely(status & SYSErr)) {
453362306a36Sopenharmony_ci		rtl8169_pcierr_interrupt(tp->dev);
453462306a36Sopenharmony_ci		goto out;
453562306a36Sopenharmony_ci	}
453662306a36Sopenharmony_ci
453762306a36Sopenharmony_ci	if (status & LinkChg)
453862306a36Sopenharmony_ci		phy_mac_interrupt(tp->phydev);
453962306a36Sopenharmony_ci
454062306a36Sopenharmony_ci	if (unlikely(status & RxFIFOOver &&
454162306a36Sopenharmony_ci	    tp->mac_version == RTL_GIGA_MAC_VER_11)) {
454262306a36Sopenharmony_ci		netif_stop_queue(tp->dev);
454362306a36Sopenharmony_ci		rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
454462306a36Sopenharmony_ci	}
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_ci	if (napi_schedule_prep(&tp->napi)) {
454762306a36Sopenharmony_ci		rtl_irq_disable(tp);
454862306a36Sopenharmony_ci		__napi_schedule(&tp->napi);
454962306a36Sopenharmony_ci	}
455062306a36Sopenharmony_ciout:
455162306a36Sopenharmony_ci	rtl_ack_events(tp, status);
455262306a36Sopenharmony_ci
455362306a36Sopenharmony_ci	return IRQ_HANDLED;
455462306a36Sopenharmony_ci}
455562306a36Sopenharmony_ci
455662306a36Sopenharmony_cistatic void rtl_task(struct work_struct *work)
455762306a36Sopenharmony_ci{
455862306a36Sopenharmony_ci	struct rtl8169_private *tp =
455962306a36Sopenharmony_ci		container_of(work, struct rtl8169_private, wk.work);
456062306a36Sopenharmony_ci	int ret;
456162306a36Sopenharmony_ci
456262306a36Sopenharmony_ci	rtnl_lock();
456362306a36Sopenharmony_ci
456462306a36Sopenharmony_ci	if (!netif_running(tp->dev) ||
456562306a36Sopenharmony_ci	    !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
456662306a36Sopenharmony_ci		goto out_unlock;
456762306a36Sopenharmony_ci
456862306a36Sopenharmony_ci	if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) {
456962306a36Sopenharmony_ci		/* if chip isn't accessible, reset bus to revive it */
457062306a36Sopenharmony_ci		if (RTL_R32(tp, TxConfig) == ~0) {
457162306a36Sopenharmony_ci			ret = pci_reset_bus(tp->pci_dev);
457262306a36Sopenharmony_ci			if (ret < 0) {
457362306a36Sopenharmony_ci				netdev_err(tp->dev, "Can't reset secondary PCI bus, detach NIC\n");
457462306a36Sopenharmony_ci				netif_device_detach(tp->dev);
457562306a36Sopenharmony_ci				goto out_unlock;
457662306a36Sopenharmony_ci			}
457762306a36Sopenharmony_ci		}
457862306a36Sopenharmony_ci
457962306a36Sopenharmony_ci		/* ASPM compatibility issues are a typical reason for tx timeouts */
458062306a36Sopenharmony_ci		ret = pci_disable_link_state(tp->pci_dev, PCIE_LINK_STATE_L1 |
458162306a36Sopenharmony_ci							  PCIE_LINK_STATE_L0S);
458262306a36Sopenharmony_ci		if (!ret)
458362306a36Sopenharmony_ci			netdev_warn_once(tp->dev, "ASPM disabled on Tx timeout\n");
458462306a36Sopenharmony_ci		goto reset;
458562306a36Sopenharmony_ci	}
458662306a36Sopenharmony_ci
458762306a36Sopenharmony_ci	if (test_and_clear_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags)) {
458862306a36Sopenharmony_cireset:
458962306a36Sopenharmony_ci		rtl_reset_work(tp);
459062306a36Sopenharmony_ci		netif_wake_queue(tp->dev);
459162306a36Sopenharmony_ci	} else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) {
459262306a36Sopenharmony_ci		rtl_reset_work(tp);
459362306a36Sopenharmony_ci	}
459462306a36Sopenharmony_ciout_unlock:
459562306a36Sopenharmony_ci	rtnl_unlock();
459662306a36Sopenharmony_ci}
459762306a36Sopenharmony_ci
459862306a36Sopenharmony_cistatic int rtl8169_poll(struct napi_struct *napi, int budget)
459962306a36Sopenharmony_ci{
460062306a36Sopenharmony_ci	struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
460162306a36Sopenharmony_ci	struct net_device *dev = tp->dev;
460262306a36Sopenharmony_ci	int work_done;
460362306a36Sopenharmony_ci
460462306a36Sopenharmony_ci	rtl_tx(dev, tp, budget);
460562306a36Sopenharmony_ci
460662306a36Sopenharmony_ci	work_done = rtl_rx(dev, tp, budget);
460762306a36Sopenharmony_ci
460862306a36Sopenharmony_ci	if (work_done < budget && napi_complete_done(napi, work_done))
460962306a36Sopenharmony_ci		rtl_irq_enable(tp);
461062306a36Sopenharmony_ci
461162306a36Sopenharmony_ci	return work_done;
461262306a36Sopenharmony_ci}
461362306a36Sopenharmony_ci
461462306a36Sopenharmony_cistatic void r8169_phylink_handler(struct net_device *ndev)
461562306a36Sopenharmony_ci{
461662306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(ndev);
461762306a36Sopenharmony_ci	struct device *d = tp_to_dev(tp);
461862306a36Sopenharmony_ci
461962306a36Sopenharmony_ci	if (netif_carrier_ok(ndev)) {
462062306a36Sopenharmony_ci		rtl_link_chg_patch(tp);
462162306a36Sopenharmony_ci		pm_request_resume(d);
462262306a36Sopenharmony_ci		netif_wake_queue(tp->dev);
462362306a36Sopenharmony_ci	} else {
462462306a36Sopenharmony_ci		/* In few cases rx is broken after link-down otherwise */
462562306a36Sopenharmony_ci		if (rtl_is_8125(tp))
462662306a36Sopenharmony_ci			rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE);
462762306a36Sopenharmony_ci		pm_runtime_idle(d);
462862306a36Sopenharmony_ci	}
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_ci	phy_print_status(tp->phydev);
463162306a36Sopenharmony_ci}
463262306a36Sopenharmony_ci
463362306a36Sopenharmony_cistatic int r8169_phy_connect(struct rtl8169_private *tp)
463462306a36Sopenharmony_ci{
463562306a36Sopenharmony_ci	struct phy_device *phydev = tp->phydev;
463662306a36Sopenharmony_ci	phy_interface_t phy_mode;
463762306a36Sopenharmony_ci	int ret;
463862306a36Sopenharmony_ci
463962306a36Sopenharmony_ci	phy_mode = tp->supports_gmii ? PHY_INTERFACE_MODE_GMII :
464062306a36Sopenharmony_ci		   PHY_INTERFACE_MODE_MII;
464162306a36Sopenharmony_ci
464262306a36Sopenharmony_ci	ret = phy_connect_direct(tp->dev, phydev, r8169_phylink_handler,
464362306a36Sopenharmony_ci				 phy_mode);
464462306a36Sopenharmony_ci	if (ret)
464562306a36Sopenharmony_ci		return ret;
464662306a36Sopenharmony_ci
464762306a36Sopenharmony_ci	if (!tp->supports_gmii)
464862306a36Sopenharmony_ci		phy_set_max_speed(phydev, SPEED_100);
464962306a36Sopenharmony_ci
465062306a36Sopenharmony_ci	phy_attached_info(phydev);
465162306a36Sopenharmony_ci
465262306a36Sopenharmony_ci	return 0;
465362306a36Sopenharmony_ci}
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_cistatic void rtl8169_down(struct rtl8169_private *tp)
465662306a36Sopenharmony_ci{
465762306a36Sopenharmony_ci	/* Clear all task flags */
465862306a36Sopenharmony_ci	bitmap_zero(tp->wk.flags, RTL_FLAG_MAX);
465962306a36Sopenharmony_ci
466062306a36Sopenharmony_ci	phy_stop(tp->phydev);
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci	rtl8169_update_counters(tp);
466362306a36Sopenharmony_ci
466462306a36Sopenharmony_ci	pci_clear_master(tp->pci_dev);
466562306a36Sopenharmony_ci	rtl_pci_commit(tp);
466662306a36Sopenharmony_ci
466762306a36Sopenharmony_ci	rtl8169_cleanup(tp);
466862306a36Sopenharmony_ci	rtl_disable_exit_l1(tp);
466962306a36Sopenharmony_ci	rtl_prepare_power_down(tp);
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_ci	if (tp->dash_type != RTL_DASH_NONE)
467262306a36Sopenharmony_ci		rtl8168_driver_stop(tp);
467362306a36Sopenharmony_ci}
467462306a36Sopenharmony_ci
467562306a36Sopenharmony_cistatic void rtl8169_up(struct rtl8169_private *tp)
467662306a36Sopenharmony_ci{
467762306a36Sopenharmony_ci	if (tp->dash_type != RTL_DASH_NONE)
467862306a36Sopenharmony_ci		rtl8168_driver_start(tp);
467962306a36Sopenharmony_ci
468062306a36Sopenharmony_ci	pci_set_master(tp->pci_dev);
468162306a36Sopenharmony_ci	phy_init_hw(tp->phydev);
468262306a36Sopenharmony_ci	phy_resume(tp->phydev);
468362306a36Sopenharmony_ci	rtl8169_init_phy(tp);
468462306a36Sopenharmony_ci	napi_enable(&tp->napi);
468562306a36Sopenharmony_ci	set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
468662306a36Sopenharmony_ci	rtl_reset_work(tp);
468762306a36Sopenharmony_ci
468862306a36Sopenharmony_ci	phy_start(tp->phydev);
468962306a36Sopenharmony_ci}
469062306a36Sopenharmony_ci
469162306a36Sopenharmony_cistatic int rtl8169_close(struct net_device *dev)
469262306a36Sopenharmony_ci{
469362306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
469462306a36Sopenharmony_ci	struct pci_dev *pdev = tp->pci_dev;
469562306a36Sopenharmony_ci
469662306a36Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_ci	netif_stop_queue(dev);
469962306a36Sopenharmony_ci	rtl8169_down(tp);
470062306a36Sopenharmony_ci	rtl8169_rx_clear(tp);
470162306a36Sopenharmony_ci
470262306a36Sopenharmony_ci	cancel_work(&tp->wk.work);
470362306a36Sopenharmony_ci
470462306a36Sopenharmony_ci	free_irq(tp->irq, tp);
470562306a36Sopenharmony_ci
470662306a36Sopenharmony_ci	phy_disconnect(tp->phydev);
470762306a36Sopenharmony_ci
470862306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
470962306a36Sopenharmony_ci			  tp->RxPhyAddr);
471062306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
471162306a36Sopenharmony_ci			  tp->TxPhyAddr);
471262306a36Sopenharmony_ci	tp->TxDescArray = NULL;
471362306a36Sopenharmony_ci	tp->RxDescArray = NULL;
471462306a36Sopenharmony_ci
471562306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
471662306a36Sopenharmony_ci
471762306a36Sopenharmony_ci	return 0;
471862306a36Sopenharmony_ci}
471962306a36Sopenharmony_ci
472062306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
472162306a36Sopenharmony_cistatic void rtl8169_netpoll(struct net_device *dev)
472262306a36Sopenharmony_ci{
472362306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
472462306a36Sopenharmony_ci
472562306a36Sopenharmony_ci	rtl8169_interrupt(tp->irq, tp);
472662306a36Sopenharmony_ci}
472762306a36Sopenharmony_ci#endif
472862306a36Sopenharmony_ci
472962306a36Sopenharmony_cistatic int rtl_open(struct net_device *dev)
473062306a36Sopenharmony_ci{
473162306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
473262306a36Sopenharmony_ci	struct pci_dev *pdev = tp->pci_dev;
473362306a36Sopenharmony_ci	unsigned long irqflags;
473462306a36Sopenharmony_ci	int retval = -ENOMEM;
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
473762306a36Sopenharmony_ci
473862306a36Sopenharmony_ci	/*
473962306a36Sopenharmony_ci	 * Rx and Tx descriptors needs 256 bytes alignment.
474062306a36Sopenharmony_ci	 * dma_alloc_coherent provides more.
474162306a36Sopenharmony_ci	 */
474262306a36Sopenharmony_ci	tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
474362306a36Sopenharmony_ci					     &tp->TxPhyAddr, GFP_KERNEL);
474462306a36Sopenharmony_ci	if (!tp->TxDescArray)
474562306a36Sopenharmony_ci		goto out;
474662306a36Sopenharmony_ci
474762306a36Sopenharmony_ci	tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
474862306a36Sopenharmony_ci					     &tp->RxPhyAddr, GFP_KERNEL);
474962306a36Sopenharmony_ci	if (!tp->RxDescArray)
475062306a36Sopenharmony_ci		goto err_free_tx_0;
475162306a36Sopenharmony_ci
475262306a36Sopenharmony_ci	retval = rtl8169_init_ring(tp);
475362306a36Sopenharmony_ci	if (retval < 0)
475462306a36Sopenharmony_ci		goto err_free_rx_1;
475562306a36Sopenharmony_ci
475662306a36Sopenharmony_ci	rtl_request_firmware(tp);
475762306a36Sopenharmony_ci
475862306a36Sopenharmony_ci	irqflags = pci_dev_msi_enabled(pdev) ? IRQF_NO_THREAD : IRQF_SHARED;
475962306a36Sopenharmony_ci	retval = request_irq(tp->irq, rtl8169_interrupt, irqflags, dev->name, tp);
476062306a36Sopenharmony_ci	if (retval < 0)
476162306a36Sopenharmony_ci		goto err_release_fw_2;
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci	retval = r8169_phy_connect(tp);
476462306a36Sopenharmony_ci	if (retval)
476562306a36Sopenharmony_ci		goto err_free_irq;
476662306a36Sopenharmony_ci
476762306a36Sopenharmony_ci	rtl8169_up(tp);
476862306a36Sopenharmony_ci	rtl8169_init_counter_offsets(tp);
476962306a36Sopenharmony_ci	netif_start_queue(dev);
477062306a36Sopenharmony_ciout:
477162306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
477262306a36Sopenharmony_ci
477362306a36Sopenharmony_ci	return retval;
477462306a36Sopenharmony_ci
477562306a36Sopenharmony_cierr_free_irq:
477662306a36Sopenharmony_ci	free_irq(tp->irq, tp);
477762306a36Sopenharmony_cierr_release_fw_2:
477862306a36Sopenharmony_ci	rtl_release_firmware(tp);
477962306a36Sopenharmony_ci	rtl8169_rx_clear(tp);
478062306a36Sopenharmony_cierr_free_rx_1:
478162306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
478262306a36Sopenharmony_ci			  tp->RxPhyAddr);
478362306a36Sopenharmony_ci	tp->RxDescArray = NULL;
478462306a36Sopenharmony_cierr_free_tx_0:
478562306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
478662306a36Sopenharmony_ci			  tp->TxPhyAddr);
478762306a36Sopenharmony_ci	tp->TxDescArray = NULL;
478862306a36Sopenharmony_ci	goto out;
478962306a36Sopenharmony_ci}
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_cistatic void
479262306a36Sopenharmony_cirtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
479362306a36Sopenharmony_ci{
479462306a36Sopenharmony_ci	struct rtl8169_private *tp = netdev_priv(dev);
479562306a36Sopenharmony_ci	struct pci_dev *pdev = tp->pci_dev;
479662306a36Sopenharmony_ci	struct rtl8169_counters *counters = tp->counters;
479762306a36Sopenharmony_ci
479862306a36Sopenharmony_ci	pm_runtime_get_noresume(&pdev->dev);
479962306a36Sopenharmony_ci
480062306a36Sopenharmony_ci	netdev_stats_to_stats64(stats, &dev->stats);
480162306a36Sopenharmony_ci	dev_fetch_sw_netstats(stats, dev->tstats);
480262306a36Sopenharmony_ci
480362306a36Sopenharmony_ci	/*
480462306a36Sopenharmony_ci	 * Fetch additional counter values missing in stats collected by driver
480562306a36Sopenharmony_ci	 * from tally counters.
480662306a36Sopenharmony_ci	 */
480762306a36Sopenharmony_ci	if (pm_runtime_active(&pdev->dev))
480862306a36Sopenharmony_ci		rtl8169_update_counters(tp);
480962306a36Sopenharmony_ci
481062306a36Sopenharmony_ci	/*
481162306a36Sopenharmony_ci	 * Subtract values fetched during initalization.
481262306a36Sopenharmony_ci	 * See rtl8169_init_counter_offsets for a description why we do that.
481362306a36Sopenharmony_ci	 */
481462306a36Sopenharmony_ci	stats->tx_errors = le64_to_cpu(counters->tx_errors) -
481562306a36Sopenharmony_ci		le64_to_cpu(tp->tc_offset.tx_errors);
481662306a36Sopenharmony_ci	stats->collisions = le32_to_cpu(counters->tx_multi_collision) -
481762306a36Sopenharmony_ci		le32_to_cpu(tp->tc_offset.tx_multi_collision);
481862306a36Sopenharmony_ci	stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted) -
481962306a36Sopenharmony_ci		le16_to_cpu(tp->tc_offset.tx_aborted);
482062306a36Sopenharmony_ci	stats->rx_missed_errors = le16_to_cpu(counters->rx_missed) -
482162306a36Sopenharmony_ci		le16_to_cpu(tp->tc_offset.rx_missed);
482262306a36Sopenharmony_ci
482362306a36Sopenharmony_ci	pm_runtime_put_noidle(&pdev->dev);
482462306a36Sopenharmony_ci}
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_cistatic void rtl8169_net_suspend(struct rtl8169_private *tp)
482762306a36Sopenharmony_ci{
482862306a36Sopenharmony_ci	netif_device_detach(tp->dev);
482962306a36Sopenharmony_ci
483062306a36Sopenharmony_ci	if (netif_running(tp->dev))
483162306a36Sopenharmony_ci		rtl8169_down(tp);
483262306a36Sopenharmony_ci}
483362306a36Sopenharmony_ci
483462306a36Sopenharmony_cistatic int rtl8169_runtime_resume(struct device *dev)
483562306a36Sopenharmony_ci{
483662306a36Sopenharmony_ci	struct rtl8169_private *tp = dev_get_drvdata(dev);
483762306a36Sopenharmony_ci
483862306a36Sopenharmony_ci	rtl_rar_set(tp, tp->dev->dev_addr);
483962306a36Sopenharmony_ci	__rtl8169_set_wol(tp, tp->saved_wolopts);
484062306a36Sopenharmony_ci
484162306a36Sopenharmony_ci	if (tp->TxDescArray)
484262306a36Sopenharmony_ci		rtl8169_up(tp);
484362306a36Sopenharmony_ci
484462306a36Sopenharmony_ci	netif_device_attach(tp->dev);
484562306a36Sopenharmony_ci
484662306a36Sopenharmony_ci	return 0;
484762306a36Sopenharmony_ci}
484862306a36Sopenharmony_ci
484962306a36Sopenharmony_cistatic int rtl8169_suspend(struct device *device)
485062306a36Sopenharmony_ci{
485162306a36Sopenharmony_ci	struct rtl8169_private *tp = dev_get_drvdata(device);
485262306a36Sopenharmony_ci
485362306a36Sopenharmony_ci	rtnl_lock();
485462306a36Sopenharmony_ci	rtl8169_net_suspend(tp);
485562306a36Sopenharmony_ci	if (!device_may_wakeup(tp_to_dev(tp)))
485662306a36Sopenharmony_ci		clk_disable_unprepare(tp->clk);
485762306a36Sopenharmony_ci	rtnl_unlock();
485862306a36Sopenharmony_ci
485962306a36Sopenharmony_ci	return 0;
486062306a36Sopenharmony_ci}
486162306a36Sopenharmony_ci
486262306a36Sopenharmony_cistatic int rtl8169_resume(struct device *device)
486362306a36Sopenharmony_ci{
486462306a36Sopenharmony_ci	struct rtl8169_private *tp = dev_get_drvdata(device);
486562306a36Sopenharmony_ci
486662306a36Sopenharmony_ci	if (!device_may_wakeup(tp_to_dev(tp)))
486762306a36Sopenharmony_ci		clk_prepare_enable(tp->clk);
486862306a36Sopenharmony_ci
486962306a36Sopenharmony_ci	/* Reportedly at least Asus X453MA truncates packets otherwise */
487062306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_37)
487162306a36Sopenharmony_ci		rtl_init_rxcfg(tp);
487262306a36Sopenharmony_ci
487362306a36Sopenharmony_ci	return rtl8169_runtime_resume(device);
487462306a36Sopenharmony_ci}
487562306a36Sopenharmony_ci
487662306a36Sopenharmony_cistatic int rtl8169_runtime_suspend(struct device *device)
487762306a36Sopenharmony_ci{
487862306a36Sopenharmony_ci	struct rtl8169_private *tp = dev_get_drvdata(device);
487962306a36Sopenharmony_ci
488062306a36Sopenharmony_ci	if (!tp->TxDescArray) {
488162306a36Sopenharmony_ci		netif_device_detach(tp->dev);
488262306a36Sopenharmony_ci		return 0;
488362306a36Sopenharmony_ci	}
488462306a36Sopenharmony_ci
488562306a36Sopenharmony_ci	rtnl_lock();
488662306a36Sopenharmony_ci	__rtl8169_set_wol(tp, WAKE_PHY);
488762306a36Sopenharmony_ci	rtl8169_net_suspend(tp);
488862306a36Sopenharmony_ci	rtnl_unlock();
488962306a36Sopenharmony_ci
489062306a36Sopenharmony_ci	return 0;
489162306a36Sopenharmony_ci}
489262306a36Sopenharmony_ci
489362306a36Sopenharmony_cistatic int rtl8169_runtime_idle(struct device *device)
489462306a36Sopenharmony_ci{
489562306a36Sopenharmony_ci	struct rtl8169_private *tp = dev_get_drvdata(device);
489662306a36Sopenharmony_ci
489762306a36Sopenharmony_ci	if (tp->dash_enabled)
489862306a36Sopenharmony_ci		return -EBUSY;
489962306a36Sopenharmony_ci
490062306a36Sopenharmony_ci	if (!netif_running(tp->dev) || !netif_carrier_ok(tp->dev))
490162306a36Sopenharmony_ci		pm_schedule_suspend(device, 10000);
490262306a36Sopenharmony_ci
490362306a36Sopenharmony_ci	return -EBUSY;
490462306a36Sopenharmony_ci}
490562306a36Sopenharmony_ci
490662306a36Sopenharmony_cistatic const struct dev_pm_ops rtl8169_pm_ops = {
490762306a36Sopenharmony_ci	SYSTEM_SLEEP_PM_OPS(rtl8169_suspend, rtl8169_resume)
490862306a36Sopenharmony_ci	RUNTIME_PM_OPS(rtl8169_runtime_suspend, rtl8169_runtime_resume,
490962306a36Sopenharmony_ci		       rtl8169_runtime_idle)
491062306a36Sopenharmony_ci};
491162306a36Sopenharmony_ci
491262306a36Sopenharmony_cistatic void rtl_shutdown(struct pci_dev *pdev)
491362306a36Sopenharmony_ci{
491462306a36Sopenharmony_ci	struct rtl8169_private *tp = pci_get_drvdata(pdev);
491562306a36Sopenharmony_ci
491662306a36Sopenharmony_ci	rtnl_lock();
491762306a36Sopenharmony_ci	rtl8169_net_suspend(tp);
491862306a36Sopenharmony_ci	rtnl_unlock();
491962306a36Sopenharmony_ci
492062306a36Sopenharmony_ci	/* Restore original MAC address */
492162306a36Sopenharmony_ci	rtl_rar_set(tp, tp->dev->perm_addr);
492262306a36Sopenharmony_ci
492362306a36Sopenharmony_ci	if (system_state == SYSTEM_POWER_OFF && !tp->dash_enabled) {
492462306a36Sopenharmony_ci		pci_wake_from_d3(pdev, tp->saved_wolopts);
492562306a36Sopenharmony_ci		pci_set_power_state(pdev, PCI_D3hot);
492662306a36Sopenharmony_ci	}
492762306a36Sopenharmony_ci}
492862306a36Sopenharmony_ci
492962306a36Sopenharmony_cistatic void rtl_remove_one(struct pci_dev *pdev)
493062306a36Sopenharmony_ci{
493162306a36Sopenharmony_ci	struct rtl8169_private *tp = pci_get_drvdata(pdev);
493262306a36Sopenharmony_ci
493362306a36Sopenharmony_ci	if (pci_dev_run_wake(pdev))
493462306a36Sopenharmony_ci		pm_runtime_get_noresume(&pdev->dev);
493562306a36Sopenharmony_ci
493662306a36Sopenharmony_ci	cancel_work_sync(&tp->wk.work);
493762306a36Sopenharmony_ci
493862306a36Sopenharmony_ci	unregister_netdev(tp->dev);
493962306a36Sopenharmony_ci
494062306a36Sopenharmony_ci	if (tp->dash_type != RTL_DASH_NONE)
494162306a36Sopenharmony_ci		rtl8168_driver_stop(tp);
494262306a36Sopenharmony_ci
494362306a36Sopenharmony_ci	rtl_release_firmware(tp);
494462306a36Sopenharmony_ci
494562306a36Sopenharmony_ci	/* restore original MAC address */
494662306a36Sopenharmony_ci	rtl_rar_set(tp, tp->dev->perm_addr);
494762306a36Sopenharmony_ci}
494862306a36Sopenharmony_ci
494962306a36Sopenharmony_cistatic const struct net_device_ops rtl_netdev_ops = {
495062306a36Sopenharmony_ci	.ndo_open		= rtl_open,
495162306a36Sopenharmony_ci	.ndo_stop		= rtl8169_close,
495262306a36Sopenharmony_ci	.ndo_get_stats64	= rtl8169_get_stats64,
495362306a36Sopenharmony_ci	.ndo_start_xmit		= rtl8169_start_xmit,
495462306a36Sopenharmony_ci	.ndo_features_check	= rtl8169_features_check,
495562306a36Sopenharmony_ci	.ndo_tx_timeout		= rtl8169_tx_timeout,
495662306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
495762306a36Sopenharmony_ci	.ndo_change_mtu		= rtl8169_change_mtu,
495862306a36Sopenharmony_ci	.ndo_fix_features	= rtl8169_fix_features,
495962306a36Sopenharmony_ci	.ndo_set_features	= rtl8169_set_features,
496062306a36Sopenharmony_ci	.ndo_set_mac_address	= rtl_set_mac_address,
496162306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl_running,
496262306a36Sopenharmony_ci	.ndo_set_rx_mode	= rtl_set_rx_mode,
496362306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
496462306a36Sopenharmony_ci	.ndo_poll_controller	= rtl8169_netpoll,
496562306a36Sopenharmony_ci#endif
496662306a36Sopenharmony_ci
496762306a36Sopenharmony_ci};
496862306a36Sopenharmony_ci
496962306a36Sopenharmony_cistatic void rtl_set_irq_mask(struct rtl8169_private *tp)
497062306a36Sopenharmony_ci{
497162306a36Sopenharmony_ci	tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
497262306a36Sopenharmony_ci
497362306a36Sopenharmony_ci	if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
497462306a36Sopenharmony_ci		tp->irq_mask |= SYSErr | RxOverflow | RxFIFOOver;
497562306a36Sopenharmony_ci	else if (tp->mac_version == RTL_GIGA_MAC_VER_11)
497662306a36Sopenharmony_ci		/* special workaround needed */
497762306a36Sopenharmony_ci		tp->irq_mask |= RxFIFOOver;
497862306a36Sopenharmony_ci	else
497962306a36Sopenharmony_ci		tp->irq_mask |= RxOverflow;
498062306a36Sopenharmony_ci}
498162306a36Sopenharmony_ci
498262306a36Sopenharmony_cistatic int rtl_alloc_irq(struct rtl8169_private *tp)
498362306a36Sopenharmony_ci{
498462306a36Sopenharmony_ci	unsigned int flags;
498562306a36Sopenharmony_ci
498662306a36Sopenharmony_ci	switch (tp->mac_version) {
498762306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
498862306a36Sopenharmony_ci		rtl_unlock_config_regs(tp);
498962306a36Sopenharmony_ci		RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable);
499062306a36Sopenharmony_ci		rtl_lock_config_regs(tp);
499162306a36Sopenharmony_ci		fallthrough;
499262306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_17:
499362306a36Sopenharmony_ci		flags = PCI_IRQ_LEGACY;
499462306a36Sopenharmony_ci		break;
499562306a36Sopenharmony_ci	default:
499662306a36Sopenharmony_ci		flags = PCI_IRQ_ALL_TYPES;
499762306a36Sopenharmony_ci		break;
499862306a36Sopenharmony_ci	}
499962306a36Sopenharmony_ci
500062306a36Sopenharmony_ci	return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags);
500162306a36Sopenharmony_ci}
500262306a36Sopenharmony_ci
500362306a36Sopenharmony_cistatic void rtl_read_mac_address(struct rtl8169_private *tp,
500462306a36Sopenharmony_ci				 u8 mac_addr[ETH_ALEN])
500562306a36Sopenharmony_ci{
500662306a36Sopenharmony_ci	/* Get MAC address */
500762306a36Sopenharmony_ci	if (rtl_is_8168evl_up(tp) && tp->mac_version != RTL_GIGA_MAC_VER_34) {
500862306a36Sopenharmony_ci		u32 value;
500962306a36Sopenharmony_ci
501062306a36Sopenharmony_ci		value = rtl_eri_read(tp, 0xe0);
501162306a36Sopenharmony_ci		put_unaligned_le32(value, mac_addr);
501262306a36Sopenharmony_ci		value = rtl_eri_read(tp, 0xe4);
501362306a36Sopenharmony_ci		put_unaligned_le16(value, mac_addr + 4);
501462306a36Sopenharmony_ci	} else if (rtl_is_8125(tp)) {
501562306a36Sopenharmony_ci		rtl_read_mac_from_reg(tp, mac_addr, MAC0_BKP);
501662306a36Sopenharmony_ci	}
501762306a36Sopenharmony_ci}
501862306a36Sopenharmony_ci
501962306a36Sopenharmony_ciDECLARE_RTL_COND(rtl_link_list_ready_cond)
502062306a36Sopenharmony_ci{
502162306a36Sopenharmony_ci	return RTL_R8(tp, MCU) & LINK_LIST_RDY;
502262306a36Sopenharmony_ci}
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_cistatic void r8168g_wait_ll_share_fifo_ready(struct rtl8169_private *tp)
502562306a36Sopenharmony_ci{
502662306a36Sopenharmony_ci	rtl_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42);
502762306a36Sopenharmony_ci}
502862306a36Sopenharmony_ci
502962306a36Sopenharmony_cistatic int r8169_mdio_read_reg(struct mii_bus *mii_bus, int phyaddr, int phyreg)
503062306a36Sopenharmony_ci{
503162306a36Sopenharmony_ci	struct rtl8169_private *tp = mii_bus->priv;
503262306a36Sopenharmony_ci
503362306a36Sopenharmony_ci	if (phyaddr > 0)
503462306a36Sopenharmony_ci		return -ENODEV;
503562306a36Sopenharmony_ci
503662306a36Sopenharmony_ci	return rtl_readphy(tp, phyreg);
503762306a36Sopenharmony_ci}
503862306a36Sopenharmony_ci
503962306a36Sopenharmony_cistatic int r8169_mdio_write_reg(struct mii_bus *mii_bus, int phyaddr,
504062306a36Sopenharmony_ci				int phyreg, u16 val)
504162306a36Sopenharmony_ci{
504262306a36Sopenharmony_ci	struct rtl8169_private *tp = mii_bus->priv;
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci	if (phyaddr > 0)
504562306a36Sopenharmony_ci		return -ENODEV;
504662306a36Sopenharmony_ci
504762306a36Sopenharmony_ci	rtl_writephy(tp, phyreg, val);
504862306a36Sopenharmony_ci
504962306a36Sopenharmony_ci	return 0;
505062306a36Sopenharmony_ci}
505162306a36Sopenharmony_ci
505262306a36Sopenharmony_cistatic int r8169_mdio_register(struct rtl8169_private *tp)
505362306a36Sopenharmony_ci{
505462306a36Sopenharmony_ci	struct pci_dev *pdev = tp->pci_dev;
505562306a36Sopenharmony_ci	struct mii_bus *new_bus;
505662306a36Sopenharmony_ci	int ret;
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ci	new_bus = devm_mdiobus_alloc(&pdev->dev);
505962306a36Sopenharmony_ci	if (!new_bus)
506062306a36Sopenharmony_ci		return -ENOMEM;
506162306a36Sopenharmony_ci
506262306a36Sopenharmony_ci	new_bus->name = "r8169";
506362306a36Sopenharmony_ci	new_bus->priv = tp;
506462306a36Sopenharmony_ci	new_bus->parent = &pdev->dev;
506562306a36Sopenharmony_ci	new_bus->irq[0] = PHY_MAC_INTERRUPT;
506662306a36Sopenharmony_ci	snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x-%x",
506762306a36Sopenharmony_ci		 pci_domain_nr(pdev->bus), pci_dev_id(pdev));
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_ci	new_bus->read = r8169_mdio_read_reg;
507062306a36Sopenharmony_ci	new_bus->write = r8169_mdio_write_reg;
507162306a36Sopenharmony_ci
507262306a36Sopenharmony_ci	ret = devm_mdiobus_register(&pdev->dev, new_bus);
507362306a36Sopenharmony_ci	if (ret)
507462306a36Sopenharmony_ci		return ret;
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ci	tp->phydev = mdiobus_get_phy(new_bus, 0);
507762306a36Sopenharmony_ci	if (!tp->phydev) {
507862306a36Sopenharmony_ci		return -ENODEV;
507962306a36Sopenharmony_ci	} else if (!tp->phydev->drv) {
508062306a36Sopenharmony_ci		/* Most chip versions fail with the genphy driver.
508162306a36Sopenharmony_ci		 * Therefore ensure that the dedicated PHY driver is loaded.
508262306a36Sopenharmony_ci		 */
508362306a36Sopenharmony_ci		dev_err(&pdev->dev, "no dedicated PHY driver found for PHY ID 0x%08x, maybe realtek.ko needs to be added to initramfs?\n",
508462306a36Sopenharmony_ci			tp->phydev->phy_id);
508562306a36Sopenharmony_ci		return -EUNATCH;
508662306a36Sopenharmony_ci	}
508762306a36Sopenharmony_ci
508862306a36Sopenharmony_ci	tp->phydev->mac_managed_pm = true;
508962306a36Sopenharmony_ci
509062306a36Sopenharmony_ci	phy_support_asym_pause(tp->phydev);
509162306a36Sopenharmony_ci
509262306a36Sopenharmony_ci	/* PHY will be woken up in rtl_open() */
509362306a36Sopenharmony_ci	phy_suspend(tp->phydev);
509462306a36Sopenharmony_ci
509562306a36Sopenharmony_ci	return 0;
509662306a36Sopenharmony_ci}
509762306a36Sopenharmony_ci
509862306a36Sopenharmony_cistatic void rtl_hw_init_8168g(struct rtl8169_private *tp)
509962306a36Sopenharmony_ci{
510062306a36Sopenharmony_ci	rtl_enable_rxdvgate(tp);
510162306a36Sopenharmony_ci
510262306a36Sopenharmony_ci	RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
510362306a36Sopenharmony_ci	msleep(1);
510462306a36Sopenharmony_ci	RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
510562306a36Sopenharmony_ci
510662306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe8de, BIT(14), 0);
510762306a36Sopenharmony_ci	r8168g_wait_ll_share_fifo_ready(tp);
510862306a36Sopenharmony_ci
510962306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe8de, 0, BIT(15));
511062306a36Sopenharmony_ci	r8168g_wait_ll_share_fifo_ready(tp);
511162306a36Sopenharmony_ci}
511262306a36Sopenharmony_ci
511362306a36Sopenharmony_cistatic void rtl_hw_init_8125(struct rtl8169_private *tp)
511462306a36Sopenharmony_ci{
511562306a36Sopenharmony_ci	rtl_enable_rxdvgate(tp);
511662306a36Sopenharmony_ci
511762306a36Sopenharmony_ci	RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
511862306a36Sopenharmony_ci	msleep(1);
511962306a36Sopenharmony_ci	RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
512062306a36Sopenharmony_ci
512162306a36Sopenharmony_ci	r8168_mac_ocp_modify(tp, 0xe8de, BIT(14), 0);
512262306a36Sopenharmony_ci	r8168g_wait_ll_share_fifo_ready(tp);
512362306a36Sopenharmony_ci
512462306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc0aa, 0x07d0);
512562306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc0a6, 0x0150);
512662306a36Sopenharmony_ci	r8168_mac_ocp_write(tp, 0xc01e, 0x5555);
512762306a36Sopenharmony_ci	r8168g_wait_ll_share_fifo_ready(tp);
512862306a36Sopenharmony_ci}
512962306a36Sopenharmony_ci
513062306a36Sopenharmony_cistatic void rtl_hw_initialize(struct rtl8169_private *tp)
513162306a36Sopenharmony_ci{
513262306a36Sopenharmony_ci	switch (tp->mac_version) {
513362306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53:
513462306a36Sopenharmony_ci		rtl8168ep_stop_cmac(tp);
513562306a36Sopenharmony_ci		fallthrough;
513662306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48:
513762306a36Sopenharmony_ci		rtl_hw_init_8168g(tp);
513862306a36Sopenharmony_ci		break;
513962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63:
514062306a36Sopenharmony_ci		rtl_hw_init_8125(tp);
514162306a36Sopenharmony_ci		break;
514262306a36Sopenharmony_ci	default:
514362306a36Sopenharmony_ci		break;
514462306a36Sopenharmony_ci	}
514562306a36Sopenharmony_ci}
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_cistatic int rtl_jumbo_max(struct rtl8169_private *tp)
514862306a36Sopenharmony_ci{
514962306a36Sopenharmony_ci	/* Non-GBit versions don't support jumbo frames */
515062306a36Sopenharmony_ci	if (!tp->supports_gmii)
515162306a36Sopenharmony_ci		return 0;
515262306a36Sopenharmony_ci
515362306a36Sopenharmony_ci	switch (tp->mac_version) {
515462306a36Sopenharmony_ci	/* RTL8169 */
515562306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
515662306a36Sopenharmony_ci		return JUMBO_7K;
515762306a36Sopenharmony_ci	/* RTL8168b */
515862306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_11:
515962306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_17:
516062306a36Sopenharmony_ci		return JUMBO_4K;
516162306a36Sopenharmony_ci	/* RTL8168c */
516262306a36Sopenharmony_ci	case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24:
516362306a36Sopenharmony_ci		return JUMBO_6K;
516462306a36Sopenharmony_ci	default:
516562306a36Sopenharmony_ci		return JUMBO_9K;
516662306a36Sopenharmony_ci	}
516762306a36Sopenharmony_ci}
516862306a36Sopenharmony_ci
516962306a36Sopenharmony_cistatic void rtl_init_mac_address(struct rtl8169_private *tp)
517062306a36Sopenharmony_ci{
517162306a36Sopenharmony_ci	u8 mac_addr[ETH_ALEN] __aligned(2) = {};
517262306a36Sopenharmony_ci	struct net_device *dev = tp->dev;
517362306a36Sopenharmony_ci	int rc;
517462306a36Sopenharmony_ci
517562306a36Sopenharmony_ci	rc = eth_platform_get_mac_address(tp_to_dev(tp), mac_addr);
517662306a36Sopenharmony_ci	if (!rc)
517762306a36Sopenharmony_ci		goto done;
517862306a36Sopenharmony_ci
517962306a36Sopenharmony_ci	rtl_read_mac_address(tp, mac_addr);
518062306a36Sopenharmony_ci	if (is_valid_ether_addr(mac_addr))
518162306a36Sopenharmony_ci		goto done;
518262306a36Sopenharmony_ci
518362306a36Sopenharmony_ci	rtl_read_mac_from_reg(tp, mac_addr, MAC0);
518462306a36Sopenharmony_ci	if (is_valid_ether_addr(mac_addr))
518562306a36Sopenharmony_ci		goto done;
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci	eth_random_addr(mac_addr);
518862306a36Sopenharmony_ci	dev->addr_assign_type = NET_ADDR_RANDOM;
518962306a36Sopenharmony_ci	dev_warn(tp_to_dev(tp), "can't read MAC address, setting random one\n");
519062306a36Sopenharmony_cidone:
519162306a36Sopenharmony_ci	eth_hw_addr_set(dev, mac_addr);
519262306a36Sopenharmony_ci	rtl_rar_set(tp, mac_addr);
519362306a36Sopenharmony_ci}
519462306a36Sopenharmony_ci
519562306a36Sopenharmony_ci/* register is set if system vendor successfully tested ASPM 1.2 */
519662306a36Sopenharmony_cistatic bool rtl_aspm_is_safe(struct rtl8169_private *tp)
519762306a36Sopenharmony_ci{
519862306a36Sopenharmony_ci	if (tp->mac_version >= RTL_GIGA_MAC_VER_61 &&
519962306a36Sopenharmony_ci	    r8168_mac_ocp_read(tp, 0xc0b2) & 0xf)
520062306a36Sopenharmony_ci		return true;
520162306a36Sopenharmony_ci
520262306a36Sopenharmony_ci	return false;
520362306a36Sopenharmony_ci}
520462306a36Sopenharmony_ci
520562306a36Sopenharmony_cistatic int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
520662306a36Sopenharmony_ci{
520762306a36Sopenharmony_ci	struct rtl8169_private *tp;
520862306a36Sopenharmony_ci	int jumbo_max, region, rc;
520962306a36Sopenharmony_ci	enum mac_version chipset;
521062306a36Sopenharmony_ci	struct net_device *dev;
521162306a36Sopenharmony_ci	u32 txconfig;
521262306a36Sopenharmony_ci	u16 xid;
521362306a36Sopenharmony_ci
521462306a36Sopenharmony_ci	dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp));
521562306a36Sopenharmony_ci	if (!dev)
521662306a36Sopenharmony_ci		return -ENOMEM;
521762306a36Sopenharmony_ci
521862306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
521962306a36Sopenharmony_ci	dev->netdev_ops = &rtl_netdev_ops;
522062306a36Sopenharmony_ci	tp = netdev_priv(dev);
522162306a36Sopenharmony_ci	tp->dev = dev;
522262306a36Sopenharmony_ci	tp->pci_dev = pdev;
522362306a36Sopenharmony_ci	tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1;
522462306a36Sopenharmony_ci	tp->eee_adv = -1;
522562306a36Sopenharmony_ci	tp->ocp_base = OCP_STD_PHY_BASE;
522662306a36Sopenharmony_ci
522762306a36Sopenharmony_ci	raw_spin_lock_init(&tp->cfg9346_usage_lock);
522862306a36Sopenharmony_ci	raw_spin_lock_init(&tp->config25_lock);
522962306a36Sopenharmony_ci	raw_spin_lock_init(&tp->mac_ocp_lock);
523062306a36Sopenharmony_ci
523162306a36Sopenharmony_ci	dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev,
523262306a36Sopenharmony_ci						   struct pcpu_sw_netstats);
523362306a36Sopenharmony_ci	if (!dev->tstats)
523462306a36Sopenharmony_ci		return -ENOMEM;
523562306a36Sopenharmony_ci
523662306a36Sopenharmony_ci	/* Get the *optional* external "ether_clk" used on some boards */
523762306a36Sopenharmony_ci	tp->clk = devm_clk_get_optional_enabled(&pdev->dev, "ether_clk");
523862306a36Sopenharmony_ci	if (IS_ERR(tp->clk))
523962306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(tp->clk), "failed to get ether_clk\n");
524062306a36Sopenharmony_ci
524162306a36Sopenharmony_ci	/* enable device (incl. PCI PM wakeup and hotplug setup) */
524262306a36Sopenharmony_ci	rc = pcim_enable_device(pdev);
524362306a36Sopenharmony_ci	if (rc < 0)
524462306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, rc, "enable failure\n");
524562306a36Sopenharmony_ci
524662306a36Sopenharmony_ci	if (pcim_set_mwi(pdev) < 0)
524762306a36Sopenharmony_ci		dev_info(&pdev->dev, "Mem-Wr-Inval unavailable\n");
524862306a36Sopenharmony_ci
524962306a36Sopenharmony_ci	/* use first MMIO region */
525062306a36Sopenharmony_ci	region = ffs(pci_select_bars(pdev, IORESOURCE_MEM)) - 1;
525162306a36Sopenharmony_ci	if (region < 0)
525262306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, -ENODEV, "no MMIO resource found\n");
525362306a36Sopenharmony_ci
525462306a36Sopenharmony_ci	rc = pcim_iomap_regions(pdev, BIT(region), KBUILD_MODNAME);
525562306a36Sopenharmony_ci	if (rc < 0)
525662306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, rc, "cannot remap MMIO, aborting\n");
525762306a36Sopenharmony_ci
525862306a36Sopenharmony_ci	tp->mmio_addr = pcim_iomap_table(pdev)[region];
525962306a36Sopenharmony_ci
526062306a36Sopenharmony_ci	txconfig = RTL_R32(tp, TxConfig);
526162306a36Sopenharmony_ci	if (txconfig == ~0U)
526262306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, -EIO, "PCI read failed\n");
526362306a36Sopenharmony_ci
526462306a36Sopenharmony_ci	xid = (txconfig >> 20) & 0xfcf;
526562306a36Sopenharmony_ci
526662306a36Sopenharmony_ci	/* Identify chip attached to board */
526762306a36Sopenharmony_ci	chipset = rtl8169_get_mac_version(xid, tp->supports_gmii);
526862306a36Sopenharmony_ci	if (chipset == RTL_GIGA_MAC_NONE)
526962306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, -ENODEV,
527062306a36Sopenharmony_ci				     "unknown chip XID %03x, contact r8169 maintainers (see MAINTAINERS file)\n",
527162306a36Sopenharmony_ci				     xid);
527262306a36Sopenharmony_ci	tp->mac_version = chipset;
527362306a36Sopenharmony_ci
527462306a36Sopenharmony_ci	/* Disable ASPM L1 as that cause random device stop working
527562306a36Sopenharmony_ci	 * problems as well as full system hangs for some PCIe devices users.
527662306a36Sopenharmony_ci	 */
527762306a36Sopenharmony_ci	if (rtl_aspm_is_safe(tp))
527862306a36Sopenharmony_ci		rc = 0;
527962306a36Sopenharmony_ci	else
528062306a36Sopenharmony_ci		rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1);
528162306a36Sopenharmony_ci	tp->aspm_manageable = !rc;
528262306a36Sopenharmony_ci
528362306a36Sopenharmony_ci	tp->dash_type = rtl_get_dash_type(tp);
528462306a36Sopenharmony_ci	tp->dash_enabled = rtl_dash_is_enabled(tp);
528562306a36Sopenharmony_ci
528662306a36Sopenharmony_ci	tp->cp_cmd = RTL_R16(tp, CPlusCmd) & CPCMD_MASK;
528762306a36Sopenharmony_ci
528862306a36Sopenharmony_ci	if (sizeof(dma_addr_t) > 4 && tp->mac_version >= RTL_GIGA_MAC_VER_18 &&
528962306a36Sopenharmony_ci	    !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)))
529062306a36Sopenharmony_ci		dev->features |= NETIF_F_HIGHDMA;
529162306a36Sopenharmony_ci
529262306a36Sopenharmony_ci	rtl_init_rxcfg(tp);
529362306a36Sopenharmony_ci
529462306a36Sopenharmony_ci	rtl8169_irq_mask_and_ack(tp);
529562306a36Sopenharmony_ci
529662306a36Sopenharmony_ci	rtl_hw_initialize(tp);
529762306a36Sopenharmony_ci
529862306a36Sopenharmony_ci	rtl_hw_reset(tp);
529962306a36Sopenharmony_ci
530062306a36Sopenharmony_ci	rc = rtl_alloc_irq(tp);
530162306a36Sopenharmony_ci	if (rc < 0)
530262306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n");
530362306a36Sopenharmony_ci
530462306a36Sopenharmony_ci	tp->irq = pci_irq_vector(pdev, 0);
530562306a36Sopenharmony_ci
530662306a36Sopenharmony_ci	INIT_WORK(&tp->wk.work, rtl_task);
530762306a36Sopenharmony_ci
530862306a36Sopenharmony_ci	rtl_init_mac_address(tp);
530962306a36Sopenharmony_ci
531062306a36Sopenharmony_ci	dev->ethtool_ops = &rtl8169_ethtool_ops;
531162306a36Sopenharmony_ci
531262306a36Sopenharmony_ci	netif_napi_add(dev, &tp->napi, rtl8169_poll);
531362306a36Sopenharmony_ci
531462306a36Sopenharmony_ci	dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
531562306a36Sopenharmony_ci			   NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
531662306a36Sopenharmony_ci	dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
531762306a36Sopenharmony_ci	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
531862306a36Sopenharmony_ci
531962306a36Sopenharmony_ci	/*
532062306a36Sopenharmony_ci	 * Pretend we are using VLANs; This bypasses a nasty bug where
532162306a36Sopenharmony_ci	 * Interrupts stop flowing on high load on 8110SCd controllers.
532262306a36Sopenharmony_ci	 */
532362306a36Sopenharmony_ci	if (tp->mac_version == RTL_GIGA_MAC_VER_05)
532462306a36Sopenharmony_ci		/* Disallow toggling */
532562306a36Sopenharmony_ci		dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
532662306a36Sopenharmony_ci
532762306a36Sopenharmony_ci	if (rtl_chip_supports_csum_v2(tp))
532862306a36Sopenharmony_ci		dev->hw_features |= NETIF_F_IPV6_CSUM;
532962306a36Sopenharmony_ci
533062306a36Sopenharmony_ci	dev->features |= dev->hw_features;
533162306a36Sopenharmony_ci
533262306a36Sopenharmony_ci	/* There has been a number of reports that using SG/TSO results in
533362306a36Sopenharmony_ci	 * tx timeouts. However for a lot of people SG/TSO works fine.
533462306a36Sopenharmony_ci	 * Therefore disable both features by default, but allow users to
533562306a36Sopenharmony_ci	 * enable them. Use at own risk!
533662306a36Sopenharmony_ci	 */
533762306a36Sopenharmony_ci	if (rtl_chip_supports_csum_v2(tp)) {
533862306a36Sopenharmony_ci		dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6;
533962306a36Sopenharmony_ci		netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V2);
534062306a36Sopenharmony_ci		netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V2);
534162306a36Sopenharmony_ci	} else {
534262306a36Sopenharmony_ci		dev->hw_features |= NETIF_F_SG | NETIF_F_TSO;
534362306a36Sopenharmony_ci		netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V1);
534462306a36Sopenharmony_ci		netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V1);
534562306a36Sopenharmony_ci	}
534662306a36Sopenharmony_ci
534762306a36Sopenharmony_ci	dev->hw_features |= NETIF_F_RXALL;
534862306a36Sopenharmony_ci	dev->hw_features |= NETIF_F_RXFCS;
534962306a36Sopenharmony_ci
535062306a36Sopenharmony_ci	netdev_sw_irq_coalesce_default_on(dev);
535162306a36Sopenharmony_ci
535262306a36Sopenharmony_ci	/* configure chip for default features */
535362306a36Sopenharmony_ci	rtl8169_set_features(dev, dev->features);
535462306a36Sopenharmony_ci
535562306a36Sopenharmony_ci	if (!tp->dash_enabled) {
535662306a36Sopenharmony_ci		rtl_set_d3_pll_down(tp, true);
535762306a36Sopenharmony_ci	} else {
535862306a36Sopenharmony_ci		rtl_set_d3_pll_down(tp, false);
535962306a36Sopenharmony_ci		dev->wol_enabled = 1;
536062306a36Sopenharmony_ci	}
536162306a36Sopenharmony_ci
536262306a36Sopenharmony_ci	jumbo_max = rtl_jumbo_max(tp);
536362306a36Sopenharmony_ci	if (jumbo_max)
536462306a36Sopenharmony_ci		dev->max_mtu = jumbo_max;
536562306a36Sopenharmony_ci
536662306a36Sopenharmony_ci	rtl_set_irq_mask(tp);
536762306a36Sopenharmony_ci
536862306a36Sopenharmony_ci	tp->fw_name = rtl_chip_infos[chipset].fw_name;
536962306a36Sopenharmony_ci
537062306a36Sopenharmony_ci	tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters),
537162306a36Sopenharmony_ci					    &tp->counters_phys_addr,
537262306a36Sopenharmony_ci					    GFP_KERNEL);
537362306a36Sopenharmony_ci	if (!tp->counters)
537462306a36Sopenharmony_ci		return -ENOMEM;
537562306a36Sopenharmony_ci
537662306a36Sopenharmony_ci	pci_set_drvdata(pdev, tp);
537762306a36Sopenharmony_ci
537862306a36Sopenharmony_ci	rc = r8169_mdio_register(tp);
537962306a36Sopenharmony_ci	if (rc)
538062306a36Sopenharmony_ci		return rc;
538162306a36Sopenharmony_ci
538262306a36Sopenharmony_ci	rc = register_netdev(dev);
538362306a36Sopenharmony_ci	if (rc)
538462306a36Sopenharmony_ci		return rc;
538562306a36Sopenharmony_ci
538662306a36Sopenharmony_ci	netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n",
538762306a36Sopenharmony_ci		    rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq);
538862306a36Sopenharmony_ci
538962306a36Sopenharmony_ci	if (jumbo_max)
539062306a36Sopenharmony_ci		netdev_info(dev, "jumbo features [frames: %d bytes, tx checksumming: %s]\n",
539162306a36Sopenharmony_ci			    jumbo_max, tp->mac_version <= RTL_GIGA_MAC_VER_06 ?
539262306a36Sopenharmony_ci			    "ok" : "ko");
539362306a36Sopenharmony_ci
539462306a36Sopenharmony_ci	if (tp->dash_type != RTL_DASH_NONE) {
539562306a36Sopenharmony_ci		netdev_info(dev, "DASH %s\n",
539662306a36Sopenharmony_ci			    tp->dash_enabled ? "enabled" : "disabled");
539762306a36Sopenharmony_ci		rtl8168_driver_start(tp);
539862306a36Sopenharmony_ci	}
539962306a36Sopenharmony_ci
540062306a36Sopenharmony_ci	if (pci_dev_run_wake(pdev))
540162306a36Sopenharmony_ci		pm_runtime_put_sync(&pdev->dev);
540262306a36Sopenharmony_ci
540362306a36Sopenharmony_ci	return 0;
540462306a36Sopenharmony_ci}
540562306a36Sopenharmony_ci
540662306a36Sopenharmony_cistatic struct pci_driver rtl8169_pci_driver = {
540762306a36Sopenharmony_ci	.name		= KBUILD_MODNAME,
540862306a36Sopenharmony_ci	.id_table	= rtl8169_pci_tbl,
540962306a36Sopenharmony_ci	.probe		= rtl_init_one,
541062306a36Sopenharmony_ci	.remove		= rtl_remove_one,
541162306a36Sopenharmony_ci	.shutdown	= rtl_shutdown,
541262306a36Sopenharmony_ci	.driver.pm	= pm_ptr(&rtl8169_pm_ops),
541362306a36Sopenharmony_ci};
541462306a36Sopenharmony_ci
541562306a36Sopenharmony_cimodule_pci_driver(rtl8169_pci_driver);
5416