18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * r8169.c: RealTek 8169/8168/8101 ethernet driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw> 68c2ecf20Sopenharmony_ci * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com> 78c2ecf20Sopenharmony_ci * Copyright (c) a lot of people too. Please respect their work. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * See MAINTAINERS file for support contact information. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 158c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 168c2ecf20Sopenharmony_ci#include <linux/clk.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 198c2ecf20Sopenharmony_ci#include <linux/phy.h> 208c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 218c2ecf20Sopenharmony_ci#include <linux/in.h> 228c2ecf20Sopenharmony_ci#include <linux/io.h> 238c2ecf20Sopenharmony_ci#include <linux/ip.h> 248c2ecf20Sopenharmony_ci#include <linux/tcp.h> 258c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 268c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 278c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 288c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 298c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 308c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 318c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "r8169.h" 348c2ecf20Sopenharmony_ci#include "r8169_firmware.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define MODULENAME "r8169" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw" 398c2ecf20Sopenharmony_ci#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw" 408c2ecf20Sopenharmony_ci#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw" 418c2ecf20Sopenharmony_ci#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw" 428c2ecf20Sopenharmony_ci#define FIRMWARE_8168E_3 "rtl_nic/rtl8168e-3.fw" 438c2ecf20Sopenharmony_ci#define FIRMWARE_8168F_1 "rtl_nic/rtl8168f-1.fw" 448c2ecf20Sopenharmony_ci#define FIRMWARE_8168F_2 "rtl_nic/rtl8168f-2.fw" 458c2ecf20Sopenharmony_ci#define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw" 468c2ecf20Sopenharmony_ci#define FIRMWARE_8402_1 "rtl_nic/rtl8402-1.fw" 478c2ecf20Sopenharmony_ci#define FIRMWARE_8411_1 "rtl_nic/rtl8411-1.fw" 488c2ecf20Sopenharmony_ci#define FIRMWARE_8411_2 "rtl_nic/rtl8411-2.fw" 498c2ecf20Sopenharmony_ci#define FIRMWARE_8106E_1 "rtl_nic/rtl8106e-1.fw" 508c2ecf20Sopenharmony_ci#define FIRMWARE_8106E_2 "rtl_nic/rtl8106e-2.fw" 518c2ecf20Sopenharmony_ci#define FIRMWARE_8168G_2 "rtl_nic/rtl8168g-2.fw" 528c2ecf20Sopenharmony_ci#define FIRMWARE_8168G_3 "rtl_nic/rtl8168g-3.fw" 538c2ecf20Sopenharmony_ci#define FIRMWARE_8168H_1 "rtl_nic/rtl8168h-1.fw" 548c2ecf20Sopenharmony_ci#define FIRMWARE_8168H_2 "rtl_nic/rtl8168h-2.fw" 558c2ecf20Sopenharmony_ci#define FIRMWARE_8168FP_3 "rtl_nic/rtl8168fp-3.fw" 568c2ecf20Sopenharmony_ci#define FIRMWARE_8107E_1 "rtl_nic/rtl8107e-1.fw" 578c2ecf20Sopenharmony_ci#define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw" 588c2ecf20Sopenharmony_ci#define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" 598c2ecf20Sopenharmony_ci#define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). 628c2ecf20Sopenharmony_ci The RTL chips use a 64 element hash table based on the Ethernet CRC. */ 638c2ecf20Sopenharmony_ci#define MC_FILTER_LIMIT 32 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */ 668c2ecf20Sopenharmony_ci#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define R8169_REGS_SIZE 256 698c2ecf20Sopenharmony_ci#define R8169_RX_BUF_SIZE (SZ_16K - 1) 708c2ecf20Sopenharmony_ci#define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ 718c2ecf20Sopenharmony_ci#define NUM_RX_DESC 256U /* Number of Rx descriptor registers */ 728c2ecf20Sopenharmony_ci#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) 738c2ecf20Sopenharmony_ci#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define OCP_STD_PHY_BASE 0xa400 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define RTL_CFG_NO_GBIT 1 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* write/read MMIO register */ 808c2ecf20Sopenharmony_ci#define RTL_W8(tp, reg, val8) writeb((val8), tp->mmio_addr + (reg)) 818c2ecf20Sopenharmony_ci#define RTL_W16(tp, reg, val16) writew((val16), tp->mmio_addr + (reg)) 828c2ecf20Sopenharmony_ci#define RTL_W32(tp, reg, val32) writel((val32), tp->mmio_addr + (reg)) 838c2ecf20Sopenharmony_ci#define RTL_R8(tp, reg) readb(tp->mmio_addr + (reg)) 848c2ecf20Sopenharmony_ci#define RTL_R16(tp, reg) readw(tp->mmio_addr + (reg)) 858c2ecf20Sopenharmony_ci#define RTL_R32(tp, reg) readl(tp->mmio_addr + (reg)) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define JUMBO_4K (4 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) 888c2ecf20Sopenharmony_ci#define JUMBO_6K (6 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) 898c2ecf20Sopenharmony_ci#define JUMBO_7K (7 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) 908c2ecf20Sopenharmony_ci#define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const struct { 938c2ecf20Sopenharmony_ci const char *name; 948c2ecf20Sopenharmony_ci const char *fw_name; 958c2ecf20Sopenharmony_ci} rtl_chip_infos[] = { 968c2ecf20Sopenharmony_ci /* PCI devices. */ 978c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_02] = {"RTL8169s" }, 988c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_03] = {"RTL8110s" }, 998c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_04] = {"RTL8169sb/8110sb" }, 1008c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_05] = {"RTL8169sc/8110sc" }, 1018c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_06] = {"RTL8169sc/8110sc" }, 1028c2ecf20Sopenharmony_ci /* PCI-E devices. */ 1038c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_07] = {"RTL8102e" }, 1048c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_08] = {"RTL8102e" }, 1058c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" }, 1068c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_10] = {"RTL8101e" }, 1078c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_11] = {"RTL8168b/8111b" }, 1088c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_12] = {"RTL8168b/8111b" }, 1098c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_13] = {"RTL8101e/RTL8100e" }, 1108c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_14] = {"RTL8401" }, 1118c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_16] = {"RTL8101e" }, 1128c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" }, 1138c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" }, 1148c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_19] = {"RTL8168c/8111c" }, 1158c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_20] = {"RTL8168c/8111c" }, 1168c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_21] = {"RTL8168c/8111c" }, 1178c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_22] = {"RTL8168c/8111c" }, 1188c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_23] = {"RTL8168cp/8111cp" }, 1198c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_24] = {"RTL8168cp/8111cp" }, 1208c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_25] = {"RTL8168d/8111d", FIRMWARE_8168D_1}, 1218c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_26] = {"RTL8168d/8111d", FIRMWARE_8168D_2}, 1228c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_27] = {"RTL8168dp/8111dp" }, 1238c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_28] = {"RTL8168dp/8111dp" }, 1248c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_29] = {"RTL8105e", FIRMWARE_8105E_1}, 1258c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_30] = {"RTL8105e", FIRMWARE_8105E_1}, 1268c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_31] = {"RTL8168dp/8111dp" }, 1278c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_32] = {"RTL8168e/8111e", FIRMWARE_8168E_1}, 1288c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_33] = {"RTL8168e/8111e", FIRMWARE_8168E_2}, 1298c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_34] = {"RTL8168evl/8111evl", FIRMWARE_8168E_3}, 1308c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_35] = {"RTL8168f/8111f", FIRMWARE_8168F_1}, 1318c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_36] = {"RTL8168f/8111f", FIRMWARE_8168F_2}, 1328c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_37] = {"RTL8402", FIRMWARE_8402_1 }, 1338c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_38] = {"RTL8411", FIRMWARE_8411_1 }, 1348c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_39] = {"RTL8106e", FIRMWARE_8106E_1}, 1358c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_40] = {"RTL8168g/8111g", FIRMWARE_8168G_2}, 1368c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_41] = {"RTL8168g/8111g" }, 1378c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_42] = {"RTL8168gu/8111gu", FIRMWARE_8168G_3}, 1388c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_43] = {"RTL8106eus", FIRMWARE_8106E_2}, 1398c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_44] = {"RTL8411b", FIRMWARE_8411_2 }, 1408c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_45] = {"RTL8168h/8111h", FIRMWARE_8168H_1}, 1418c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_46] = {"RTL8168h/8111h", FIRMWARE_8168H_2}, 1428c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_47] = {"RTL8107e", FIRMWARE_8107E_1}, 1438c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_48] = {"RTL8107e", FIRMWARE_8107E_2}, 1448c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_49] = {"RTL8168ep/8111ep" }, 1458c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_50] = {"RTL8168ep/8111ep" }, 1468c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep" }, 1478c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_52] = {"RTL8168fp/RTL8117", FIRMWARE_8168FP_3}, 1488c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_60] = {"RTL8125A" }, 1498c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3}, 1508c2ecf20Sopenharmony_ci /* reserve 62 for CFG_METHOD_4 in the vendor driver */ 1518c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic const struct pci_device_id rtl8169_pci_tbl[] = { 1558c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x2502) }, 1568c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x2600) }, 1578c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x8129) }, 1588c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x8136), RTL_CFG_NO_GBIT }, 1598c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x8161) }, 1608c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x8162) }, 1618c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x8167) }, 1628c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x8168) }, 1638c2ecf20Sopenharmony_ci { PCI_VDEVICE(NCUBE, 0x8168) }, 1648c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x8169) }, 1658c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_DLINK, 0x4300, 1668c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0 }, 1678c2ecf20Sopenharmony_ci { PCI_VDEVICE(DLINK, 0x4300) }, 1688c2ecf20Sopenharmony_ci { PCI_VDEVICE(DLINK, 0x4302) }, 1698c2ecf20Sopenharmony_ci { PCI_VDEVICE(AT, 0xc107) }, 1708c2ecf20Sopenharmony_ci { PCI_VDEVICE(USR, 0x0116) }, 1718c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024 }, 1728c2ecf20Sopenharmony_ci { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 }, 1738c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x8125) }, 1748c2ecf20Sopenharmony_ci { PCI_VDEVICE(REALTEK, 0x3000) }, 1758c2ecf20Sopenharmony_ci {} 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cienum rtl_registers { 1818c2ecf20Sopenharmony_ci MAC0 = 0, /* Ethernet hardware address. */ 1828c2ecf20Sopenharmony_ci MAC4 = 4, 1838c2ecf20Sopenharmony_ci MAR0 = 8, /* Multicast filter. */ 1848c2ecf20Sopenharmony_ci CounterAddrLow = 0x10, 1858c2ecf20Sopenharmony_ci CounterAddrHigh = 0x14, 1868c2ecf20Sopenharmony_ci TxDescStartAddrLow = 0x20, 1878c2ecf20Sopenharmony_ci TxDescStartAddrHigh = 0x24, 1888c2ecf20Sopenharmony_ci TxHDescStartAddrLow = 0x28, 1898c2ecf20Sopenharmony_ci TxHDescStartAddrHigh = 0x2c, 1908c2ecf20Sopenharmony_ci FLASH = 0x30, 1918c2ecf20Sopenharmony_ci ERSR = 0x36, 1928c2ecf20Sopenharmony_ci ChipCmd = 0x37, 1938c2ecf20Sopenharmony_ci TxPoll = 0x38, 1948c2ecf20Sopenharmony_ci IntrMask = 0x3c, 1958c2ecf20Sopenharmony_ci IntrStatus = 0x3e, 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci TxConfig = 0x40, 1988c2ecf20Sopenharmony_ci#define TXCFG_AUTO_FIFO (1 << 7) /* 8111e-vl */ 1998c2ecf20Sopenharmony_ci#define TXCFG_EMPTY (1 << 11) /* 8111e-vl */ 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci RxConfig = 0x44, 2028c2ecf20Sopenharmony_ci#define RX128_INT_EN (1 << 15) /* 8111c and later */ 2038c2ecf20Sopenharmony_ci#define RX_MULTI_EN (1 << 14) /* 8111c only */ 2048c2ecf20Sopenharmony_ci#define RXCFG_FIFO_SHIFT 13 2058c2ecf20Sopenharmony_ci /* No threshold before first PCI xfer */ 2068c2ecf20Sopenharmony_ci#define RX_FIFO_THRESH (7 << RXCFG_FIFO_SHIFT) 2078c2ecf20Sopenharmony_ci#define RX_EARLY_OFF (1 << 11) 2088c2ecf20Sopenharmony_ci#define RX_PAUSE_SLOT_ON (1 << 11) /* 8125b and later */ 2098c2ecf20Sopenharmony_ci#define RXCFG_DMA_SHIFT 8 2108c2ecf20Sopenharmony_ci /* Unlimited maximum PCI burst. */ 2118c2ecf20Sopenharmony_ci#define RX_DMA_BURST (7 << RXCFG_DMA_SHIFT) 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci Cfg9346 = 0x50, 2148c2ecf20Sopenharmony_ci Config0 = 0x51, 2158c2ecf20Sopenharmony_ci Config1 = 0x52, 2168c2ecf20Sopenharmony_ci Config2 = 0x53, 2178c2ecf20Sopenharmony_ci#define PME_SIGNAL (1 << 5) /* 8168c and later */ 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci Config3 = 0x54, 2208c2ecf20Sopenharmony_ci Config4 = 0x55, 2218c2ecf20Sopenharmony_ci Config5 = 0x56, 2228c2ecf20Sopenharmony_ci PHYAR = 0x60, 2238c2ecf20Sopenharmony_ci PHYstatus = 0x6c, 2248c2ecf20Sopenharmony_ci RxMaxSize = 0xda, 2258c2ecf20Sopenharmony_ci CPlusCmd = 0xe0, 2268c2ecf20Sopenharmony_ci IntrMitigate = 0xe2, 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci#define RTL_COALESCE_TX_USECS GENMASK(15, 12) 2298c2ecf20Sopenharmony_ci#define RTL_COALESCE_TX_FRAMES GENMASK(11, 8) 2308c2ecf20Sopenharmony_ci#define RTL_COALESCE_RX_USECS GENMASK(7, 4) 2318c2ecf20Sopenharmony_ci#define RTL_COALESCE_RX_FRAMES GENMASK(3, 0) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#define RTL_COALESCE_T_MAX 0x0fU 2348c2ecf20Sopenharmony_ci#define RTL_COALESCE_FRAME_MAX (RTL_COALESCE_T_MAX * 4) 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci RxDescAddrLow = 0xe4, 2378c2ecf20Sopenharmony_ci RxDescAddrHigh = 0xe8, 2388c2ecf20Sopenharmony_ci EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */ 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define NoEarlyTx 0x3f /* Max value : no early transmit. */ 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci MaxTxPacketSize = 0xec, /* 8101/8168. Unit of 128 bytes. */ 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#define TxPacketMax (8064 >> 7) 2458c2ecf20Sopenharmony_ci#define EarlySize 0x27 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci FuncEvent = 0xf0, 2488c2ecf20Sopenharmony_ci FuncEventMask = 0xf4, 2498c2ecf20Sopenharmony_ci FuncPresetState = 0xf8, 2508c2ecf20Sopenharmony_ci IBCR0 = 0xf8, 2518c2ecf20Sopenharmony_ci IBCR2 = 0xf9, 2528c2ecf20Sopenharmony_ci IBIMR0 = 0xfa, 2538c2ecf20Sopenharmony_ci IBISR0 = 0xfb, 2548c2ecf20Sopenharmony_ci FuncForceEvent = 0xfc, 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cienum rtl8168_8101_registers { 2588c2ecf20Sopenharmony_ci CSIDR = 0x64, 2598c2ecf20Sopenharmony_ci CSIAR = 0x68, 2608c2ecf20Sopenharmony_ci#define CSIAR_FLAG 0x80000000 2618c2ecf20Sopenharmony_ci#define CSIAR_WRITE_CMD 0x80000000 2628c2ecf20Sopenharmony_ci#define CSIAR_BYTE_ENABLE 0x0000f000 2638c2ecf20Sopenharmony_ci#define CSIAR_ADDR_MASK 0x00000fff 2648c2ecf20Sopenharmony_ci PMCH = 0x6f, 2658c2ecf20Sopenharmony_ci EPHYAR = 0x80, 2668c2ecf20Sopenharmony_ci#define EPHYAR_FLAG 0x80000000 2678c2ecf20Sopenharmony_ci#define EPHYAR_WRITE_CMD 0x80000000 2688c2ecf20Sopenharmony_ci#define EPHYAR_REG_MASK 0x1f 2698c2ecf20Sopenharmony_ci#define EPHYAR_REG_SHIFT 16 2708c2ecf20Sopenharmony_ci#define EPHYAR_DATA_MASK 0xffff 2718c2ecf20Sopenharmony_ci DLLPR = 0xd0, 2728c2ecf20Sopenharmony_ci#define PFM_EN (1 << 6) 2738c2ecf20Sopenharmony_ci#define TX_10M_PS_EN (1 << 7) 2748c2ecf20Sopenharmony_ci DBG_REG = 0xd1, 2758c2ecf20Sopenharmony_ci#define FIX_NAK_1 (1 << 4) 2768c2ecf20Sopenharmony_ci#define FIX_NAK_2 (1 << 3) 2778c2ecf20Sopenharmony_ci TWSI = 0xd2, 2788c2ecf20Sopenharmony_ci MCU = 0xd3, 2798c2ecf20Sopenharmony_ci#define NOW_IS_OOB (1 << 7) 2808c2ecf20Sopenharmony_ci#define TX_EMPTY (1 << 5) 2818c2ecf20Sopenharmony_ci#define RX_EMPTY (1 << 4) 2828c2ecf20Sopenharmony_ci#define RXTX_EMPTY (TX_EMPTY | RX_EMPTY) 2838c2ecf20Sopenharmony_ci#define EN_NDP (1 << 3) 2848c2ecf20Sopenharmony_ci#define EN_OOB_RESET (1 << 2) 2858c2ecf20Sopenharmony_ci#define LINK_LIST_RDY (1 << 1) 2868c2ecf20Sopenharmony_ci EFUSEAR = 0xdc, 2878c2ecf20Sopenharmony_ci#define EFUSEAR_FLAG 0x80000000 2888c2ecf20Sopenharmony_ci#define EFUSEAR_WRITE_CMD 0x80000000 2898c2ecf20Sopenharmony_ci#define EFUSEAR_READ_CMD 0x00000000 2908c2ecf20Sopenharmony_ci#define EFUSEAR_REG_MASK 0x03ff 2918c2ecf20Sopenharmony_ci#define EFUSEAR_REG_SHIFT 8 2928c2ecf20Sopenharmony_ci#define EFUSEAR_DATA_MASK 0xff 2938c2ecf20Sopenharmony_ci MISC_1 = 0xf2, 2948c2ecf20Sopenharmony_ci#define PFM_D3COLD_EN (1 << 6) 2958c2ecf20Sopenharmony_ci}; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cienum rtl8168_registers { 2988c2ecf20Sopenharmony_ci LED_FREQ = 0x1a, 2998c2ecf20Sopenharmony_ci EEE_LED = 0x1b, 3008c2ecf20Sopenharmony_ci ERIDR = 0x70, 3018c2ecf20Sopenharmony_ci ERIAR = 0x74, 3028c2ecf20Sopenharmony_ci#define ERIAR_FLAG 0x80000000 3038c2ecf20Sopenharmony_ci#define ERIAR_WRITE_CMD 0x80000000 3048c2ecf20Sopenharmony_ci#define ERIAR_READ_CMD 0x00000000 3058c2ecf20Sopenharmony_ci#define ERIAR_ADDR_BYTE_ALIGN 4 3068c2ecf20Sopenharmony_ci#define ERIAR_TYPE_SHIFT 16 3078c2ecf20Sopenharmony_ci#define ERIAR_EXGMAC (0x00 << ERIAR_TYPE_SHIFT) 3088c2ecf20Sopenharmony_ci#define ERIAR_MSIX (0x01 << ERIAR_TYPE_SHIFT) 3098c2ecf20Sopenharmony_ci#define ERIAR_ASF (0x02 << ERIAR_TYPE_SHIFT) 3108c2ecf20Sopenharmony_ci#define ERIAR_OOB (0x02 << ERIAR_TYPE_SHIFT) 3118c2ecf20Sopenharmony_ci#define ERIAR_MASK_SHIFT 12 3128c2ecf20Sopenharmony_ci#define ERIAR_MASK_0001 (0x1 << ERIAR_MASK_SHIFT) 3138c2ecf20Sopenharmony_ci#define ERIAR_MASK_0011 (0x3 << ERIAR_MASK_SHIFT) 3148c2ecf20Sopenharmony_ci#define ERIAR_MASK_0100 (0x4 << ERIAR_MASK_SHIFT) 3158c2ecf20Sopenharmony_ci#define ERIAR_MASK_0101 (0x5 << ERIAR_MASK_SHIFT) 3168c2ecf20Sopenharmony_ci#define ERIAR_MASK_1111 (0xf << ERIAR_MASK_SHIFT) 3178c2ecf20Sopenharmony_ci EPHY_RXER_NUM = 0x7c, 3188c2ecf20Sopenharmony_ci OCPDR = 0xb0, /* OCP GPHY access */ 3198c2ecf20Sopenharmony_ci#define OCPDR_WRITE_CMD 0x80000000 3208c2ecf20Sopenharmony_ci#define OCPDR_READ_CMD 0x00000000 3218c2ecf20Sopenharmony_ci#define OCPDR_REG_MASK 0x7f 3228c2ecf20Sopenharmony_ci#define OCPDR_GPHY_REG_SHIFT 16 3238c2ecf20Sopenharmony_ci#define OCPDR_DATA_MASK 0xffff 3248c2ecf20Sopenharmony_ci OCPAR = 0xb4, 3258c2ecf20Sopenharmony_ci#define OCPAR_FLAG 0x80000000 3268c2ecf20Sopenharmony_ci#define OCPAR_GPHY_WRITE_CMD 0x8000f060 3278c2ecf20Sopenharmony_ci#define OCPAR_GPHY_READ_CMD 0x0000f060 3288c2ecf20Sopenharmony_ci GPHY_OCP = 0xb8, 3298c2ecf20Sopenharmony_ci RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */ 3308c2ecf20Sopenharmony_ci MISC = 0xf0, /* 8168e only. */ 3318c2ecf20Sopenharmony_ci#define TXPLA_RST (1 << 29) 3328c2ecf20Sopenharmony_ci#define DISABLE_LAN_EN (1 << 23) /* Enable GPIO pin */ 3338c2ecf20Sopenharmony_ci#define PWM_EN (1 << 22) 3348c2ecf20Sopenharmony_ci#define RXDV_GATED_EN (1 << 19) 3358c2ecf20Sopenharmony_ci#define EARLY_TALLY_EN (1 << 16) 3368c2ecf20Sopenharmony_ci}; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cienum rtl8125_registers { 3398c2ecf20Sopenharmony_ci IntrMask_8125 = 0x38, 3408c2ecf20Sopenharmony_ci IntrStatus_8125 = 0x3c, 3418c2ecf20Sopenharmony_ci TxPoll_8125 = 0x90, 3428c2ecf20Sopenharmony_ci MAC0_BKP = 0x19e0, 3438c2ecf20Sopenharmony_ci EEE_TXIDLE_TIMER_8125 = 0x6048, 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci#define RX_VLAN_INNER_8125 BIT(22) 3478c2ecf20Sopenharmony_ci#define RX_VLAN_OUTER_8125 BIT(23) 3488c2ecf20Sopenharmony_ci#define RX_VLAN_8125 (RX_VLAN_INNER_8125 | RX_VLAN_OUTER_8125) 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci#define RX_FETCH_DFLT_8125 (8 << 27) 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cienum rtl_register_content { 3538c2ecf20Sopenharmony_ci /* InterruptStatusBits */ 3548c2ecf20Sopenharmony_ci SYSErr = 0x8000, 3558c2ecf20Sopenharmony_ci PCSTimeout = 0x4000, 3568c2ecf20Sopenharmony_ci SWInt = 0x0100, 3578c2ecf20Sopenharmony_ci TxDescUnavail = 0x0080, 3588c2ecf20Sopenharmony_ci RxFIFOOver = 0x0040, 3598c2ecf20Sopenharmony_ci LinkChg = 0x0020, 3608c2ecf20Sopenharmony_ci RxOverflow = 0x0010, 3618c2ecf20Sopenharmony_ci TxErr = 0x0008, 3628c2ecf20Sopenharmony_ci TxOK = 0x0004, 3638c2ecf20Sopenharmony_ci RxErr = 0x0002, 3648c2ecf20Sopenharmony_ci RxOK = 0x0001, 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* RxStatusDesc */ 3678c2ecf20Sopenharmony_ci RxRWT = (1 << 22), 3688c2ecf20Sopenharmony_ci RxRES = (1 << 21), 3698c2ecf20Sopenharmony_ci RxRUNT = (1 << 20), 3708c2ecf20Sopenharmony_ci RxCRC = (1 << 19), 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* ChipCmdBits */ 3738c2ecf20Sopenharmony_ci StopReq = 0x80, 3748c2ecf20Sopenharmony_ci CmdReset = 0x10, 3758c2ecf20Sopenharmony_ci CmdRxEnb = 0x08, 3768c2ecf20Sopenharmony_ci CmdTxEnb = 0x04, 3778c2ecf20Sopenharmony_ci RxBufEmpty = 0x01, 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* TXPoll register p.5 */ 3808c2ecf20Sopenharmony_ci HPQ = 0x80, /* Poll cmd on the high prio queue */ 3818c2ecf20Sopenharmony_ci NPQ = 0x40, /* Poll cmd on the low prio queue */ 3828c2ecf20Sopenharmony_ci FSWInt = 0x01, /* Forced software interrupt */ 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Cfg9346Bits */ 3858c2ecf20Sopenharmony_ci Cfg9346_Lock = 0x00, 3868c2ecf20Sopenharmony_ci Cfg9346_Unlock = 0xc0, 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* rx_mode_bits */ 3898c2ecf20Sopenharmony_ci AcceptErr = 0x20, 3908c2ecf20Sopenharmony_ci AcceptRunt = 0x10, 3918c2ecf20Sopenharmony_ci#define RX_CONFIG_ACCEPT_ERR_MASK 0x30 3928c2ecf20Sopenharmony_ci AcceptBroadcast = 0x08, 3938c2ecf20Sopenharmony_ci AcceptMulticast = 0x04, 3948c2ecf20Sopenharmony_ci AcceptMyPhys = 0x02, 3958c2ecf20Sopenharmony_ci AcceptAllPhys = 0x01, 3968c2ecf20Sopenharmony_ci#define RX_CONFIG_ACCEPT_OK_MASK 0x0f 3978c2ecf20Sopenharmony_ci#define RX_CONFIG_ACCEPT_MASK 0x3f 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* TxConfigBits */ 4008c2ecf20Sopenharmony_ci TxInterFrameGapShift = 24, 4018c2ecf20Sopenharmony_ci TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Config1 register p.24 */ 4048c2ecf20Sopenharmony_ci LEDS1 = (1 << 7), 4058c2ecf20Sopenharmony_ci LEDS0 = (1 << 6), 4068c2ecf20Sopenharmony_ci Speed_down = (1 << 4), 4078c2ecf20Sopenharmony_ci MEMMAP = (1 << 3), 4088c2ecf20Sopenharmony_ci IOMAP = (1 << 2), 4098c2ecf20Sopenharmony_ci VPD = (1 << 1), 4108c2ecf20Sopenharmony_ci PMEnable = (1 << 0), /* Power Management Enable */ 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Config2 register p. 25 */ 4138c2ecf20Sopenharmony_ci ClkReqEn = (1 << 7), /* Clock Request Enable */ 4148c2ecf20Sopenharmony_ci MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */ 4158c2ecf20Sopenharmony_ci PCI_Clock_66MHz = 0x01, 4168c2ecf20Sopenharmony_ci PCI_Clock_33MHz = 0x00, 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* Config3 register p.25 */ 4198c2ecf20Sopenharmony_ci MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ 4208c2ecf20Sopenharmony_ci LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ 4218c2ecf20Sopenharmony_ci Jumbo_En0 = (1 << 2), /* 8168 only. Reserved in the 8168b */ 4228c2ecf20Sopenharmony_ci Rdy_to_L23 = (1 << 1), /* L23 Enable */ 4238c2ecf20Sopenharmony_ci Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */ 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Config4 register */ 4268c2ecf20Sopenharmony_ci Jumbo_En1 = (1 << 1), /* 8168 only. Reserved in the 8168b */ 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* Config5 register p.27 */ 4298c2ecf20Sopenharmony_ci BWF = (1 << 6), /* Accept Broadcast wakeup frame */ 4308c2ecf20Sopenharmony_ci MWF = (1 << 5), /* Accept Multicast wakeup frame */ 4318c2ecf20Sopenharmony_ci UWF = (1 << 4), /* Accept Unicast wakeup frame */ 4328c2ecf20Sopenharmony_ci Spi_en = (1 << 3), 4338c2ecf20Sopenharmony_ci LanWake = (1 << 1), /* LanWake enable/disable */ 4348c2ecf20Sopenharmony_ci PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ 4358c2ecf20Sopenharmony_ci ASPM_en = (1 << 0), /* ASPM enable */ 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* CPlusCmd p.31 */ 4388c2ecf20Sopenharmony_ci EnableBist = (1 << 15), // 8168 8101 4398c2ecf20Sopenharmony_ci Mac_dbgo_oe = (1 << 14), // 8168 8101 4408c2ecf20Sopenharmony_ci EnAnaPLL = (1 << 14), // 8169 4418c2ecf20Sopenharmony_ci Normal_mode = (1 << 13), // unused 4428c2ecf20Sopenharmony_ci Force_half_dup = (1 << 12), // 8168 8101 4438c2ecf20Sopenharmony_ci Force_rxflow_en = (1 << 11), // 8168 8101 4448c2ecf20Sopenharmony_ci Force_txflow_en = (1 << 10), // 8168 8101 4458c2ecf20Sopenharmony_ci Cxpl_dbg_sel = (1 << 9), // 8168 8101 4468c2ecf20Sopenharmony_ci ASF = (1 << 8), // 8168 8101 4478c2ecf20Sopenharmony_ci PktCntrDisable = (1 << 7), // 8168 8101 4488c2ecf20Sopenharmony_ci Mac_dbgo_sel = 0x001c, // 8168 4498c2ecf20Sopenharmony_ci RxVlan = (1 << 6), 4508c2ecf20Sopenharmony_ci RxChkSum = (1 << 5), 4518c2ecf20Sopenharmony_ci PCIDAC = (1 << 4), 4528c2ecf20Sopenharmony_ci PCIMulRW = (1 << 3), 4538c2ecf20Sopenharmony_ci#define INTT_MASK GENMASK(1, 0) 4548c2ecf20Sopenharmony_ci#define CPCMD_MASK (Normal_mode | RxVlan | RxChkSum | INTT_MASK) 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* rtl8169_PHYstatus */ 4578c2ecf20Sopenharmony_ci TBI_Enable = 0x80, 4588c2ecf20Sopenharmony_ci TxFlowCtrl = 0x40, 4598c2ecf20Sopenharmony_ci RxFlowCtrl = 0x20, 4608c2ecf20Sopenharmony_ci _1000bpsF = 0x10, 4618c2ecf20Sopenharmony_ci _100bps = 0x08, 4628c2ecf20Sopenharmony_ci _10bps = 0x04, 4638c2ecf20Sopenharmony_ci LinkStatus = 0x02, 4648c2ecf20Sopenharmony_ci FullDup = 0x01, 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* ResetCounterCommand */ 4678c2ecf20Sopenharmony_ci CounterReset = 0x1, 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* DumpCounterCommand */ 4708c2ecf20Sopenharmony_ci CounterDump = 0x8, 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* magic enable v2 */ 4738c2ecf20Sopenharmony_ci MagicPacket_v2 = (1 << 16), /* Wake up when receives a Magic Packet */ 4748c2ecf20Sopenharmony_ci}; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cienum rtl_desc_bit { 4778c2ecf20Sopenharmony_ci /* First doubleword. */ 4788c2ecf20Sopenharmony_ci DescOwn = (1 << 31), /* Descriptor is owned by NIC */ 4798c2ecf20Sopenharmony_ci RingEnd = (1 << 30), /* End of descriptor ring */ 4808c2ecf20Sopenharmony_ci FirstFrag = (1 << 29), /* First segment of a packet */ 4818c2ecf20Sopenharmony_ci LastFrag = (1 << 28), /* Final segment of a packet */ 4828c2ecf20Sopenharmony_ci}; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci/* Generic case. */ 4858c2ecf20Sopenharmony_cienum rtl_tx_desc_bit { 4868c2ecf20Sopenharmony_ci /* First doubleword. */ 4878c2ecf20Sopenharmony_ci TD_LSO = (1 << 27), /* Large Send Offload */ 4888c2ecf20Sopenharmony_ci#define TD_MSS_MAX 0x07ffu /* MSS value */ 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* Second doubleword. */ 4918c2ecf20Sopenharmony_ci TxVlanTag = (1 << 17), /* Add VLAN tag */ 4928c2ecf20Sopenharmony_ci}; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* 8169, 8168b and 810x except 8102e. */ 4958c2ecf20Sopenharmony_cienum rtl_tx_desc_bit_0 { 4968c2ecf20Sopenharmony_ci /* First doubleword. */ 4978c2ecf20Sopenharmony_ci#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */ 4988c2ecf20Sopenharmony_ci TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */ 4998c2ecf20Sopenharmony_ci TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */ 5008c2ecf20Sopenharmony_ci TD0_IP_CS = (1 << 18), /* Calculate IP checksum */ 5018c2ecf20Sopenharmony_ci}; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/* 8102e, 8168c and beyond. */ 5048c2ecf20Sopenharmony_cienum rtl_tx_desc_bit_1 { 5058c2ecf20Sopenharmony_ci /* First doubleword. */ 5068c2ecf20Sopenharmony_ci TD1_GTSENV4 = (1 << 26), /* Giant Send for IPv4 */ 5078c2ecf20Sopenharmony_ci TD1_GTSENV6 = (1 << 25), /* Giant Send for IPv6 */ 5088c2ecf20Sopenharmony_ci#define GTTCPHO_SHIFT 18 5098c2ecf20Sopenharmony_ci#define GTTCPHO_MAX 0x7f 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* Second doubleword. */ 5128c2ecf20Sopenharmony_ci#define TCPHO_SHIFT 18 5138c2ecf20Sopenharmony_ci#define TCPHO_MAX 0x3ff 5148c2ecf20Sopenharmony_ci#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */ 5158c2ecf20Sopenharmony_ci TD1_IPv6_CS = (1 << 28), /* Calculate IPv6 checksum */ 5168c2ecf20Sopenharmony_ci TD1_IPv4_CS = (1 << 29), /* Calculate IPv4 checksum */ 5178c2ecf20Sopenharmony_ci TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */ 5188c2ecf20Sopenharmony_ci TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */ 5198c2ecf20Sopenharmony_ci}; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cienum rtl_rx_desc_bit { 5228c2ecf20Sopenharmony_ci /* Rx private */ 5238c2ecf20Sopenharmony_ci PID1 = (1 << 18), /* Protocol ID bit 1/2 */ 5248c2ecf20Sopenharmony_ci PID0 = (1 << 17), /* Protocol ID bit 0/2 */ 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci#define RxProtoUDP (PID1) 5278c2ecf20Sopenharmony_ci#define RxProtoTCP (PID0) 5288c2ecf20Sopenharmony_ci#define RxProtoIP (PID1 | PID0) 5298c2ecf20Sopenharmony_ci#define RxProtoMask RxProtoIP 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci IPFail = (1 << 16), /* IP checksum failed */ 5328c2ecf20Sopenharmony_ci UDPFail = (1 << 15), /* UDP/IP checksum failed */ 5338c2ecf20Sopenharmony_ci TCPFail = (1 << 14), /* TCP/IP checksum failed */ 5348c2ecf20Sopenharmony_ci RxVlanTag = (1 << 16), /* VLAN tag available */ 5358c2ecf20Sopenharmony_ci}; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci#define RTL_GSO_MAX_SIZE_V1 32000 5388c2ecf20Sopenharmony_ci#define RTL_GSO_MAX_SEGS_V1 24 5398c2ecf20Sopenharmony_ci#define RTL_GSO_MAX_SIZE_V2 64000 5408c2ecf20Sopenharmony_ci#define RTL_GSO_MAX_SEGS_V2 64 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistruct TxDesc { 5438c2ecf20Sopenharmony_ci __le32 opts1; 5448c2ecf20Sopenharmony_ci __le32 opts2; 5458c2ecf20Sopenharmony_ci __le64 addr; 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistruct RxDesc { 5498c2ecf20Sopenharmony_ci __le32 opts1; 5508c2ecf20Sopenharmony_ci __le32 opts2; 5518c2ecf20Sopenharmony_ci __le64 addr; 5528c2ecf20Sopenharmony_ci}; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistruct ring_info { 5558c2ecf20Sopenharmony_ci struct sk_buff *skb; 5568c2ecf20Sopenharmony_ci u32 len; 5578c2ecf20Sopenharmony_ci}; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistruct rtl8169_counters { 5608c2ecf20Sopenharmony_ci __le64 tx_packets; 5618c2ecf20Sopenharmony_ci __le64 rx_packets; 5628c2ecf20Sopenharmony_ci __le64 tx_errors; 5638c2ecf20Sopenharmony_ci __le32 rx_errors; 5648c2ecf20Sopenharmony_ci __le16 rx_missed; 5658c2ecf20Sopenharmony_ci __le16 align_errors; 5668c2ecf20Sopenharmony_ci __le32 tx_one_collision; 5678c2ecf20Sopenharmony_ci __le32 tx_multi_collision; 5688c2ecf20Sopenharmony_ci __le64 rx_unicast; 5698c2ecf20Sopenharmony_ci __le64 rx_broadcast; 5708c2ecf20Sopenharmony_ci __le32 rx_multicast; 5718c2ecf20Sopenharmony_ci __le16 tx_aborted; 5728c2ecf20Sopenharmony_ci __le16 tx_underun; 5738c2ecf20Sopenharmony_ci}; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistruct rtl8169_tc_offsets { 5768c2ecf20Sopenharmony_ci bool inited; 5778c2ecf20Sopenharmony_ci __le64 tx_errors; 5788c2ecf20Sopenharmony_ci __le32 tx_multi_collision; 5798c2ecf20Sopenharmony_ci __le16 tx_aborted; 5808c2ecf20Sopenharmony_ci __le16 rx_missed; 5818c2ecf20Sopenharmony_ci}; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cienum rtl_flag { 5848c2ecf20Sopenharmony_ci RTL_FLAG_TASK_ENABLED = 0, 5858c2ecf20Sopenharmony_ci RTL_FLAG_TASK_RESET_PENDING, 5868c2ecf20Sopenharmony_ci RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, 5878c2ecf20Sopenharmony_ci RTL_FLAG_TASK_TX_TIMEOUT, 5888c2ecf20Sopenharmony_ci RTL_FLAG_MAX 5898c2ecf20Sopenharmony_ci}; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistruct rtl8169_stats { 5928c2ecf20Sopenharmony_ci u64 packets; 5938c2ecf20Sopenharmony_ci u64 bytes; 5948c2ecf20Sopenharmony_ci struct u64_stats_sync syncp; 5958c2ecf20Sopenharmony_ci}; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistruct rtl8169_private { 5988c2ecf20Sopenharmony_ci void __iomem *mmio_addr; /* memory map physical address */ 5998c2ecf20Sopenharmony_ci struct pci_dev *pci_dev; 6008c2ecf20Sopenharmony_ci struct net_device *dev; 6018c2ecf20Sopenharmony_ci struct phy_device *phydev; 6028c2ecf20Sopenharmony_ci struct napi_struct napi; 6038c2ecf20Sopenharmony_ci enum mac_version mac_version; 6048c2ecf20Sopenharmony_ci u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ 6058c2ecf20Sopenharmony_ci u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ 6068c2ecf20Sopenharmony_ci u32 dirty_tx; 6078c2ecf20Sopenharmony_ci struct rtl8169_stats rx_stats; 6088c2ecf20Sopenharmony_ci struct rtl8169_stats tx_stats; 6098c2ecf20Sopenharmony_ci struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */ 6108c2ecf20Sopenharmony_ci struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */ 6118c2ecf20Sopenharmony_ci dma_addr_t TxPhyAddr; 6128c2ecf20Sopenharmony_ci dma_addr_t RxPhyAddr; 6138c2ecf20Sopenharmony_ci struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ 6148c2ecf20Sopenharmony_ci struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */ 6158c2ecf20Sopenharmony_ci u16 cp_cmd; 6168c2ecf20Sopenharmony_ci u32 irq_mask; 6178c2ecf20Sopenharmony_ci struct clk *clk; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci struct { 6208c2ecf20Sopenharmony_ci DECLARE_BITMAP(flags, RTL_FLAG_MAX); 6218c2ecf20Sopenharmony_ci struct work_struct work; 6228c2ecf20Sopenharmony_ci } wk; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci unsigned supports_gmii:1; 6258c2ecf20Sopenharmony_ci unsigned aspm_manageable:1; 6268c2ecf20Sopenharmony_ci dma_addr_t counters_phys_addr; 6278c2ecf20Sopenharmony_ci struct rtl8169_counters *counters; 6288c2ecf20Sopenharmony_ci struct rtl8169_tc_offsets tc_offset; 6298c2ecf20Sopenharmony_ci u32 saved_wolopts; 6308c2ecf20Sopenharmony_ci int eee_adv; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci const char *fw_name; 6338c2ecf20Sopenharmony_ci struct rtl_fw *rtl_fw; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci u32 ocp_base; 6368c2ecf20Sopenharmony_ci}; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_citypedef void (*rtl_generic_fct)(struct rtl8169_private *tp); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>"); 6418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); 6428c2ecf20Sopenharmony_ciMODULE_SOFTDEP("pre: realtek"); 6438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6448c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168D_1); 6458c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168D_2); 6468c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168E_1); 6478c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168E_2); 6488c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168E_3); 6498c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8105E_1); 6508c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168F_1); 6518c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168F_2); 6528c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8402_1); 6538c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8411_1); 6548c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8411_2); 6558c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8106E_1); 6568c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8106E_2); 6578c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168G_2); 6588c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168G_3); 6598c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168H_1); 6608c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168H_2); 6618c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8168FP_3); 6628c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8107E_1); 6638c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8107E_2); 6648c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8125A_3); 6658c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_8125B_2); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic inline struct device *tp_to_dev(struct rtl8169_private *tp) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci return &tp->pci_dev->dev; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic void rtl_lock_config_regs(struct rtl8169_private *tp) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci RTL_W8(tp, Cfg9346, Cfg9346_Lock); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic void rtl_unlock_config_regs(struct rtl8169_private *tp) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci RTL_W8(tp, Cfg9346, Cfg9346_Unlock); 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic void rtl_pci_commit(struct rtl8169_private *tp) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci /* Read an arbitrary register to commit a preceding PCI write */ 6858c2ecf20Sopenharmony_ci RTL_R8(tp, ChipCmd); 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic bool rtl_is_8125(struct rtl8169_private *tp) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci return tp->mac_version >= RTL_GIGA_MAC_VER_60; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic bool rtl_is_8168evl_up(struct rtl8169_private *tp) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci return tp->mac_version >= RTL_GIGA_MAC_VER_34 && 6968c2ecf20Sopenharmony_ci tp->mac_version != RTL_GIGA_MAC_VER_39 && 6978c2ecf20Sopenharmony_ci tp->mac_version <= RTL_GIGA_MAC_VER_52; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic bool rtl_supports_eee(struct rtl8169_private *tp) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci return tp->mac_version >= RTL_GIGA_MAC_VER_34 && 7038c2ecf20Sopenharmony_ci tp->mac_version != RTL_GIGA_MAC_VER_37 && 7048c2ecf20Sopenharmony_ci tp->mac_version != RTL_GIGA_MAC_VER_39; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic void rtl_get_priv_stats(struct rtl8169_stats *stats, 7088c2ecf20Sopenharmony_ci u64 *pkts, u64 *bytes) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci unsigned int start; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci do { 7138c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&stats->syncp); 7148c2ecf20Sopenharmony_ci *pkts = stats->packets; 7158c2ecf20Sopenharmony_ci *bytes = stats->bytes; 7168c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic void rtl_inc_priv_stats(struct rtl8169_stats *stats, 7208c2ecf20Sopenharmony_ci u64 pkts, u64 bytes) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 7238c2ecf20Sopenharmony_ci stats->packets += pkts; 7248c2ecf20Sopenharmony_ci stats->bytes += bytes; 7258c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic void rtl_read_mac_from_reg(struct rtl8169_private *tp, u8 *mac, int reg) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci int i; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 7338c2ecf20Sopenharmony_ci mac[i] = RTL_R8(tp, reg + i); 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistruct rtl_cond { 7378c2ecf20Sopenharmony_ci bool (*check)(struct rtl8169_private *); 7388c2ecf20Sopenharmony_ci const char *msg; 7398c2ecf20Sopenharmony_ci}; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c, 7428c2ecf20Sopenharmony_ci unsigned long usecs, int n, bool high) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci int i; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 7478c2ecf20Sopenharmony_ci if (c->check(tp) == high) 7488c2ecf20Sopenharmony_ci return true; 7498c2ecf20Sopenharmony_ci fsleep(usecs); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (net_ratelimit()) 7538c2ecf20Sopenharmony_ci netdev_err(tp->dev, "%s == %d (loop: %d, delay: %lu).\n", 7548c2ecf20Sopenharmony_ci c->msg, !high, n, usecs); 7558c2ecf20Sopenharmony_ci return false; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic bool rtl_loop_wait_high(struct rtl8169_private *tp, 7598c2ecf20Sopenharmony_ci const struct rtl_cond *c, 7608c2ecf20Sopenharmony_ci unsigned long d, int n) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci return rtl_loop_wait(tp, c, d, n, true); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic bool rtl_loop_wait_low(struct rtl8169_private *tp, 7668c2ecf20Sopenharmony_ci const struct rtl_cond *c, 7678c2ecf20Sopenharmony_ci unsigned long d, int n) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci return rtl_loop_wait(tp, c, d, n, false); 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci#define DECLARE_RTL_COND(name) \ 7738c2ecf20Sopenharmony_cistatic bool name ## _check(struct rtl8169_private *); \ 7748c2ecf20Sopenharmony_ci \ 7758c2ecf20Sopenharmony_cistatic const struct rtl_cond name = { \ 7768c2ecf20Sopenharmony_ci .check = name ## _check, \ 7778c2ecf20Sopenharmony_ci .msg = #name \ 7788c2ecf20Sopenharmony_ci}; \ 7798c2ecf20Sopenharmony_ci \ 7808c2ecf20Sopenharmony_cistatic bool name ## _check(struct rtl8169_private *tp) 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci if (reg & 0xffff0001) { 7858c2ecf20Sopenharmony_ci if (net_ratelimit()) 7868c2ecf20Sopenharmony_ci netdev_err(tp->dev, "Invalid ocp reg %x!\n", reg); 7878c2ecf20Sopenharmony_ci return true; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci return false; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_ocp_gphy_cond) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci return RTL_R32(tp, GPHY_OCP) & OCPAR_FLAG; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci if (rtl_ocp_reg_failure(tp, reg)) 8008c2ecf20Sopenharmony_ci return; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci RTL_W32(tp, GPHY_OCP, OCPAR_FLAG | (reg << 15) | data); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10); 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci if (rtl_ocp_reg_failure(tp, reg)) 8108c2ecf20Sopenharmony_ci return 0; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci RTL_W32(tp, GPHY_OCP, reg << 15); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return rtl_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ? 8158c2ecf20Sopenharmony_ci (RTL_R32(tp, GPHY_OCP) & 0xffff) : -ETIMEDOUT; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci if (rtl_ocp_reg_failure(tp, reg)) 8218c2ecf20Sopenharmony_ci return; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci RTL_W32(tp, OCPDR, OCPAR_FLAG | (reg << 15) | data); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci if (rtl_ocp_reg_failure(tp, reg)) 8298c2ecf20Sopenharmony_ci return 0; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci RTL_W32(tp, OCPDR, reg << 15); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return RTL_R32(tp, OCPDR); 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic void r8168_mac_ocp_modify(struct rtl8169_private *tp, u32 reg, u16 mask, 8378c2ecf20Sopenharmony_ci u16 set) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci u16 data = r8168_mac_ocp_read(tp, reg); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, reg, (data & ~mask) | set); 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci if (reg == 0x1f) { 8478c2ecf20Sopenharmony_ci tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE; 8488c2ecf20Sopenharmony_ci return; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (tp->ocp_base != OCP_STD_PHY_BASE) 8528c2ecf20Sopenharmony_ci reg -= 0x10; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value); 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int r8168g_mdio_read(struct rtl8169_private *tp, int reg) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci if (reg == 0x1f) 8608c2ecf20Sopenharmony_ci return tp->ocp_base == OCP_STD_PHY_BASE ? 0 : tp->ocp_base >> 4; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (tp->ocp_base != OCP_STD_PHY_BASE) 8638c2ecf20Sopenharmony_ci reg -= 0x10; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2); 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic void mac_mcu_write(struct rtl8169_private *tp, int reg, int value) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci if (reg == 0x1f) { 8718c2ecf20Sopenharmony_ci tp->ocp_base = value << 4; 8728c2ecf20Sopenharmony_ci return; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, tp->ocp_base + reg, value); 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic int mac_mcu_read(struct rtl8169_private *tp, int reg) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci return r8168_mac_ocp_read(tp, tp->ocp_base + reg); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_phyar_cond) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci return RTL_R32(tp, PHYAR) & 0x80000000; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci RTL_W32(tp, PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff)); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_phyar_cond, 25, 20); 8938c2ecf20Sopenharmony_ci /* 8948c2ecf20Sopenharmony_ci * According to hardware specs a 20us delay is required after write 8958c2ecf20Sopenharmony_ci * complete indication, but before sending next command. 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_ci udelay(20); 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic int r8169_mdio_read(struct rtl8169_private *tp, int reg) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci int value; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci RTL_W32(tp, PHYAR, 0x0 | (reg & 0x1f) << 16); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci value = rtl_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ? 9078c2ecf20Sopenharmony_ci RTL_R32(tp, PHYAR) & 0xffff : -ETIMEDOUT; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* 9108c2ecf20Sopenharmony_ci * According to hardware specs a 20us delay is required after read 9118c2ecf20Sopenharmony_ci * complete indication, but before sending next command. 9128c2ecf20Sopenharmony_ci */ 9138c2ecf20Sopenharmony_ci udelay(20); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return value; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_ocpar_cond) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci return RTL_R32(tp, OCPAR) & OCPAR_FLAG; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci RTL_W32(tp, OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT)); 9268c2ecf20Sopenharmony_ci RTL_W32(tp, OCPAR, OCPAR_GPHY_WRITE_CMD); 9278c2ecf20Sopenharmony_ci RTL_W32(tp, EPHY_RXER_NUM, 0); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100); 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci r8168dp_1_mdio_access(tp, reg, 9358c2ecf20Sopenharmony_ci OCPDR_WRITE_CMD | (value & OCPDR_DATA_MASK)); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci r8168dp_1_mdio_access(tp, reg, OCPDR_READ_CMD); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci mdelay(1); 9438c2ecf20Sopenharmony_ci RTL_W32(tp, OCPAR, OCPAR_GPHY_READ_CMD); 9448c2ecf20Sopenharmony_ci RTL_W32(tp, EPHY_RXER_NUM, 0); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci return rtl_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ? 9478c2ecf20Sopenharmony_ci RTL_R32(tp, OCPDR) & OCPDR_DATA_MASK : -ETIMEDOUT; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic void r8168dp_2_mdio_start(struct rtl8169_private *tp) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci RTL_W32(tp, 0xd0, RTL_R32(tp, 0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic void r8168dp_2_mdio_stop(struct rtl8169_private *tp) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci RTL_W32(tp, 0xd0, RTL_R32(tp, 0xd0) | R8168DP_1_MDIO_ACCESS_BIT); 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci r8168dp_2_mdio_start(tp); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci r8169_mdio_write(tp, reg, value); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci r8168dp_2_mdio_stop(tp); 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci int value; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* Work around issue with chip reporting wrong PHY ID */ 9768c2ecf20Sopenharmony_ci if (reg == MII_PHYSID2) 9778c2ecf20Sopenharmony_ci return 0xc912; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci r8168dp_2_mdio_start(tp); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci value = r8169_mdio_read(tp, reg); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci r8168dp_2_mdio_stop(tp); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci return value; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic void rtl_writephy(struct rtl8169_private *tp, int location, int val) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci switch (tp->mac_version) { 9918c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_27: 9928c2ecf20Sopenharmony_ci r8168dp_1_mdio_write(tp, location, val); 9938c2ecf20Sopenharmony_ci break; 9948c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_28: 9958c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_31: 9968c2ecf20Sopenharmony_ci r8168dp_2_mdio_write(tp, location, val); 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: 9998c2ecf20Sopenharmony_ci r8168g_mdio_write(tp, location, val); 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci default: 10028c2ecf20Sopenharmony_ci r8169_mdio_write(tp, location, val); 10038c2ecf20Sopenharmony_ci break; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic int rtl_readphy(struct rtl8169_private *tp, int location) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci switch (tp->mac_version) { 10108c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_27: 10118c2ecf20Sopenharmony_ci return r8168dp_1_mdio_read(tp, location); 10128c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_28: 10138c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_31: 10148c2ecf20Sopenharmony_ci return r8168dp_2_mdio_read(tp, location); 10158c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: 10168c2ecf20Sopenharmony_ci return r8168g_mdio_read(tp, location); 10178c2ecf20Sopenharmony_ci default: 10188c2ecf20Sopenharmony_ci return r8169_mdio_read(tp, location); 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_ephyar_cond) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci return RTL_R32(tp, EPHYAR) & EPHYAR_FLAG; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci RTL_W32(tp, EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) | 10308c2ecf20Sopenharmony_ci (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci udelay(10); 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci RTL_W32(tp, EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci return rtl_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ? 10428c2ecf20Sopenharmony_ci RTL_R32(tp, EPHYAR) & EPHYAR_DATA_MASK : ~0; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci /* based on RTL8168FP_OOBMAC_BASE in vendor driver */ 10488c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_52 && type == ERIAR_OOB) 10498c2ecf20Sopenharmony_ci *cmd |= 0xf70 << 18; 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_eriar_cond) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci return RTL_R32(tp, ERIAR) & ERIAR_FLAG; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic void _rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask, 10588c2ecf20Sopenharmony_ci u32 val, int type) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci u32 cmd = ERIAR_WRITE_CMD | type | mask | addr; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci BUG_ON((addr & 3) || (mask == 0)); 10638c2ecf20Sopenharmony_ci RTL_W32(tp, ERIDR, val); 10648c2ecf20Sopenharmony_ci r8168fp_adjust_ocp_cmd(tp, &cmd, type); 10658c2ecf20Sopenharmony_ci RTL_W32(tp, ERIAR, cmd); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_eriar_cond, 100, 100); 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cistatic void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask, 10718c2ecf20Sopenharmony_ci u32 val) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci _rtl_eri_write(tp, addr, mask, val, ERIAR_EXGMAC); 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic u32 _rtl_eri_read(struct rtl8169_private *tp, int addr, int type) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci u32 cmd = ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci r8168fp_adjust_ocp_cmd(tp, &cmd, type); 10818c2ecf20Sopenharmony_ci RTL_W32(tp, ERIAR, cmd); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci return rtl_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ? 10848c2ecf20Sopenharmony_ci RTL_R32(tp, ERIDR) : ~0; 10858c2ecf20Sopenharmony_ci} 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic u32 rtl_eri_read(struct rtl8169_private *tp, int addr) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci return _rtl_eri_read(tp, addr, ERIAR_EXGMAC); 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic void rtl_w0w1_eri(struct rtl8169_private *tp, int addr, u32 p, u32 m) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci u32 val = rtl_eri_read(tp, addr); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci rtl_eri_write(tp, addr, ERIAR_MASK_1111, (val & ~m) | p); 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic void rtl_eri_set_bits(struct rtl8169_private *tp, int addr, u32 p) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci rtl_w0w1_eri(tp, addr, p, 0); 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic void rtl_eri_clear_bits(struct rtl8169_private *tp, int addr, u32 m) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci rtl_w0w1_eri(tp, addr, 0, m); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic u32 r8168dp_ocp_read(struct rtl8169_private *tp, u16 reg) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci RTL_W32(tp, OCPAR, 0x0fu << 12 | (reg & 0x0fff)); 11128c2ecf20Sopenharmony_ci return rtl_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ? 11138c2ecf20Sopenharmony_ci RTL_R32(tp, OCPDR) : ~0; 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic u32 r8168ep_ocp_read(struct rtl8169_private *tp, u16 reg) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci return _rtl_eri_read(tp, reg, ERIAR_OOB); 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic void r8168dp_ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, 11228c2ecf20Sopenharmony_ci u32 data) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci RTL_W32(tp, OCPDR, data); 11258c2ecf20Sopenharmony_ci RTL_W32(tp, OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff)); 11268c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20); 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic void r8168ep_ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, 11308c2ecf20Sopenharmony_ci u32 data) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci _rtl_eri_write(tp, reg, ((u32)mask & 0x0f) << ERIAR_MASK_SHIFT, 11338c2ecf20Sopenharmony_ci data, ERIAR_OOB); 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cistatic void r8168dp_oob_notify(struct rtl8169_private *tp, u8 cmd) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xe8, ERIAR_MASK_0001, cmd); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci r8168dp_ocp_write(tp, 0x1, 0x30, 0x00000001); 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci#define OOB_CMD_RESET 0x00 11448c2ecf20Sopenharmony_ci#define OOB_CMD_DRIVER_START 0x05 11458c2ecf20Sopenharmony_ci#define OOB_CMD_DRIVER_STOP 0x06 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_dp_ocp_read_cond) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci u16 reg; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci reg = rtl8168_get_ocp_reg(tp); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci return r8168dp_ocp_read(tp, reg) & 0x00000800; 11598c2ecf20Sopenharmony_ci} 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_ep_ocp_read_cond) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci return r8168ep_ocp_read(tp, 0x124) & 0x00000001; 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_ocp_tx_cond) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci return RTL_R8(tp, IBISR0) & 0x20; 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cistatic void rtl8168ep_stop_cmac(struct rtl8169_private *tp) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci RTL_W8(tp, IBCR2, RTL_R8(tp, IBCR2) & ~0x01); 11748c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_ocp_tx_cond, 50000, 2000); 11758c2ecf20Sopenharmony_ci RTL_W8(tp, IBISR0, RTL_R8(tp, IBISR0) | 0x20); 11768c2ecf20Sopenharmony_ci RTL_W8(tp, IBCR0, RTL_R8(tp, IBCR0) & ~0x01); 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic void rtl8168dp_driver_start(struct rtl8169_private *tp) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci r8168dp_oob_notify(tp, OOB_CMD_DRIVER_START); 11828c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cistatic void rtl8168ep_driver_start(struct rtl8169_private *tp) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_START); 11888c2ecf20Sopenharmony_ci r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); 11898c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 10); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic void rtl8168_driver_start(struct rtl8169_private *tp) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci switch (tp->mac_version) { 11958c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_27: 11968c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_28: 11978c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_31: 11988c2ecf20Sopenharmony_ci rtl8168dp_driver_start(tp); 11998c2ecf20Sopenharmony_ci break; 12008c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: 12018c2ecf20Sopenharmony_ci rtl8168ep_driver_start(tp); 12028c2ecf20Sopenharmony_ci break; 12038c2ecf20Sopenharmony_ci default: 12048c2ecf20Sopenharmony_ci BUG(); 12058c2ecf20Sopenharmony_ci break; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic void rtl8168dp_driver_stop(struct rtl8169_private *tp) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci r8168dp_oob_notify(tp, OOB_CMD_DRIVER_STOP); 12128c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic void rtl8168ep_driver_stop(struct rtl8169_private *tp) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci rtl8168ep_stop_cmac(tp); 12188c2ecf20Sopenharmony_ci r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP); 12198c2ecf20Sopenharmony_ci r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); 12208c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic void rtl8168_driver_stop(struct rtl8169_private *tp) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci switch (tp->mac_version) { 12268c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_27: 12278c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_28: 12288c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_31: 12298c2ecf20Sopenharmony_ci rtl8168dp_driver_stop(tp); 12308c2ecf20Sopenharmony_ci break; 12318c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: 12328c2ecf20Sopenharmony_ci rtl8168ep_driver_stop(tp); 12338c2ecf20Sopenharmony_ci break; 12348c2ecf20Sopenharmony_ci default: 12358c2ecf20Sopenharmony_ci BUG(); 12368c2ecf20Sopenharmony_ci break; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci} 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic bool r8168dp_check_dash(struct rtl8169_private *tp) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci u16 reg = rtl8168_get_ocp_reg(tp); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci return !!(r8168dp_ocp_read(tp, reg) & 0x00008000); 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic bool r8168ep_check_dash(struct rtl8169_private *tp) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci return r8168ep_ocp_read(tp, 0x128) & 0x00000001; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic bool r8168_check_dash(struct rtl8169_private *tp) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci switch (tp->mac_version) { 12558c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_27: 12568c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_28: 12578c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_31: 12588c2ecf20Sopenharmony_ci return r8168dp_check_dash(tp); 12598c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: 12608c2ecf20Sopenharmony_ci return r8168ep_check_dash(tp); 12618c2ecf20Sopenharmony_ci default: 12628c2ecf20Sopenharmony_ci return false; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci} 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_cistatic void rtl_reset_packet_filter(struct rtl8169_private *tp) 12678c2ecf20Sopenharmony_ci{ 12688c2ecf20Sopenharmony_ci rtl_eri_clear_bits(tp, 0xdc, BIT(0)); 12698c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0xdc, BIT(0)); 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_efusear_cond) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci return RTL_R32(tp, EFUSEAR) & EFUSEAR_FLAG; 12758c2ecf20Sopenharmony_ci} 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ciu8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr) 12788c2ecf20Sopenharmony_ci{ 12798c2ecf20Sopenharmony_ci RTL_W32(tp, EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return rtl_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ? 12828c2ecf20Sopenharmony_ci RTL_R32(tp, EFUSEAR) & EFUSEAR_DATA_MASK : ~0; 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic u32 rtl_get_events(struct rtl8169_private *tp) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) 12888c2ecf20Sopenharmony_ci return RTL_R32(tp, IntrStatus_8125); 12898c2ecf20Sopenharmony_ci else 12908c2ecf20Sopenharmony_ci return RTL_R16(tp, IntrStatus); 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic void rtl_ack_events(struct rtl8169_private *tp, u32 bits) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) 12968c2ecf20Sopenharmony_ci RTL_W32(tp, IntrStatus_8125, bits); 12978c2ecf20Sopenharmony_ci else 12988c2ecf20Sopenharmony_ci RTL_W16(tp, IntrStatus, bits); 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_cistatic void rtl_irq_disable(struct rtl8169_private *tp) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) 13048c2ecf20Sopenharmony_ci RTL_W32(tp, IntrMask_8125, 0); 13058c2ecf20Sopenharmony_ci else 13068c2ecf20Sopenharmony_ci RTL_W16(tp, IntrMask, 0); 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic void rtl_irq_enable(struct rtl8169_private *tp) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) 13128c2ecf20Sopenharmony_ci RTL_W32(tp, IntrMask_8125, tp->irq_mask); 13138c2ecf20Sopenharmony_ci else 13148c2ecf20Sopenharmony_ci RTL_W16(tp, IntrMask, tp->irq_mask); 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci rtl_irq_disable(tp); 13208c2ecf20Sopenharmony_ci rtl_ack_events(tp, 0xffffffff); 13218c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic void rtl_link_chg_patch(struct rtl8169_private *tp) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci struct phy_device *phydev = tp->phydev; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_34 || 13298c2ecf20Sopenharmony_ci tp->mac_version == RTL_GIGA_MAC_VER_38) { 13308c2ecf20Sopenharmony_ci if (phydev->speed == SPEED_1000) { 13318c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011); 13328c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005); 13338c2ecf20Sopenharmony_ci } else if (phydev->speed == SPEED_100) { 13348c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f); 13358c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005); 13368c2ecf20Sopenharmony_ci } else { 13378c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f); 13388c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f); 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci rtl_reset_packet_filter(tp); 13418c2ecf20Sopenharmony_ci } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 || 13428c2ecf20Sopenharmony_ci tp->mac_version == RTL_GIGA_MAC_VER_36) { 13438c2ecf20Sopenharmony_ci if (phydev->speed == SPEED_1000) { 13448c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011); 13458c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005); 13468c2ecf20Sopenharmony_ci } else { 13478c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f); 13488c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f); 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) { 13518c2ecf20Sopenharmony_ci if (phydev->speed == SPEED_10) { 13528c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02); 13538c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060a); 13548c2ecf20Sopenharmony_ci } else { 13558c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000); 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci wol->supported = WAKE_ANY; 13678c2ecf20Sopenharmony_ci wol->wolopts = tp->saved_wolopts; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci static const struct { 13738c2ecf20Sopenharmony_ci u32 opt; 13748c2ecf20Sopenharmony_ci u16 reg; 13758c2ecf20Sopenharmony_ci u8 mask; 13768c2ecf20Sopenharmony_ci } cfg[] = { 13778c2ecf20Sopenharmony_ci { WAKE_PHY, Config3, LinkUp }, 13788c2ecf20Sopenharmony_ci { WAKE_UCAST, Config5, UWF }, 13798c2ecf20Sopenharmony_ci { WAKE_BCAST, Config5, BWF }, 13808c2ecf20Sopenharmony_ci { WAKE_MCAST, Config5, MWF }, 13818c2ecf20Sopenharmony_ci { WAKE_ANY, Config5, LanWake }, 13828c2ecf20Sopenharmony_ci { WAKE_MAGIC, Config3, MagicPacket } 13838c2ecf20Sopenharmony_ci }; 13848c2ecf20Sopenharmony_ci unsigned int i, tmp = ARRAY_SIZE(cfg); 13858c2ecf20Sopenharmony_ci u8 options; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci rtl_unlock_config_regs(tp); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (rtl_is_8168evl_up(tp)) { 13908c2ecf20Sopenharmony_ci tmp--; 13918c2ecf20Sopenharmony_ci if (wolopts & WAKE_MAGIC) 13928c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2); 13938c2ecf20Sopenharmony_ci else 13948c2ecf20Sopenharmony_ci rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2); 13958c2ecf20Sopenharmony_ci } else if (rtl_is_8125(tp)) { 13968c2ecf20Sopenharmony_ci tmp--; 13978c2ecf20Sopenharmony_ci if (wolopts & WAKE_MAGIC) 13988c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0)); 13998c2ecf20Sopenharmony_ci else 14008c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci for (i = 0; i < tmp; i++) { 14048c2ecf20Sopenharmony_ci options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; 14058c2ecf20Sopenharmony_ci if (wolopts & cfg[i].opt) 14068c2ecf20Sopenharmony_ci options |= cfg[i].mask; 14078c2ecf20Sopenharmony_ci RTL_W8(tp, cfg[i].reg, options); 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci switch (tp->mac_version) { 14118c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: 14128c2ecf20Sopenharmony_ci options = RTL_R8(tp, Config1) & ~PMEnable; 14138c2ecf20Sopenharmony_ci if (wolopts) 14148c2ecf20Sopenharmony_ci options |= PMEnable; 14158c2ecf20Sopenharmony_ci RTL_W8(tp, Config1, options); 14168c2ecf20Sopenharmony_ci break; 14178c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_34: 14188c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_37: 14198c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63: 14208c2ecf20Sopenharmony_ci options = RTL_R8(tp, Config2) & ~PME_SIGNAL; 14218c2ecf20Sopenharmony_ci if (wolopts) 14228c2ecf20Sopenharmony_ci options |= PME_SIGNAL; 14238c2ecf20Sopenharmony_ci RTL_W8(tp, Config2, options); 14248c2ecf20Sopenharmony_ci break; 14258c2ecf20Sopenharmony_ci default: 14268c2ecf20Sopenharmony_ci break; 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci rtl_lock_config_regs(tp); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci device_set_wakeup_enable(tp_to_dev(tp), wolopts); 14328c2ecf20Sopenharmony_ci tp->dev->wol_enabled = wolopts ? 1 : 0; 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cistatic int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (wol->wolopts & ~WAKE_ANY) 14408c2ecf20Sopenharmony_ci return -EINVAL; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci tp->saved_wolopts = wol->wolopts; 14438c2ecf20Sopenharmony_ci __rtl8169_set_wol(tp, tp->saved_wolopts); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci return 0; 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_cistatic void rtl8169_get_drvinfo(struct net_device *dev, 14498c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 14528c2ecf20Sopenharmony_ci struct rtl_fw *rtl_fw = tp->rtl_fw; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci strlcpy(info->driver, MODULENAME, sizeof(info->driver)); 14558c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info)); 14568c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version)); 14578c2ecf20Sopenharmony_ci if (rtl_fw) 14588c2ecf20Sopenharmony_ci strlcpy(info->fw_version, rtl_fw->version, 14598c2ecf20Sopenharmony_ci sizeof(info->fw_version)); 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cistatic int rtl8169_get_regs_len(struct net_device *dev) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci return R8169_REGS_SIZE; 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic netdev_features_t rtl8169_fix_features(struct net_device *dev, 14688c2ecf20Sopenharmony_ci netdev_features_t features) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (dev->mtu > TD_MSS_MAX) 14738c2ecf20Sopenharmony_ci features &= ~NETIF_F_ALL_TSO; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if (dev->mtu > ETH_DATA_LEN && 14768c2ecf20Sopenharmony_ci tp->mac_version > RTL_GIGA_MAC_VER_06) 14778c2ecf20Sopenharmony_ci features &= ~(NETIF_F_CSUM_MASK | NETIF_F_ALL_TSO); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci return features; 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic void rtl_set_rx_config_features(struct rtl8169_private *tp, 14838c2ecf20Sopenharmony_ci netdev_features_t features) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci u32 rx_config = RTL_R32(tp, RxConfig); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (features & NETIF_F_RXALL) 14888c2ecf20Sopenharmony_ci rx_config |= RX_CONFIG_ACCEPT_ERR_MASK; 14898c2ecf20Sopenharmony_ci else 14908c2ecf20Sopenharmony_ci rx_config &= ~RX_CONFIG_ACCEPT_ERR_MASK; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) { 14938c2ecf20Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) 14948c2ecf20Sopenharmony_ci rx_config |= RX_VLAN_8125; 14958c2ecf20Sopenharmony_ci else 14968c2ecf20Sopenharmony_ci rx_config &= ~RX_VLAN_8125; 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, rx_config); 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_cistatic int rtl8169_set_features(struct net_device *dev, 15038c2ecf20Sopenharmony_ci netdev_features_t features) 15048c2ecf20Sopenharmony_ci{ 15058c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci rtl_set_rx_config_features(tp, features); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (features & NETIF_F_RXCSUM) 15108c2ecf20Sopenharmony_ci tp->cp_cmd |= RxChkSum; 15118c2ecf20Sopenharmony_ci else 15128c2ecf20Sopenharmony_ci tp->cp_cmd &= ~RxChkSum; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci if (!rtl_is_8125(tp)) { 15158c2ecf20Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) 15168c2ecf20Sopenharmony_ci tp->cp_cmd |= RxVlan; 15178c2ecf20Sopenharmony_ci else 15188c2ecf20Sopenharmony_ci tp->cp_cmd &= ~RxVlan; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci RTL_W16(tp, CPlusCmd, tp->cp_cmd); 15228c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci return 0; 15258c2ecf20Sopenharmony_ci} 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_cistatic inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb) 15288c2ecf20Sopenharmony_ci{ 15298c2ecf20Sopenharmony_ci return (skb_vlan_tag_present(skb)) ? 15308c2ecf20Sopenharmony_ci TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00; 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci u32 opts2 = le32_to_cpu(desc->opts2); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (opts2 & RxVlanTag) 15388c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff)); 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs, 15428c2ecf20Sopenharmony_ci void *p) 15438c2ecf20Sopenharmony_ci{ 15448c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 15458c2ecf20Sopenharmony_ci u32 __iomem *data = tp->mmio_addr; 15468c2ecf20Sopenharmony_ci u32 *dw = p; 15478c2ecf20Sopenharmony_ci int i; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci for (i = 0; i < R8169_REGS_SIZE; i += 4) 15508c2ecf20Sopenharmony_ci memcpy_fromio(dw++, data++, 4); 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cistatic const char rtl8169_gstrings[][ETH_GSTRING_LEN] = { 15548c2ecf20Sopenharmony_ci "tx_packets", 15558c2ecf20Sopenharmony_ci "rx_packets", 15568c2ecf20Sopenharmony_ci "tx_errors", 15578c2ecf20Sopenharmony_ci "rx_errors", 15588c2ecf20Sopenharmony_ci "rx_missed", 15598c2ecf20Sopenharmony_ci "align_errors", 15608c2ecf20Sopenharmony_ci "tx_single_collisions", 15618c2ecf20Sopenharmony_ci "tx_multi_collisions", 15628c2ecf20Sopenharmony_ci "unicast", 15638c2ecf20Sopenharmony_ci "broadcast", 15648c2ecf20Sopenharmony_ci "multicast", 15658c2ecf20Sopenharmony_ci "tx_aborted", 15668c2ecf20Sopenharmony_ci "tx_underrun", 15678c2ecf20Sopenharmony_ci}; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic int rtl8169_get_sset_count(struct net_device *dev, int sset) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci switch (sset) { 15728c2ecf20Sopenharmony_ci case ETH_SS_STATS: 15738c2ecf20Sopenharmony_ci return ARRAY_SIZE(rtl8169_gstrings); 15748c2ecf20Sopenharmony_ci default: 15758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci} 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_counters_cond) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci return RTL_R32(tp, CounterAddrLow) & (CounterReset | CounterDump); 15828c2ecf20Sopenharmony_ci} 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_cistatic void rtl8169_do_counters(struct rtl8169_private *tp, u32 counter_cmd) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci dma_addr_t paddr = tp->counters_phys_addr; 15878c2ecf20Sopenharmony_ci u32 cmd; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci RTL_W32(tp, CounterAddrHigh, (u64)paddr >> 32); 15908c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 15918c2ecf20Sopenharmony_ci cmd = (u64)paddr & DMA_BIT_MASK(32); 15928c2ecf20Sopenharmony_ci RTL_W32(tp, CounterAddrLow, cmd); 15938c2ecf20Sopenharmony_ci RTL_W32(tp, CounterAddrLow, cmd | counter_cmd); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_counters_cond, 10, 1000); 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_cistatic void rtl8169_reset_counters(struct rtl8169_private *tp) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci /* 16018c2ecf20Sopenharmony_ci * Versions prior to RTL_GIGA_MAC_VER_19 don't support resetting the 16028c2ecf20Sopenharmony_ci * tally counters. 16038c2ecf20Sopenharmony_ci */ 16048c2ecf20Sopenharmony_ci if (tp->mac_version >= RTL_GIGA_MAC_VER_19) 16058c2ecf20Sopenharmony_ci rtl8169_do_counters(tp, CounterReset); 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_cistatic void rtl8169_update_counters(struct rtl8169_private *tp) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci u8 val = RTL_R8(tp, ChipCmd); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* 16138c2ecf20Sopenharmony_ci * Some chips are unable to dump tally counters when the receiver 16148c2ecf20Sopenharmony_ci * is disabled. If 0xff chip may be in a PCI power-save state. 16158c2ecf20Sopenharmony_ci */ 16168c2ecf20Sopenharmony_ci if (val & CmdRxEnb && val != 0xff) 16178c2ecf20Sopenharmony_ci rtl8169_do_counters(tp, CounterDump); 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic void rtl8169_init_counter_offsets(struct rtl8169_private *tp) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci struct rtl8169_counters *counters = tp->counters; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci /* 16258c2ecf20Sopenharmony_ci * rtl8169_init_counter_offsets is called from rtl_open. On chip 16268c2ecf20Sopenharmony_ci * versions prior to RTL_GIGA_MAC_VER_19 the tally counters are only 16278c2ecf20Sopenharmony_ci * reset by a power cycle, while the counter values collected by the 16288c2ecf20Sopenharmony_ci * driver are reset at every driver unload/load cycle. 16298c2ecf20Sopenharmony_ci * 16308c2ecf20Sopenharmony_ci * To make sure the HW values returned by @get_stats64 match the SW 16318c2ecf20Sopenharmony_ci * values, we collect the initial values at first open(*) and use them 16328c2ecf20Sopenharmony_ci * as offsets to normalize the values returned by @get_stats64. 16338c2ecf20Sopenharmony_ci * 16348c2ecf20Sopenharmony_ci * (*) We can't call rtl8169_init_counter_offsets from rtl_init_one 16358c2ecf20Sopenharmony_ci * for the reason stated in rtl8169_update_counters; CmdRxEnb is only 16368c2ecf20Sopenharmony_ci * set at open time by rtl_hw_start. 16378c2ecf20Sopenharmony_ci */ 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci if (tp->tc_offset.inited) 16408c2ecf20Sopenharmony_ci return; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci rtl8169_reset_counters(tp); 16438c2ecf20Sopenharmony_ci rtl8169_update_counters(tp); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci tp->tc_offset.tx_errors = counters->tx_errors; 16468c2ecf20Sopenharmony_ci tp->tc_offset.tx_multi_collision = counters->tx_multi_collision; 16478c2ecf20Sopenharmony_ci tp->tc_offset.tx_aborted = counters->tx_aborted; 16488c2ecf20Sopenharmony_ci tp->tc_offset.rx_missed = counters->rx_missed; 16498c2ecf20Sopenharmony_ci tp->tc_offset.inited = true; 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic void rtl8169_get_ethtool_stats(struct net_device *dev, 16538c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 16548c2ecf20Sopenharmony_ci{ 16558c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 16568c2ecf20Sopenharmony_ci struct rtl8169_counters *counters; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci counters = tp->counters; 16598c2ecf20Sopenharmony_ci rtl8169_update_counters(tp); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci data[0] = le64_to_cpu(counters->tx_packets); 16628c2ecf20Sopenharmony_ci data[1] = le64_to_cpu(counters->rx_packets); 16638c2ecf20Sopenharmony_ci data[2] = le64_to_cpu(counters->tx_errors); 16648c2ecf20Sopenharmony_ci data[3] = le32_to_cpu(counters->rx_errors); 16658c2ecf20Sopenharmony_ci data[4] = le16_to_cpu(counters->rx_missed); 16668c2ecf20Sopenharmony_ci data[5] = le16_to_cpu(counters->align_errors); 16678c2ecf20Sopenharmony_ci data[6] = le32_to_cpu(counters->tx_one_collision); 16688c2ecf20Sopenharmony_ci data[7] = le32_to_cpu(counters->tx_multi_collision); 16698c2ecf20Sopenharmony_ci data[8] = le64_to_cpu(counters->rx_unicast); 16708c2ecf20Sopenharmony_ci data[9] = le64_to_cpu(counters->rx_broadcast); 16718c2ecf20Sopenharmony_ci data[10] = le32_to_cpu(counters->rx_multicast); 16728c2ecf20Sopenharmony_ci data[11] = le16_to_cpu(counters->tx_aborted); 16738c2ecf20Sopenharmony_ci data[12] = le16_to_cpu(counters->tx_underun); 16748c2ecf20Sopenharmony_ci} 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_cistatic void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci switch(stringset) { 16798c2ecf20Sopenharmony_ci case ETH_SS_STATS: 16808c2ecf20Sopenharmony_ci memcpy(data, rtl8169_gstrings, sizeof(rtl8169_gstrings)); 16818c2ecf20Sopenharmony_ci break; 16828c2ecf20Sopenharmony_ci } 16838c2ecf20Sopenharmony_ci} 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci/* 16868c2ecf20Sopenharmony_ci * Interrupt coalescing 16878c2ecf20Sopenharmony_ci * 16888c2ecf20Sopenharmony_ci * > 1 - the availability of the IntrMitigate (0xe2) register through the 16898c2ecf20Sopenharmony_ci * > 8169, 8168 and 810x line of chipsets 16908c2ecf20Sopenharmony_ci * 16918c2ecf20Sopenharmony_ci * 8169, 8168, and 8136(810x) serial chipsets support it. 16928c2ecf20Sopenharmony_ci * 16938c2ecf20Sopenharmony_ci * > 2 - the Tx timer unit at gigabit speed 16948c2ecf20Sopenharmony_ci * 16958c2ecf20Sopenharmony_ci * The unit of the timer depends on both the speed and the setting of CPlusCmd 16968c2ecf20Sopenharmony_ci * (0xe0) bit 1 and bit 0. 16978c2ecf20Sopenharmony_ci * 16988c2ecf20Sopenharmony_ci * For 8169 16998c2ecf20Sopenharmony_ci * bit[1:0] \ speed 1000M 100M 10M 17008c2ecf20Sopenharmony_ci * 0 0 320ns 2.56us 40.96us 17018c2ecf20Sopenharmony_ci * 0 1 2.56us 20.48us 327.7us 17028c2ecf20Sopenharmony_ci * 1 0 5.12us 40.96us 655.4us 17038c2ecf20Sopenharmony_ci * 1 1 10.24us 81.92us 1.31ms 17048c2ecf20Sopenharmony_ci * 17058c2ecf20Sopenharmony_ci * For the other 17068c2ecf20Sopenharmony_ci * bit[1:0] \ speed 1000M 100M 10M 17078c2ecf20Sopenharmony_ci * 0 0 5us 2.56us 40.96us 17088c2ecf20Sopenharmony_ci * 0 1 40us 20.48us 327.7us 17098c2ecf20Sopenharmony_ci * 1 0 80us 40.96us 655.4us 17108c2ecf20Sopenharmony_ci * 1 1 160us 81.92us 1.31ms 17118c2ecf20Sopenharmony_ci */ 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci/* rx/tx scale factors for all CPlusCmd[0:1] cases */ 17148c2ecf20Sopenharmony_cistruct rtl_coalesce_info { 17158c2ecf20Sopenharmony_ci u32 speed; 17168c2ecf20Sopenharmony_ci u32 scale_nsecs[4]; 17178c2ecf20Sopenharmony_ci}; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci/* produce array with base delay *1, *8, *8*2, *8*2*2 */ 17208c2ecf20Sopenharmony_ci#define COALESCE_DELAY(d) { (d), 8 * (d), 16 * (d), 32 * (d) } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_cistatic const struct rtl_coalesce_info rtl_coalesce_info_8169[] = { 17238c2ecf20Sopenharmony_ci { SPEED_1000, COALESCE_DELAY(320) }, 17248c2ecf20Sopenharmony_ci { SPEED_100, COALESCE_DELAY(2560) }, 17258c2ecf20Sopenharmony_ci { SPEED_10, COALESCE_DELAY(40960) }, 17268c2ecf20Sopenharmony_ci { 0 }, 17278c2ecf20Sopenharmony_ci}; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic const struct rtl_coalesce_info rtl_coalesce_info_8168_8136[] = { 17308c2ecf20Sopenharmony_ci { SPEED_1000, COALESCE_DELAY(5000) }, 17318c2ecf20Sopenharmony_ci { SPEED_100, COALESCE_DELAY(2560) }, 17328c2ecf20Sopenharmony_ci { SPEED_10, COALESCE_DELAY(40960) }, 17338c2ecf20Sopenharmony_ci { 0 }, 17348c2ecf20Sopenharmony_ci}; 17358c2ecf20Sopenharmony_ci#undef COALESCE_DELAY 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci/* get rx/tx scale vector corresponding to current speed */ 17388c2ecf20Sopenharmony_cistatic const struct rtl_coalesce_info * 17398c2ecf20Sopenharmony_cirtl_coalesce_info(struct rtl8169_private *tp) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci const struct rtl_coalesce_info *ci; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci if (tp->mac_version <= RTL_GIGA_MAC_VER_06) 17448c2ecf20Sopenharmony_ci ci = rtl_coalesce_info_8169; 17458c2ecf20Sopenharmony_ci else 17468c2ecf20Sopenharmony_ci ci = rtl_coalesce_info_8168_8136; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci /* if speed is unknown assume highest one */ 17498c2ecf20Sopenharmony_ci if (tp->phydev->speed == SPEED_UNKNOWN) 17508c2ecf20Sopenharmony_ci return ci; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci for (; ci->speed; ci++) { 17538c2ecf20Sopenharmony_ci if (tp->phydev->speed == ci->speed) 17548c2ecf20Sopenharmony_ci return ci; 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci return ERR_PTR(-ELNRNG); 17588c2ecf20Sopenharmony_ci} 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_cistatic int rtl_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) 17618c2ecf20Sopenharmony_ci{ 17628c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 17638c2ecf20Sopenharmony_ci const struct rtl_coalesce_info *ci; 17648c2ecf20Sopenharmony_ci u32 scale, c_us, c_fr; 17658c2ecf20Sopenharmony_ci u16 intrmit; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) 17688c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci memset(ec, 0, sizeof(*ec)); 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci /* get rx/tx scale corresponding to current speed and CPlusCmd[0:1] */ 17738c2ecf20Sopenharmony_ci ci = rtl_coalesce_info(tp); 17748c2ecf20Sopenharmony_ci if (IS_ERR(ci)) 17758c2ecf20Sopenharmony_ci return PTR_ERR(ci); 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci scale = ci->scale_nsecs[tp->cp_cmd & INTT_MASK]; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci intrmit = RTL_R16(tp, IntrMitigate); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci c_us = FIELD_GET(RTL_COALESCE_TX_USECS, intrmit); 17828c2ecf20Sopenharmony_ci ec->tx_coalesce_usecs = DIV_ROUND_UP(c_us * scale, 1000); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci c_fr = FIELD_GET(RTL_COALESCE_TX_FRAMES, intrmit); 17858c2ecf20Sopenharmony_ci /* ethtool_coalesce states usecs and max_frames must not both be 0 */ 17868c2ecf20Sopenharmony_ci ec->tx_max_coalesced_frames = (c_us || c_fr) ? c_fr * 4 : 1; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci c_us = FIELD_GET(RTL_COALESCE_RX_USECS, intrmit); 17898c2ecf20Sopenharmony_ci ec->rx_coalesce_usecs = DIV_ROUND_UP(c_us * scale, 1000); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci c_fr = FIELD_GET(RTL_COALESCE_RX_FRAMES, intrmit); 17928c2ecf20Sopenharmony_ci ec->rx_max_coalesced_frames = (c_us || c_fr) ? c_fr * 4 : 1; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci return 0; 17958c2ecf20Sopenharmony_ci} 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci/* choose appropriate scale factor and CPlusCmd[0:1] for (speed, usec) */ 17988c2ecf20Sopenharmony_cistatic int rtl_coalesce_choose_scale(struct rtl8169_private *tp, u32 usec, 17998c2ecf20Sopenharmony_ci u16 *cp01) 18008c2ecf20Sopenharmony_ci{ 18018c2ecf20Sopenharmony_ci const struct rtl_coalesce_info *ci; 18028c2ecf20Sopenharmony_ci u16 i; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci ci = rtl_coalesce_info(tp); 18058c2ecf20Sopenharmony_ci if (IS_ERR(ci)) 18068c2ecf20Sopenharmony_ci return PTR_ERR(ci); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 18098c2ecf20Sopenharmony_ci if (usec <= ci->scale_nsecs[i] * RTL_COALESCE_T_MAX / 1000U) { 18108c2ecf20Sopenharmony_ci *cp01 = i; 18118c2ecf20Sopenharmony_ci return ci->scale_nsecs[i]; 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci return -ERANGE; 18168c2ecf20Sopenharmony_ci} 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_cistatic int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 18218c2ecf20Sopenharmony_ci u32 tx_fr = ec->tx_max_coalesced_frames; 18228c2ecf20Sopenharmony_ci u32 rx_fr = ec->rx_max_coalesced_frames; 18238c2ecf20Sopenharmony_ci u32 coal_usec_max, units; 18248c2ecf20Sopenharmony_ci u16 w = 0, cp01 = 0; 18258c2ecf20Sopenharmony_ci int scale; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) 18288c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if (rx_fr > RTL_COALESCE_FRAME_MAX || tx_fr > RTL_COALESCE_FRAME_MAX) 18318c2ecf20Sopenharmony_ci return -ERANGE; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci coal_usec_max = max(ec->rx_coalesce_usecs, ec->tx_coalesce_usecs); 18348c2ecf20Sopenharmony_ci scale = rtl_coalesce_choose_scale(tp, coal_usec_max, &cp01); 18358c2ecf20Sopenharmony_ci if (scale < 0) 18368c2ecf20Sopenharmony_ci return scale; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci /* Accept max_frames=1 we returned in rtl_get_coalesce. Accept it 18398c2ecf20Sopenharmony_ci * not only when usecs=0 because of e.g. the following scenario: 18408c2ecf20Sopenharmony_ci * 18418c2ecf20Sopenharmony_ci * - both rx_usecs=0 & rx_frames=0 in hardware (no delay on RX) 18428c2ecf20Sopenharmony_ci * - rtl_get_coalesce returns rx_usecs=0, rx_frames=1 18438c2ecf20Sopenharmony_ci * - then user does `ethtool -C eth0 rx-usecs 100` 18448c2ecf20Sopenharmony_ci * 18458c2ecf20Sopenharmony_ci * Since ethtool sends to kernel whole ethtool_coalesce settings, 18468c2ecf20Sopenharmony_ci * if we want to ignore rx_frames then it has to be set to 0. 18478c2ecf20Sopenharmony_ci */ 18488c2ecf20Sopenharmony_ci if (rx_fr == 1) 18498c2ecf20Sopenharmony_ci rx_fr = 0; 18508c2ecf20Sopenharmony_ci if (tx_fr == 1) 18518c2ecf20Sopenharmony_ci tx_fr = 0; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci /* HW requires time limit to be set if frame limit is set */ 18548c2ecf20Sopenharmony_ci if ((tx_fr && !ec->tx_coalesce_usecs) || 18558c2ecf20Sopenharmony_ci (rx_fr && !ec->rx_coalesce_usecs)) 18568c2ecf20Sopenharmony_ci return -EINVAL; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci w |= FIELD_PREP(RTL_COALESCE_TX_FRAMES, DIV_ROUND_UP(tx_fr, 4)); 18598c2ecf20Sopenharmony_ci w |= FIELD_PREP(RTL_COALESCE_RX_FRAMES, DIV_ROUND_UP(rx_fr, 4)); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci units = DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000U, scale); 18628c2ecf20Sopenharmony_ci w |= FIELD_PREP(RTL_COALESCE_TX_USECS, units); 18638c2ecf20Sopenharmony_ci units = DIV_ROUND_UP(ec->rx_coalesce_usecs * 1000U, scale); 18648c2ecf20Sopenharmony_ci w |= FIELD_PREP(RTL_COALESCE_RX_USECS, units); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci RTL_W16(tp, IntrMitigate, w); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci /* Meaning of PktCntrDisable bit changed from RTL8168e-vl */ 18698c2ecf20Sopenharmony_ci if (rtl_is_8168evl_up(tp)) { 18708c2ecf20Sopenharmony_ci if (!rx_fr && !tx_fr) 18718c2ecf20Sopenharmony_ci /* disable packet counter */ 18728c2ecf20Sopenharmony_ci tp->cp_cmd |= PktCntrDisable; 18738c2ecf20Sopenharmony_ci else 18748c2ecf20Sopenharmony_ci tp->cp_cmd &= ~PktCntrDisable; 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci tp->cp_cmd = (tp->cp_cmd & ~INTT_MASK) | cp01; 18788c2ecf20Sopenharmony_ci RTL_W16(tp, CPlusCmd, tp->cp_cmd); 18798c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci return 0; 18828c2ecf20Sopenharmony_ci} 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_cistatic int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data) 18858c2ecf20Sopenharmony_ci{ 18868c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if (!rtl_supports_eee(tp)) 18898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci return phy_ethtool_get_eee(tp->phydev, data); 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_cistatic int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 18978c2ecf20Sopenharmony_ci int ret; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci if (!rtl_supports_eee(tp)) 19008c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci ret = phy_ethtool_set_eee(tp->phydev, data); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (!ret) 19058c2ecf20Sopenharmony_ci tp->eee_adv = phy_read_mmd(dev->phydev, MDIO_MMD_AN, 19068c2ecf20Sopenharmony_ci MDIO_AN_EEE_ADV); 19078c2ecf20Sopenharmony_ci return ret; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_cistatic const struct ethtool_ops rtl8169_ethtool_ops = { 19118c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 19128c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES, 19138c2ecf20Sopenharmony_ci .get_drvinfo = rtl8169_get_drvinfo, 19148c2ecf20Sopenharmony_ci .get_regs_len = rtl8169_get_regs_len, 19158c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 19168c2ecf20Sopenharmony_ci .get_coalesce = rtl_get_coalesce, 19178c2ecf20Sopenharmony_ci .set_coalesce = rtl_set_coalesce, 19188c2ecf20Sopenharmony_ci .get_regs = rtl8169_get_regs, 19198c2ecf20Sopenharmony_ci .get_wol = rtl8169_get_wol, 19208c2ecf20Sopenharmony_ci .set_wol = rtl8169_set_wol, 19218c2ecf20Sopenharmony_ci .get_strings = rtl8169_get_strings, 19228c2ecf20Sopenharmony_ci .get_sset_count = rtl8169_get_sset_count, 19238c2ecf20Sopenharmony_ci .get_ethtool_stats = rtl8169_get_ethtool_stats, 19248c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 19258c2ecf20Sopenharmony_ci .nway_reset = phy_ethtool_nway_reset, 19268c2ecf20Sopenharmony_ci .get_eee = rtl8169_get_eee, 19278c2ecf20Sopenharmony_ci .set_eee = rtl8169_set_eee, 19288c2ecf20Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 19298c2ecf20Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 19308c2ecf20Sopenharmony_ci}; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_cistatic void rtl_enable_eee(struct rtl8169_private *tp) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci struct phy_device *phydev = tp->phydev; 19358c2ecf20Sopenharmony_ci int adv; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci /* respect EEE advertisement the user may have set */ 19388c2ecf20Sopenharmony_ci if (tp->eee_adv >= 0) 19398c2ecf20Sopenharmony_ci adv = tp->eee_adv; 19408c2ecf20Sopenharmony_ci else 19418c2ecf20Sopenharmony_ci adv = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci if (adv >= 0) 19448c2ecf20Sopenharmony_ci phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv); 19458c2ecf20Sopenharmony_ci} 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_cistatic enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) 19488c2ecf20Sopenharmony_ci{ 19498c2ecf20Sopenharmony_ci /* 19508c2ecf20Sopenharmony_ci * The driver currently handles the 8168Bf and the 8168Be identically 19518c2ecf20Sopenharmony_ci * but they can be identified more specifically through the test below 19528c2ecf20Sopenharmony_ci * if needed: 19538c2ecf20Sopenharmony_ci * 19548c2ecf20Sopenharmony_ci * (RTL_R32(tp, TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be 19558c2ecf20Sopenharmony_ci * 19568c2ecf20Sopenharmony_ci * Same thing for the 8101Eb and the 8101Ec: 19578c2ecf20Sopenharmony_ci * 19588c2ecf20Sopenharmony_ci * (RTL_R32(tp, TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec 19598c2ecf20Sopenharmony_ci */ 19608c2ecf20Sopenharmony_ci static const struct rtl_mac_info { 19618c2ecf20Sopenharmony_ci u16 mask; 19628c2ecf20Sopenharmony_ci u16 val; 19638c2ecf20Sopenharmony_ci enum mac_version ver; 19648c2ecf20Sopenharmony_ci } mac_info[] = { 19658c2ecf20Sopenharmony_ci /* 8125B family. */ 19668c2ecf20Sopenharmony_ci { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 }, 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci /* 8125A family. */ 19698c2ecf20Sopenharmony_ci { 0x7cf, 0x608, RTL_GIGA_MAC_VER_60 }, 19708c2ecf20Sopenharmony_ci { 0x7c8, 0x608, RTL_GIGA_MAC_VER_61 }, 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci /* RTL8117 */ 19738c2ecf20Sopenharmony_ci { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52 }, 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci /* 8168EP family. */ 19768c2ecf20Sopenharmony_ci { 0x7cf, 0x502, RTL_GIGA_MAC_VER_51 }, 19778c2ecf20Sopenharmony_ci { 0x7cf, 0x501, RTL_GIGA_MAC_VER_50 }, 19788c2ecf20Sopenharmony_ci { 0x7cf, 0x500, RTL_GIGA_MAC_VER_49 }, 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci /* 8168H family. */ 19818c2ecf20Sopenharmony_ci { 0x7cf, 0x541, RTL_GIGA_MAC_VER_46 }, 19828c2ecf20Sopenharmony_ci { 0x7cf, 0x540, RTL_GIGA_MAC_VER_45 }, 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci /* 8168G family. */ 19858c2ecf20Sopenharmony_ci { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44 }, 19868c2ecf20Sopenharmony_ci { 0x7cf, 0x509, RTL_GIGA_MAC_VER_42 }, 19878c2ecf20Sopenharmony_ci { 0x7cf, 0x4c1, RTL_GIGA_MAC_VER_41 }, 19888c2ecf20Sopenharmony_ci { 0x7cf, 0x4c0, RTL_GIGA_MAC_VER_40 }, 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci /* 8168F family. */ 19918c2ecf20Sopenharmony_ci { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38 }, 19928c2ecf20Sopenharmony_ci { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36 }, 19938c2ecf20Sopenharmony_ci { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35 }, 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci /* 8168E family. */ 19968c2ecf20Sopenharmony_ci { 0x7c8, 0x2c8, RTL_GIGA_MAC_VER_34 }, 19978c2ecf20Sopenharmony_ci { 0x7cf, 0x2c1, RTL_GIGA_MAC_VER_32 }, 19988c2ecf20Sopenharmony_ci { 0x7c8, 0x2c0, RTL_GIGA_MAC_VER_33 }, 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci /* 8168D family. */ 20018c2ecf20Sopenharmony_ci { 0x7cf, 0x281, RTL_GIGA_MAC_VER_25 }, 20028c2ecf20Sopenharmony_ci { 0x7c8, 0x280, RTL_GIGA_MAC_VER_26 }, 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci /* 8168DP family. */ 20058c2ecf20Sopenharmony_ci { 0x7cf, 0x288, RTL_GIGA_MAC_VER_27 }, 20068c2ecf20Sopenharmony_ci { 0x7cf, 0x28a, RTL_GIGA_MAC_VER_28 }, 20078c2ecf20Sopenharmony_ci { 0x7cf, 0x28b, RTL_GIGA_MAC_VER_31 }, 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci /* 8168C family. */ 20108c2ecf20Sopenharmony_ci { 0x7cf, 0x3c9, RTL_GIGA_MAC_VER_23 }, 20118c2ecf20Sopenharmony_ci { 0x7cf, 0x3c8, RTL_GIGA_MAC_VER_18 }, 20128c2ecf20Sopenharmony_ci { 0x7c8, 0x3c8, RTL_GIGA_MAC_VER_24 }, 20138c2ecf20Sopenharmony_ci { 0x7cf, 0x3c0, RTL_GIGA_MAC_VER_19 }, 20148c2ecf20Sopenharmony_ci { 0x7cf, 0x3c2, RTL_GIGA_MAC_VER_20 }, 20158c2ecf20Sopenharmony_ci { 0x7cf, 0x3c3, RTL_GIGA_MAC_VER_21 }, 20168c2ecf20Sopenharmony_ci { 0x7c8, 0x3c0, RTL_GIGA_MAC_VER_22 }, 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci /* 8168B family. */ 20198c2ecf20Sopenharmony_ci { 0x7cf, 0x380, RTL_GIGA_MAC_VER_12 }, 20208c2ecf20Sopenharmony_ci { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 }, 20218c2ecf20Sopenharmony_ci { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 }, 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci /* 8101 family. */ 20248c2ecf20Sopenharmony_ci { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39 }, 20258c2ecf20Sopenharmony_ci { 0x7c8, 0x440, RTL_GIGA_MAC_VER_37 }, 20268c2ecf20Sopenharmony_ci { 0x7cf, 0x409, RTL_GIGA_MAC_VER_29 }, 20278c2ecf20Sopenharmony_ci { 0x7c8, 0x408, RTL_GIGA_MAC_VER_30 }, 20288c2ecf20Sopenharmony_ci { 0x7cf, 0x349, RTL_GIGA_MAC_VER_08 }, 20298c2ecf20Sopenharmony_ci { 0x7cf, 0x249, RTL_GIGA_MAC_VER_08 }, 20308c2ecf20Sopenharmony_ci { 0x7cf, 0x348, RTL_GIGA_MAC_VER_07 }, 20318c2ecf20Sopenharmony_ci { 0x7cf, 0x248, RTL_GIGA_MAC_VER_07 }, 20328c2ecf20Sopenharmony_ci { 0x7cf, 0x340, RTL_GIGA_MAC_VER_13 }, 20338c2ecf20Sopenharmony_ci { 0x7cf, 0x240, RTL_GIGA_MAC_VER_14 }, 20348c2ecf20Sopenharmony_ci { 0x7cf, 0x343, RTL_GIGA_MAC_VER_10 }, 20358c2ecf20Sopenharmony_ci { 0x7cf, 0x342, RTL_GIGA_MAC_VER_16 }, 20368c2ecf20Sopenharmony_ci { 0x7c8, 0x348, RTL_GIGA_MAC_VER_09 }, 20378c2ecf20Sopenharmony_ci { 0x7c8, 0x248, RTL_GIGA_MAC_VER_09 }, 20388c2ecf20Sopenharmony_ci { 0x7c8, 0x340, RTL_GIGA_MAC_VER_16 }, 20398c2ecf20Sopenharmony_ci /* FIXME: where did these entries come from ? -- FR */ 20408c2ecf20Sopenharmony_ci { 0xfc8, 0x388, RTL_GIGA_MAC_VER_13 }, 20418c2ecf20Sopenharmony_ci { 0xfc8, 0x308, RTL_GIGA_MAC_VER_13 }, 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci /* 8110 family. */ 20448c2ecf20Sopenharmony_ci { 0xfc8, 0x980, RTL_GIGA_MAC_VER_06 }, 20458c2ecf20Sopenharmony_ci { 0xfc8, 0x180, RTL_GIGA_MAC_VER_05 }, 20468c2ecf20Sopenharmony_ci { 0xfc8, 0x100, RTL_GIGA_MAC_VER_04 }, 20478c2ecf20Sopenharmony_ci { 0xfc8, 0x040, RTL_GIGA_MAC_VER_03 }, 20488c2ecf20Sopenharmony_ci { 0xfc8, 0x008, RTL_GIGA_MAC_VER_02 }, 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci /* Catch-all */ 20518c2ecf20Sopenharmony_ci { 0x000, 0x000, RTL_GIGA_MAC_NONE } 20528c2ecf20Sopenharmony_ci }; 20538c2ecf20Sopenharmony_ci const struct rtl_mac_info *p = mac_info; 20548c2ecf20Sopenharmony_ci enum mac_version ver; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci while ((xid & p->mask) != p->val) 20578c2ecf20Sopenharmony_ci p++; 20588c2ecf20Sopenharmony_ci ver = p->ver; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci if (ver != RTL_GIGA_MAC_NONE && !gmii) { 20618c2ecf20Sopenharmony_ci if (ver == RTL_GIGA_MAC_VER_42) 20628c2ecf20Sopenharmony_ci ver = RTL_GIGA_MAC_VER_43; 20638c2ecf20Sopenharmony_ci else if (ver == RTL_GIGA_MAC_VER_45) 20648c2ecf20Sopenharmony_ci ver = RTL_GIGA_MAC_VER_47; 20658c2ecf20Sopenharmony_ci else if (ver == RTL_GIGA_MAC_VER_46) 20668c2ecf20Sopenharmony_ci ver = RTL_GIGA_MAC_VER_48; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci return ver; 20708c2ecf20Sopenharmony_ci} 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_cistatic void rtl_release_firmware(struct rtl8169_private *tp) 20738c2ecf20Sopenharmony_ci{ 20748c2ecf20Sopenharmony_ci if (tp->rtl_fw) { 20758c2ecf20Sopenharmony_ci rtl_fw_release_firmware(tp->rtl_fw); 20768c2ecf20Sopenharmony_ci kfree(tp->rtl_fw); 20778c2ecf20Sopenharmony_ci tp->rtl_fw = NULL; 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci} 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_civoid r8169_apply_firmware(struct rtl8169_private *tp) 20828c2ecf20Sopenharmony_ci{ 20838c2ecf20Sopenharmony_ci int val; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci /* TODO: release firmware if rtl_fw_write_firmware signals failure. */ 20868c2ecf20Sopenharmony_ci if (tp->rtl_fw) { 20878c2ecf20Sopenharmony_ci rtl_fw_write_firmware(tp, tp->rtl_fw); 20888c2ecf20Sopenharmony_ci /* At least one firmware doesn't reset tp->ocp_base. */ 20898c2ecf20Sopenharmony_ci tp->ocp_base = OCP_STD_PHY_BASE; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci /* PHY soft reset may still be in progress */ 20928c2ecf20Sopenharmony_ci phy_read_poll_timeout(tp->phydev, MII_BMCR, val, 20938c2ecf20Sopenharmony_ci !(val & BMCR_RESET), 20948c2ecf20Sopenharmony_ci 50000, 600000, true); 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci} 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_cistatic void rtl8168_config_eee_mac(struct rtl8169_private *tp) 20998c2ecf20Sopenharmony_ci{ 21008c2ecf20Sopenharmony_ci /* Adjust EEE LED frequency */ 21018c2ecf20Sopenharmony_ci if (tp->mac_version != RTL_GIGA_MAC_VER_38) 21028c2ecf20Sopenharmony_ci RTL_W8(tp, EEE_LED, RTL_R8(tp, EEE_LED) & ~0x07); 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x1b0, 0x0003); 21058c2ecf20Sopenharmony_ci} 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_cistatic void rtl8125a_config_eee_mac(struct rtl8169_private *tp) 21088c2ecf20Sopenharmony_ci{ 21098c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0)); 21108c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xeb62, 0, BIT(2) | BIT(1)); 21118c2ecf20Sopenharmony_ci} 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_cistatic void rtl8125_set_eee_txidle_timer(struct rtl8169_private *tp) 21148c2ecf20Sopenharmony_ci{ 21158c2ecf20Sopenharmony_ci RTL_W16(tp, EEE_TXIDLE_TIMER_8125, tp->dev->mtu + ETH_HLEN + 0x20); 21168c2ecf20Sopenharmony_ci} 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_cistatic void rtl8125b_config_eee_mac(struct rtl8169_private *tp) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci rtl8125_set_eee_txidle_timer(tp); 21218c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0)); 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_cistatic void rtl_rar_exgmac_set(struct rtl8169_private *tp, u8 *addr) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci const u16 w[] = { 21278c2ecf20Sopenharmony_ci addr[0] | (addr[1] << 8), 21288c2ecf20Sopenharmony_ci addr[2] | (addr[3] << 8), 21298c2ecf20Sopenharmony_ci addr[4] | (addr[5] << 8) 21308c2ecf20Sopenharmony_ci }; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xe0, ERIAR_MASK_1111, w[0] | (w[1] << 16)); 21338c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xe4, ERIAR_MASK_1111, w[2]); 21348c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xf0, ERIAR_MASK_1111, w[0] << 16); 21358c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xf4, ERIAR_MASK_1111, w[1] | (w[2] << 16)); 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ciu16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp) 21398c2ecf20Sopenharmony_ci{ 21408c2ecf20Sopenharmony_ci u16 data1, data2, ioffset; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xdd02, 0x807d); 21438c2ecf20Sopenharmony_ci data1 = r8168_mac_ocp_read(tp, 0xdd02); 21448c2ecf20Sopenharmony_ci data2 = r8168_mac_ocp_read(tp, 0xdd00); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci ioffset = (data2 >> 1) & 0x7ff8; 21478c2ecf20Sopenharmony_ci ioffset |= data2 & 0x0007; 21488c2ecf20Sopenharmony_ci if (data1 & BIT(7)) 21498c2ecf20Sopenharmony_ci ioffset |= BIT(15); 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci return ioffset; 21528c2ecf20Sopenharmony_ci} 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_cistatic void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag) 21558c2ecf20Sopenharmony_ci{ 21568c2ecf20Sopenharmony_ci set_bit(flag, tp->wk.flags); 21578c2ecf20Sopenharmony_ci schedule_work(&tp->wk.work); 21588c2ecf20Sopenharmony_ci} 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_cistatic void rtl8169_init_phy(struct rtl8169_private *tp) 21618c2ecf20Sopenharmony_ci{ 21628c2ecf20Sopenharmony_ci r8169_hw_phy_config(tp, tp->phydev, tp->mac_version); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { 21658c2ecf20Sopenharmony_ci pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40); 21668c2ecf20Sopenharmony_ci pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08); 21678c2ecf20Sopenharmony_ci /* set undocumented MAC Reg C+CR Offset 0x82h */ 21688c2ecf20Sopenharmony_ci RTL_W8(tp, 0x82, 0x01); 21698c2ecf20Sopenharmony_ci } 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_05 && 21728c2ecf20Sopenharmony_ci tp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_GIGABYTE && 21738c2ecf20Sopenharmony_ci tp->pci_dev->subsystem_device == 0xe000) 21748c2ecf20Sopenharmony_ci phy_write_paged(tp->phydev, 0x0001, 0x10, 0xf01b); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci /* We may have called phy_speed_down before */ 21778c2ecf20Sopenharmony_ci phy_speed_up(tp->phydev); 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci if (rtl_supports_eee(tp)) 21808c2ecf20Sopenharmony_ci rtl_enable_eee(tp); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci genphy_soft_reset(tp->phydev); 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_cistatic void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci rtl_unlock_config_regs(tp); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci RTL_W32(tp, MAC4, addr[4] | addr[5] << 8); 21908c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci RTL_W32(tp, MAC0, addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 21938c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_34) 21968c2ecf20Sopenharmony_ci rtl_rar_exgmac_set(tp, addr); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci rtl_lock_config_regs(tp); 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_cistatic int rtl_set_mac_address(struct net_device *dev, void *p) 22028c2ecf20Sopenharmony_ci{ 22038c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 22048c2ecf20Sopenharmony_ci int ret; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci ret = eth_mac_addr(dev, p); 22078c2ecf20Sopenharmony_ci if (ret) 22088c2ecf20Sopenharmony_ci return ret; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci rtl_rar_set(tp, dev->dev_addr); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci return 0; 22138c2ecf20Sopenharmony_ci} 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_cistatic void rtl_wol_suspend_quirk(struct rtl8169_private *tp) 22168c2ecf20Sopenharmony_ci{ 22178c2ecf20Sopenharmony_ci switch (tp->mac_version) { 22188c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_25: 22198c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_26: 22208c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_29: 22218c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_30: 22228c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_32: 22238c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_33: 22248c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_34: 22258c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_63: 22268c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) | 22278c2ecf20Sopenharmony_ci AcceptBroadcast | AcceptMulticast | AcceptMyPhys); 22288c2ecf20Sopenharmony_ci break; 22298c2ecf20Sopenharmony_ci default: 22308c2ecf20Sopenharmony_ci break; 22318c2ecf20Sopenharmony_ci } 22328c2ecf20Sopenharmony_ci} 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_cistatic void rtl_pll_power_down(struct rtl8169_private *tp) 22358c2ecf20Sopenharmony_ci{ 22368c2ecf20Sopenharmony_ci if (r8168_check_dash(tp)) 22378c2ecf20Sopenharmony_ci return; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_32 || 22408c2ecf20Sopenharmony_ci tp->mac_version == RTL_GIGA_MAC_VER_33) 22418c2ecf20Sopenharmony_ci rtl_ephy_write(tp, 0x19, 0xff64); 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci if (device_may_wakeup(tp_to_dev(tp))) { 22448c2ecf20Sopenharmony_ci phy_speed_down(tp->phydev, false); 22458c2ecf20Sopenharmony_ci rtl_wol_suspend_quirk(tp); 22468c2ecf20Sopenharmony_ci return; 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci switch (tp->mac_version) { 22508c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: 22518c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: 22528c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_33: 22538c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_37: 22548c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_39: 22558c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_43: 22568c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_44: 22578c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_45: 22588c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_46: 22598c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_47: 22608c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_48: 22618c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_50 ... RTL_GIGA_MAC_VER_63: 22628c2ecf20Sopenharmony_ci RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~0x80); 22638c2ecf20Sopenharmony_ci break; 22648c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_40: 22658c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_41: 22668c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_49: 22678c2ecf20Sopenharmony_ci rtl_eri_clear_bits(tp, 0x1a8, 0xfc000000); 22688c2ecf20Sopenharmony_ci RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~0x80); 22698c2ecf20Sopenharmony_ci break; 22708c2ecf20Sopenharmony_ci default: 22718c2ecf20Sopenharmony_ci break; 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci} 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_cistatic void rtl_pll_power_up(struct rtl8169_private *tp) 22768c2ecf20Sopenharmony_ci{ 22778c2ecf20Sopenharmony_ci switch (tp->mac_version) { 22788c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: 22798c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: 22808c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_33: 22818c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_37: 22828c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_39: 22838c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_43: 22848c2ecf20Sopenharmony_ci RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | 0x80); 22858c2ecf20Sopenharmony_ci break; 22868c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_44: 22878c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_45: 22888c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_46: 22898c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_47: 22908c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_48: 22918c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_50 ... RTL_GIGA_MAC_VER_63: 22928c2ecf20Sopenharmony_ci RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | 0xc0); 22938c2ecf20Sopenharmony_ci break; 22948c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_40: 22958c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_41: 22968c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_49: 22978c2ecf20Sopenharmony_ci RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | 0xc0); 22988c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x1a8, 0xfc000000); 22998c2ecf20Sopenharmony_ci break; 23008c2ecf20Sopenharmony_ci default: 23018c2ecf20Sopenharmony_ci break; 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci phy_resume(tp->phydev); 23058c2ecf20Sopenharmony_ci} 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_cistatic void rtl_init_rxcfg(struct rtl8169_private *tp) 23088c2ecf20Sopenharmony_ci{ 23098c2ecf20Sopenharmony_ci switch (tp->mac_version) { 23108c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: 23118c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_10 ... RTL_GIGA_MAC_VER_17: 23128c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, RX_FIFO_THRESH | RX_DMA_BURST); 23138c2ecf20Sopenharmony_ci break; 23148c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24: 23158c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_36: 23168c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_38: 23178c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST); 23188c2ecf20Sopenharmony_ci break; 23198c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52: 23208c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF); 23218c2ecf20Sopenharmony_ci break; 23228c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_61: 23238c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); 23248c2ecf20Sopenharmony_ci break; 23258c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_63: 23268c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | 23278c2ecf20Sopenharmony_ci RX_PAUSE_SLOT_ON); 23288c2ecf20Sopenharmony_ci break; 23298c2ecf20Sopenharmony_ci default: 23308c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, RX128_INT_EN | RX_DMA_BURST); 23318c2ecf20Sopenharmony_ci break; 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci} 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_cistatic void rtl8169_init_ring_indexes(struct rtl8169_private *tp) 23368c2ecf20Sopenharmony_ci{ 23378c2ecf20Sopenharmony_ci tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0; 23388c2ecf20Sopenharmony_ci} 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_cistatic void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) 23418c2ecf20Sopenharmony_ci{ 23428c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); 23438c2ecf20Sopenharmony_ci RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1); 23448c2ecf20Sopenharmony_ci} 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_cistatic void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) 23478c2ecf20Sopenharmony_ci{ 23488c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); 23498c2ecf20Sopenharmony_ci RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1); 23508c2ecf20Sopenharmony_ci} 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_cistatic void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp) 23538c2ecf20Sopenharmony_ci{ 23548c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); 23558c2ecf20Sopenharmony_ci} 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_cistatic void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp) 23588c2ecf20Sopenharmony_ci{ 23598c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); 23608c2ecf20Sopenharmony_ci} 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_cistatic void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) 23638c2ecf20Sopenharmony_ci{ 23648c2ecf20Sopenharmony_ci RTL_W8(tp, MaxTxPacketSize, 0x24); 23658c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); 23668c2ecf20Sopenharmony_ci RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01); 23678c2ecf20Sopenharmony_ci} 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_cistatic void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) 23708c2ecf20Sopenharmony_ci{ 23718c2ecf20Sopenharmony_ci RTL_W8(tp, MaxTxPacketSize, 0x3f); 23728c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); 23738c2ecf20Sopenharmony_ci RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); 23748c2ecf20Sopenharmony_ci} 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_cistatic void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) 23778c2ecf20Sopenharmony_ci{ 23788c2ecf20Sopenharmony_ci RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0)); 23798c2ecf20Sopenharmony_ci} 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_cistatic void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) 23828c2ecf20Sopenharmony_ci{ 23838c2ecf20Sopenharmony_ci RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); 23848c2ecf20Sopenharmony_ci} 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_cistatic void rtl_jumbo_config(struct rtl8169_private *tp) 23878c2ecf20Sopenharmony_ci{ 23888c2ecf20Sopenharmony_ci bool jumbo = tp->dev->mtu > ETH_DATA_LEN; 23898c2ecf20Sopenharmony_ci int readrq = 4096; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci rtl_unlock_config_regs(tp); 23928c2ecf20Sopenharmony_ci switch (tp->mac_version) { 23938c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_12: 23948c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_17: 23958c2ecf20Sopenharmony_ci if (jumbo) { 23968c2ecf20Sopenharmony_ci readrq = 512; 23978c2ecf20Sopenharmony_ci r8168b_1_hw_jumbo_enable(tp); 23988c2ecf20Sopenharmony_ci } else { 23998c2ecf20Sopenharmony_ci r8168b_1_hw_jumbo_disable(tp); 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci break; 24028c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26: 24038c2ecf20Sopenharmony_ci if (jumbo) { 24048c2ecf20Sopenharmony_ci readrq = 512; 24058c2ecf20Sopenharmony_ci r8168c_hw_jumbo_enable(tp); 24068c2ecf20Sopenharmony_ci } else { 24078c2ecf20Sopenharmony_ci r8168c_hw_jumbo_disable(tp); 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci break; 24108c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_27 ... RTL_GIGA_MAC_VER_28: 24118c2ecf20Sopenharmony_ci if (jumbo) 24128c2ecf20Sopenharmony_ci r8168dp_hw_jumbo_enable(tp); 24138c2ecf20Sopenharmony_ci else 24148c2ecf20Sopenharmony_ci r8168dp_hw_jumbo_disable(tp); 24158c2ecf20Sopenharmony_ci break; 24168c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33: 24178c2ecf20Sopenharmony_ci if (jumbo) { 24188c2ecf20Sopenharmony_ci pcie_set_readrq(tp->pci_dev, 512); 24198c2ecf20Sopenharmony_ci r8168e_hw_jumbo_enable(tp); 24208c2ecf20Sopenharmony_ci } else { 24218c2ecf20Sopenharmony_ci r8168e_hw_jumbo_disable(tp); 24228c2ecf20Sopenharmony_ci } 24238c2ecf20Sopenharmony_ci break; 24248c2ecf20Sopenharmony_ci default: 24258c2ecf20Sopenharmony_ci break; 24268c2ecf20Sopenharmony_ci } 24278c2ecf20Sopenharmony_ci rtl_lock_config_regs(tp); 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci if (pci_is_pcie(tp->pci_dev) && tp->supports_gmii) 24308c2ecf20Sopenharmony_ci pcie_set_readrq(tp->pci_dev, readrq); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci /* Chip doesn't support pause in jumbo mode */ 24338c2ecf20Sopenharmony_ci linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, 24348c2ecf20Sopenharmony_ci tp->phydev->advertising, !jumbo); 24358c2ecf20Sopenharmony_ci linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, 24368c2ecf20Sopenharmony_ci tp->phydev->advertising, !jumbo); 24378c2ecf20Sopenharmony_ci phy_start_aneg(tp->phydev); 24388c2ecf20Sopenharmony_ci} 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_chipcmd_cond) 24418c2ecf20Sopenharmony_ci{ 24428c2ecf20Sopenharmony_ci return RTL_R8(tp, ChipCmd) & CmdReset; 24438c2ecf20Sopenharmony_ci} 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_cistatic void rtl_hw_reset(struct rtl8169_private *tp) 24468c2ecf20Sopenharmony_ci{ 24478c2ecf20Sopenharmony_ci RTL_W8(tp, ChipCmd, CmdReset); 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); 24508c2ecf20Sopenharmony_ci} 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_cistatic void rtl_request_firmware(struct rtl8169_private *tp) 24538c2ecf20Sopenharmony_ci{ 24548c2ecf20Sopenharmony_ci struct rtl_fw *rtl_fw; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci /* firmware loaded already or no firmware available */ 24578c2ecf20Sopenharmony_ci if (tp->rtl_fw || !tp->fw_name) 24588c2ecf20Sopenharmony_ci return; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL); 24618c2ecf20Sopenharmony_ci if (!rtl_fw) 24628c2ecf20Sopenharmony_ci return; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci rtl_fw->phy_write = rtl_writephy; 24658c2ecf20Sopenharmony_ci rtl_fw->phy_read = rtl_readphy; 24668c2ecf20Sopenharmony_ci rtl_fw->mac_mcu_write = mac_mcu_write; 24678c2ecf20Sopenharmony_ci rtl_fw->mac_mcu_read = mac_mcu_read; 24688c2ecf20Sopenharmony_ci rtl_fw->fw_name = tp->fw_name; 24698c2ecf20Sopenharmony_ci rtl_fw->dev = tp_to_dev(tp); 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci if (rtl_fw_request_firmware(rtl_fw)) 24728c2ecf20Sopenharmony_ci kfree(rtl_fw); 24738c2ecf20Sopenharmony_ci else 24748c2ecf20Sopenharmony_ci tp->rtl_fw = rtl_fw; 24758c2ecf20Sopenharmony_ci} 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_cistatic void rtl_rx_close(struct rtl8169_private *tp) 24788c2ecf20Sopenharmony_ci{ 24798c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) & ~RX_CONFIG_ACCEPT_MASK); 24808c2ecf20Sopenharmony_ci} 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_npq_cond) 24838c2ecf20Sopenharmony_ci{ 24848c2ecf20Sopenharmony_ci return RTL_R8(tp, TxPoll) & NPQ; 24858c2ecf20Sopenharmony_ci} 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_txcfg_empty_cond) 24888c2ecf20Sopenharmony_ci{ 24898c2ecf20Sopenharmony_ci return RTL_R32(tp, TxConfig) & TXCFG_EMPTY; 24908c2ecf20Sopenharmony_ci} 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_rxtx_empty_cond) 24938c2ecf20Sopenharmony_ci{ 24948c2ecf20Sopenharmony_ci return (RTL_R8(tp, MCU) & RXTX_EMPTY) == RXTX_EMPTY; 24958c2ecf20Sopenharmony_ci} 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_rxtx_empty_cond_2) 24988c2ecf20Sopenharmony_ci{ 24998c2ecf20Sopenharmony_ci /* IntrMitigate has new functionality on RTL8125 */ 25008c2ecf20Sopenharmony_ci return (RTL_R16(tp, IntrMitigate) & 0x0103) == 0x0103; 25018c2ecf20Sopenharmony_ci} 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_cistatic void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) 25048c2ecf20Sopenharmony_ci{ 25058c2ecf20Sopenharmony_ci switch (tp->mac_version) { 25068c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52: 25078c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42); 25088c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); 25098c2ecf20Sopenharmony_ci break; 25108c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_60 ... RTL_GIGA_MAC_VER_61: 25118c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); 25128c2ecf20Sopenharmony_ci break; 25138c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_63: 25148c2ecf20Sopenharmony_ci RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); 25158c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); 25168c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); 25178c2ecf20Sopenharmony_ci break; 25188c2ecf20Sopenharmony_ci default: 25198c2ecf20Sopenharmony_ci break; 25208c2ecf20Sopenharmony_ci } 25218c2ecf20Sopenharmony_ci} 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_cistatic void rtl_enable_rxdvgate(struct rtl8169_private *tp) 25248c2ecf20Sopenharmony_ci{ 25258c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) | RXDV_GATED_EN); 25268c2ecf20Sopenharmony_ci fsleep(2000); 25278c2ecf20Sopenharmony_ci rtl_wait_txrx_fifo_empty(tp); 25288c2ecf20Sopenharmony_ci} 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_cistatic void rtl_set_tx_config_registers(struct rtl8169_private *tp) 25318c2ecf20Sopenharmony_ci{ 25328c2ecf20Sopenharmony_ci u32 val = TX_DMA_BURST << TxDMAShift | 25338c2ecf20Sopenharmony_ci InterFrameGap << TxInterFrameGapShift; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci if (rtl_is_8168evl_up(tp)) 25368c2ecf20Sopenharmony_ci val |= TXCFG_AUTO_FIFO; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci RTL_W32(tp, TxConfig, val); 25398c2ecf20Sopenharmony_ci} 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_cistatic void rtl_set_rx_max_size(struct rtl8169_private *tp) 25428c2ecf20Sopenharmony_ci{ 25438c2ecf20Sopenharmony_ci /* Low hurts. Let's disable the filtering. */ 25448c2ecf20Sopenharmony_ci RTL_W16(tp, RxMaxSize, R8169_RX_BUF_SIZE + 1); 25458c2ecf20Sopenharmony_ci} 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_cistatic void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp) 25488c2ecf20Sopenharmony_ci{ 25498c2ecf20Sopenharmony_ci /* 25508c2ecf20Sopenharmony_ci * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh 25518c2ecf20Sopenharmony_ci * register to be written before TxDescAddrLow to work. 25528c2ecf20Sopenharmony_ci * Switching from MMIO to I/O access fixes the issue as well. 25538c2ecf20Sopenharmony_ci */ 25548c2ecf20Sopenharmony_ci RTL_W32(tp, TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32); 25558c2ecf20Sopenharmony_ci RTL_W32(tp, TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32)); 25568c2ecf20Sopenharmony_ci RTL_W32(tp, RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32); 25578c2ecf20Sopenharmony_ci RTL_W32(tp, RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32)); 25588c2ecf20Sopenharmony_ci} 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_cistatic void rtl8169_set_magic_reg(struct rtl8169_private *tp) 25618c2ecf20Sopenharmony_ci{ 25628c2ecf20Sopenharmony_ci u32 val; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_05) 25658c2ecf20Sopenharmony_ci val = 0x000fff00; 25668c2ecf20Sopenharmony_ci else if (tp->mac_version == RTL_GIGA_MAC_VER_06) 25678c2ecf20Sopenharmony_ci val = 0x00ffff00; 25688c2ecf20Sopenharmony_ci else 25698c2ecf20Sopenharmony_ci return; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci if (RTL_R8(tp, Config2) & PCI_Clock_66MHz) 25728c2ecf20Sopenharmony_ci val |= 0xff; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci RTL_W32(tp, 0x7c, val); 25758c2ecf20Sopenharmony_ci} 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_cistatic void rtl_set_rx_mode(struct net_device *dev) 25788c2ecf20Sopenharmony_ci{ 25798c2ecf20Sopenharmony_ci u32 rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast; 25808c2ecf20Sopenharmony_ci /* Multicast hash filter */ 25818c2ecf20Sopenharmony_ci u32 mc_filter[2] = { 0xffffffff, 0xffffffff }; 25828c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 25838c2ecf20Sopenharmony_ci u32 tmp; 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 25868c2ecf20Sopenharmony_ci rx_mode |= AcceptAllPhys; 25878c2ecf20Sopenharmony_ci } else if (!(dev->flags & IFF_MULTICAST)) { 25888c2ecf20Sopenharmony_ci rx_mode &= ~AcceptMulticast; 25898c2ecf20Sopenharmony_ci } else if (netdev_mc_count(dev) > MC_FILTER_LIMIT || 25908c2ecf20Sopenharmony_ci dev->flags & IFF_ALLMULTI || 25918c2ecf20Sopenharmony_ci tp->mac_version == RTL_GIGA_MAC_VER_35) { 25928c2ecf20Sopenharmony_ci /* accept all multicasts */ 25938c2ecf20Sopenharmony_ci } else if (netdev_mc_empty(dev)) { 25948c2ecf20Sopenharmony_ci rx_mode &= ~AcceptMulticast; 25958c2ecf20Sopenharmony_ci } else { 25968c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci mc_filter[1] = mc_filter[0] = 0; 25998c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 26008c2ecf20Sopenharmony_ci u32 bit_nr = eth_hw_addr_crc(ha) >> 26; 26018c2ecf20Sopenharmony_ci mc_filter[bit_nr >> 5] |= BIT(bit_nr & 31); 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci if (tp->mac_version > RTL_GIGA_MAC_VER_06) { 26058c2ecf20Sopenharmony_ci tmp = mc_filter[0]; 26068c2ecf20Sopenharmony_ci mc_filter[0] = swab32(mc_filter[1]); 26078c2ecf20Sopenharmony_ci mc_filter[1] = swab32(tmp); 26088c2ecf20Sopenharmony_ci } 26098c2ecf20Sopenharmony_ci } 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci RTL_W32(tp, MAR0 + 4, mc_filter[1]); 26128c2ecf20Sopenharmony_ci RTL_W32(tp, MAR0 + 0, mc_filter[0]); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci tmp = RTL_R32(tp, RxConfig); 26158c2ecf20Sopenharmony_ci RTL_W32(tp, RxConfig, (tmp & ~RX_CONFIG_ACCEPT_OK_MASK) | rx_mode); 26168c2ecf20Sopenharmony_ci} 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_csiar_cond) 26198c2ecf20Sopenharmony_ci{ 26208c2ecf20Sopenharmony_ci return RTL_R32(tp, CSIAR) & CSIAR_FLAG; 26218c2ecf20Sopenharmony_ci} 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_cistatic void rtl_csi_write(struct rtl8169_private *tp, int addr, int value) 26248c2ecf20Sopenharmony_ci{ 26258c2ecf20Sopenharmony_ci u32 func = PCI_FUNC(tp->pci_dev->devfn); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci RTL_W32(tp, CSIDR, value); 26288c2ecf20Sopenharmony_ci RTL_W32(tp, CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | 26298c2ecf20Sopenharmony_ci CSIAR_BYTE_ENABLE | func << 16); 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_csiar_cond, 10, 100); 26328c2ecf20Sopenharmony_ci} 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_cistatic u32 rtl_csi_read(struct rtl8169_private *tp, int addr) 26358c2ecf20Sopenharmony_ci{ 26368c2ecf20Sopenharmony_ci u32 func = PCI_FUNC(tp->pci_dev->devfn); 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci RTL_W32(tp, CSIAR, (addr & CSIAR_ADDR_MASK) | func << 16 | 26398c2ecf20Sopenharmony_ci CSIAR_BYTE_ENABLE); 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci return rtl_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ? 26428c2ecf20Sopenharmony_ci RTL_R32(tp, CSIDR) : ~0; 26438c2ecf20Sopenharmony_ci} 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_cistatic void rtl_csi_access_enable(struct rtl8169_private *tp, u8 val) 26468c2ecf20Sopenharmony_ci{ 26478c2ecf20Sopenharmony_ci struct pci_dev *pdev = tp->pci_dev; 26488c2ecf20Sopenharmony_ci u32 csi; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci /* According to Realtek the value at config space address 0x070f 26518c2ecf20Sopenharmony_ci * controls the L0s/L1 entrance latency. We try standard ECAM access 26528c2ecf20Sopenharmony_ci * first and if it fails fall back to CSI. 26538c2ecf20Sopenharmony_ci */ 26548c2ecf20Sopenharmony_ci if (pdev->cfg_size > 0x070f && 26558c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, 0x070f, val) == PCIBIOS_SUCCESSFUL) 26568c2ecf20Sopenharmony_ci return; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci netdev_notice_once(tp->dev, 26598c2ecf20Sopenharmony_ci "No native access to PCI extended config space, falling back to CSI\n"); 26608c2ecf20Sopenharmony_ci csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff; 26618c2ecf20Sopenharmony_ci rtl_csi_write(tp, 0x070c, csi | val << 24); 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_cistatic void rtl_set_def_aspm_entry_latency(struct rtl8169_private *tp) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci rtl_csi_access_enable(tp, 0x27); 26678c2ecf20Sopenharmony_ci} 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_cistruct ephy_info { 26708c2ecf20Sopenharmony_ci unsigned int offset; 26718c2ecf20Sopenharmony_ci u16 mask; 26728c2ecf20Sopenharmony_ci u16 bits; 26738c2ecf20Sopenharmony_ci}; 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_cistatic void __rtl_ephy_init(struct rtl8169_private *tp, 26768c2ecf20Sopenharmony_ci const struct ephy_info *e, int len) 26778c2ecf20Sopenharmony_ci{ 26788c2ecf20Sopenharmony_ci u16 w; 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci while (len-- > 0) { 26818c2ecf20Sopenharmony_ci w = (rtl_ephy_read(tp, e->offset) & ~e->mask) | e->bits; 26828c2ecf20Sopenharmony_ci rtl_ephy_write(tp, e->offset, w); 26838c2ecf20Sopenharmony_ci e++; 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci} 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci#define rtl_ephy_init(tp, a) __rtl_ephy_init(tp, a, ARRAY_SIZE(a)) 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_cistatic void rtl_disable_clock_request(struct rtl8169_private *tp) 26908c2ecf20Sopenharmony_ci{ 26918c2ecf20Sopenharmony_ci pcie_capability_clear_word(tp->pci_dev, PCI_EXP_LNKCTL, 26928c2ecf20Sopenharmony_ci PCI_EXP_LNKCTL_CLKREQ_EN); 26938c2ecf20Sopenharmony_ci} 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_cistatic void rtl_enable_clock_request(struct rtl8169_private *tp) 26968c2ecf20Sopenharmony_ci{ 26978c2ecf20Sopenharmony_ci pcie_capability_set_word(tp->pci_dev, PCI_EXP_LNKCTL, 26988c2ecf20Sopenharmony_ci PCI_EXP_LNKCTL_CLKREQ_EN); 26998c2ecf20Sopenharmony_ci} 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_cistatic void rtl_pcie_state_l2l3_disable(struct rtl8169_private *tp) 27028c2ecf20Sopenharmony_ci{ 27038c2ecf20Sopenharmony_ci /* work around an issue when PCI reset occurs during L2/L3 state */ 27048c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Rdy_to_L23); 27058c2ecf20Sopenharmony_ci} 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_cistatic void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci /* Don't enable ASPM in the chip if OS can't control ASPM */ 27108c2ecf20Sopenharmony_ci if (enable && tp->aspm_manageable) { 27118c2ecf20Sopenharmony_ci RTL_W8(tp, Config5, RTL_R8(tp, Config5) | ASPM_en); 27128c2ecf20Sopenharmony_ci RTL_W8(tp, Config2, RTL_R8(tp, Config2) | ClkReqEn); 27138c2ecf20Sopenharmony_ci } else { 27148c2ecf20Sopenharmony_ci RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~ClkReqEn); 27158c2ecf20Sopenharmony_ci RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~ASPM_en); 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci udelay(10); 27198c2ecf20Sopenharmony_ci} 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_cistatic void rtl_set_fifo_size(struct rtl8169_private *tp, u16 rx_stat, 27228c2ecf20Sopenharmony_ci u16 tx_stat, u16 rx_dyn, u16 tx_dyn) 27238c2ecf20Sopenharmony_ci{ 27248c2ecf20Sopenharmony_ci /* Usage of dynamic vs. static FIFO is controlled by bit 27258c2ecf20Sopenharmony_ci * TXCFG_AUTO_FIFO. Exact meaning of FIFO values isn't known. 27268c2ecf20Sopenharmony_ci */ 27278c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, (rx_stat << 16) | rx_dyn); 27288c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, (tx_stat << 16) | tx_dyn); 27298c2ecf20Sopenharmony_ci} 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_cistatic void rtl8168g_set_pause_thresholds(struct rtl8169_private *tp, 27328c2ecf20Sopenharmony_ci u8 low, u8 high) 27338c2ecf20Sopenharmony_ci{ 27348c2ecf20Sopenharmony_ci /* FIFO thresholds for pause flow control */ 27358c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, low); 27368c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, high); 27378c2ecf20Sopenharmony_ci} 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168b(struct rtl8169_private *tp) 27408c2ecf20Sopenharmony_ci{ 27418c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); 27428c2ecf20Sopenharmony_ci} 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_cistatic void __rtl_hw_start_8168cp(struct rtl8169_private *tp) 27458c2ecf20Sopenharmony_ci{ 27468c2ecf20Sopenharmony_ci RTL_W8(tp, Config1, RTL_R8(tp, Config1) | Speed_down); 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci rtl_disable_clock_request(tp); 27518c2ecf20Sopenharmony_ci} 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168cp_1(struct rtl8169_private *tp) 27548c2ecf20Sopenharmony_ci{ 27558c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168cp[] = { 27568c2ecf20Sopenharmony_ci { 0x01, 0, 0x0001 }, 27578c2ecf20Sopenharmony_ci { 0x02, 0x0800, 0x1000 }, 27588c2ecf20Sopenharmony_ci { 0x03, 0, 0x0042 }, 27598c2ecf20Sopenharmony_ci { 0x06, 0x0080, 0x0000 }, 27608c2ecf20Sopenharmony_ci { 0x07, 0, 0x2000 } 27618c2ecf20Sopenharmony_ci }; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168cp); 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci __rtl_hw_start_8168cp(tp); 27688c2ecf20Sopenharmony_ci} 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168cp_2(struct rtl8169_private *tp) 27718c2ecf20Sopenharmony_ci{ 27728c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); 27758c2ecf20Sopenharmony_ci} 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168cp_3(struct rtl8169_private *tp) 27788c2ecf20Sopenharmony_ci{ 27798c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci /* Magic. */ 27848c2ecf20Sopenharmony_ci RTL_W8(tp, DBG_REG, 0x20); 27858c2ecf20Sopenharmony_ci} 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168c_1(struct rtl8169_private *tp) 27888c2ecf20Sopenharmony_ci{ 27898c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168c_1[] = { 27908c2ecf20Sopenharmony_ci { 0x02, 0x0800, 0x1000 }, 27918c2ecf20Sopenharmony_ci { 0x03, 0, 0x0002 }, 27928c2ecf20Sopenharmony_ci { 0x06, 0x0080, 0x0000 } 27938c2ecf20Sopenharmony_ci }; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci RTL_W8(tp, DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2); 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168c_1); 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci __rtl_hw_start_8168cp(tp); 28028c2ecf20Sopenharmony_ci} 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168c_2(struct rtl8169_private *tp) 28058c2ecf20Sopenharmony_ci{ 28068c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168c_2[] = { 28078c2ecf20Sopenharmony_ci { 0x01, 0, 0x0001 }, 28088c2ecf20Sopenharmony_ci { 0x03, 0x0400, 0x0020 } 28098c2ecf20Sopenharmony_ci }; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168c_2); 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci __rtl_hw_start_8168cp(tp); 28168c2ecf20Sopenharmony_ci} 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168c_3(struct rtl8169_private *tp) 28198c2ecf20Sopenharmony_ci{ 28208c2ecf20Sopenharmony_ci rtl_hw_start_8168c_2(tp); 28218c2ecf20Sopenharmony_ci} 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168c_4(struct rtl8169_private *tp) 28248c2ecf20Sopenharmony_ci{ 28258c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci __rtl_hw_start_8168cp(tp); 28288c2ecf20Sopenharmony_ci} 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168d(struct rtl8169_private *tp) 28318c2ecf20Sopenharmony_ci{ 28328c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci rtl_disable_clock_request(tp); 28358c2ecf20Sopenharmony_ci} 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168d_4(struct rtl8169_private *tp) 28388c2ecf20Sopenharmony_ci{ 28398c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168d_4[] = { 28408c2ecf20Sopenharmony_ci { 0x0b, 0x0000, 0x0048 }, 28418c2ecf20Sopenharmony_ci { 0x19, 0x0020, 0x0050 }, 28428c2ecf20Sopenharmony_ci { 0x0c, 0x0100, 0x0020 }, 28438c2ecf20Sopenharmony_ci { 0x10, 0x0004, 0x0000 }, 28448c2ecf20Sopenharmony_ci }; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168d_4); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci rtl_enable_clock_request(tp); 28518c2ecf20Sopenharmony_ci} 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168e_1(struct rtl8169_private *tp) 28548c2ecf20Sopenharmony_ci{ 28558c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168e_1[] = { 28568c2ecf20Sopenharmony_ci { 0x00, 0x0200, 0x0100 }, 28578c2ecf20Sopenharmony_ci { 0x00, 0x0000, 0x0004 }, 28588c2ecf20Sopenharmony_ci { 0x06, 0x0002, 0x0001 }, 28598c2ecf20Sopenharmony_ci { 0x06, 0x0000, 0x0030 }, 28608c2ecf20Sopenharmony_ci { 0x07, 0x0000, 0x2000 }, 28618c2ecf20Sopenharmony_ci { 0x00, 0x0000, 0x0020 }, 28628c2ecf20Sopenharmony_ci { 0x03, 0x5800, 0x2000 }, 28638c2ecf20Sopenharmony_ci { 0x03, 0x0000, 0x0001 }, 28648c2ecf20Sopenharmony_ci { 0x01, 0x0800, 0x1000 }, 28658c2ecf20Sopenharmony_ci { 0x07, 0x0000, 0x4000 }, 28668c2ecf20Sopenharmony_ci { 0x1e, 0x0000, 0x2000 }, 28678c2ecf20Sopenharmony_ci { 0x19, 0xffff, 0xfe6c }, 28688c2ecf20Sopenharmony_ci { 0x0a, 0x0000, 0x0040 } 28698c2ecf20Sopenharmony_ci }; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168e_1); 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci rtl_disable_clock_request(tp); 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci /* Reset tx FIFO pointer */ 28788c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) | TXPLA_RST); 28798c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~TXPLA_RST); 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~Spi_en); 28828c2ecf20Sopenharmony_ci} 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168e_2(struct rtl8169_private *tp) 28858c2ecf20Sopenharmony_ci{ 28868c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168e_2[] = { 28878c2ecf20Sopenharmony_ci { 0x09, 0x0000, 0x0080 }, 28888c2ecf20Sopenharmony_ci { 0x19, 0x0000, 0x0224 }, 28898c2ecf20Sopenharmony_ci { 0x00, 0x0000, 0x0004 }, 28908c2ecf20Sopenharmony_ci { 0x0c, 0x3df0, 0x0200 }, 28918c2ecf20Sopenharmony_ci }; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168e_2); 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); 28988c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xb8, ERIAR_MASK_1111, 0x0000); 28998c2ecf20Sopenharmony_ci rtl_set_fifo_size(tp, 0x10, 0x10, 0x02, 0x06); 29008c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x0d4, 0x1f00); 29018c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x1d0, BIT(1)); 29028c2ecf20Sopenharmony_ci rtl_reset_packet_filter(tp); 29038c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x1b0, BIT(4)); 29048c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050); 29058c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060); 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci rtl_disable_clock_request(tp); 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB); 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci rtl8168_config_eee_mac(tp); 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN); 29148c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) | PWM_EN); 29158c2ecf20Sopenharmony_ci RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~Spi_en); 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 29188c2ecf20Sopenharmony_ci} 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168f(struct rtl8169_private *tp) 29218c2ecf20Sopenharmony_ci{ 29228c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); 29258c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xb8, ERIAR_MASK_1111, 0x0000); 29268c2ecf20Sopenharmony_ci rtl_set_fifo_size(tp, 0x10, 0x10, 0x02, 0x06); 29278c2ecf20Sopenharmony_ci rtl_reset_packet_filter(tp); 29288c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x1b0, BIT(4)); 29298c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x1d0, BIT(4) | BIT(1)); 29308c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050); 29318c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060); 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci rtl_disable_clock_request(tp); 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB); 29368c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN); 29378c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) | PWM_EN); 29388c2ecf20Sopenharmony_ci RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~Spi_en); 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci rtl8168_config_eee_mac(tp); 29418c2ecf20Sopenharmony_ci} 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168f_1(struct rtl8169_private *tp) 29448c2ecf20Sopenharmony_ci{ 29458c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168f_1[] = { 29468c2ecf20Sopenharmony_ci { 0x06, 0x00c0, 0x0020 }, 29478c2ecf20Sopenharmony_ci { 0x08, 0x0001, 0x0002 }, 29488c2ecf20Sopenharmony_ci { 0x09, 0x0000, 0x0080 }, 29498c2ecf20Sopenharmony_ci { 0x19, 0x0000, 0x0224 }, 29508c2ecf20Sopenharmony_ci { 0x00, 0x0000, 0x0008 }, 29518c2ecf20Sopenharmony_ci { 0x0c, 0x3df0, 0x0200 }, 29528c2ecf20Sopenharmony_ci }; 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_ci rtl_hw_start_8168f(tp); 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168f_1); 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x0d4, 0x1f00); 29598c2ecf20Sopenharmony_ci} 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_cistatic void rtl_hw_start_8411(struct rtl8169_private *tp) 29628c2ecf20Sopenharmony_ci{ 29638c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168f_1[] = { 29648c2ecf20Sopenharmony_ci { 0x06, 0x00c0, 0x0020 }, 29658c2ecf20Sopenharmony_ci { 0x0f, 0xffff, 0x5200 }, 29668c2ecf20Sopenharmony_ci { 0x19, 0x0000, 0x0224 }, 29678c2ecf20Sopenharmony_ci { 0x00, 0x0000, 0x0008 }, 29688c2ecf20Sopenharmony_ci { 0x0c, 0x3df0, 0x0200 }, 29698c2ecf20Sopenharmony_ci }; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci rtl_hw_start_8168f(tp); 29728c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168f_1); 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x0d4, 0x0c00); 29778c2ecf20Sopenharmony_ci} 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168g(struct rtl8169_private *tp) 29808c2ecf20Sopenharmony_ci{ 29818c2ecf20Sopenharmony_ci rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06); 29828c2ecf20Sopenharmony_ci rtl8168g_set_pause_thresholds(tp, 0x38, 0x48); 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci rtl_reset_packet_filter(tp); 29878c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f); 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN); 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); 29928c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); 29938c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0x0d4, 0x1f80); 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci rtl8168_config_eee_mac(tp); 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci rtl_w0w1_eri(tp, 0x2fc, 0x01, 0x06); 29988c2ecf20Sopenharmony_ci rtl_eri_clear_bits(tp, 0x1b0, BIT(12)); 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 30018c2ecf20Sopenharmony_ci} 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168g_1(struct rtl8169_private *tp) 30048c2ecf20Sopenharmony_ci{ 30058c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168g_1[] = { 30068c2ecf20Sopenharmony_ci { 0x00, 0x0008, 0x0000 }, 30078c2ecf20Sopenharmony_ci { 0x0c, 0x3ff0, 0x0820 }, 30088c2ecf20Sopenharmony_ci { 0x1e, 0x0000, 0x0001 }, 30098c2ecf20Sopenharmony_ci { 0x19, 0x8000, 0x0000 } 30108c2ecf20Sopenharmony_ci }; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci rtl_hw_start_8168g(tp); 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 30158c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 30168c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168g_1); 30178c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 30188c2ecf20Sopenharmony_ci} 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168g_2(struct rtl8169_private *tp) 30218c2ecf20Sopenharmony_ci{ 30228c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168g_2[] = { 30238c2ecf20Sopenharmony_ci { 0x00, 0x0008, 0x0000 }, 30248c2ecf20Sopenharmony_ci { 0x0c, 0x3ff0, 0x0820 }, 30258c2ecf20Sopenharmony_ci { 0x19, 0xffff, 0x7c00 }, 30268c2ecf20Sopenharmony_ci { 0x1e, 0xffff, 0x20eb }, 30278c2ecf20Sopenharmony_ci { 0x0d, 0xffff, 0x1666 }, 30288c2ecf20Sopenharmony_ci { 0x00, 0xffff, 0x10a3 }, 30298c2ecf20Sopenharmony_ci { 0x06, 0xffff, 0xf050 }, 30308c2ecf20Sopenharmony_ci { 0x04, 0x0000, 0x0010 }, 30318c2ecf20Sopenharmony_ci { 0x1d, 0x4000, 0x0000 }, 30328c2ecf20Sopenharmony_ci }; 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci rtl_hw_start_8168g(tp); 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 30378c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 30388c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168g_2); 30398c2ecf20Sopenharmony_ci} 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_cistatic void rtl_hw_start_8411_2(struct rtl8169_private *tp) 30428c2ecf20Sopenharmony_ci{ 30438c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8411_2[] = { 30448c2ecf20Sopenharmony_ci { 0x00, 0x0008, 0x0000 }, 30458c2ecf20Sopenharmony_ci { 0x0c, 0x37d0, 0x0820 }, 30468c2ecf20Sopenharmony_ci { 0x1e, 0x0000, 0x0001 }, 30478c2ecf20Sopenharmony_ci { 0x19, 0x8021, 0x0000 }, 30488c2ecf20Sopenharmony_ci { 0x1e, 0x0000, 0x2000 }, 30498c2ecf20Sopenharmony_ci { 0x0d, 0x0100, 0x0200 }, 30508c2ecf20Sopenharmony_ci { 0x00, 0x0000, 0x0080 }, 30518c2ecf20Sopenharmony_ci { 0x06, 0x0000, 0x0010 }, 30528c2ecf20Sopenharmony_ci { 0x04, 0x0000, 0x0010 }, 30538c2ecf20Sopenharmony_ci { 0x1d, 0x0000, 0x4000 }, 30548c2ecf20Sopenharmony_ci }; 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci rtl_hw_start_8168g(tp); 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 30598c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 30608c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8411_2); 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci /* The following Realtek-provided magic fixes an issue with the RX unit 30638c2ecf20Sopenharmony_ci * getting confused after the PHY having been powered-down. 30648c2ecf20Sopenharmony_ci */ 30658c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC28, 0x0000); 30668c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC2A, 0x0000); 30678c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC2C, 0x0000); 30688c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC2E, 0x0000); 30698c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC30, 0x0000); 30708c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC32, 0x0000); 30718c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC34, 0x0000); 30728c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC36, 0x0000); 30738c2ecf20Sopenharmony_ci mdelay(3); 30748c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC26, 0x0000); 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF800, 0xE008); 30778c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF802, 0xE00A); 30788c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF804, 0xE00C); 30798c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF806, 0xE00E); 30808c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF808, 0xE027); 30818c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF80A, 0xE04F); 30828c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF80C, 0xE05E); 30838c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF80E, 0xE065); 30848c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF810, 0xC602); 30858c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF812, 0xBE00); 30868c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF814, 0x0000); 30878c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF816, 0xC502); 30888c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF818, 0xBD00); 30898c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF81A, 0x074C); 30908c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF81C, 0xC302); 30918c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF81E, 0xBB00); 30928c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF820, 0x080A); 30938c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF822, 0x6420); 30948c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF824, 0x48C2); 30958c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF826, 0x8C20); 30968c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF828, 0xC516); 30978c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF82A, 0x64A4); 30988c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF82C, 0x49C0); 30998c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF82E, 0xF009); 31008c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF830, 0x74A2); 31018c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF832, 0x8CA5); 31028c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF834, 0x74A0); 31038c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF836, 0xC50E); 31048c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF838, 0x9CA2); 31058c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF83A, 0x1C11); 31068c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0); 31078c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF83E, 0xE006); 31088c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF840, 0x74F8); 31098c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF842, 0x48C4); 31108c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF844, 0x8CF8); 31118c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF846, 0xC404); 31128c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF848, 0xBC00); 31138c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF84A, 0xC403); 31148c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF84C, 0xBC00); 31158c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2); 31168c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF850, 0x0C0A); 31178c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF852, 0xE434); 31188c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF854, 0xD3C0); 31198c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF856, 0x49D9); 31208c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF858, 0xF01F); 31218c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF85A, 0xC526); 31228c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF85C, 0x64A5); 31238c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF85E, 0x1400); 31248c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF860, 0xF007); 31258c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF862, 0x0C01); 31268c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF864, 0x8CA5); 31278c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF866, 0x1C15); 31288c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF868, 0xC51B); 31298c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0); 31308c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF86C, 0xE013); 31318c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF86E, 0xC519); 31328c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF870, 0x74A0); 31338c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF872, 0x48C4); 31348c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF874, 0x8CA0); 31358c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF876, 0xC516); 31368c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF878, 0x74A4); 31378c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF87A, 0x48C8); 31388c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF87C, 0x48CA); 31398c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4); 31408c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF880, 0xC512); 31418c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF882, 0x1B00); 31428c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF884, 0x9BA0); 31438c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF886, 0x1B1C); 31448c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF888, 0x483F); 31458c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2); 31468c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF88C, 0x1B04); 31478c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF88E, 0xC508); 31488c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF890, 0x9BA0); 31498c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF892, 0xC505); 31508c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF894, 0xBD00); 31518c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF896, 0xC502); 31528c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF898, 0xBD00); 31538c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF89A, 0x0300); 31548c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF89C, 0x051E); 31558c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF89E, 0xE434); 31568c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8A0, 0xE018); 31578c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8A2, 0xE092); 31588c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20); 31598c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0); 31608c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F); 31618c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4); 31628c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3); 31638c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8AE, 0xF007); 31648c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0); 31658c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8B2, 0xF103); 31668c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8B4, 0xC607); 31678c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00); 31688c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8B8, 0xC606); 31698c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00); 31708c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8BC, 0xC602); 31718c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00); 31728c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C); 31738c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28); 31748c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C); 31758c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00); 31768c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8C8, 0xC707); 31778c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00); 31788c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2); 31798c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1); 31808c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8D0, 0xC502); 31818c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00); 31828c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA); 31838c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0); 31848c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8D8, 0xC502); 31858c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00); 31868c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xF8DC, 0x0132); 31878c2ecf20Sopenharmony_ci 31888c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC26, 0x8000); 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC2A, 0x0743); 31918c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC2C, 0x0801); 31928c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC2E, 0x0BE9); 31938c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC30, 0x02FD); 31948c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC32, 0x0C25); 31958c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC34, 0x00A9); 31968c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xFC36, 0x012D); 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 31998c2ecf20Sopenharmony_ci} 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168h_1(struct rtl8169_private *tp) 32028c2ecf20Sopenharmony_ci{ 32038c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168h_1[] = { 32048c2ecf20Sopenharmony_ci { 0x1e, 0x0800, 0x0001 }, 32058c2ecf20Sopenharmony_ci { 0x1d, 0x0000, 0x0800 }, 32068c2ecf20Sopenharmony_ci { 0x05, 0xffff, 0x2089 }, 32078c2ecf20Sopenharmony_ci { 0x06, 0xffff, 0x5881 }, 32088c2ecf20Sopenharmony_ci { 0x04, 0xffff, 0x854a }, 32098c2ecf20Sopenharmony_ci { 0x01, 0xffff, 0x068b } 32108c2ecf20Sopenharmony_ci }; 32118c2ecf20Sopenharmony_ci int rg_saw_cnt; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 32148c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 32158c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168h_1); 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06); 32188c2ecf20Sopenharmony_ci rtl8168g_set_pause_thresholds(tp, 0x38, 0x48); 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci rtl_reset_packet_filter(tp); 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0xd4, 0x1f00); 32258c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0xdc, 0x001c); 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87); 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN); 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); 32328c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci rtl8168_config_eee_mac(tp); 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN); 32378c2ecf20Sopenharmony_ci RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN); 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci rtl_eri_clear_bits(tp, 0x1b0, BIT(12)); 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff; 32468c2ecf20Sopenharmony_ci if (rg_saw_cnt > 0) { 32478c2ecf20Sopenharmony_ci u16 sw_cnt_1ms_ini; 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci sw_cnt_1ms_ini = 16000000/rg_saw_cnt; 32508c2ecf20Sopenharmony_ci sw_cnt_1ms_ini &= 0x0fff; 32518c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini); 32528c2ecf20Sopenharmony_ci } 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0070); 32558c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe052, 0x6000, 0x8008); 32568c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe0d6, 0x01ff, 0x017f); 32578c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd420, 0x0fff, 0x047f); 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xe63e, 0x0001); 32608c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xe63e, 0x0000); 32618c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc094, 0x0000); 32628c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc09e, 0x0000); 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 32658c2ecf20Sopenharmony_ci} 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168ep(struct rtl8169_private *tp) 32688c2ecf20Sopenharmony_ci{ 32698c2ecf20Sopenharmony_ci rtl8168ep_stop_cmac(tp); 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06); 32728c2ecf20Sopenharmony_ci rtl8168g_set_pause_thresholds(tp, 0x2f, 0x5f); 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci rtl_reset_packet_filter(tp); 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0xd4, 0x1f80); 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87); 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN); 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); 32858c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci rtl8168_config_eee_mac(tp); 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci rtl_w0w1_eri(tp, 0x2fc, 0x01, 0x06); 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN); 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 32948c2ecf20Sopenharmony_ci} 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168ep_1(struct rtl8169_private *tp) 32978c2ecf20Sopenharmony_ci{ 32988c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168ep_1[] = { 32998c2ecf20Sopenharmony_ci { 0x00, 0xffff, 0x10ab }, 33008c2ecf20Sopenharmony_ci { 0x06, 0xffff, 0xf030 }, 33018c2ecf20Sopenharmony_ci { 0x08, 0xffff, 0x2006 }, 33028c2ecf20Sopenharmony_ci { 0x0d, 0xffff, 0x1666 }, 33038c2ecf20Sopenharmony_ci { 0x0c, 0x3ff0, 0x0000 } 33048c2ecf20Sopenharmony_ci }; 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 33078c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 33088c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168ep_1); 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci rtl_hw_start_8168ep(tp); 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 33138c2ecf20Sopenharmony_ci} 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168ep_2(struct rtl8169_private *tp) 33168c2ecf20Sopenharmony_ci{ 33178c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168ep_2[] = { 33188c2ecf20Sopenharmony_ci { 0x00, 0xffff, 0x10a3 }, 33198c2ecf20Sopenharmony_ci { 0x19, 0xffff, 0xfc00 }, 33208c2ecf20Sopenharmony_ci { 0x1e, 0xffff, 0x20ea } 33218c2ecf20Sopenharmony_ci }; 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 33248c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 33258c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168ep_2); 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci rtl_hw_start_8168ep(tp); 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN); 33308c2ecf20Sopenharmony_ci RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN); 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 33338c2ecf20Sopenharmony_ci} 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168ep_3(struct rtl8169_private *tp) 33368c2ecf20Sopenharmony_ci{ 33378c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8168ep_3[] = { 33388c2ecf20Sopenharmony_ci { 0x00, 0x0000, 0x0080 }, 33398c2ecf20Sopenharmony_ci { 0x0d, 0x0100, 0x0200 }, 33408c2ecf20Sopenharmony_ci { 0x19, 0x8021, 0x0000 }, 33418c2ecf20Sopenharmony_ci { 0x1e, 0x0000, 0x2000 }, 33428c2ecf20Sopenharmony_ci }; 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 33458c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 33468c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8168ep_3); 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci rtl_hw_start_8168ep(tp); 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN); 33518c2ecf20Sopenharmony_ci RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN); 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd3e2, 0x0fff, 0x0271); 33548c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd3e4, 0x00ff, 0x0000); 33558c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe860, 0x0000, 0x0080); 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 33588c2ecf20Sopenharmony_ci} 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_cistatic void rtl_hw_start_8117(struct rtl8169_private *tp) 33618c2ecf20Sopenharmony_ci{ 33628c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8117[] = { 33638c2ecf20Sopenharmony_ci { 0x19, 0x0040, 0x1100 }, 33648c2ecf20Sopenharmony_ci { 0x59, 0x0040, 0x1100 }, 33658c2ecf20Sopenharmony_ci }; 33668c2ecf20Sopenharmony_ci int rg_saw_cnt; 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci rtl8168ep_stop_cmac(tp); 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 33718c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 33728c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8117); 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ci rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06); 33758c2ecf20Sopenharmony_ci rtl8168g_set_pause_thresholds(tp, 0x2f, 0x5f); 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 33788c2ecf20Sopenharmony_ci 33798c2ecf20Sopenharmony_ci rtl_reset_packet_filter(tp); 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci rtl_eri_set_bits(tp, 0xd4, 0x1f90); 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87); 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN); 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); 33888c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci rtl8168_config_eee_mac(tp); 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN); 33938c2ecf20Sopenharmony_ci RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN); 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN); 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_ci rtl_eri_clear_bits(tp, 0x1b0, BIT(12)); 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff; 34028c2ecf20Sopenharmony_ci if (rg_saw_cnt > 0) { 34038c2ecf20Sopenharmony_ci u16 sw_cnt_1ms_ini; 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci sw_cnt_1ms_ini = (16000000 / rg_saw_cnt) & 0x0fff; 34068c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini); 34078c2ecf20Sopenharmony_ci } 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0070); 34108c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xea80, 0x0003); 34118c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe052, 0x0000, 0x0009); 34128c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd420, 0x0fff, 0x047f); 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xe63e, 0x0001); 34158c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xe63e, 0x0000); 34168c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc094, 0x0000); 34178c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc09e, 0x0000); 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci /* firmware is for MAC only */ 34208c2ecf20Sopenharmony_ci r8169_apply_firmware(tp); 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 34238c2ecf20Sopenharmony_ci} 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_cistatic void rtl_hw_start_8102e_1(struct rtl8169_private *tp) 34268c2ecf20Sopenharmony_ci{ 34278c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8102e_1[] = { 34288c2ecf20Sopenharmony_ci { 0x01, 0, 0x6e65 }, 34298c2ecf20Sopenharmony_ci { 0x02, 0, 0x091f }, 34308c2ecf20Sopenharmony_ci { 0x03, 0, 0xc2f9 }, 34318c2ecf20Sopenharmony_ci { 0x06, 0, 0xafb5 }, 34328c2ecf20Sopenharmony_ci { 0x07, 0, 0x0e00 }, 34338c2ecf20Sopenharmony_ci { 0x19, 0, 0xec80 }, 34348c2ecf20Sopenharmony_ci { 0x01, 0, 0x2e65 }, 34358c2ecf20Sopenharmony_ci { 0x01, 0, 0x6e65 } 34368c2ecf20Sopenharmony_ci }; 34378c2ecf20Sopenharmony_ci u8 cfg1; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci RTL_W8(tp, DBG_REG, FIX_NAK_1); 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci RTL_W8(tp, Config1, 34448c2ecf20Sopenharmony_ci LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); 34458c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci cfg1 = RTL_R8(tp, Config1); 34488c2ecf20Sopenharmony_ci if ((cfg1 & LEDS0) && (cfg1 & LEDS1)) 34498c2ecf20Sopenharmony_ci RTL_W8(tp, Config1, cfg1 & ~LEDS0); 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8102e_1); 34528c2ecf20Sopenharmony_ci} 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_cistatic void rtl_hw_start_8102e_2(struct rtl8169_private *tp) 34558c2ecf20Sopenharmony_ci{ 34568c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci RTL_W8(tp, Config1, MEMMAP | IOMAP | VPD | PMEnable); 34598c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); 34608c2ecf20Sopenharmony_ci} 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_cistatic void rtl_hw_start_8102e_3(struct rtl8169_private *tp) 34638c2ecf20Sopenharmony_ci{ 34648c2ecf20Sopenharmony_ci rtl_hw_start_8102e_2(tp); 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci rtl_ephy_write(tp, 0x03, 0xc2f9); 34678c2ecf20Sopenharmony_ci} 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_cistatic void rtl_hw_start_8401(struct rtl8169_private *tp) 34708c2ecf20Sopenharmony_ci{ 34718c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8401[] = { 34728c2ecf20Sopenharmony_ci { 0x01, 0xffff, 0x6fe5 }, 34738c2ecf20Sopenharmony_ci { 0x03, 0xffff, 0x0599 }, 34748c2ecf20Sopenharmony_ci { 0x06, 0xffff, 0xaf25 }, 34758c2ecf20Sopenharmony_ci { 0x07, 0xffff, 0x8e68 }, 34768c2ecf20Sopenharmony_ci }; 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8401); 34798c2ecf20Sopenharmony_ci RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); 34808c2ecf20Sopenharmony_ci} 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_cistatic void rtl_hw_start_8105e_1(struct rtl8169_private *tp) 34838c2ecf20Sopenharmony_ci{ 34848c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8105e_1[] = { 34858c2ecf20Sopenharmony_ci { 0x07, 0, 0x4000 }, 34868c2ecf20Sopenharmony_ci { 0x19, 0, 0x0200 }, 34878c2ecf20Sopenharmony_ci { 0x19, 0, 0x0020 }, 34888c2ecf20Sopenharmony_ci { 0x1e, 0, 0x2000 }, 34898c2ecf20Sopenharmony_ci { 0x03, 0, 0x0001 }, 34908c2ecf20Sopenharmony_ci { 0x19, 0, 0x0100 }, 34918c2ecf20Sopenharmony_ci { 0x19, 0, 0x0004 }, 34928c2ecf20Sopenharmony_ci { 0x0a, 0, 0x0020 } 34938c2ecf20Sopenharmony_ci }; 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_ci /* Force LAN exit from ASPM if Rx/Tx are not idle */ 34968c2ecf20Sopenharmony_ci RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) | 0x002800); 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci /* Disable Early Tally Counter */ 34998c2ecf20Sopenharmony_ci RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) & ~0x010000); 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci RTL_W8(tp, MCU, RTL_R8(tp, MCU) | EN_NDP | EN_OOB_RESET); 35028c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN); 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8105e_1); 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 35078c2ecf20Sopenharmony_ci} 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_cistatic void rtl_hw_start_8105e_2(struct rtl8169_private *tp) 35108c2ecf20Sopenharmony_ci{ 35118c2ecf20Sopenharmony_ci rtl_hw_start_8105e_1(tp); 35128c2ecf20Sopenharmony_ci rtl_ephy_write(tp, 0x1e, rtl_ephy_read(tp, 0x1e) | 0x8000); 35138c2ecf20Sopenharmony_ci} 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_cistatic void rtl_hw_start_8402(struct rtl8169_private *tp) 35168c2ecf20Sopenharmony_ci{ 35178c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8402[] = { 35188c2ecf20Sopenharmony_ci { 0x19, 0xffff, 0xff64 }, 35198c2ecf20Sopenharmony_ci { 0x1e, 0, 0x4000 } 35208c2ecf20Sopenharmony_ci }; 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci /* Force LAN exit from ASPM if Rx/Tx are not idle */ 35258c2ecf20Sopenharmony_ci RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) | 0x002800); 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB); 35288c2ecf20Sopenharmony_ci 35298c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8402); 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci rtl_set_fifo_size(tp, 0x00, 0x00, 0x02, 0x06); 35328c2ecf20Sopenharmony_ci rtl_reset_packet_filter(tp); 35338c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); 35348c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); 35358c2ecf20Sopenharmony_ci rtl_w0w1_eri(tp, 0x0d4, 0x0e00, 0xff00); 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci /* disable EEE */ 35388c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000); 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 35418c2ecf20Sopenharmony_ci} 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_cistatic void rtl_hw_start_8106(struct rtl8169_private *tp) 35448c2ecf20Sopenharmony_ci{ 35458c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci /* Force LAN exit from ASPM if Rx/Tx are not idle */ 35488c2ecf20Sopenharmony_ci RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) | 0x002800); 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, (RTL_R32(tp, MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN); 35518c2ecf20Sopenharmony_ci RTL_W8(tp, MCU, RTL_R8(tp, MCU) | EN_NDP | EN_OOB_RESET); 35528c2ecf20Sopenharmony_ci RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN); 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000); 35558c2ecf20Sopenharmony_ci 35568c2ecf20Sopenharmony_ci /* disable EEE */ 35578c2ecf20Sopenharmony_ci rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000); 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 35608c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 35618c2ecf20Sopenharmony_ci} 35628c2ecf20Sopenharmony_ci 35638c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_mac_ocp_e00e_cond) 35648c2ecf20Sopenharmony_ci{ 35658c2ecf20Sopenharmony_ci return r8168_mac_ocp_read(tp, 0xe00e) & BIT(13); 35668c2ecf20Sopenharmony_ci} 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_cistatic void rtl_hw_start_8125_common(struct rtl8169_private *tp) 35698c2ecf20Sopenharmony_ci{ 35708c2ecf20Sopenharmony_ci rtl_pcie_state_l2l3_disable(tp); 35718c2ecf20Sopenharmony_ci 35728c2ecf20Sopenharmony_ci RTL_W16(tp, 0x382, 0x221b); 35738c2ecf20Sopenharmony_ci RTL_W8(tp, 0x4500, 0); 35748c2ecf20Sopenharmony_ci RTL_W16(tp, 0x4800, 0); 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci /* disable UPS */ 35778c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000); 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci RTL_W8(tp, Config1, RTL_R8(tp, Config1) & ~0x10); 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc140, 0xffff); 35828c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc142, 0xffff); 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd3e2, 0x0fff, 0x03a9); 35858c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd3e4, 0x00ff, 0x0000); 35868c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe860, 0x0000, 0x0080); 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci /* disable new tx descriptor format */ 35898c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_63) 35928c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); 35938c2ecf20Sopenharmony_ci else 35948c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); 35958c2ecf20Sopenharmony_ci 35968c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_63) 35978c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0000); 35988c2ecf20Sopenharmony_ci else 35998c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0020); 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xc0b4, 0x0000, 0x000c); 36028c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xeb6a, 0x00ff, 0x0033); 36038c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xeb50, 0x03e0, 0x0040); 36048c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); 36058c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); 36068c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); 36078c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe0c0, 0x4f0f, 0x4403); 36088c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe052, 0x0080, 0x0068); 36098c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xc0ac, 0x0080, 0x1f00); 36108c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xd430, 0x0fff, 0x047f); 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); 36138c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xeb54, 0x0000, 0x0001); 36148c2ecf20Sopenharmony_ci udelay(1); 36158c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xeb54, 0x0001, 0x0000); 36168c2ecf20Sopenharmony_ci RTL_W16(tp, 0x1880, RTL_R16(tp, 0x1880) & ~0x0030); 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xe098, 0xc302); 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_mac_ocp_e00e_cond, 1000, 10); 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_63) 36238c2ecf20Sopenharmony_ci rtl8125b_config_eee_mac(tp); 36248c2ecf20Sopenharmony_ci else 36258c2ecf20Sopenharmony_ci rtl8125a_config_eee_mac(tp); 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN); 36288c2ecf20Sopenharmony_ci udelay(10); 36298c2ecf20Sopenharmony_ci} 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_cistatic void rtl_hw_start_8125a_1(struct rtl8169_private *tp) 36328c2ecf20Sopenharmony_ci{ 36338c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8125a_1[] = { 36348c2ecf20Sopenharmony_ci { 0x01, 0xffff, 0xa812 }, 36358c2ecf20Sopenharmony_ci { 0x09, 0xffff, 0x520c }, 36368c2ecf20Sopenharmony_ci { 0x04, 0xffff, 0xd000 }, 36378c2ecf20Sopenharmony_ci { 0x0d, 0xffff, 0xf702 }, 36388c2ecf20Sopenharmony_ci { 0x0a, 0xffff, 0x8653 }, 36398c2ecf20Sopenharmony_ci { 0x06, 0xffff, 0x001e }, 36408c2ecf20Sopenharmony_ci { 0x08, 0xffff, 0x3595 }, 36418c2ecf20Sopenharmony_ci { 0x20, 0xffff, 0x9455 }, 36428c2ecf20Sopenharmony_ci { 0x21, 0xffff, 0x99ff }, 36438c2ecf20Sopenharmony_ci { 0x02, 0xffff, 0x6046 }, 36448c2ecf20Sopenharmony_ci { 0x29, 0xffff, 0xfe00 }, 36458c2ecf20Sopenharmony_ci { 0x23, 0xffff, 0xab62 }, 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci { 0x41, 0xffff, 0xa80c }, 36488c2ecf20Sopenharmony_ci { 0x49, 0xffff, 0x520c }, 36498c2ecf20Sopenharmony_ci { 0x44, 0xffff, 0xd000 }, 36508c2ecf20Sopenharmony_ci { 0x4d, 0xffff, 0xf702 }, 36518c2ecf20Sopenharmony_ci { 0x4a, 0xffff, 0x8653 }, 36528c2ecf20Sopenharmony_ci { 0x46, 0xffff, 0x001e }, 36538c2ecf20Sopenharmony_ci { 0x48, 0xffff, 0x3595 }, 36548c2ecf20Sopenharmony_ci { 0x60, 0xffff, 0x9455 }, 36558c2ecf20Sopenharmony_ci { 0x61, 0xffff, 0x99ff }, 36568c2ecf20Sopenharmony_ci { 0x42, 0xffff, 0x6046 }, 36578c2ecf20Sopenharmony_ci { 0x69, 0xffff, 0xfe00 }, 36588c2ecf20Sopenharmony_ci { 0x63, 0xffff, 0xab62 }, 36598c2ecf20Sopenharmony_ci }; 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 36648c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 36658c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8125a_1); 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci rtl_hw_start_8125_common(tp); 36688c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 36698c2ecf20Sopenharmony_ci} 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_cistatic void rtl_hw_start_8125a_2(struct rtl8169_private *tp) 36728c2ecf20Sopenharmony_ci{ 36738c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8125a_2[] = { 36748c2ecf20Sopenharmony_ci { 0x04, 0xffff, 0xd000 }, 36758c2ecf20Sopenharmony_ci { 0x0a, 0xffff, 0x8653 }, 36768c2ecf20Sopenharmony_ci { 0x23, 0xffff, 0xab66 }, 36778c2ecf20Sopenharmony_ci { 0x20, 0xffff, 0x9455 }, 36788c2ecf20Sopenharmony_ci { 0x21, 0xffff, 0x99ff }, 36798c2ecf20Sopenharmony_ci { 0x29, 0xffff, 0xfe04 }, 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci { 0x44, 0xffff, 0xd000 }, 36828c2ecf20Sopenharmony_ci { 0x4a, 0xffff, 0x8653 }, 36838c2ecf20Sopenharmony_ci { 0x63, 0xffff, 0xab66 }, 36848c2ecf20Sopenharmony_ci { 0x60, 0xffff, 0x9455 }, 36858c2ecf20Sopenharmony_ci { 0x61, 0xffff, 0x99ff }, 36868c2ecf20Sopenharmony_ci { 0x69, 0xffff, 0xfe04 }, 36878c2ecf20Sopenharmony_ci }; 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci /* disable aspm and clock request before access ephy */ 36928c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 36938c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8125a_2); 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci rtl_hw_start_8125_common(tp); 36968c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 36978c2ecf20Sopenharmony_ci} 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_cistatic void rtl_hw_start_8125b(struct rtl8169_private *tp) 37008c2ecf20Sopenharmony_ci{ 37018c2ecf20Sopenharmony_ci static const struct ephy_info e_info_8125b[] = { 37028c2ecf20Sopenharmony_ci { 0x0b, 0xffff, 0xa908 }, 37038c2ecf20Sopenharmony_ci { 0x1e, 0xffff, 0x20eb }, 37048c2ecf20Sopenharmony_ci { 0x4b, 0xffff, 0xa908 }, 37058c2ecf20Sopenharmony_ci { 0x5e, 0xffff, 0x20eb }, 37068c2ecf20Sopenharmony_ci { 0x22, 0x0030, 0x0020 }, 37078c2ecf20Sopenharmony_ci { 0x62, 0x0030, 0x0020 }, 37088c2ecf20Sopenharmony_ci }; 37098c2ecf20Sopenharmony_ci 37108c2ecf20Sopenharmony_ci rtl_set_def_aspm_entry_latency(tp); 37118c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, false); 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci rtl_ephy_init(tp, e_info_8125b); 37148c2ecf20Sopenharmony_ci rtl_hw_start_8125_common(tp); 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci rtl_hw_aspm_clkreq_enable(tp, true); 37178c2ecf20Sopenharmony_ci} 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_cistatic void rtl_hw_config(struct rtl8169_private *tp) 37208c2ecf20Sopenharmony_ci{ 37218c2ecf20Sopenharmony_ci static const rtl_generic_fct hw_configs[] = { 37228c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_07] = rtl_hw_start_8102e_1, 37238c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3, 37248c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2, 37258c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_10] = NULL, 37268c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b, 37278c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_12] = rtl_hw_start_8168b, 37288c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_13] = NULL, 37298c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_14] = rtl_hw_start_8401, 37308c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_16] = NULL, 37318c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b, 37328c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1, 37338c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_19] = rtl_hw_start_8168c_1, 37348c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_20] = rtl_hw_start_8168c_2, 37358c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_21] = rtl_hw_start_8168c_3, 37368c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_22] = rtl_hw_start_8168c_4, 37378c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_23] = rtl_hw_start_8168cp_2, 37388c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_24] = rtl_hw_start_8168cp_3, 37398c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_25] = rtl_hw_start_8168d, 37408c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_26] = rtl_hw_start_8168d, 37418c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_27] = rtl_hw_start_8168d, 37428c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_28] = rtl_hw_start_8168d_4, 37438c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_29] = rtl_hw_start_8105e_1, 37448c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_30] = rtl_hw_start_8105e_2, 37458c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_31] = rtl_hw_start_8168d, 37468c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_32] = rtl_hw_start_8168e_1, 37478c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_33] = rtl_hw_start_8168e_1, 37488c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_34] = rtl_hw_start_8168e_2, 37498c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_35] = rtl_hw_start_8168f_1, 37508c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_36] = rtl_hw_start_8168f_1, 37518c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_37] = rtl_hw_start_8402, 37528c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_38] = rtl_hw_start_8411, 37538c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_39] = rtl_hw_start_8106, 37548c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_40] = rtl_hw_start_8168g_1, 37558c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_41] = rtl_hw_start_8168g_1, 37568c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_42] = rtl_hw_start_8168g_2, 37578c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_43] = rtl_hw_start_8168g_2, 37588c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_44] = rtl_hw_start_8411_2, 37598c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_45] = rtl_hw_start_8168h_1, 37608c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_46] = rtl_hw_start_8168h_1, 37618c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_47] = rtl_hw_start_8168h_1, 37628c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_48] = rtl_hw_start_8168h_1, 37638c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_49] = rtl_hw_start_8168ep_1, 37648c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_50] = rtl_hw_start_8168ep_2, 37658c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_51] = rtl_hw_start_8168ep_3, 37668c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_52] = rtl_hw_start_8117, 37678c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_60] = rtl_hw_start_8125a_1, 37688c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, 37698c2ecf20Sopenharmony_ci [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, 37708c2ecf20Sopenharmony_ci }; 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci if (hw_configs[tp->mac_version]) 37738c2ecf20Sopenharmony_ci hw_configs[tp->mac_version](tp); 37748c2ecf20Sopenharmony_ci} 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_cistatic void rtl_hw_start_8125(struct rtl8169_private *tp) 37778c2ecf20Sopenharmony_ci{ 37788c2ecf20Sopenharmony_ci int i; 37798c2ecf20Sopenharmony_ci 37808c2ecf20Sopenharmony_ci /* disable interrupt coalescing */ 37818c2ecf20Sopenharmony_ci for (i = 0xa00; i < 0xb00; i += 4) 37828c2ecf20Sopenharmony_ci RTL_W32(tp, i, 0); 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci rtl_hw_config(tp); 37858c2ecf20Sopenharmony_ci} 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_cistatic void rtl_hw_start_8168(struct rtl8169_private *tp) 37888c2ecf20Sopenharmony_ci{ 37898c2ecf20Sopenharmony_ci if (rtl_is_8168evl_up(tp)) 37908c2ecf20Sopenharmony_ci RTL_W8(tp, MaxTxPacketSize, EarlySize); 37918c2ecf20Sopenharmony_ci else 37928c2ecf20Sopenharmony_ci RTL_W8(tp, MaxTxPacketSize, TxPacketMax); 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci rtl_hw_config(tp); 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci /* disable interrupt coalescing */ 37978c2ecf20Sopenharmony_ci RTL_W16(tp, IntrMitigate, 0x0000); 37988c2ecf20Sopenharmony_ci} 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_cistatic void rtl_hw_start_8169(struct rtl8169_private *tp) 38018c2ecf20Sopenharmony_ci{ 38028c2ecf20Sopenharmony_ci RTL_W8(tp, EarlyTxThres, NoEarlyTx); 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci tp->cp_cmd |= PCIMulRW; 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_02 || 38078c2ecf20Sopenharmony_ci tp->mac_version == RTL_GIGA_MAC_VER_03) 38088c2ecf20Sopenharmony_ci tp->cp_cmd |= EnAnaPLL; 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci RTL_W16(tp, CPlusCmd, tp->cp_cmd); 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci rtl8169_set_magic_reg(tp); 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci /* disable interrupt coalescing */ 38158c2ecf20Sopenharmony_ci RTL_W16(tp, IntrMitigate, 0x0000); 38168c2ecf20Sopenharmony_ci} 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_cistatic void rtl_hw_start(struct rtl8169_private *tp) 38198c2ecf20Sopenharmony_ci{ 38208c2ecf20Sopenharmony_ci rtl_unlock_config_regs(tp); 38218c2ecf20Sopenharmony_ci 38228c2ecf20Sopenharmony_ci RTL_W16(tp, CPlusCmd, tp->cp_cmd); 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci if (tp->mac_version <= RTL_GIGA_MAC_VER_06) 38258c2ecf20Sopenharmony_ci rtl_hw_start_8169(tp); 38268c2ecf20Sopenharmony_ci else if (rtl_is_8125(tp)) 38278c2ecf20Sopenharmony_ci rtl_hw_start_8125(tp); 38288c2ecf20Sopenharmony_ci else 38298c2ecf20Sopenharmony_ci rtl_hw_start_8168(tp); 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci rtl_set_rx_max_size(tp); 38328c2ecf20Sopenharmony_ci rtl_set_rx_tx_desc_registers(tp); 38338c2ecf20Sopenharmony_ci rtl_lock_config_regs(tp); 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_ci rtl_jumbo_config(tp); 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci /* Initially a 10 us delay. Turned it into a PCI commit. - FR */ 38388c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 38398c2ecf20Sopenharmony_ci 38408c2ecf20Sopenharmony_ci RTL_W8(tp, ChipCmd, CmdTxEnb | CmdRxEnb); 38418c2ecf20Sopenharmony_ci rtl_init_rxcfg(tp); 38428c2ecf20Sopenharmony_ci rtl_set_tx_config_registers(tp); 38438c2ecf20Sopenharmony_ci rtl_set_rx_config_features(tp, tp->dev->features); 38448c2ecf20Sopenharmony_ci rtl_set_rx_mode(tp->dev); 38458c2ecf20Sopenharmony_ci rtl_irq_enable(tp); 38468c2ecf20Sopenharmony_ci} 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_cistatic int rtl8169_change_mtu(struct net_device *dev, int new_mtu) 38498c2ecf20Sopenharmony_ci{ 38508c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 38518c2ecf20Sopenharmony_ci 38528c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 38538c2ecf20Sopenharmony_ci netdev_update_features(dev); 38548c2ecf20Sopenharmony_ci rtl_jumbo_config(tp); 38558c2ecf20Sopenharmony_ci 38568c2ecf20Sopenharmony_ci switch (tp->mac_version) { 38578c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_61: 38588c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_63: 38598c2ecf20Sopenharmony_ci rtl8125_set_eee_txidle_timer(tp); 38608c2ecf20Sopenharmony_ci break; 38618c2ecf20Sopenharmony_ci default: 38628c2ecf20Sopenharmony_ci break; 38638c2ecf20Sopenharmony_ci } 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ci return 0; 38668c2ecf20Sopenharmony_ci} 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_cistatic void rtl8169_mark_to_asic(struct RxDesc *desc) 38698c2ecf20Sopenharmony_ci{ 38708c2ecf20Sopenharmony_ci u32 eor = le32_to_cpu(desc->opts1) & RingEnd; 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci desc->opts2 = 0; 38738c2ecf20Sopenharmony_ci /* Force memory writes to complete before releasing descriptor */ 38748c2ecf20Sopenharmony_ci dma_wmb(); 38758c2ecf20Sopenharmony_ci WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE)); 38768c2ecf20Sopenharmony_ci} 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_cistatic struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp, 38798c2ecf20Sopenharmony_ci struct RxDesc *desc) 38808c2ecf20Sopenharmony_ci{ 38818c2ecf20Sopenharmony_ci struct device *d = tp_to_dev(tp); 38828c2ecf20Sopenharmony_ci int node = dev_to_node(d); 38838c2ecf20Sopenharmony_ci dma_addr_t mapping; 38848c2ecf20Sopenharmony_ci struct page *data; 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci data = alloc_pages_node(node, GFP_KERNEL, get_order(R8169_RX_BUF_SIZE)); 38878c2ecf20Sopenharmony_ci if (!data) 38888c2ecf20Sopenharmony_ci return NULL; 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ci mapping = dma_map_page(d, data, 0, R8169_RX_BUF_SIZE, DMA_FROM_DEVICE); 38918c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(d, mapping))) { 38928c2ecf20Sopenharmony_ci netdev_err(tp->dev, "Failed to map RX DMA!\n"); 38938c2ecf20Sopenharmony_ci __free_pages(data, get_order(R8169_RX_BUF_SIZE)); 38948c2ecf20Sopenharmony_ci return NULL; 38958c2ecf20Sopenharmony_ci } 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci desc->addr = cpu_to_le64(mapping); 38988c2ecf20Sopenharmony_ci rtl8169_mark_to_asic(desc); 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_ci return data; 39018c2ecf20Sopenharmony_ci} 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_cistatic void rtl8169_rx_clear(struct rtl8169_private *tp) 39048c2ecf20Sopenharmony_ci{ 39058c2ecf20Sopenharmony_ci unsigned int i; 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DESC && tp->Rx_databuff[i]; i++) { 39088c2ecf20Sopenharmony_ci dma_unmap_page(tp_to_dev(tp), 39098c2ecf20Sopenharmony_ci le64_to_cpu(tp->RxDescArray[i].addr), 39108c2ecf20Sopenharmony_ci R8169_RX_BUF_SIZE, DMA_FROM_DEVICE); 39118c2ecf20Sopenharmony_ci __free_pages(tp->Rx_databuff[i], get_order(R8169_RX_BUF_SIZE)); 39128c2ecf20Sopenharmony_ci tp->Rx_databuff[i] = NULL; 39138c2ecf20Sopenharmony_ci tp->RxDescArray[i].addr = 0; 39148c2ecf20Sopenharmony_ci tp->RxDescArray[i].opts1 = 0; 39158c2ecf20Sopenharmony_ci } 39168c2ecf20Sopenharmony_ci} 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_cistatic int rtl8169_rx_fill(struct rtl8169_private *tp) 39198c2ecf20Sopenharmony_ci{ 39208c2ecf20Sopenharmony_ci unsigned int i; 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DESC; i++) { 39238c2ecf20Sopenharmony_ci struct page *data; 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i); 39268c2ecf20Sopenharmony_ci if (!data) { 39278c2ecf20Sopenharmony_ci rtl8169_rx_clear(tp); 39288c2ecf20Sopenharmony_ci return -ENOMEM; 39298c2ecf20Sopenharmony_ci } 39308c2ecf20Sopenharmony_ci tp->Rx_databuff[i] = data; 39318c2ecf20Sopenharmony_ci } 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci /* mark as last descriptor in the ring */ 39348c2ecf20Sopenharmony_ci tp->RxDescArray[NUM_RX_DESC - 1].opts1 |= cpu_to_le32(RingEnd); 39358c2ecf20Sopenharmony_ci 39368c2ecf20Sopenharmony_ci return 0; 39378c2ecf20Sopenharmony_ci} 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_cistatic int rtl8169_init_ring(struct rtl8169_private *tp) 39408c2ecf20Sopenharmony_ci{ 39418c2ecf20Sopenharmony_ci rtl8169_init_ring_indexes(tp); 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci memset(tp->tx_skb, 0, sizeof(tp->tx_skb)); 39448c2ecf20Sopenharmony_ci memset(tp->Rx_databuff, 0, sizeof(tp->Rx_databuff)); 39458c2ecf20Sopenharmony_ci 39468c2ecf20Sopenharmony_ci return rtl8169_rx_fill(tp); 39478c2ecf20Sopenharmony_ci} 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_cistatic void rtl8169_unmap_tx_skb(struct rtl8169_private *tp, unsigned int entry) 39508c2ecf20Sopenharmony_ci{ 39518c2ecf20Sopenharmony_ci struct ring_info *tx_skb = tp->tx_skb + entry; 39528c2ecf20Sopenharmony_ci struct TxDesc *desc = tp->TxDescArray + entry; 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_ci dma_unmap_single(tp_to_dev(tp), le64_to_cpu(desc->addr), tx_skb->len, 39558c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 39568c2ecf20Sopenharmony_ci memset(desc, 0, sizeof(*desc)); 39578c2ecf20Sopenharmony_ci memset(tx_skb, 0, sizeof(*tx_skb)); 39588c2ecf20Sopenharmony_ci} 39598c2ecf20Sopenharmony_ci 39608c2ecf20Sopenharmony_cistatic void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start, 39618c2ecf20Sopenharmony_ci unsigned int n) 39628c2ecf20Sopenharmony_ci{ 39638c2ecf20Sopenharmony_ci unsigned int i; 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 39668c2ecf20Sopenharmony_ci unsigned int entry = (start + i) % NUM_TX_DESC; 39678c2ecf20Sopenharmony_ci struct ring_info *tx_skb = tp->tx_skb + entry; 39688c2ecf20Sopenharmony_ci unsigned int len = tx_skb->len; 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci if (len) { 39718c2ecf20Sopenharmony_ci struct sk_buff *skb = tx_skb->skb; 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci rtl8169_unmap_tx_skb(tp, entry); 39748c2ecf20Sopenharmony_ci if (skb) 39758c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 39768c2ecf20Sopenharmony_ci } 39778c2ecf20Sopenharmony_ci } 39788c2ecf20Sopenharmony_ci} 39798c2ecf20Sopenharmony_ci 39808c2ecf20Sopenharmony_cistatic void rtl8169_tx_clear(struct rtl8169_private *tp) 39818c2ecf20Sopenharmony_ci{ 39828c2ecf20Sopenharmony_ci rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC); 39838c2ecf20Sopenharmony_ci netdev_reset_queue(tp->dev); 39848c2ecf20Sopenharmony_ci} 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_cistatic void rtl8169_cleanup(struct rtl8169_private *tp, bool going_down) 39878c2ecf20Sopenharmony_ci{ 39888c2ecf20Sopenharmony_ci napi_disable(&tp->napi); 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci /* Give a racing hard_start_xmit a few cycles to complete. */ 39918c2ecf20Sopenharmony_ci synchronize_net(); 39928c2ecf20Sopenharmony_ci 39938c2ecf20Sopenharmony_ci /* Disable interrupts */ 39948c2ecf20Sopenharmony_ci rtl8169_irq_mask_and_ack(tp); 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci rtl_rx_close(tp); 39978c2ecf20Sopenharmony_ci 39988c2ecf20Sopenharmony_ci if (going_down && tp->dev->wol_enabled) 39998c2ecf20Sopenharmony_ci goto no_reset; 40008c2ecf20Sopenharmony_ci 40018c2ecf20Sopenharmony_ci switch (tp->mac_version) { 40028c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_27: 40038c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_28: 40048c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_31: 40058c2ecf20Sopenharmony_ci rtl_loop_wait_low(tp, &rtl_npq_cond, 20, 2000); 40068c2ecf20Sopenharmony_ci break; 40078c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: 40088c2ecf20Sopenharmony_ci RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); 40098c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); 40108c2ecf20Sopenharmony_ci break; 40118c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: 40128c2ecf20Sopenharmony_ci rtl_enable_rxdvgate(tp); 40138c2ecf20Sopenharmony_ci fsleep(2000); 40148c2ecf20Sopenharmony_ci break; 40158c2ecf20Sopenharmony_ci default: 40168c2ecf20Sopenharmony_ci RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); 40178c2ecf20Sopenharmony_ci fsleep(100); 40188c2ecf20Sopenharmony_ci break; 40198c2ecf20Sopenharmony_ci } 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci rtl_hw_reset(tp); 40228c2ecf20Sopenharmony_cino_reset: 40238c2ecf20Sopenharmony_ci rtl8169_tx_clear(tp); 40248c2ecf20Sopenharmony_ci rtl8169_init_ring_indexes(tp); 40258c2ecf20Sopenharmony_ci} 40268c2ecf20Sopenharmony_ci 40278c2ecf20Sopenharmony_cistatic void rtl_reset_work(struct rtl8169_private *tp) 40288c2ecf20Sopenharmony_ci{ 40298c2ecf20Sopenharmony_ci int i; 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci netif_stop_queue(tp->dev); 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci rtl8169_cleanup(tp, false); 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_DESC; i++) 40368c2ecf20Sopenharmony_ci rtl8169_mark_to_asic(tp->RxDescArray + i); 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci napi_enable(&tp->napi); 40398c2ecf20Sopenharmony_ci rtl_hw_start(tp); 40408c2ecf20Sopenharmony_ci} 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_cistatic void rtl8169_tx_timeout(struct net_device *dev, unsigned int txqueue) 40438c2ecf20Sopenharmony_ci{ 40448c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci rtl_schedule_task(tp, RTL_FLAG_TASK_TX_TIMEOUT); 40478c2ecf20Sopenharmony_ci} 40488c2ecf20Sopenharmony_ci 40498c2ecf20Sopenharmony_cistatic int rtl8169_tx_map(struct rtl8169_private *tp, const u32 *opts, u32 len, 40508c2ecf20Sopenharmony_ci void *addr, unsigned int entry, bool desc_own) 40518c2ecf20Sopenharmony_ci{ 40528c2ecf20Sopenharmony_ci struct TxDesc *txd = tp->TxDescArray + entry; 40538c2ecf20Sopenharmony_ci struct device *d = tp_to_dev(tp); 40548c2ecf20Sopenharmony_ci dma_addr_t mapping; 40558c2ecf20Sopenharmony_ci u32 opts1; 40568c2ecf20Sopenharmony_ci int ret; 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE); 40598c2ecf20Sopenharmony_ci ret = dma_mapping_error(d, mapping); 40608c2ecf20Sopenharmony_ci if (unlikely(ret)) { 40618c2ecf20Sopenharmony_ci if (net_ratelimit()) 40628c2ecf20Sopenharmony_ci netdev_err(tp->dev, "Failed to map TX data!\n"); 40638c2ecf20Sopenharmony_ci return ret; 40648c2ecf20Sopenharmony_ci } 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci txd->addr = cpu_to_le64(mapping); 40678c2ecf20Sopenharmony_ci txd->opts2 = cpu_to_le32(opts[1]); 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci opts1 = opts[0] | len; 40708c2ecf20Sopenharmony_ci if (entry == NUM_TX_DESC - 1) 40718c2ecf20Sopenharmony_ci opts1 |= RingEnd; 40728c2ecf20Sopenharmony_ci if (desc_own) 40738c2ecf20Sopenharmony_ci opts1 |= DescOwn; 40748c2ecf20Sopenharmony_ci txd->opts1 = cpu_to_le32(opts1); 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci tp->tx_skb[entry].len = len; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci return 0; 40798c2ecf20Sopenharmony_ci} 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_cistatic int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, 40828c2ecf20Sopenharmony_ci const u32 *opts, unsigned int entry) 40838c2ecf20Sopenharmony_ci{ 40848c2ecf20Sopenharmony_ci struct skb_shared_info *info = skb_shinfo(skb); 40858c2ecf20Sopenharmony_ci unsigned int cur_frag; 40868c2ecf20Sopenharmony_ci 40878c2ecf20Sopenharmony_ci for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) { 40888c2ecf20Sopenharmony_ci const skb_frag_t *frag = info->frags + cur_frag; 40898c2ecf20Sopenharmony_ci void *addr = skb_frag_address(frag); 40908c2ecf20Sopenharmony_ci u32 len = skb_frag_size(frag); 40918c2ecf20Sopenharmony_ci 40928c2ecf20Sopenharmony_ci entry = (entry + 1) % NUM_TX_DESC; 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_ci if (unlikely(rtl8169_tx_map(tp, opts, len, addr, entry, true))) 40958c2ecf20Sopenharmony_ci goto err_out; 40968c2ecf20Sopenharmony_ci } 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci return 0; 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_cierr_out: 41018c2ecf20Sopenharmony_ci rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag); 41028c2ecf20Sopenharmony_ci return -EIO; 41038c2ecf20Sopenharmony_ci} 41048c2ecf20Sopenharmony_ci 41058c2ecf20Sopenharmony_cistatic bool rtl_skb_is_udp(struct sk_buff *skb) 41068c2ecf20Sopenharmony_ci{ 41078c2ecf20Sopenharmony_ci int no = skb_network_offset(skb); 41088c2ecf20Sopenharmony_ci struct ipv6hdr *i6h, _i6h; 41098c2ecf20Sopenharmony_ci struct iphdr *ih, _ih; 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci switch (vlan_get_protocol(skb)) { 41128c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 41138c2ecf20Sopenharmony_ci ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih); 41148c2ecf20Sopenharmony_ci return ih && ih->protocol == IPPROTO_UDP; 41158c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 41168c2ecf20Sopenharmony_ci i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h); 41178c2ecf20Sopenharmony_ci return i6h && i6h->nexthdr == IPPROTO_UDP; 41188c2ecf20Sopenharmony_ci default: 41198c2ecf20Sopenharmony_ci return false; 41208c2ecf20Sopenharmony_ci } 41218c2ecf20Sopenharmony_ci} 41228c2ecf20Sopenharmony_ci 41238c2ecf20Sopenharmony_ci#define RTL_MIN_PATCH_LEN 47 41248c2ecf20Sopenharmony_ci 41258c2ecf20Sopenharmony_ci/* see rtl8125_get_patch_pad_len() in r8125 vendor driver */ 41268c2ecf20Sopenharmony_cistatic unsigned int rtl8125_quirk_udp_padto(struct rtl8169_private *tp, 41278c2ecf20Sopenharmony_ci struct sk_buff *skb) 41288c2ecf20Sopenharmony_ci{ 41298c2ecf20Sopenharmony_ci unsigned int padto = 0, len = skb->len; 41308c2ecf20Sopenharmony_ci 41318c2ecf20Sopenharmony_ci if (rtl_is_8125(tp) && len < 128 + RTL_MIN_PATCH_LEN && 41328c2ecf20Sopenharmony_ci rtl_skb_is_udp(skb) && skb_transport_header_was_set(skb)) { 41338c2ecf20Sopenharmony_ci unsigned int trans_data_len = skb_tail_pointer(skb) - 41348c2ecf20Sopenharmony_ci skb_transport_header(skb); 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci if (trans_data_len >= offsetof(struct udphdr, len) && 41378c2ecf20Sopenharmony_ci trans_data_len < RTL_MIN_PATCH_LEN) { 41388c2ecf20Sopenharmony_ci u16 dest = ntohs(udp_hdr(skb)->dest); 41398c2ecf20Sopenharmony_ci 41408c2ecf20Sopenharmony_ci /* dest is a standard PTP port */ 41418c2ecf20Sopenharmony_ci if (dest == 319 || dest == 320) 41428c2ecf20Sopenharmony_ci padto = len + RTL_MIN_PATCH_LEN - trans_data_len; 41438c2ecf20Sopenharmony_ci } 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_ci if (trans_data_len < sizeof(struct udphdr)) 41468c2ecf20Sopenharmony_ci padto = max_t(unsigned int, padto, 41478c2ecf20Sopenharmony_ci len + sizeof(struct udphdr) - trans_data_len); 41488c2ecf20Sopenharmony_ci } 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_ci return padto; 41518c2ecf20Sopenharmony_ci} 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_cistatic unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp, 41548c2ecf20Sopenharmony_ci struct sk_buff *skb) 41558c2ecf20Sopenharmony_ci{ 41568c2ecf20Sopenharmony_ci unsigned int padto; 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci padto = rtl8125_quirk_udp_padto(tp, skb); 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci switch (tp->mac_version) { 41618c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_34: 41628c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_60: 41638c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_61: 41648c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_63: 41658c2ecf20Sopenharmony_ci padto = max_t(unsigned int, padto, ETH_ZLEN); 41668c2ecf20Sopenharmony_ci default: 41678c2ecf20Sopenharmony_ci break; 41688c2ecf20Sopenharmony_ci } 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_ci return padto; 41718c2ecf20Sopenharmony_ci} 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_cistatic void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts) 41748c2ecf20Sopenharmony_ci{ 41758c2ecf20Sopenharmony_ci u32 mss = skb_shinfo(skb)->gso_size; 41768c2ecf20Sopenharmony_ci 41778c2ecf20Sopenharmony_ci if (mss) { 41788c2ecf20Sopenharmony_ci opts[0] |= TD_LSO; 41798c2ecf20Sopenharmony_ci opts[0] |= mss << TD0_MSS_SHIFT; 41808c2ecf20Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 41818c2ecf20Sopenharmony_ci const struct iphdr *ip = ip_hdr(skb); 41828c2ecf20Sopenharmony_ci 41838c2ecf20Sopenharmony_ci if (ip->protocol == IPPROTO_TCP) 41848c2ecf20Sopenharmony_ci opts[0] |= TD0_IP_CS | TD0_TCP_CS; 41858c2ecf20Sopenharmony_ci else if (ip->protocol == IPPROTO_UDP) 41868c2ecf20Sopenharmony_ci opts[0] |= TD0_IP_CS | TD0_UDP_CS; 41878c2ecf20Sopenharmony_ci else 41888c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 41898c2ecf20Sopenharmony_ci } 41908c2ecf20Sopenharmony_ci} 41918c2ecf20Sopenharmony_ci 41928c2ecf20Sopenharmony_cistatic bool rtl8169_tso_csum_v2(struct rtl8169_private *tp, 41938c2ecf20Sopenharmony_ci struct sk_buff *skb, u32 *opts) 41948c2ecf20Sopenharmony_ci{ 41958c2ecf20Sopenharmony_ci struct skb_shared_info *shinfo = skb_shinfo(skb); 41968c2ecf20Sopenharmony_ci u32 mss = shinfo->gso_size; 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci if (mss) { 41998c2ecf20Sopenharmony_ci if (shinfo->gso_type & SKB_GSO_TCPV4) { 42008c2ecf20Sopenharmony_ci opts[0] |= TD1_GTSENV4; 42018c2ecf20Sopenharmony_ci } else if (shinfo->gso_type & SKB_GSO_TCPV6) { 42028c2ecf20Sopenharmony_ci if (skb_cow_head(skb, 0)) 42038c2ecf20Sopenharmony_ci return false; 42048c2ecf20Sopenharmony_ci 42058c2ecf20Sopenharmony_ci tcp_v6_gso_csum_prep(skb); 42068c2ecf20Sopenharmony_ci opts[0] |= TD1_GTSENV6; 42078c2ecf20Sopenharmony_ci } else { 42088c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 42098c2ecf20Sopenharmony_ci } 42108c2ecf20Sopenharmony_ci 42118c2ecf20Sopenharmony_ci opts[0] |= skb_transport_offset(skb) << GTTCPHO_SHIFT; 42128c2ecf20Sopenharmony_ci opts[1] |= mss << TD1_MSS_SHIFT; 42138c2ecf20Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 42148c2ecf20Sopenharmony_ci u8 ip_protocol; 42158c2ecf20Sopenharmony_ci 42168c2ecf20Sopenharmony_ci switch (vlan_get_protocol(skb)) { 42178c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 42188c2ecf20Sopenharmony_ci opts[1] |= TD1_IPv4_CS; 42198c2ecf20Sopenharmony_ci ip_protocol = ip_hdr(skb)->protocol; 42208c2ecf20Sopenharmony_ci break; 42218c2ecf20Sopenharmony_ci 42228c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 42238c2ecf20Sopenharmony_ci opts[1] |= TD1_IPv6_CS; 42248c2ecf20Sopenharmony_ci ip_protocol = ipv6_hdr(skb)->nexthdr; 42258c2ecf20Sopenharmony_ci break; 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci default: 42288c2ecf20Sopenharmony_ci ip_protocol = IPPROTO_RAW; 42298c2ecf20Sopenharmony_ci break; 42308c2ecf20Sopenharmony_ci } 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci if (ip_protocol == IPPROTO_TCP) 42338c2ecf20Sopenharmony_ci opts[1] |= TD1_TCP_CS; 42348c2ecf20Sopenharmony_ci else if (ip_protocol == IPPROTO_UDP) 42358c2ecf20Sopenharmony_ci opts[1] |= TD1_UDP_CS; 42368c2ecf20Sopenharmony_ci else 42378c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci opts[1] |= skb_transport_offset(skb) << TCPHO_SHIFT; 42408c2ecf20Sopenharmony_ci } else { 42418c2ecf20Sopenharmony_ci unsigned int padto = rtl_quirk_packet_padto(tp, skb); 42428c2ecf20Sopenharmony_ci 42438c2ecf20Sopenharmony_ci /* skb_padto would free the skb on error */ 42448c2ecf20Sopenharmony_ci return !__skb_put_padto(skb, padto, false); 42458c2ecf20Sopenharmony_ci } 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci return true; 42488c2ecf20Sopenharmony_ci} 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_cistatic bool rtl_tx_slots_avail(struct rtl8169_private *tp, 42518c2ecf20Sopenharmony_ci unsigned int nr_frags) 42528c2ecf20Sopenharmony_ci{ 42538c2ecf20Sopenharmony_ci unsigned int slots_avail = tp->dirty_tx + NUM_TX_DESC - tp->cur_tx; 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci /* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */ 42568c2ecf20Sopenharmony_ci return slots_avail > nr_frags; 42578c2ecf20Sopenharmony_ci} 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_ci/* Versions RTL8102e and from RTL8168c onwards support csum_v2 */ 42608c2ecf20Sopenharmony_cistatic bool rtl_chip_supports_csum_v2(struct rtl8169_private *tp) 42618c2ecf20Sopenharmony_ci{ 42628c2ecf20Sopenharmony_ci switch (tp->mac_version) { 42638c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: 42648c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_10 ... RTL_GIGA_MAC_VER_17: 42658c2ecf20Sopenharmony_ci return false; 42668c2ecf20Sopenharmony_ci default: 42678c2ecf20Sopenharmony_ci return true; 42688c2ecf20Sopenharmony_ci } 42698c2ecf20Sopenharmony_ci} 42708c2ecf20Sopenharmony_ci 42718c2ecf20Sopenharmony_cistatic void rtl8169_doorbell(struct rtl8169_private *tp) 42728c2ecf20Sopenharmony_ci{ 42738c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) 42748c2ecf20Sopenharmony_ci RTL_W16(tp, TxPoll_8125, BIT(0)); 42758c2ecf20Sopenharmony_ci else 42768c2ecf20Sopenharmony_ci RTL_W8(tp, TxPoll, NPQ); 42778c2ecf20Sopenharmony_ci} 42788c2ecf20Sopenharmony_ci 42798c2ecf20Sopenharmony_cistatic netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, 42808c2ecf20Sopenharmony_ci struct net_device *dev) 42818c2ecf20Sopenharmony_ci{ 42828c2ecf20Sopenharmony_ci unsigned int frags = skb_shinfo(skb)->nr_frags; 42838c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 42848c2ecf20Sopenharmony_ci unsigned int entry = tp->cur_tx % NUM_TX_DESC; 42858c2ecf20Sopenharmony_ci struct TxDesc *txd_first, *txd_last; 42868c2ecf20Sopenharmony_ci bool stop_queue, door_bell; 42878c2ecf20Sopenharmony_ci u32 opts[2]; 42888c2ecf20Sopenharmony_ci 42898c2ecf20Sopenharmony_ci txd_first = tp->TxDescArray + entry; 42908c2ecf20Sopenharmony_ci 42918c2ecf20Sopenharmony_ci if (unlikely(!rtl_tx_slots_avail(tp, frags))) { 42928c2ecf20Sopenharmony_ci if (net_ratelimit()) 42938c2ecf20Sopenharmony_ci netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); 42948c2ecf20Sopenharmony_ci goto err_stop_0; 42958c2ecf20Sopenharmony_ci } 42968c2ecf20Sopenharmony_ci 42978c2ecf20Sopenharmony_ci if (unlikely(le32_to_cpu(txd_first->opts1) & DescOwn)) 42988c2ecf20Sopenharmony_ci goto err_stop_0; 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci opts[1] = rtl8169_tx_vlan_tag(skb); 43018c2ecf20Sopenharmony_ci opts[0] = 0; 43028c2ecf20Sopenharmony_ci 43038c2ecf20Sopenharmony_ci if (!rtl_chip_supports_csum_v2(tp)) 43048c2ecf20Sopenharmony_ci rtl8169_tso_csum_v1(skb, opts); 43058c2ecf20Sopenharmony_ci else if (!rtl8169_tso_csum_v2(tp, skb, opts)) 43068c2ecf20Sopenharmony_ci goto err_dma_0; 43078c2ecf20Sopenharmony_ci 43088c2ecf20Sopenharmony_ci if (unlikely(rtl8169_tx_map(tp, opts, skb_headlen(skb), skb->data, 43098c2ecf20Sopenharmony_ci entry, false))) 43108c2ecf20Sopenharmony_ci goto err_dma_0; 43118c2ecf20Sopenharmony_ci 43128c2ecf20Sopenharmony_ci if (frags) { 43138c2ecf20Sopenharmony_ci if (rtl8169_xmit_frags(tp, skb, opts, entry)) 43148c2ecf20Sopenharmony_ci goto err_dma_1; 43158c2ecf20Sopenharmony_ci entry = (entry + frags) % NUM_TX_DESC; 43168c2ecf20Sopenharmony_ci } 43178c2ecf20Sopenharmony_ci 43188c2ecf20Sopenharmony_ci txd_last = tp->TxDescArray + entry; 43198c2ecf20Sopenharmony_ci txd_last->opts1 |= cpu_to_le32(LastFrag); 43208c2ecf20Sopenharmony_ci tp->tx_skb[entry].skb = skb; 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_ci /* Force memory writes to complete before releasing descriptor */ 43258c2ecf20Sopenharmony_ci dma_wmb(); 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci door_bell = __netdev_sent_queue(dev, skb->len, netdev_xmit_more()); 43288c2ecf20Sopenharmony_ci 43298c2ecf20Sopenharmony_ci txd_first->opts1 |= cpu_to_le32(DescOwn | FirstFrag); 43308c2ecf20Sopenharmony_ci 43318c2ecf20Sopenharmony_ci /* rtl_tx needs to see descriptor changes before updated tp->cur_tx */ 43328c2ecf20Sopenharmony_ci smp_wmb(); 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_ci tp->cur_tx += frags + 1; 43358c2ecf20Sopenharmony_ci 43368c2ecf20Sopenharmony_ci stop_queue = !rtl_tx_slots_avail(tp, MAX_SKB_FRAGS); 43378c2ecf20Sopenharmony_ci if (unlikely(stop_queue)) { 43388c2ecf20Sopenharmony_ci /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must 43398c2ecf20Sopenharmony_ci * not miss a ring update when it notices a stopped queue. 43408c2ecf20Sopenharmony_ci */ 43418c2ecf20Sopenharmony_ci smp_wmb(); 43428c2ecf20Sopenharmony_ci netif_stop_queue(dev); 43438c2ecf20Sopenharmony_ci door_bell = true; 43448c2ecf20Sopenharmony_ci } 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_ci if (door_bell) 43478c2ecf20Sopenharmony_ci rtl8169_doorbell(tp); 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_ci if (unlikely(stop_queue)) { 43508c2ecf20Sopenharmony_ci /* Sync with rtl_tx: 43518c2ecf20Sopenharmony_ci * - publish queue status and cur_tx ring index (write barrier) 43528c2ecf20Sopenharmony_ci * - refresh dirty_tx ring index (read barrier). 43538c2ecf20Sopenharmony_ci * May the current thread have a pessimistic view of the ring 43548c2ecf20Sopenharmony_ci * status and forget to wake up queue, a racing rtl_tx thread 43558c2ecf20Sopenharmony_ci * can't. 43568c2ecf20Sopenharmony_ci */ 43578c2ecf20Sopenharmony_ci smp_mb(); 43588c2ecf20Sopenharmony_ci if (rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) 43598c2ecf20Sopenharmony_ci netif_start_queue(dev); 43608c2ecf20Sopenharmony_ci } 43618c2ecf20Sopenharmony_ci 43628c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_cierr_dma_1: 43658c2ecf20Sopenharmony_ci rtl8169_unmap_tx_skb(tp, entry); 43668c2ecf20Sopenharmony_cierr_dma_0: 43678c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 43688c2ecf20Sopenharmony_ci dev->stats.tx_dropped++; 43698c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_cierr_stop_0: 43728c2ecf20Sopenharmony_ci netif_stop_queue(dev); 43738c2ecf20Sopenharmony_ci dev->stats.tx_dropped++; 43748c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 43758c2ecf20Sopenharmony_ci} 43768c2ecf20Sopenharmony_ci 43778c2ecf20Sopenharmony_cistatic unsigned int rtl_last_frag_len(struct sk_buff *skb) 43788c2ecf20Sopenharmony_ci{ 43798c2ecf20Sopenharmony_ci struct skb_shared_info *info = skb_shinfo(skb); 43808c2ecf20Sopenharmony_ci unsigned int nr_frags = info->nr_frags; 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_ci if (!nr_frags) 43838c2ecf20Sopenharmony_ci return UINT_MAX; 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci return skb_frag_size(info->frags + nr_frags - 1); 43868c2ecf20Sopenharmony_ci} 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_ci/* Workaround for hw issues with TSO on RTL8168evl */ 43898c2ecf20Sopenharmony_cistatic netdev_features_t rtl8168evl_fix_tso(struct sk_buff *skb, 43908c2ecf20Sopenharmony_ci netdev_features_t features) 43918c2ecf20Sopenharmony_ci{ 43928c2ecf20Sopenharmony_ci /* IPv4 header has options field */ 43938c2ecf20Sopenharmony_ci if (vlan_get_protocol(skb) == htons(ETH_P_IP) && 43948c2ecf20Sopenharmony_ci ip_hdrlen(skb) > sizeof(struct iphdr)) 43958c2ecf20Sopenharmony_ci features &= ~NETIF_F_ALL_TSO; 43968c2ecf20Sopenharmony_ci 43978c2ecf20Sopenharmony_ci /* IPv4 TCP header has options field */ 43988c2ecf20Sopenharmony_ci else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 && 43998c2ecf20Sopenharmony_ci tcp_hdrlen(skb) > sizeof(struct tcphdr)) 44008c2ecf20Sopenharmony_ci features &= ~NETIF_F_ALL_TSO; 44018c2ecf20Sopenharmony_ci 44028c2ecf20Sopenharmony_ci else if (rtl_last_frag_len(skb) <= 6) 44038c2ecf20Sopenharmony_ci features &= ~NETIF_F_ALL_TSO; 44048c2ecf20Sopenharmony_ci 44058c2ecf20Sopenharmony_ci return features; 44068c2ecf20Sopenharmony_ci} 44078c2ecf20Sopenharmony_ci 44088c2ecf20Sopenharmony_cistatic netdev_features_t rtl8169_features_check(struct sk_buff *skb, 44098c2ecf20Sopenharmony_ci struct net_device *dev, 44108c2ecf20Sopenharmony_ci netdev_features_t features) 44118c2ecf20Sopenharmony_ci{ 44128c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 44138c2ecf20Sopenharmony_ci 44148c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) { 44158c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_34) 44168c2ecf20Sopenharmony_ci features = rtl8168evl_fix_tso(skb, features); 44178c2ecf20Sopenharmony_ci 44188c2ecf20Sopenharmony_ci if (skb_transport_offset(skb) > GTTCPHO_MAX && 44198c2ecf20Sopenharmony_ci rtl_chip_supports_csum_v2(tp)) 44208c2ecf20Sopenharmony_ci features &= ~NETIF_F_ALL_TSO; 44218c2ecf20Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 44228c2ecf20Sopenharmony_ci /* work around hw bug on some chip versions */ 44238c2ecf20Sopenharmony_ci if (skb->len < ETH_ZLEN) 44248c2ecf20Sopenharmony_ci features &= ~NETIF_F_CSUM_MASK; 44258c2ecf20Sopenharmony_ci 44268c2ecf20Sopenharmony_ci if (rtl_quirk_packet_padto(tp, skb)) 44278c2ecf20Sopenharmony_ci features &= ~NETIF_F_CSUM_MASK; 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci if (skb_transport_offset(skb) > TCPHO_MAX && 44308c2ecf20Sopenharmony_ci rtl_chip_supports_csum_v2(tp)) 44318c2ecf20Sopenharmony_ci features &= ~NETIF_F_CSUM_MASK; 44328c2ecf20Sopenharmony_ci } 44338c2ecf20Sopenharmony_ci 44348c2ecf20Sopenharmony_ci return vlan_features_check(skb, features); 44358c2ecf20Sopenharmony_ci} 44368c2ecf20Sopenharmony_ci 44378c2ecf20Sopenharmony_cistatic void rtl8169_pcierr_interrupt(struct net_device *dev) 44388c2ecf20Sopenharmony_ci{ 44398c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 44408c2ecf20Sopenharmony_ci struct pci_dev *pdev = tp->pci_dev; 44418c2ecf20Sopenharmony_ci int pci_status_errs; 44428c2ecf20Sopenharmony_ci u16 pci_cmd; 44438c2ecf20Sopenharmony_ci 44448c2ecf20Sopenharmony_ci pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); 44458c2ecf20Sopenharmony_ci 44468c2ecf20Sopenharmony_ci pci_status_errs = pci_status_get_and_clear_errors(pdev); 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_ci if (net_ratelimit()) 44498c2ecf20Sopenharmony_ci netdev_err(dev, "PCI error (cmd = 0x%04x, status_errs = 0x%04x)\n", 44508c2ecf20Sopenharmony_ci pci_cmd, pci_status_errs); 44518c2ecf20Sopenharmony_ci /* 44528c2ecf20Sopenharmony_ci * The recovery sequence below admits a very elaborated explanation: 44538c2ecf20Sopenharmony_ci * - it seems to work; 44548c2ecf20Sopenharmony_ci * - I did not see what else could be done; 44558c2ecf20Sopenharmony_ci * - it makes iop3xx happy. 44568c2ecf20Sopenharmony_ci * 44578c2ecf20Sopenharmony_ci * Feel free to adjust to your needs. 44588c2ecf20Sopenharmony_ci */ 44598c2ecf20Sopenharmony_ci if (pdev->broken_parity_status) 44608c2ecf20Sopenharmony_ci pci_cmd &= ~PCI_COMMAND_PARITY; 44618c2ecf20Sopenharmony_ci else 44628c2ecf20Sopenharmony_ci pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY; 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_ci rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); 44678c2ecf20Sopenharmony_ci} 44688c2ecf20Sopenharmony_ci 44698c2ecf20Sopenharmony_cistatic void rtl_tx(struct net_device *dev, struct rtl8169_private *tp, 44708c2ecf20Sopenharmony_ci int budget) 44718c2ecf20Sopenharmony_ci{ 44728c2ecf20Sopenharmony_ci unsigned int dirty_tx, tx_left, bytes_compl = 0, pkts_compl = 0; 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci dirty_tx = tp->dirty_tx; 44758c2ecf20Sopenharmony_ci smp_rmb(); 44768c2ecf20Sopenharmony_ci 44778c2ecf20Sopenharmony_ci for (tx_left = tp->cur_tx - dirty_tx; tx_left > 0; tx_left--) { 44788c2ecf20Sopenharmony_ci unsigned int entry = dirty_tx % NUM_TX_DESC; 44798c2ecf20Sopenharmony_ci struct sk_buff *skb = tp->tx_skb[entry].skb; 44808c2ecf20Sopenharmony_ci u32 status; 44818c2ecf20Sopenharmony_ci 44828c2ecf20Sopenharmony_ci status = le32_to_cpu(READ_ONCE(tp->TxDescArray[entry].opts1)); 44838c2ecf20Sopenharmony_ci if (status & DescOwn) 44848c2ecf20Sopenharmony_ci break; 44858c2ecf20Sopenharmony_ci 44868c2ecf20Sopenharmony_ci rtl8169_unmap_tx_skb(tp, entry); 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci if (skb) { 44898c2ecf20Sopenharmony_ci pkts_compl++; 44908c2ecf20Sopenharmony_ci bytes_compl += skb->len; 44918c2ecf20Sopenharmony_ci napi_consume_skb(skb, budget); 44928c2ecf20Sopenharmony_ci } 44938c2ecf20Sopenharmony_ci dirty_tx++; 44948c2ecf20Sopenharmony_ci } 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci if (tp->dirty_tx != dirty_tx) { 44978c2ecf20Sopenharmony_ci netdev_completed_queue(dev, pkts_compl, bytes_compl); 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_ci rtl_inc_priv_stats(&tp->tx_stats, pkts_compl, bytes_compl); 45008c2ecf20Sopenharmony_ci 45018c2ecf20Sopenharmony_ci tp->dirty_tx = dirty_tx; 45028c2ecf20Sopenharmony_ci /* Sync with rtl8169_start_xmit: 45038c2ecf20Sopenharmony_ci * - publish dirty_tx ring index (write barrier) 45048c2ecf20Sopenharmony_ci * - refresh cur_tx ring index and queue status (read barrier) 45058c2ecf20Sopenharmony_ci * May the current thread miss the stopped queue condition, 45068c2ecf20Sopenharmony_ci * a racing xmit thread can only have a right view of the 45078c2ecf20Sopenharmony_ci * ring status. 45088c2ecf20Sopenharmony_ci */ 45098c2ecf20Sopenharmony_ci smp_mb(); 45108c2ecf20Sopenharmony_ci if (netif_queue_stopped(dev) && 45118c2ecf20Sopenharmony_ci rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) { 45128c2ecf20Sopenharmony_ci netif_wake_queue(dev); 45138c2ecf20Sopenharmony_ci } 45148c2ecf20Sopenharmony_ci /* 45158c2ecf20Sopenharmony_ci * 8168 hack: TxPoll requests are lost when the Tx packets are 45168c2ecf20Sopenharmony_ci * too close. Let's kick an extra TxPoll request when a burst 45178c2ecf20Sopenharmony_ci * of start_xmit activity is detected (if it is not detected, 45188c2ecf20Sopenharmony_ci * it is slow enough). -- FR 45198c2ecf20Sopenharmony_ci */ 45208c2ecf20Sopenharmony_ci if (tp->cur_tx != dirty_tx) 45218c2ecf20Sopenharmony_ci rtl8169_doorbell(tp); 45228c2ecf20Sopenharmony_ci } 45238c2ecf20Sopenharmony_ci} 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_cistatic inline int rtl8169_fragmented_frame(u32 status) 45268c2ecf20Sopenharmony_ci{ 45278c2ecf20Sopenharmony_ci return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag); 45288c2ecf20Sopenharmony_ci} 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_cistatic inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1) 45318c2ecf20Sopenharmony_ci{ 45328c2ecf20Sopenharmony_ci u32 status = opts1 & RxProtoMask; 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci if (((status == RxProtoTCP) && !(opts1 & TCPFail)) || 45358c2ecf20Sopenharmony_ci ((status == RxProtoUDP) && !(opts1 & UDPFail))) 45368c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 45378c2ecf20Sopenharmony_ci else 45388c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 45398c2ecf20Sopenharmony_ci} 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_cistatic int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget) 45428c2ecf20Sopenharmony_ci{ 45438c2ecf20Sopenharmony_ci unsigned int cur_rx, rx_left, count; 45448c2ecf20Sopenharmony_ci struct device *d = tp_to_dev(tp); 45458c2ecf20Sopenharmony_ci 45468c2ecf20Sopenharmony_ci cur_rx = tp->cur_rx; 45478c2ecf20Sopenharmony_ci 45488c2ecf20Sopenharmony_ci for (rx_left = min(budget, NUM_RX_DESC); rx_left > 0; rx_left--, cur_rx++) { 45498c2ecf20Sopenharmony_ci unsigned int pkt_size, entry = cur_rx % NUM_RX_DESC; 45508c2ecf20Sopenharmony_ci struct RxDesc *desc = tp->RxDescArray + entry; 45518c2ecf20Sopenharmony_ci struct sk_buff *skb; 45528c2ecf20Sopenharmony_ci const void *rx_buf; 45538c2ecf20Sopenharmony_ci dma_addr_t addr; 45548c2ecf20Sopenharmony_ci u32 status; 45558c2ecf20Sopenharmony_ci 45568c2ecf20Sopenharmony_ci status = le32_to_cpu(READ_ONCE(desc->opts1)); 45578c2ecf20Sopenharmony_ci if (status & DescOwn) 45588c2ecf20Sopenharmony_ci break; 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci /* This barrier is needed to keep us from reading 45618c2ecf20Sopenharmony_ci * any other fields out of the Rx descriptor until 45628c2ecf20Sopenharmony_ci * we know the status of DescOwn 45638c2ecf20Sopenharmony_ci */ 45648c2ecf20Sopenharmony_ci dma_rmb(); 45658c2ecf20Sopenharmony_ci 45668c2ecf20Sopenharmony_ci if (unlikely(status & RxRES)) { 45678c2ecf20Sopenharmony_ci if (net_ratelimit()) 45688c2ecf20Sopenharmony_ci netdev_warn(dev, "Rx ERROR. status = %08x\n", 45698c2ecf20Sopenharmony_ci status); 45708c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 45718c2ecf20Sopenharmony_ci if (status & (RxRWT | RxRUNT)) 45728c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 45738c2ecf20Sopenharmony_ci if (status & RxCRC) 45748c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci if (!(dev->features & NETIF_F_RXALL)) 45778c2ecf20Sopenharmony_ci goto release_descriptor; 45788c2ecf20Sopenharmony_ci else if (status & RxRWT || !(status & (RxRUNT | RxCRC))) 45798c2ecf20Sopenharmony_ci goto release_descriptor; 45808c2ecf20Sopenharmony_ci } 45818c2ecf20Sopenharmony_ci 45828c2ecf20Sopenharmony_ci pkt_size = status & GENMASK(13, 0); 45838c2ecf20Sopenharmony_ci if (likely(!(dev->features & NETIF_F_RXFCS))) 45848c2ecf20Sopenharmony_ci pkt_size -= ETH_FCS_LEN; 45858c2ecf20Sopenharmony_ci 45868c2ecf20Sopenharmony_ci /* The driver does not support incoming fragmented frames. 45878c2ecf20Sopenharmony_ci * They are seen as a symptom of over-mtu sized frames. 45888c2ecf20Sopenharmony_ci */ 45898c2ecf20Sopenharmony_ci if (unlikely(rtl8169_fragmented_frame(status))) { 45908c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 45918c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 45928c2ecf20Sopenharmony_ci goto release_descriptor; 45938c2ecf20Sopenharmony_ci } 45948c2ecf20Sopenharmony_ci 45958c2ecf20Sopenharmony_ci skb = napi_alloc_skb(&tp->napi, pkt_size); 45968c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 45978c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 45988c2ecf20Sopenharmony_ci goto release_descriptor; 45998c2ecf20Sopenharmony_ci } 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_ci addr = le64_to_cpu(desc->addr); 46028c2ecf20Sopenharmony_ci rx_buf = page_address(tp->Rx_databuff[entry]); 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE); 46058c2ecf20Sopenharmony_ci prefetch(rx_buf); 46068c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, rx_buf, pkt_size); 46078c2ecf20Sopenharmony_ci skb->tail += pkt_size; 46088c2ecf20Sopenharmony_ci skb->len = pkt_size; 46098c2ecf20Sopenharmony_ci dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE); 46108c2ecf20Sopenharmony_ci 46118c2ecf20Sopenharmony_ci rtl8169_rx_csum(skb, status); 46128c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 46138c2ecf20Sopenharmony_ci 46148c2ecf20Sopenharmony_ci rtl8169_rx_vlan_tag(desc, skb); 46158c2ecf20Sopenharmony_ci 46168c2ecf20Sopenharmony_ci if (skb->pkt_type == PACKET_MULTICAST) 46178c2ecf20Sopenharmony_ci dev->stats.multicast++; 46188c2ecf20Sopenharmony_ci 46198c2ecf20Sopenharmony_ci napi_gro_receive(&tp->napi, skb); 46208c2ecf20Sopenharmony_ci 46218c2ecf20Sopenharmony_ci rtl_inc_priv_stats(&tp->rx_stats, 1, pkt_size); 46228c2ecf20Sopenharmony_cirelease_descriptor: 46238c2ecf20Sopenharmony_ci rtl8169_mark_to_asic(desc); 46248c2ecf20Sopenharmony_ci } 46258c2ecf20Sopenharmony_ci 46268c2ecf20Sopenharmony_ci count = cur_rx - tp->cur_rx; 46278c2ecf20Sopenharmony_ci tp->cur_rx = cur_rx; 46288c2ecf20Sopenharmony_ci 46298c2ecf20Sopenharmony_ci return count; 46308c2ecf20Sopenharmony_ci} 46318c2ecf20Sopenharmony_ci 46328c2ecf20Sopenharmony_cistatic irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) 46338c2ecf20Sopenharmony_ci{ 46348c2ecf20Sopenharmony_ci struct rtl8169_private *tp = dev_instance; 46358c2ecf20Sopenharmony_ci u32 status = rtl_get_events(tp); 46368c2ecf20Sopenharmony_ci 46378c2ecf20Sopenharmony_ci if ((status & 0xffff) == 0xffff || !(status & tp->irq_mask)) 46388c2ecf20Sopenharmony_ci return IRQ_NONE; 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci if (unlikely(status & SYSErr)) { 46418c2ecf20Sopenharmony_ci rtl8169_pcierr_interrupt(tp->dev); 46428c2ecf20Sopenharmony_ci goto out; 46438c2ecf20Sopenharmony_ci } 46448c2ecf20Sopenharmony_ci 46458c2ecf20Sopenharmony_ci if (status & LinkChg) 46468c2ecf20Sopenharmony_ci phy_mac_interrupt(tp->phydev); 46478c2ecf20Sopenharmony_ci 46488c2ecf20Sopenharmony_ci if (unlikely(status & RxFIFOOver && 46498c2ecf20Sopenharmony_ci tp->mac_version == RTL_GIGA_MAC_VER_11)) { 46508c2ecf20Sopenharmony_ci netif_stop_queue(tp->dev); 46518c2ecf20Sopenharmony_ci rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); 46528c2ecf20Sopenharmony_ci } 46538c2ecf20Sopenharmony_ci 46548c2ecf20Sopenharmony_ci rtl_irq_disable(tp); 46558c2ecf20Sopenharmony_ci napi_schedule(&tp->napi); 46568c2ecf20Sopenharmony_ciout: 46578c2ecf20Sopenharmony_ci rtl_ack_events(tp, status); 46588c2ecf20Sopenharmony_ci 46598c2ecf20Sopenharmony_ci return IRQ_HANDLED; 46608c2ecf20Sopenharmony_ci} 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_cistatic void rtl_task(struct work_struct *work) 46638c2ecf20Sopenharmony_ci{ 46648c2ecf20Sopenharmony_ci struct rtl8169_private *tp = 46658c2ecf20Sopenharmony_ci container_of(work, struct rtl8169_private, wk.work); 46668c2ecf20Sopenharmony_ci int ret; 46678c2ecf20Sopenharmony_ci 46688c2ecf20Sopenharmony_ci rtnl_lock(); 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_ci if (!netif_running(tp->dev) || 46718c2ecf20Sopenharmony_ci !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) 46728c2ecf20Sopenharmony_ci goto out_unlock; 46738c2ecf20Sopenharmony_ci 46748c2ecf20Sopenharmony_ci if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { 46758c2ecf20Sopenharmony_ci /* ASPM compatibility issues are a typical reason for tx timeouts */ 46768c2ecf20Sopenharmony_ci ret = pci_disable_link_state(tp->pci_dev, PCIE_LINK_STATE_L1 | 46778c2ecf20Sopenharmony_ci PCIE_LINK_STATE_L0S); 46788c2ecf20Sopenharmony_ci if (!ret) 46798c2ecf20Sopenharmony_ci netdev_warn_once(tp->dev, "ASPM disabled on Tx timeout\n"); 46808c2ecf20Sopenharmony_ci goto reset; 46818c2ecf20Sopenharmony_ci } 46828c2ecf20Sopenharmony_ci 46838c2ecf20Sopenharmony_ci if (test_and_clear_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags)) { 46848c2ecf20Sopenharmony_cireset: 46858c2ecf20Sopenharmony_ci rtl_reset_work(tp); 46868c2ecf20Sopenharmony_ci netif_wake_queue(tp->dev); 46878c2ecf20Sopenharmony_ci } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { 46888c2ecf20Sopenharmony_ci rtl_reset_work(tp); 46898c2ecf20Sopenharmony_ci } 46908c2ecf20Sopenharmony_ciout_unlock: 46918c2ecf20Sopenharmony_ci rtnl_unlock(); 46928c2ecf20Sopenharmony_ci} 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_cistatic int rtl8169_poll(struct napi_struct *napi, int budget) 46958c2ecf20Sopenharmony_ci{ 46968c2ecf20Sopenharmony_ci struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi); 46978c2ecf20Sopenharmony_ci struct net_device *dev = tp->dev; 46988c2ecf20Sopenharmony_ci int work_done; 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci work_done = rtl_rx(dev, tp, (u32) budget); 47018c2ecf20Sopenharmony_ci 47028c2ecf20Sopenharmony_ci rtl_tx(dev, tp, budget); 47038c2ecf20Sopenharmony_ci 47048c2ecf20Sopenharmony_ci if (work_done < budget && napi_complete_done(napi, work_done)) 47058c2ecf20Sopenharmony_ci rtl_irq_enable(tp); 47068c2ecf20Sopenharmony_ci 47078c2ecf20Sopenharmony_ci return work_done; 47088c2ecf20Sopenharmony_ci} 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_cistatic void r8169_phylink_handler(struct net_device *ndev) 47118c2ecf20Sopenharmony_ci{ 47128c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(ndev); 47138c2ecf20Sopenharmony_ci struct device *d = tp_to_dev(tp); 47148c2ecf20Sopenharmony_ci 47158c2ecf20Sopenharmony_ci if (netif_carrier_ok(ndev)) { 47168c2ecf20Sopenharmony_ci rtl_link_chg_patch(tp); 47178c2ecf20Sopenharmony_ci pm_request_resume(d); 47188c2ecf20Sopenharmony_ci netif_wake_queue(tp->dev); 47198c2ecf20Sopenharmony_ci } else { 47208c2ecf20Sopenharmony_ci /* In few cases rx is broken after link-down otherwise */ 47218c2ecf20Sopenharmony_ci if (rtl_is_8125(tp)) 47228c2ecf20Sopenharmony_ci rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE); 47238c2ecf20Sopenharmony_ci pm_runtime_idle(d); 47248c2ecf20Sopenharmony_ci } 47258c2ecf20Sopenharmony_ci 47268c2ecf20Sopenharmony_ci if (net_ratelimit()) 47278c2ecf20Sopenharmony_ci phy_print_status(tp->phydev); 47288c2ecf20Sopenharmony_ci} 47298c2ecf20Sopenharmony_ci 47308c2ecf20Sopenharmony_cistatic int r8169_phy_connect(struct rtl8169_private *tp) 47318c2ecf20Sopenharmony_ci{ 47328c2ecf20Sopenharmony_ci struct phy_device *phydev = tp->phydev; 47338c2ecf20Sopenharmony_ci phy_interface_t phy_mode; 47348c2ecf20Sopenharmony_ci int ret; 47358c2ecf20Sopenharmony_ci 47368c2ecf20Sopenharmony_ci phy_mode = tp->supports_gmii ? PHY_INTERFACE_MODE_GMII : 47378c2ecf20Sopenharmony_ci PHY_INTERFACE_MODE_MII; 47388c2ecf20Sopenharmony_ci 47398c2ecf20Sopenharmony_ci ret = phy_connect_direct(tp->dev, phydev, r8169_phylink_handler, 47408c2ecf20Sopenharmony_ci phy_mode); 47418c2ecf20Sopenharmony_ci if (ret) 47428c2ecf20Sopenharmony_ci return ret; 47438c2ecf20Sopenharmony_ci 47448c2ecf20Sopenharmony_ci if (!tp->supports_gmii) 47458c2ecf20Sopenharmony_ci phy_set_max_speed(phydev, SPEED_100); 47468c2ecf20Sopenharmony_ci 47478c2ecf20Sopenharmony_ci phy_attached_info(phydev); 47488c2ecf20Sopenharmony_ci 47498c2ecf20Sopenharmony_ci return 0; 47508c2ecf20Sopenharmony_ci} 47518c2ecf20Sopenharmony_ci 47528c2ecf20Sopenharmony_cistatic void rtl8169_down(struct rtl8169_private *tp) 47538c2ecf20Sopenharmony_ci{ 47548c2ecf20Sopenharmony_ci /* Clear all task flags */ 47558c2ecf20Sopenharmony_ci bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); 47568c2ecf20Sopenharmony_ci 47578c2ecf20Sopenharmony_ci phy_stop(tp->phydev); 47588c2ecf20Sopenharmony_ci 47598c2ecf20Sopenharmony_ci rtl8169_update_counters(tp); 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci pci_clear_master(tp->pci_dev); 47628c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 47638c2ecf20Sopenharmony_ci 47648c2ecf20Sopenharmony_ci rtl8169_cleanup(tp, true); 47658c2ecf20Sopenharmony_ci 47668c2ecf20Sopenharmony_ci rtl_pll_power_down(tp); 47678c2ecf20Sopenharmony_ci} 47688c2ecf20Sopenharmony_ci 47698c2ecf20Sopenharmony_cistatic void rtl8169_up(struct rtl8169_private *tp) 47708c2ecf20Sopenharmony_ci{ 47718c2ecf20Sopenharmony_ci pci_set_master(tp->pci_dev); 47728c2ecf20Sopenharmony_ci rtl_pll_power_up(tp); 47738c2ecf20Sopenharmony_ci rtl8169_init_phy(tp); 47748c2ecf20Sopenharmony_ci napi_enable(&tp->napi); 47758c2ecf20Sopenharmony_ci set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); 47768c2ecf20Sopenharmony_ci rtl_reset_work(tp); 47778c2ecf20Sopenharmony_ci 47788c2ecf20Sopenharmony_ci phy_start(tp->phydev); 47798c2ecf20Sopenharmony_ci} 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_cistatic int rtl8169_close(struct net_device *dev) 47828c2ecf20Sopenharmony_ci{ 47838c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 47848c2ecf20Sopenharmony_ci struct pci_dev *pdev = tp->pci_dev; 47858c2ecf20Sopenharmony_ci 47868c2ecf20Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 47878c2ecf20Sopenharmony_ci 47888c2ecf20Sopenharmony_ci netif_stop_queue(dev); 47898c2ecf20Sopenharmony_ci rtl8169_down(tp); 47908c2ecf20Sopenharmony_ci rtl8169_rx_clear(tp); 47918c2ecf20Sopenharmony_ci 47928c2ecf20Sopenharmony_ci cancel_work(&tp->wk.work); 47938c2ecf20Sopenharmony_ci 47948c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pdev, 0), tp); 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci phy_disconnect(tp->phydev); 47978c2ecf20Sopenharmony_ci 47988c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, 47998c2ecf20Sopenharmony_ci tp->RxPhyAddr); 48008c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray, 48018c2ecf20Sopenharmony_ci tp->TxPhyAddr); 48028c2ecf20Sopenharmony_ci tp->TxDescArray = NULL; 48038c2ecf20Sopenharmony_ci tp->RxDescArray = NULL; 48048c2ecf20Sopenharmony_ci 48058c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 48068c2ecf20Sopenharmony_ci 48078c2ecf20Sopenharmony_ci return 0; 48088c2ecf20Sopenharmony_ci} 48098c2ecf20Sopenharmony_ci 48108c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 48118c2ecf20Sopenharmony_cistatic void rtl8169_netpoll(struct net_device *dev) 48128c2ecf20Sopenharmony_ci{ 48138c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 48148c2ecf20Sopenharmony_ci 48158c2ecf20Sopenharmony_ci rtl8169_interrupt(pci_irq_vector(tp->pci_dev, 0), tp); 48168c2ecf20Sopenharmony_ci} 48178c2ecf20Sopenharmony_ci#endif 48188c2ecf20Sopenharmony_ci 48198c2ecf20Sopenharmony_cistatic int rtl_open(struct net_device *dev) 48208c2ecf20Sopenharmony_ci{ 48218c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 48228c2ecf20Sopenharmony_ci struct pci_dev *pdev = tp->pci_dev; 48238c2ecf20Sopenharmony_ci int retval = -ENOMEM; 48248c2ecf20Sopenharmony_ci 48258c2ecf20Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 48268c2ecf20Sopenharmony_ci 48278c2ecf20Sopenharmony_ci /* 48288c2ecf20Sopenharmony_ci * Rx and Tx descriptors needs 256 bytes alignment. 48298c2ecf20Sopenharmony_ci * dma_alloc_coherent provides more. 48308c2ecf20Sopenharmony_ci */ 48318c2ecf20Sopenharmony_ci tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES, 48328c2ecf20Sopenharmony_ci &tp->TxPhyAddr, GFP_KERNEL); 48338c2ecf20Sopenharmony_ci if (!tp->TxDescArray) 48348c2ecf20Sopenharmony_ci goto err_pm_runtime_put; 48358c2ecf20Sopenharmony_ci 48368c2ecf20Sopenharmony_ci tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES, 48378c2ecf20Sopenharmony_ci &tp->RxPhyAddr, GFP_KERNEL); 48388c2ecf20Sopenharmony_ci if (!tp->RxDescArray) 48398c2ecf20Sopenharmony_ci goto err_free_tx_0; 48408c2ecf20Sopenharmony_ci 48418c2ecf20Sopenharmony_ci retval = rtl8169_init_ring(tp); 48428c2ecf20Sopenharmony_ci if (retval < 0) 48438c2ecf20Sopenharmony_ci goto err_free_rx_1; 48448c2ecf20Sopenharmony_ci 48458c2ecf20Sopenharmony_ci rtl_request_firmware(tp); 48468c2ecf20Sopenharmony_ci 48478c2ecf20Sopenharmony_ci retval = request_irq(pci_irq_vector(pdev, 0), rtl8169_interrupt, 48488c2ecf20Sopenharmony_ci IRQF_SHARED, dev->name, tp); 48498c2ecf20Sopenharmony_ci if (retval < 0) 48508c2ecf20Sopenharmony_ci goto err_release_fw_2; 48518c2ecf20Sopenharmony_ci 48528c2ecf20Sopenharmony_ci retval = r8169_phy_connect(tp); 48538c2ecf20Sopenharmony_ci if (retval) 48548c2ecf20Sopenharmony_ci goto err_free_irq; 48558c2ecf20Sopenharmony_ci 48568c2ecf20Sopenharmony_ci rtl8169_up(tp); 48578c2ecf20Sopenharmony_ci rtl8169_init_counter_offsets(tp); 48588c2ecf20Sopenharmony_ci netif_start_queue(dev); 48598c2ecf20Sopenharmony_ci 48608c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 48618c2ecf20Sopenharmony_ciout: 48628c2ecf20Sopenharmony_ci return retval; 48638c2ecf20Sopenharmony_ci 48648c2ecf20Sopenharmony_cierr_free_irq: 48658c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pdev, 0), tp); 48668c2ecf20Sopenharmony_cierr_release_fw_2: 48678c2ecf20Sopenharmony_ci rtl_release_firmware(tp); 48688c2ecf20Sopenharmony_ci rtl8169_rx_clear(tp); 48698c2ecf20Sopenharmony_cierr_free_rx_1: 48708c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, 48718c2ecf20Sopenharmony_ci tp->RxPhyAddr); 48728c2ecf20Sopenharmony_ci tp->RxDescArray = NULL; 48738c2ecf20Sopenharmony_cierr_free_tx_0: 48748c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray, 48758c2ecf20Sopenharmony_ci tp->TxPhyAddr); 48768c2ecf20Sopenharmony_ci tp->TxDescArray = NULL; 48778c2ecf20Sopenharmony_cierr_pm_runtime_put: 48788c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 48798c2ecf20Sopenharmony_ci goto out; 48808c2ecf20Sopenharmony_ci} 48818c2ecf20Sopenharmony_ci 48828c2ecf20Sopenharmony_cistatic void 48838c2ecf20Sopenharmony_cirtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 48848c2ecf20Sopenharmony_ci{ 48858c2ecf20Sopenharmony_ci struct rtl8169_private *tp = netdev_priv(dev); 48868c2ecf20Sopenharmony_ci struct pci_dev *pdev = tp->pci_dev; 48878c2ecf20Sopenharmony_ci struct rtl8169_counters *counters = tp->counters; 48888c2ecf20Sopenharmony_ci 48898c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&pdev->dev); 48908c2ecf20Sopenharmony_ci 48918c2ecf20Sopenharmony_ci netdev_stats_to_stats64(stats, &dev->stats); 48928c2ecf20Sopenharmony_ci 48938c2ecf20Sopenharmony_ci rtl_get_priv_stats(&tp->rx_stats, &stats->rx_packets, &stats->rx_bytes); 48948c2ecf20Sopenharmony_ci rtl_get_priv_stats(&tp->tx_stats, &stats->tx_packets, &stats->tx_bytes); 48958c2ecf20Sopenharmony_ci 48968c2ecf20Sopenharmony_ci /* 48978c2ecf20Sopenharmony_ci * Fetch additional counter values missing in stats collected by driver 48988c2ecf20Sopenharmony_ci * from tally counters. 48998c2ecf20Sopenharmony_ci */ 49008c2ecf20Sopenharmony_ci if (pm_runtime_active(&pdev->dev)) 49018c2ecf20Sopenharmony_ci rtl8169_update_counters(tp); 49028c2ecf20Sopenharmony_ci 49038c2ecf20Sopenharmony_ci /* 49048c2ecf20Sopenharmony_ci * Subtract values fetched during initalization. 49058c2ecf20Sopenharmony_ci * See rtl8169_init_counter_offsets for a description why we do that. 49068c2ecf20Sopenharmony_ci */ 49078c2ecf20Sopenharmony_ci stats->tx_errors = le64_to_cpu(counters->tx_errors) - 49088c2ecf20Sopenharmony_ci le64_to_cpu(tp->tc_offset.tx_errors); 49098c2ecf20Sopenharmony_ci stats->collisions = le32_to_cpu(counters->tx_multi_collision) - 49108c2ecf20Sopenharmony_ci le32_to_cpu(tp->tc_offset.tx_multi_collision); 49118c2ecf20Sopenharmony_ci stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted) - 49128c2ecf20Sopenharmony_ci le16_to_cpu(tp->tc_offset.tx_aborted); 49138c2ecf20Sopenharmony_ci stats->rx_missed_errors = le16_to_cpu(counters->rx_missed) - 49148c2ecf20Sopenharmony_ci le16_to_cpu(tp->tc_offset.rx_missed); 49158c2ecf20Sopenharmony_ci 49168c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 49178c2ecf20Sopenharmony_ci} 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_cistatic void rtl8169_net_suspend(struct rtl8169_private *tp) 49208c2ecf20Sopenharmony_ci{ 49218c2ecf20Sopenharmony_ci netif_device_detach(tp->dev); 49228c2ecf20Sopenharmony_ci 49238c2ecf20Sopenharmony_ci if (netif_running(tp->dev)) 49248c2ecf20Sopenharmony_ci rtl8169_down(tp); 49258c2ecf20Sopenharmony_ci} 49268c2ecf20Sopenharmony_ci 49278c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 49288c2ecf20Sopenharmony_ci 49298c2ecf20Sopenharmony_cistatic int rtl8169_net_resume(struct rtl8169_private *tp) 49308c2ecf20Sopenharmony_ci{ 49318c2ecf20Sopenharmony_ci rtl_rar_set(tp, tp->dev->dev_addr); 49328c2ecf20Sopenharmony_ci 49338c2ecf20Sopenharmony_ci if (tp->TxDescArray) 49348c2ecf20Sopenharmony_ci rtl8169_up(tp); 49358c2ecf20Sopenharmony_ci 49368c2ecf20Sopenharmony_ci netif_device_attach(tp->dev); 49378c2ecf20Sopenharmony_ci 49388c2ecf20Sopenharmony_ci return 0; 49398c2ecf20Sopenharmony_ci} 49408c2ecf20Sopenharmony_ci 49418c2ecf20Sopenharmony_cistatic int __maybe_unused rtl8169_suspend(struct device *device) 49428c2ecf20Sopenharmony_ci{ 49438c2ecf20Sopenharmony_ci struct rtl8169_private *tp = dev_get_drvdata(device); 49448c2ecf20Sopenharmony_ci 49458c2ecf20Sopenharmony_ci rtnl_lock(); 49468c2ecf20Sopenharmony_ci rtl8169_net_suspend(tp); 49478c2ecf20Sopenharmony_ci if (!device_may_wakeup(tp_to_dev(tp))) 49488c2ecf20Sopenharmony_ci clk_disable_unprepare(tp->clk); 49498c2ecf20Sopenharmony_ci rtnl_unlock(); 49508c2ecf20Sopenharmony_ci 49518c2ecf20Sopenharmony_ci return 0; 49528c2ecf20Sopenharmony_ci} 49538c2ecf20Sopenharmony_ci 49548c2ecf20Sopenharmony_cistatic int __maybe_unused rtl8169_resume(struct device *device) 49558c2ecf20Sopenharmony_ci{ 49568c2ecf20Sopenharmony_ci struct rtl8169_private *tp = dev_get_drvdata(device); 49578c2ecf20Sopenharmony_ci 49588c2ecf20Sopenharmony_ci if (!device_may_wakeup(tp_to_dev(tp))) 49598c2ecf20Sopenharmony_ci clk_prepare_enable(tp->clk); 49608c2ecf20Sopenharmony_ci 49618c2ecf20Sopenharmony_ci /* Reportedly at least Asus X453MA truncates packets otherwise */ 49628c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_37) 49638c2ecf20Sopenharmony_ci rtl_init_rxcfg(tp); 49648c2ecf20Sopenharmony_ci 49658c2ecf20Sopenharmony_ci return rtl8169_net_resume(tp); 49668c2ecf20Sopenharmony_ci} 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_cistatic int rtl8169_runtime_suspend(struct device *device) 49698c2ecf20Sopenharmony_ci{ 49708c2ecf20Sopenharmony_ci struct rtl8169_private *tp = dev_get_drvdata(device); 49718c2ecf20Sopenharmony_ci 49728c2ecf20Sopenharmony_ci if (!tp->TxDescArray) { 49738c2ecf20Sopenharmony_ci netif_device_detach(tp->dev); 49748c2ecf20Sopenharmony_ci return 0; 49758c2ecf20Sopenharmony_ci } 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci rtnl_lock(); 49788c2ecf20Sopenharmony_ci __rtl8169_set_wol(tp, WAKE_PHY); 49798c2ecf20Sopenharmony_ci rtl8169_net_suspend(tp); 49808c2ecf20Sopenharmony_ci rtnl_unlock(); 49818c2ecf20Sopenharmony_ci 49828c2ecf20Sopenharmony_ci return 0; 49838c2ecf20Sopenharmony_ci} 49848c2ecf20Sopenharmony_ci 49858c2ecf20Sopenharmony_cistatic int rtl8169_runtime_resume(struct device *device) 49868c2ecf20Sopenharmony_ci{ 49878c2ecf20Sopenharmony_ci struct rtl8169_private *tp = dev_get_drvdata(device); 49888c2ecf20Sopenharmony_ci 49898c2ecf20Sopenharmony_ci __rtl8169_set_wol(tp, tp->saved_wolopts); 49908c2ecf20Sopenharmony_ci 49918c2ecf20Sopenharmony_ci return rtl8169_net_resume(tp); 49928c2ecf20Sopenharmony_ci} 49938c2ecf20Sopenharmony_ci 49948c2ecf20Sopenharmony_cistatic int rtl8169_runtime_idle(struct device *device) 49958c2ecf20Sopenharmony_ci{ 49968c2ecf20Sopenharmony_ci struct rtl8169_private *tp = dev_get_drvdata(device); 49978c2ecf20Sopenharmony_ci 49988c2ecf20Sopenharmony_ci if (!netif_running(tp->dev) || !netif_carrier_ok(tp->dev)) 49998c2ecf20Sopenharmony_ci pm_schedule_suspend(device, 10000); 50008c2ecf20Sopenharmony_ci 50018c2ecf20Sopenharmony_ci return -EBUSY; 50028c2ecf20Sopenharmony_ci} 50038c2ecf20Sopenharmony_ci 50048c2ecf20Sopenharmony_cistatic const struct dev_pm_ops rtl8169_pm_ops = { 50058c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(rtl8169_suspend, rtl8169_resume) 50068c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(rtl8169_runtime_suspend, rtl8169_runtime_resume, 50078c2ecf20Sopenharmony_ci rtl8169_runtime_idle) 50088c2ecf20Sopenharmony_ci}; 50098c2ecf20Sopenharmony_ci 50108c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 50118c2ecf20Sopenharmony_ci 50128c2ecf20Sopenharmony_cistatic void rtl_wol_shutdown_quirk(struct rtl8169_private *tp) 50138c2ecf20Sopenharmony_ci{ 50148c2ecf20Sopenharmony_ci /* WoL fails with 8168b when the receiver is disabled. */ 50158c2ecf20Sopenharmony_ci switch (tp->mac_version) { 50168c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_11: 50178c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_12: 50188c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_17: 50198c2ecf20Sopenharmony_ci pci_clear_master(tp->pci_dev); 50208c2ecf20Sopenharmony_ci 50218c2ecf20Sopenharmony_ci RTL_W8(tp, ChipCmd, CmdRxEnb); 50228c2ecf20Sopenharmony_ci rtl_pci_commit(tp); 50238c2ecf20Sopenharmony_ci break; 50248c2ecf20Sopenharmony_ci default: 50258c2ecf20Sopenharmony_ci break; 50268c2ecf20Sopenharmony_ci } 50278c2ecf20Sopenharmony_ci} 50288c2ecf20Sopenharmony_ci 50298c2ecf20Sopenharmony_cistatic void rtl_shutdown(struct pci_dev *pdev) 50308c2ecf20Sopenharmony_ci{ 50318c2ecf20Sopenharmony_ci struct rtl8169_private *tp = pci_get_drvdata(pdev); 50328c2ecf20Sopenharmony_ci 50338c2ecf20Sopenharmony_ci rtnl_lock(); 50348c2ecf20Sopenharmony_ci rtl8169_net_suspend(tp); 50358c2ecf20Sopenharmony_ci rtnl_unlock(); 50368c2ecf20Sopenharmony_ci 50378c2ecf20Sopenharmony_ci /* Restore original MAC address */ 50388c2ecf20Sopenharmony_ci rtl_rar_set(tp, tp->dev->perm_addr); 50398c2ecf20Sopenharmony_ci 50408c2ecf20Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF) { 50418c2ecf20Sopenharmony_ci if (tp->saved_wolopts) { 50428c2ecf20Sopenharmony_ci rtl_wol_suspend_quirk(tp); 50438c2ecf20Sopenharmony_ci rtl_wol_shutdown_quirk(tp); 50448c2ecf20Sopenharmony_ci } 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci pci_wake_from_d3(pdev, true); 50478c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 50488c2ecf20Sopenharmony_ci } 50498c2ecf20Sopenharmony_ci} 50508c2ecf20Sopenharmony_ci 50518c2ecf20Sopenharmony_cistatic void rtl_remove_one(struct pci_dev *pdev) 50528c2ecf20Sopenharmony_ci{ 50538c2ecf20Sopenharmony_ci struct rtl8169_private *tp = pci_get_drvdata(pdev); 50548c2ecf20Sopenharmony_ci 50558c2ecf20Sopenharmony_ci if (pci_dev_run_wake(pdev)) 50568c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&pdev->dev); 50578c2ecf20Sopenharmony_ci 50588c2ecf20Sopenharmony_ci cancel_work_sync(&tp->wk.work); 50598c2ecf20Sopenharmony_ci 50608c2ecf20Sopenharmony_ci unregister_netdev(tp->dev); 50618c2ecf20Sopenharmony_ci 50628c2ecf20Sopenharmony_ci if (r8168_check_dash(tp)) 50638c2ecf20Sopenharmony_ci rtl8168_driver_stop(tp); 50648c2ecf20Sopenharmony_ci 50658c2ecf20Sopenharmony_ci rtl_release_firmware(tp); 50668c2ecf20Sopenharmony_ci 50678c2ecf20Sopenharmony_ci /* restore original MAC address */ 50688c2ecf20Sopenharmony_ci rtl_rar_set(tp, tp->dev->perm_addr); 50698c2ecf20Sopenharmony_ci} 50708c2ecf20Sopenharmony_ci 50718c2ecf20Sopenharmony_cistatic const struct net_device_ops rtl_netdev_ops = { 50728c2ecf20Sopenharmony_ci .ndo_open = rtl_open, 50738c2ecf20Sopenharmony_ci .ndo_stop = rtl8169_close, 50748c2ecf20Sopenharmony_ci .ndo_get_stats64 = rtl8169_get_stats64, 50758c2ecf20Sopenharmony_ci .ndo_start_xmit = rtl8169_start_xmit, 50768c2ecf20Sopenharmony_ci .ndo_features_check = rtl8169_features_check, 50778c2ecf20Sopenharmony_ci .ndo_tx_timeout = rtl8169_tx_timeout, 50788c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 50798c2ecf20Sopenharmony_ci .ndo_change_mtu = rtl8169_change_mtu, 50808c2ecf20Sopenharmony_ci .ndo_fix_features = rtl8169_fix_features, 50818c2ecf20Sopenharmony_ci .ndo_set_features = rtl8169_set_features, 50828c2ecf20Sopenharmony_ci .ndo_set_mac_address = rtl_set_mac_address, 50838c2ecf20Sopenharmony_ci .ndo_do_ioctl = phy_do_ioctl_running, 50848c2ecf20Sopenharmony_ci .ndo_set_rx_mode = rtl_set_rx_mode, 50858c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 50868c2ecf20Sopenharmony_ci .ndo_poll_controller = rtl8169_netpoll, 50878c2ecf20Sopenharmony_ci#endif 50888c2ecf20Sopenharmony_ci 50898c2ecf20Sopenharmony_ci}; 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_cistatic void rtl_set_irq_mask(struct rtl8169_private *tp) 50928c2ecf20Sopenharmony_ci{ 50938c2ecf20Sopenharmony_ci tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg; 50948c2ecf20Sopenharmony_ci 50958c2ecf20Sopenharmony_ci if (tp->mac_version <= RTL_GIGA_MAC_VER_06) 50968c2ecf20Sopenharmony_ci tp->irq_mask |= SYSErr | RxOverflow | RxFIFOOver; 50978c2ecf20Sopenharmony_ci else if (tp->mac_version == RTL_GIGA_MAC_VER_11) 50988c2ecf20Sopenharmony_ci /* special workaround needed */ 50998c2ecf20Sopenharmony_ci tp->irq_mask |= RxFIFOOver; 51008c2ecf20Sopenharmony_ci else 51018c2ecf20Sopenharmony_ci tp->irq_mask |= RxOverflow; 51028c2ecf20Sopenharmony_ci} 51038c2ecf20Sopenharmony_ci 51048c2ecf20Sopenharmony_cistatic int rtl_alloc_irq(struct rtl8169_private *tp) 51058c2ecf20Sopenharmony_ci{ 51068c2ecf20Sopenharmony_ci unsigned int flags; 51078c2ecf20Sopenharmony_ci 51088c2ecf20Sopenharmony_ci switch (tp->mac_version) { 51098c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: 51108c2ecf20Sopenharmony_ci rtl_unlock_config_regs(tp); 51118c2ecf20Sopenharmony_ci RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable); 51128c2ecf20Sopenharmony_ci rtl_lock_config_regs(tp); 51138c2ecf20Sopenharmony_ci fallthrough; 51148c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_17: 51158c2ecf20Sopenharmony_ci flags = PCI_IRQ_LEGACY; 51168c2ecf20Sopenharmony_ci break; 51178c2ecf20Sopenharmony_ci default: 51188c2ecf20Sopenharmony_ci flags = PCI_IRQ_ALL_TYPES; 51198c2ecf20Sopenharmony_ci break; 51208c2ecf20Sopenharmony_ci } 51218c2ecf20Sopenharmony_ci 51228c2ecf20Sopenharmony_ci return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags); 51238c2ecf20Sopenharmony_ci} 51248c2ecf20Sopenharmony_ci 51258c2ecf20Sopenharmony_cistatic void rtl_read_mac_address(struct rtl8169_private *tp, 51268c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN]) 51278c2ecf20Sopenharmony_ci{ 51288c2ecf20Sopenharmony_ci /* Get MAC address */ 51298c2ecf20Sopenharmony_ci if (rtl_is_8168evl_up(tp) && tp->mac_version != RTL_GIGA_MAC_VER_34) { 51308c2ecf20Sopenharmony_ci u32 value = rtl_eri_read(tp, 0xe0); 51318c2ecf20Sopenharmony_ci 51328c2ecf20Sopenharmony_ci mac_addr[0] = (value >> 0) & 0xff; 51338c2ecf20Sopenharmony_ci mac_addr[1] = (value >> 8) & 0xff; 51348c2ecf20Sopenharmony_ci mac_addr[2] = (value >> 16) & 0xff; 51358c2ecf20Sopenharmony_ci mac_addr[3] = (value >> 24) & 0xff; 51368c2ecf20Sopenharmony_ci 51378c2ecf20Sopenharmony_ci value = rtl_eri_read(tp, 0xe4); 51388c2ecf20Sopenharmony_ci mac_addr[4] = (value >> 0) & 0xff; 51398c2ecf20Sopenharmony_ci mac_addr[5] = (value >> 8) & 0xff; 51408c2ecf20Sopenharmony_ci } else if (rtl_is_8125(tp)) { 51418c2ecf20Sopenharmony_ci rtl_read_mac_from_reg(tp, mac_addr, MAC0_BKP); 51428c2ecf20Sopenharmony_ci } 51438c2ecf20Sopenharmony_ci} 51448c2ecf20Sopenharmony_ci 51458c2ecf20Sopenharmony_ciDECLARE_RTL_COND(rtl_link_list_ready_cond) 51468c2ecf20Sopenharmony_ci{ 51478c2ecf20Sopenharmony_ci return RTL_R8(tp, MCU) & LINK_LIST_RDY; 51488c2ecf20Sopenharmony_ci} 51498c2ecf20Sopenharmony_ci 51508c2ecf20Sopenharmony_cistatic void r8168g_wait_ll_share_fifo_ready(struct rtl8169_private *tp) 51518c2ecf20Sopenharmony_ci{ 51528c2ecf20Sopenharmony_ci rtl_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42); 51538c2ecf20Sopenharmony_ci} 51548c2ecf20Sopenharmony_ci 51558c2ecf20Sopenharmony_cistatic int r8169_mdio_read_reg(struct mii_bus *mii_bus, int phyaddr, int phyreg) 51568c2ecf20Sopenharmony_ci{ 51578c2ecf20Sopenharmony_ci struct rtl8169_private *tp = mii_bus->priv; 51588c2ecf20Sopenharmony_ci 51598c2ecf20Sopenharmony_ci if (phyaddr > 0) 51608c2ecf20Sopenharmony_ci return -ENODEV; 51618c2ecf20Sopenharmony_ci 51628c2ecf20Sopenharmony_ci return rtl_readphy(tp, phyreg); 51638c2ecf20Sopenharmony_ci} 51648c2ecf20Sopenharmony_ci 51658c2ecf20Sopenharmony_cistatic int r8169_mdio_write_reg(struct mii_bus *mii_bus, int phyaddr, 51668c2ecf20Sopenharmony_ci int phyreg, u16 val) 51678c2ecf20Sopenharmony_ci{ 51688c2ecf20Sopenharmony_ci struct rtl8169_private *tp = mii_bus->priv; 51698c2ecf20Sopenharmony_ci 51708c2ecf20Sopenharmony_ci if (phyaddr > 0) 51718c2ecf20Sopenharmony_ci return -ENODEV; 51728c2ecf20Sopenharmony_ci 51738c2ecf20Sopenharmony_ci rtl_writephy(tp, phyreg, val); 51748c2ecf20Sopenharmony_ci 51758c2ecf20Sopenharmony_ci return 0; 51768c2ecf20Sopenharmony_ci} 51778c2ecf20Sopenharmony_ci 51788c2ecf20Sopenharmony_cistatic int r8169_mdio_register(struct rtl8169_private *tp) 51798c2ecf20Sopenharmony_ci{ 51808c2ecf20Sopenharmony_ci struct pci_dev *pdev = tp->pci_dev; 51818c2ecf20Sopenharmony_ci struct mii_bus *new_bus; 51828c2ecf20Sopenharmony_ci int ret; 51838c2ecf20Sopenharmony_ci 51848c2ecf20Sopenharmony_ci new_bus = devm_mdiobus_alloc(&pdev->dev); 51858c2ecf20Sopenharmony_ci if (!new_bus) 51868c2ecf20Sopenharmony_ci return -ENOMEM; 51878c2ecf20Sopenharmony_ci 51888c2ecf20Sopenharmony_ci new_bus->name = "r8169"; 51898c2ecf20Sopenharmony_ci new_bus->priv = tp; 51908c2ecf20Sopenharmony_ci new_bus->parent = &pdev->dev; 51918c2ecf20Sopenharmony_ci new_bus->irq[0] = PHY_IGNORE_INTERRUPT; 51928c2ecf20Sopenharmony_ci snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x-%x", 51938c2ecf20Sopenharmony_ci pci_domain_nr(pdev->bus), pci_dev_id(pdev)); 51948c2ecf20Sopenharmony_ci 51958c2ecf20Sopenharmony_ci new_bus->read = r8169_mdio_read_reg; 51968c2ecf20Sopenharmony_ci new_bus->write = r8169_mdio_write_reg; 51978c2ecf20Sopenharmony_ci 51988c2ecf20Sopenharmony_ci ret = devm_mdiobus_register(&pdev->dev, new_bus); 51998c2ecf20Sopenharmony_ci if (ret) 52008c2ecf20Sopenharmony_ci return ret; 52018c2ecf20Sopenharmony_ci 52028c2ecf20Sopenharmony_ci tp->phydev = mdiobus_get_phy(new_bus, 0); 52038c2ecf20Sopenharmony_ci if (!tp->phydev) { 52048c2ecf20Sopenharmony_ci return -ENODEV; 52058c2ecf20Sopenharmony_ci } else if (!tp->phydev->drv) { 52068c2ecf20Sopenharmony_ci /* Most chip versions fail with the genphy driver. 52078c2ecf20Sopenharmony_ci * Therefore ensure that the dedicated PHY driver is loaded. 52088c2ecf20Sopenharmony_ci */ 52098c2ecf20Sopenharmony_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", 52108c2ecf20Sopenharmony_ci tp->phydev->phy_id); 52118c2ecf20Sopenharmony_ci return -EUNATCH; 52128c2ecf20Sopenharmony_ci } 52138c2ecf20Sopenharmony_ci 52148c2ecf20Sopenharmony_ci /* PHY will be woken up in rtl_open() */ 52158c2ecf20Sopenharmony_ci phy_suspend(tp->phydev); 52168c2ecf20Sopenharmony_ci 52178c2ecf20Sopenharmony_ci return 0; 52188c2ecf20Sopenharmony_ci} 52198c2ecf20Sopenharmony_ci 52208c2ecf20Sopenharmony_cistatic void rtl_hw_init_8168g(struct rtl8169_private *tp) 52218c2ecf20Sopenharmony_ci{ 52228c2ecf20Sopenharmony_ci rtl_enable_rxdvgate(tp); 52238c2ecf20Sopenharmony_ci 52248c2ecf20Sopenharmony_ci RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) & ~(CmdTxEnb | CmdRxEnb)); 52258c2ecf20Sopenharmony_ci msleep(1); 52268c2ecf20Sopenharmony_ci RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB); 52278c2ecf20Sopenharmony_ci 52288c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe8de, BIT(14), 0); 52298c2ecf20Sopenharmony_ci r8168g_wait_ll_share_fifo_ready(tp); 52308c2ecf20Sopenharmony_ci 52318c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe8de, 0, BIT(15)); 52328c2ecf20Sopenharmony_ci r8168g_wait_ll_share_fifo_ready(tp); 52338c2ecf20Sopenharmony_ci} 52348c2ecf20Sopenharmony_ci 52358c2ecf20Sopenharmony_cistatic void rtl_hw_init_8125(struct rtl8169_private *tp) 52368c2ecf20Sopenharmony_ci{ 52378c2ecf20Sopenharmony_ci rtl_enable_rxdvgate(tp); 52388c2ecf20Sopenharmony_ci 52398c2ecf20Sopenharmony_ci RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) & ~(CmdTxEnb | CmdRxEnb)); 52408c2ecf20Sopenharmony_ci msleep(1); 52418c2ecf20Sopenharmony_ci RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB); 52428c2ecf20Sopenharmony_ci 52438c2ecf20Sopenharmony_ci r8168_mac_ocp_modify(tp, 0xe8de, BIT(14), 0); 52448c2ecf20Sopenharmony_ci r8168g_wait_ll_share_fifo_ready(tp); 52458c2ecf20Sopenharmony_ci 52468c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc0aa, 0x07d0); 52478c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc0a6, 0x0150); 52488c2ecf20Sopenharmony_ci r8168_mac_ocp_write(tp, 0xc01e, 0x5555); 52498c2ecf20Sopenharmony_ci r8168g_wait_ll_share_fifo_ready(tp); 52508c2ecf20Sopenharmony_ci} 52518c2ecf20Sopenharmony_ci 52528c2ecf20Sopenharmony_cistatic void rtl_hw_initialize(struct rtl8169_private *tp) 52538c2ecf20Sopenharmony_ci{ 52548c2ecf20Sopenharmony_ci switch (tp->mac_version) { 52558c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: 52568c2ecf20Sopenharmony_ci rtl8168ep_stop_cmac(tp); 52578c2ecf20Sopenharmony_ci fallthrough; 52588c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: 52598c2ecf20Sopenharmony_ci rtl_hw_init_8168g(tp); 52608c2ecf20Sopenharmony_ci break; 52618c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_60 ... RTL_GIGA_MAC_VER_63: 52628c2ecf20Sopenharmony_ci rtl_hw_init_8125(tp); 52638c2ecf20Sopenharmony_ci break; 52648c2ecf20Sopenharmony_ci default: 52658c2ecf20Sopenharmony_ci break; 52668c2ecf20Sopenharmony_ci } 52678c2ecf20Sopenharmony_ci} 52688c2ecf20Sopenharmony_ci 52698c2ecf20Sopenharmony_cistatic int rtl_jumbo_max(struct rtl8169_private *tp) 52708c2ecf20Sopenharmony_ci{ 52718c2ecf20Sopenharmony_ci /* Non-GBit versions don't support jumbo frames */ 52728c2ecf20Sopenharmony_ci if (!tp->supports_gmii) 52738c2ecf20Sopenharmony_ci return 0; 52748c2ecf20Sopenharmony_ci 52758c2ecf20Sopenharmony_ci switch (tp->mac_version) { 52768c2ecf20Sopenharmony_ci /* RTL8169 */ 52778c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: 52788c2ecf20Sopenharmony_ci return JUMBO_7K; 52798c2ecf20Sopenharmony_ci /* RTL8168b */ 52808c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_11: 52818c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_12: 52828c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_17: 52838c2ecf20Sopenharmony_ci return JUMBO_4K; 52848c2ecf20Sopenharmony_ci /* RTL8168c */ 52858c2ecf20Sopenharmony_ci case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24: 52868c2ecf20Sopenharmony_ci return JUMBO_6K; 52878c2ecf20Sopenharmony_ci default: 52888c2ecf20Sopenharmony_ci return JUMBO_9K; 52898c2ecf20Sopenharmony_ci } 52908c2ecf20Sopenharmony_ci} 52918c2ecf20Sopenharmony_ci 52928c2ecf20Sopenharmony_cistatic void rtl_disable_clk(void *data) 52938c2ecf20Sopenharmony_ci{ 52948c2ecf20Sopenharmony_ci clk_disable_unprepare(data); 52958c2ecf20Sopenharmony_ci} 52968c2ecf20Sopenharmony_ci 52978c2ecf20Sopenharmony_cistatic int rtl_get_ether_clk(struct rtl8169_private *tp) 52988c2ecf20Sopenharmony_ci{ 52998c2ecf20Sopenharmony_ci struct device *d = tp_to_dev(tp); 53008c2ecf20Sopenharmony_ci struct clk *clk; 53018c2ecf20Sopenharmony_ci int rc; 53028c2ecf20Sopenharmony_ci 53038c2ecf20Sopenharmony_ci clk = devm_clk_get(d, "ether_clk"); 53048c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 53058c2ecf20Sopenharmony_ci rc = PTR_ERR(clk); 53068c2ecf20Sopenharmony_ci if (rc == -ENOENT) 53078c2ecf20Sopenharmony_ci /* clk-core allows NULL (for suspend / resume) */ 53088c2ecf20Sopenharmony_ci rc = 0; 53098c2ecf20Sopenharmony_ci else if (rc != -EPROBE_DEFER) 53108c2ecf20Sopenharmony_ci dev_err(d, "failed to get clk: %d\n", rc); 53118c2ecf20Sopenharmony_ci } else { 53128c2ecf20Sopenharmony_ci tp->clk = clk; 53138c2ecf20Sopenharmony_ci rc = clk_prepare_enable(clk); 53148c2ecf20Sopenharmony_ci if (rc) 53158c2ecf20Sopenharmony_ci dev_err(d, "failed to enable clk: %d\n", rc); 53168c2ecf20Sopenharmony_ci else 53178c2ecf20Sopenharmony_ci rc = devm_add_action_or_reset(d, rtl_disable_clk, clk); 53188c2ecf20Sopenharmony_ci } 53198c2ecf20Sopenharmony_ci 53208c2ecf20Sopenharmony_ci return rc; 53218c2ecf20Sopenharmony_ci} 53228c2ecf20Sopenharmony_ci 53238c2ecf20Sopenharmony_cistatic void rtl_init_mac_address(struct rtl8169_private *tp) 53248c2ecf20Sopenharmony_ci{ 53258c2ecf20Sopenharmony_ci struct net_device *dev = tp->dev; 53268c2ecf20Sopenharmony_ci u8 *mac_addr = dev->dev_addr; 53278c2ecf20Sopenharmony_ci int rc; 53288c2ecf20Sopenharmony_ci 53298c2ecf20Sopenharmony_ci rc = eth_platform_get_mac_address(tp_to_dev(tp), mac_addr); 53308c2ecf20Sopenharmony_ci if (!rc) 53318c2ecf20Sopenharmony_ci goto done; 53328c2ecf20Sopenharmony_ci 53338c2ecf20Sopenharmony_ci rtl_read_mac_address(tp, mac_addr); 53348c2ecf20Sopenharmony_ci if (is_valid_ether_addr(mac_addr)) 53358c2ecf20Sopenharmony_ci goto done; 53368c2ecf20Sopenharmony_ci 53378c2ecf20Sopenharmony_ci rtl_read_mac_from_reg(tp, mac_addr, MAC0); 53388c2ecf20Sopenharmony_ci if (is_valid_ether_addr(mac_addr)) 53398c2ecf20Sopenharmony_ci goto done; 53408c2ecf20Sopenharmony_ci 53418c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 53428c2ecf20Sopenharmony_ci dev_warn(tp_to_dev(tp), "can't read MAC address, setting random one\n"); 53438c2ecf20Sopenharmony_cidone: 53448c2ecf20Sopenharmony_ci rtl_rar_set(tp, mac_addr); 53458c2ecf20Sopenharmony_ci} 53468c2ecf20Sopenharmony_ci 53478c2ecf20Sopenharmony_cistatic int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 53488c2ecf20Sopenharmony_ci{ 53498c2ecf20Sopenharmony_ci struct rtl8169_private *tp; 53508c2ecf20Sopenharmony_ci int jumbo_max, region, rc; 53518c2ecf20Sopenharmony_ci enum mac_version chipset; 53528c2ecf20Sopenharmony_ci struct net_device *dev; 53538c2ecf20Sopenharmony_ci u16 xid; 53548c2ecf20Sopenharmony_ci 53558c2ecf20Sopenharmony_ci dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp)); 53568c2ecf20Sopenharmony_ci if (!dev) 53578c2ecf20Sopenharmony_ci return -ENOMEM; 53588c2ecf20Sopenharmony_ci 53598c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 53608c2ecf20Sopenharmony_ci dev->netdev_ops = &rtl_netdev_ops; 53618c2ecf20Sopenharmony_ci tp = netdev_priv(dev); 53628c2ecf20Sopenharmony_ci tp->dev = dev; 53638c2ecf20Sopenharmony_ci tp->pci_dev = pdev; 53648c2ecf20Sopenharmony_ci tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; 53658c2ecf20Sopenharmony_ci tp->eee_adv = -1; 53668c2ecf20Sopenharmony_ci tp->ocp_base = OCP_STD_PHY_BASE; 53678c2ecf20Sopenharmony_ci 53688c2ecf20Sopenharmony_ci /* Get the *optional* external "ether_clk" used on some boards */ 53698c2ecf20Sopenharmony_ci rc = rtl_get_ether_clk(tp); 53708c2ecf20Sopenharmony_ci if (rc) 53718c2ecf20Sopenharmony_ci return rc; 53728c2ecf20Sopenharmony_ci 53738c2ecf20Sopenharmony_ci /* Disable ASPM completely as that cause random device stop working 53748c2ecf20Sopenharmony_ci * problems as well as full system hangs for some PCIe devices users. 53758c2ecf20Sopenharmony_ci */ 53768c2ecf20Sopenharmony_ci rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | 53778c2ecf20Sopenharmony_ci PCIE_LINK_STATE_L1); 53788c2ecf20Sopenharmony_ci tp->aspm_manageable = !rc; 53798c2ecf20Sopenharmony_ci 53808c2ecf20Sopenharmony_ci /* enable device (incl. PCI PM wakeup and hotplug setup) */ 53818c2ecf20Sopenharmony_ci rc = pcim_enable_device(pdev); 53828c2ecf20Sopenharmony_ci if (rc < 0) { 53838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "enable failure\n"); 53848c2ecf20Sopenharmony_ci return rc; 53858c2ecf20Sopenharmony_ci } 53868c2ecf20Sopenharmony_ci 53878c2ecf20Sopenharmony_ci if (pcim_set_mwi(pdev) < 0) 53888c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Mem-Wr-Inval unavailable\n"); 53898c2ecf20Sopenharmony_ci 53908c2ecf20Sopenharmony_ci /* use first MMIO region */ 53918c2ecf20Sopenharmony_ci region = ffs(pci_select_bars(pdev, IORESOURCE_MEM)) - 1; 53928c2ecf20Sopenharmony_ci if (region < 0) { 53938c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no MMIO resource found\n"); 53948c2ecf20Sopenharmony_ci return -ENODEV; 53958c2ecf20Sopenharmony_ci } 53968c2ecf20Sopenharmony_ci 53978c2ecf20Sopenharmony_ci /* check for weird/broken PCI region reporting */ 53988c2ecf20Sopenharmony_ci if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) { 53998c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n"); 54008c2ecf20Sopenharmony_ci return -ENODEV; 54018c2ecf20Sopenharmony_ci } 54028c2ecf20Sopenharmony_ci 54038c2ecf20Sopenharmony_ci rc = pcim_iomap_regions(pdev, BIT(region), MODULENAME); 54048c2ecf20Sopenharmony_ci if (rc < 0) { 54058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); 54068c2ecf20Sopenharmony_ci return rc; 54078c2ecf20Sopenharmony_ci } 54088c2ecf20Sopenharmony_ci 54098c2ecf20Sopenharmony_ci tp->mmio_addr = pcim_iomap_table(pdev)[region]; 54108c2ecf20Sopenharmony_ci 54118c2ecf20Sopenharmony_ci xid = (RTL_R32(tp, TxConfig) >> 20) & 0xfcf; 54128c2ecf20Sopenharmony_ci 54138c2ecf20Sopenharmony_ci /* Identify chip attached to board */ 54148c2ecf20Sopenharmony_ci chipset = rtl8169_get_mac_version(xid, tp->supports_gmii); 54158c2ecf20Sopenharmony_ci if (chipset == RTL_GIGA_MAC_NONE) { 54168c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unknown chip XID %03x\n", xid); 54178c2ecf20Sopenharmony_ci return -ENODEV; 54188c2ecf20Sopenharmony_ci } 54198c2ecf20Sopenharmony_ci 54208c2ecf20Sopenharmony_ci tp->mac_version = chipset; 54218c2ecf20Sopenharmony_ci 54228c2ecf20Sopenharmony_ci tp->cp_cmd = RTL_R16(tp, CPlusCmd) & CPCMD_MASK; 54238c2ecf20Sopenharmony_ci 54248c2ecf20Sopenharmony_ci if (sizeof(dma_addr_t) > 4 && tp->mac_version >= RTL_GIGA_MAC_VER_18 && 54258c2ecf20Sopenharmony_ci !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) 54268c2ecf20Sopenharmony_ci dev->features |= NETIF_F_HIGHDMA; 54278c2ecf20Sopenharmony_ci 54288c2ecf20Sopenharmony_ci rtl_init_rxcfg(tp); 54298c2ecf20Sopenharmony_ci 54308c2ecf20Sopenharmony_ci rtl8169_irq_mask_and_ack(tp); 54318c2ecf20Sopenharmony_ci 54328c2ecf20Sopenharmony_ci rtl_hw_initialize(tp); 54338c2ecf20Sopenharmony_ci 54348c2ecf20Sopenharmony_ci rtl_hw_reset(tp); 54358c2ecf20Sopenharmony_ci 54368c2ecf20Sopenharmony_ci rc = rtl_alloc_irq(tp); 54378c2ecf20Sopenharmony_ci if (rc < 0) { 54388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't allocate interrupt\n"); 54398c2ecf20Sopenharmony_ci return rc; 54408c2ecf20Sopenharmony_ci } 54418c2ecf20Sopenharmony_ci 54428c2ecf20Sopenharmony_ci INIT_WORK(&tp->wk.work, rtl_task); 54438c2ecf20Sopenharmony_ci u64_stats_init(&tp->rx_stats.syncp); 54448c2ecf20Sopenharmony_ci u64_stats_init(&tp->tx_stats.syncp); 54458c2ecf20Sopenharmony_ci 54468c2ecf20Sopenharmony_ci rtl_init_mac_address(tp); 54478c2ecf20Sopenharmony_ci 54488c2ecf20Sopenharmony_ci dev->ethtool_ops = &rtl8169_ethtool_ops; 54498c2ecf20Sopenharmony_ci 54508c2ecf20Sopenharmony_ci netif_napi_add(dev, &tp->napi, rtl8169_poll, NAPI_POLL_WEIGHT); 54518c2ecf20Sopenharmony_ci 54528c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | 54538c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; 54548c2ecf20Sopenharmony_ci dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; 54558c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 54568c2ecf20Sopenharmony_ci 54578c2ecf20Sopenharmony_ci /* 54588c2ecf20Sopenharmony_ci * Pretend we are using VLANs; This bypasses a nasty bug where 54598c2ecf20Sopenharmony_ci * Interrupts stop flowing on high load on 8110SCd controllers. 54608c2ecf20Sopenharmony_ci */ 54618c2ecf20Sopenharmony_ci if (tp->mac_version == RTL_GIGA_MAC_VER_05) 54628c2ecf20Sopenharmony_ci /* Disallow toggling */ 54638c2ecf20Sopenharmony_ci dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX; 54648c2ecf20Sopenharmony_ci 54658c2ecf20Sopenharmony_ci if (rtl_chip_supports_csum_v2(tp)) 54668c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_IPV6_CSUM; 54678c2ecf20Sopenharmony_ci 54688c2ecf20Sopenharmony_ci dev->features |= dev->hw_features; 54698c2ecf20Sopenharmony_ci 54708c2ecf20Sopenharmony_ci /* There has been a number of reports that using SG/TSO results in 54718c2ecf20Sopenharmony_ci * tx timeouts. However for a lot of people SG/TSO works fine. 54728c2ecf20Sopenharmony_ci * Therefore disable both features by default, but allow users to 54738c2ecf20Sopenharmony_ci * enable them. Use at own risk! 54748c2ecf20Sopenharmony_ci */ 54758c2ecf20Sopenharmony_ci if (rtl_chip_supports_csum_v2(tp)) { 54768c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; 54778c2ecf20Sopenharmony_ci dev->gso_max_size = RTL_GSO_MAX_SIZE_V2; 54788c2ecf20Sopenharmony_ci dev->gso_max_segs = RTL_GSO_MAX_SEGS_V2; 54798c2ecf20Sopenharmony_ci } else { 54808c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_SG | NETIF_F_TSO; 54818c2ecf20Sopenharmony_ci dev->gso_max_size = RTL_GSO_MAX_SIZE_V1; 54828c2ecf20Sopenharmony_ci dev->gso_max_segs = RTL_GSO_MAX_SEGS_V1; 54838c2ecf20Sopenharmony_ci } 54848c2ecf20Sopenharmony_ci 54858c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_RXALL; 54868c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_RXFCS; 54878c2ecf20Sopenharmony_ci 54888c2ecf20Sopenharmony_ci /* configure chip for default features */ 54898c2ecf20Sopenharmony_ci rtl8169_set_features(dev, dev->features); 54908c2ecf20Sopenharmony_ci 54918c2ecf20Sopenharmony_ci jumbo_max = rtl_jumbo_max(tp); 54928c2ecf20Sopenharmony_ci if (jumbo_max) 54938c2ecf20Sopenharmony_ci dev->max_mtu = jumbo_max; 54948c2ecf20Sopenharmony_ci 54958c2ecf20Sopenharmony_ci rtl_set_irq_mask(tp); 54968c2ecf20Sopenharmony_ci 54978c2ecf20Sopenharmony_ci tp->fw_name = rtl_chip_infos[chipset].fw_name; 54988c2ecf20Sopenharmony_ci 54998c2ecf20Sopenharmony_ci tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters), 55008c2ecf20Sopenharmony_ci &tp->counters_phys_addr, 55018c2ecf20Sopenharmony_ci GFP_KERNEL); 55028c2ecf20Sopenharmony_ci if (!tp->counters) 55038c2ecf20Sopenharmony_ci return -ENOMEM; 55048c2ecf20Sopenharmony_ci 55058c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, tp); 55068c2ecf20Sopenharmony_ci 55078c2ecf20Sopenharmony_ci rc = r8169_mdio_register(tp); 55088c2ecf20Sopenharmony_ci if (rc) 55098c2ecf20Sopenharmony_ci return rc; 55108c2ecf20Sopenharmony_ci 55118c2ecf20Sopenharmony_ci /* chip gets powered up in rtl_open() */ 55128c2ecf20Sopenharmony_ci rtl_pll_power_down(tp); 55138c2ecf20Sopenharmony_ci 55148c2ecf20Sopenharmony_ci rc = register_netdev(dev); 55158c2ecf20Sopenharmony_ci if (rc) 55168c2ecf20Sopenharmony_ci return rc; 55178c2ecf20Sopenharmony_ci 55188c2ecf20Sopenharmony_ci netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", 55198c2ecf20Sopenharmony_ci rtl_chip_infos[chipset].name, dev->dev_addr, xid, 55208c2ecf20Sopenharmony_ci pci_irq_vector(pdev, 0)); 55218c2ecf20Sopenharmony_ci 55228c2ecf20Sopenharmony_ci if (jumbo_max) 55238c2ecf20Sopenharmony_ci netdev_info(dev, "jumbo features [frames: %d bytes, tx checksumming: %s]\n", 55248c2ecf20Sopenharmony_ci jumbo_max, tp->mac_version <= RTL_GIGA_MAC_VER_06 ? 55258c2ecf20Sopenharmony_ci "ok" : "ko"); 55268c2ecf20Sopenharmony_ci 55278c2ecf20Sopenharmony_ci if (r8168_check_dash(tp)) { 55288c2ecf20Sopenharmony_ci netdev_info(dev, "DASH enabled\n"); 55298c2ecf20Sopenharmony_ci rtl8168_driver_start(tp); 55308c2ecf20Sopenharmony_ci } 55318c2ecf20Sopenharmony_ci 55328c2ecf20Sopenharmony_ci if (pci_dev_run_wake(pdev)) 55338c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 55348c2ecf20Sopenharmony_ci 55358c2ecf20Sopenharmony_ci return 0; 55368c2ecf20Sopenharmony_ci} 55378c2ecf20Sopenharmony_ci 55388c2ecf20Sopenharmony_cistatic struct pci_driver rtl8169_pci_driver = { 55398c2ecf20Sopenharmony_ci .name = MODULENAME, 55408c2ecf20Sopenharmony_ci .id_table = rtl8169_pci_tbl, 55418c2ecf20Sopenharmony_ci .probe = rtl_init_one, 55428c2ecf20Sopenharmony_ci .remove = rtl_remove_one, 55438c2ecf20Sopenharmony_ci .shutdown = rtl_shutdown, 55448c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 55458c2ecf20Sopenharmony_ci .driver.pm = &rtl8169_pm_ops, 55468c2ecf20Sopenharmony_ci#endif 55478c2ecf20Sopenharmony_ci}; 55488c2ecf20Sopenharmony_ci 55498c2ecf20Sopenharmony_cimodule_pci_driver(rtl8169_pci_driver); 5550