diff --git a/r8125/Makefile b/r8125/Makefile index 02d5800..83275cc 100644 --- a/r8125/Makefile +++ b/r8125/Makefile @@ -1,9 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only ################################################################################ # # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2019 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free @@ -40,6 +41,14 @@ ENABLE_S5_KEEP_CURR_MAC = n ENABLE_EEE = y ENABLE_S0_MAGIC_PACKET = n ENABLE_TX_NO_CLOSE = y +ENABLE_MULTIPLE_TX_QUEUE = n +ENABLE_PTP_SUPPORT = n +ENABLE_PTP_MASTER_MODE = n +ENABLE_RSS_SUPPORT = n +ENABLE_LIB_SUPPORT = n +ENABLE_USE_FIRMWARE_FILE = n +DISABLE_PM_SUPPORT = n +DISABLE_MULTI_MSIX_VECTOR = n ifneq ($(KERNELRELEASE),) obj-m := r8125.o @@ -48,15 +57,15 @@ ifneq ($(KERNELRELEASE),) EXTRA_CFLAGS += -DCONFIG_SOC_LAN endif ifeq ($(ENABLE_REALWOW_SUPPORT), y) - r8125-objs += r8125_realwow.o + r8125-objs += r8125_realwow.o EXTRA_CFLAGS += -DENABLE_REALWOW_SUPPORT endif ifeq ($(ENABLE_DASH_SUPPORT), y) - r8125-objs += r8125_dash.o + r8125-objs += r8125_dash.o EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT endif ifeq ($(ENABLE_DASH_PRINTER_SUPPORT), y) - r8125-objs += r8125_dash.o + r8125-objs += r8125_dash.o EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT -DENABLE_DASH_PRINTER_SUPPORT endif EXTRA_CFLAGS += -DCONFIG_R8125_NAPI @@ -82,6 +91,34 @@ ifneq ($(KERNELRELEASE),) ifeq ($(ENABLE_TX_NO_CLOSE), y) EXTRA_CFLAGS += -DENABLE_TX_NO_CLOSE endif + ifeq ($(ENABLE_MULTIPLE_TX_QUEUE), y) + EXTRA_CFLAGS += -DENABLE_MULTIPLE_TX_QUEUE + endif + ifeq ($(ENABLE_PTP_SUPPORT), y) + r8125-objs += r8125_ptp.o + EXTRA_CFLAGS += -DENABLE_PTP_SUPPORT + endif + ifeq ($(ENABLE_PTP_MASTER_MODE), y) + EXTRA_CFLAGS += -DENABLE_PTP_MASTER_MODE + endif + ifeq ($(ENABLE_RSS_SUPPORT), y) + r8125-objs += r8125_rss.o + EXTRA_CFLAGS += -DENABLE_RSS_SUPPORT + endif + ifeq ($(ENABLE_LIB_SUPPORT), y) + r8125-objs += r8125_lib.o + EXTRA_CFLAGS += -DENABLE_LIB_SUPPORT + endif + ifeq ($(ENABLE_USE_FIRMWARE_FILE), y) + r8125-objs += r8125_firmware.o + EXTRA_CFLAGS += -DENABLE_USE_FIRMWARE_FILE + endif + ifeq ($(DISABLE_PM_SUPPORT), y) + EXTRA_CFLAGS += -DDISABLE_PM_SUPPORT + endif + ifeq ($(DISABLE_MULTI_MSIX_VECTOR), y) + EXTRA_CFLAGS += -DDISABLE_MULTI_MSIX_VECTOR + endif else BASEDIR := /lib/modules/$(shell uname -r) KERNELDIR ?= $(BASEDIR)/build diff --git a/r8125/Makefile_linux24x b/r8125/Makefile_linux24x index c15e49c..d043fb0 100644 --- a/r8125/Makefile_linux24x +++ b/r8125/Makefile_linux24x @@ -1,9 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only ################################################################################ # # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2019 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free diff --git a/r8125/r8125.h b/r8125/r8125.h index 5c91a75..3449d28 100644 --- a/r8125/r8125.h +++ b/r8125/r8125.h @@ -5,7 +5,7 @@ # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2020 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free @@ -35,19 +35,13 @@ #ifndef __R8125_H #define __R8125_H -//The vmkernel network api is from 2.6.24,not the default 2.6.18 -#ifndef LINUX_VERSION_CODE #include -#undef LINUX_VERSION_CODE -#define LINUX_VERSION_CODE KERNEL_VERSION(2,6,24) -#endif + +//#include #include #include - -//#ifdef ENABLE_DASH_SUPPORT #include "r8125_dash.h" -//#endif #ifdef ENABLE_REALWOW_SUPPORT #include "r8125_realwow.h" @@ -58,13 +52,33 @@ #endif #ifdef ENABLE_RSS_SUPPORT -#include "r8125_rss.h" + #include "r8125_rss.h" +#else + #define RTL8125_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */ + #define RTL8125_MAX_INDIRECTION_TABLE_ENTRIES 128 #endif #ifdef ENABLE_LIB_SUPPORT #include "r8125_lib.h" #endif + +//Redefine Linux kernel version +#if defined(LINUX_VERSION_CODE) && defined(__VMKLNX__) +#undef LINUX_VERSION_CODE +#define LINUX_VERSION_CODE KERNEL_VERSION(2,6,24) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +typedef int netdev_tx_t; +#endif + +/* +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)&& !defined(ENABLE_LIB_SUPPORT) +#define RTL_USE_NEW_INTR_API +#endif +*/ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) #define skb_transport_offset(skb) (skb->h.raw - skb->data) #endif @@ -371,12 +385,12 @@ do { \ #define RSS_SUFFIX "" #endif -#define RTL8125_VERSION "9.004.01" NAPI_SUFFIX DASH_SUFFIX REALWOW_SUFFIX PTP_SUFFIX RSS_SUFFIX +#define RTL8125_VERSION "9.007.01" NAPI_SUFFIX DASH_SUFFIX REALWOW_SUFFIX PTP_SUFFIX RSS_SUFFIX #define MODULENAME "r8125" #define PFX MODULENAME ": " #define GPL_CLAIM "\ -r8125 Copyright (C) 2020 Realtek NIC software team \n \ +r8125 Copyright (C) 2021 Realtek NIC software team \n \ This program comes with ABSOLUTELY NO WARRANTY; for details, please see . \n \ This is free software, and you are welcome to redistribute it under certain conditions; see . \n" @@ -474,8 +488,10 @@ This is free software, and you are welcome to redistribute it under certain cond #define R8125_MAX_RX_QUEUES (4) #define R8125_MAX_QUEUES R8125_MAX_RX_QUEUES +#define OCP_STD_PHY_BASE 0xa400 + #ifdef ENABLE_LIB_SUPPORT -#define R8125_MULTI_RX_Q(tp) 1 +#define R8125_MULTI_RX_Q(tp) 0 #else #define R8125_MULTI_RX_Q(tp) (tp->num_rx_rings > 1) #endif @@ -511,7 +527,7 @@ This is free software, and you are welcome to redistribute it under certain cond #endif #ifndef NETDEV_TX_LOCKED -#define NETDEV_TX_LOCKED -1 /* driver tx lock was already taken */ +#define NETDEV_TX_LOCKED -1t /* driver tx lock was already taken */ #endif #ifndef ADVERTISED_Pause @@ -547,6 +563,9 @@ This is free software, and you are welcome to redistribute it under certain cond #endif #define RTK_ADVERTISE_2500FULL 0x80 +#define RTK_LPA_ADVERTISE_2500FULL 0x20 +#define RTK_LPA_ADVERTISE_5000FULL 0x40 +#define RTK_LPA_ADVERTISE_10000FULL 0x800 /* Tx NO CLOSE */ #define MAX_TX_NO_CLOSE_DESC_PTR_V2 0x10000 @@ -556,6 +575,19 @@ This is free software, and you are welcome to redistribute it under certain cond #define ETH_MIN_MTU 68 #endif +#define D0_SPEED_UP_SPEED_DISABLE 0 +#define D0_SPEED_UP_SPEED_1000 1 +#define D0_SPEED_UP_SPEED_2500 2 + +#define RTL8125_MAC_MCU_PAGE_SIZE 256 //256 words + +#ifndef WRITE_ONCE +#define WRITE_ONCE(var, val) (*((volatile typeof(val) *)(&(var))) = (val)) +#endif +#ifndef READ_ONCE +#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var)))) +#endif + /*****************************************************************************/ //#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) @@ -642,6 +674,23 @@ typedef int napi_budget; #define RTL_NAPI_DEL(priv) netif_napi_del(&priv->napi) #endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) +/*****************************************************************************/ +#ifdef CONFIG_R8125_NAPI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) +#define RTL_NAPI_CONSUME_SKB_ANY(skb, budget) napi_consume_skb(skb, budget) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) +#define RTL_NAPI_CONSUME_SKB_ANY(skb, budget) dev_consume_skb_any(skb); +#else +#define RTL_NAPI_CONSUME_SKB_ANY(skb, budget) dev_kfree_skb_any(skb); +#endif //LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) +#else //CONFIG_R8125_NAPI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) +#define RTL_NAPI_CONSUME_SKB_ANY(skb, budget) dev_consume_skb_any(skb); +#else +#define RTL_NAPI_CONSUME_SKB_ANY(skb, budget) dev_kfree_skb_any(skb); +#endif +#endif //CONFIG_R8125_NAPI + /*****************************************************************************/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) #ifdef __CHECKER__ @@ -1084,6 +1133,55 @@ struct _kc_ethtool_pauseparam { #define ETHTOOL_BUSINFO_LEN 32 #endif + + +/*****************************************************************************/ +// Backport Definitions // +/*****************************************************************************/ +#if defined(__VMKLNX__) +/** + * struct ethtool_eee - Energy Efficient Ethernet information + * @cmd: ETHTOOL_{G,S}EEE + * @supported: Mask of %SUPPORTED_* flags for the speed/duplex combinations + * for which there is EEE support. + * @advertised: Mask of %ADVERTISED_* flags for the speed/duplex combinations + * advertised as eee capable. + * @lp_advertised: Mask of %ADVERTISED_* flags for the speed/duplex + * combinations advertised by the link partner as eee capable. + * @eee_active: Result of the eee auto negotiation. + * @eee_enabled: EEE configured mode (enabled/disabled). + * @tx_lpi_enabled: Whether the interface should assert its tx lpi, given + * that eee was negotiated. + * @tx_lpi_timer: Time in microseconds the interface delays prior to asserting + * its tx lpi (after reaching 'idle' state). Effective only when eee + * was negotiated and tx_lpi_enabled was set. + */ +struct ethtool_eee { + __u32 cmd; + __u32 supported; + __u32 advertised; + __u32 lp_advertised; + __u32 eee_active; + __u32 eee_enabled; + __u32 tx_lpi_enabled; + __u32 tx_lpi_timer; + __u32 reserved[2]; +}; + +#define MDIO_EEE_10GT 0x0008 /* 10GT EEE cap */ +#define MDIO_EEE_1000KX 0x0010 /* 1000KX EEE cap */ +#define MDIO_EEE_10GKX4 0x0020 /* 10G KX4 EEE cap */ +#define MDIO_EEE_10GKR 0x0040 /* 10G KR EEE cap */ + + + + +#endif //#if defined(__VMKLNX__) + + +/****************************Backport End Here********************************/ + + /*****************************************************************************/ enum RTL8125_registers { @@ -1178,16 +1276,24 @@ enum RTL8125_registers { TIMER_INT3_8125 = 0x00F4, INT_MITI_V2_0_RX = 0x0A00, INT_MITI_V2_0_TX = 0x0A02, + INT_MITI_V2_1_RX = 0x0A08, INT_MITI_V2_1_TX = 0x0A0A, IMR_V2_CLEAR_REG_8125 = 0x0D00, ISR_V2_8125 = 0x0D04, IMR_V2_SET_REG_8125 = 0x0D0C, + TDU_STA_8125 = 0x0D08, + RDU_STA_8125 = 0x0D0A, + TX_NEW_CTRL = 0x203E, TNPDS_Q1_LOW_8125 = 0x2100, + PLA_TXQ0_IDLE_CREDIT = 0x2500, + PLA_TXQ1_IDLE_CREDIT = 0x2504, SW_TAIL_PTR0_8125 = 0x2800, HW_CLO_PTR0_8125 = 0x2802, RDSAR_Q1_LOW_8125 = 0x4000, RSS_CTRL_8125 = 0x4500, Q_NUM_CTRL_8125 = 0x4800, + RSS_KEY_8125 = 0x4600, + RSS_INDIRECTION_TBL_8125_V2 = 0x4700, EEE_TXIDLE_TIMER_8125 = 0x6048, PTP_CTRL_8125 = 0x6800, PTP_STATUS_8125 = 0x6802, @@ -1270,6 +1376,7 @@ enum RTL8125_register_content { RxCfg_128_int_en = (1 << 15), RxCfg_fet_multi_en = (1 << 14), RxCfg_half_refetch = (1 << 13), + RxCfg_pause_slot_en = (1 << 11), RxCfg_9356SEL = (1 << 6), /* TxConfigBits */ @@ -1438,6 +1545,7 @@ enum RTL8125_register_content { ISRIMR_V2_ROK_Q0 = (1 << 0), ISRIMR_TOK_Q0 = (1 << 16), ISRIMR_TOK_Q1 = (1 << 18), + ISRIMR_V2_LINKCHG = (1 << 21), /* Magic Number */ RTL8125_MAGIC_NUMBER = 0x0badbadbadbadbadull, @@ -1695,6 +1803,14 @@ struct pci_resource { u32 pci_sn_h; }; +enum r8125_flag { + R8125_FLAG_DOWN = 0, + R8125_FLAG_TASK_RESET_PENDING, + R8125_FLAG_TASK_ESD_CHECK_PENDING, + R8125_FLAG_TASK_LINKCHG_CHECK_PENDING, + R8125_FLAG_MAX +}; + struct rtl8125_tx_ring { void* priv; u32 index; @@ -1743,6 +1859,218 @@ struct r8125_irq { char name[IFNAMSIZ + 10]; }; +#pragma pack(1) +struct rtl8125_regs { + //00 + u8 mac_id[6]; + u16 reg_06; + u8 mar[8]; + //10 + u64 dtccr; + u16 ledsel0; + u16 legreg; + u32 tctr3; + //20 + u32 txq0_dsc_st_addr_0; + u32 txq0_dsc_st_addr_2; + u64 reg_28; + //30 + u16 rit; + u16 ritc; + u16 reg_34; + u8 reg_36; + u8 command; + u32 imr0; + u32 isr0; + //40 + u32 tcr; + u32 rcr; + u32 tctr0; + u32 tctr1; + //50 + u8 cr93c46; + u8 config0; + u8 config1; + u8 config2; + u8 config3; + u8 config4; + u8 config5; + u8 tdfnr; + u32 timer_int0; + u32 timer_int1; + //60 + u32 gphy_mdcmdio; + u32 csidr; + u32 csiar; + u16 phy_status; + u8 config6; + u8 pmch; + //70 + u32 eridr; + u32 eriar; + u16 config7; + u16 reg_7a; + u32 ephy_rxerr_cnt; + //80 + u32 ephy_mdcmdio; + u16 ledsel2; + u16 ledsel1; + u32 tctr2; + u32 timer_int2; + //90 + u8 tppoll0; + u8 reg_91; + u16 reg_92; + u16 led_feature; + u16 ledsel3; + u16 eee_led_config; + u16 reg_9a; + u32 reg_9c; + //a0 + u32 reg_a0; + u32 reg_a4; + u32 reg_a8; + u32 reg_ac; + //b0 + u32 patch_dbg; + u32 reg_b4; + u32 gphy_ocp; + u32 reg_bc; + //c0 + u32 reg_c0; + u32 reg_c4; + u32 reg_c8; + u16 otp_cmd; + u16 otp_pg_config; + //d0 + u16 phy_pwr; + u8 twsi_ctrl; + u8 oob_ctrl; + u16 mac_dbgo; + u16 mac_dbg; + u16 reg_d8; + u16 rms; + u32 efuse_data; + //e0 + u16 cplus_cmd; + u16 reg_e2; + u32 rxq0_dsc_st_addr_0; + u32 rxq0_dsc_st_addr_2; + u16 reg_ec; + u16 tx10midle_cnt; + //f0 + u16 misc0; + u16 misc1; + u32 timer_int3; + u32 cmac_ib; + u16 reg_fc; + u16 sw_rst; +}; +#pragma pack() + +struct rtl8125_regs_save { + union { + u8 mac_io[R8125_MAC_REGS_SIZE]; + + struct rtl8125_regs mac_reg; + }; + u16 pcie_phy[R8125_EPHY_REGS_SIZE/2]; + u16 eth_phy[R8125_PHY_REGS_SIZE/2]; + u32 eri_reg[R8125_ERI_REGS_SIZE/4]; + u32 pci_reg[R8125_PCI_REGS_SIZE/4]; + u16 sw_tail_ptr_reg[R8125_MAX_TX_QUEUES]; + u16 hw_clo_ptr_reg[R8125_MAX_TX_QUEUES]; + + //ktime_t begin_ktime; + //ktime_t end_ktime; + //u64 duration_ns; + + u16 sw0_tail_ptr; + u16 next_hwq0_clo_ptr; + u16 sw1_tail_ptr; + u16 next_hwq1_clo_ptr; + + u16 int_miti_rxq0; + u16 int_miti_txq0; + u16 int_miti_rxq1; + u16 int_miti_txq1; + u8 int_config; + u32 imr_new; + u32 isr_new; + + u8 tdu_status; + u16 rdu_status; + + u16 tc_mode; + + u32 txq1_dsc_st_addr_0; + u32 txq1_dsc_st_addr_2; + + u32 pla_tx_q0_idle_credit; + u32 pla_tx_q1_idle_credit; + + u32 rxq1_dsc_st_addr_0; + u32 rxq1_dsc_st_addr_2; + + u32 rss_ctrl; + u8 rss_key[RTL8125_RSS_KEY_SIZE]; + u8 rss_i_table[RTL8125_MAX_INDIRECTION_TABLE_ENTRIES]; + u16 rss_queue_num_sel_r; +}; + +struct rtl8125_counters { + /* legacy */ + u64 tx_packets; + u64 rx_packets; + u64 tx_errors; + u32 rx_errors; + u16 rx_missed; + u16 align_errors; + u32 tx_one_collision; + u32 tx_multi_collision; + u64 rx_unicast; + u64 rx_broadcast; + u32 rx_multicast; + u16 tx_aborted; + u16 tx_underrun; + + /* extended */ + u64 tx_octets; + u64 rx_octets; + u64 rx_multicast64; + u64 tx_unicast64; + u64 tx_broadcast64; + u64 tx_multicast64; + u32 tx_pause_on; + u32 tx_pause_off; + u32 tx_pause_all; + u32 tx_deferred; + u32 tx_late_collision; + u32 tx_all_collision; + u32 tx_aborted32; + u32 align_errors32; + u32 rx_frame_too_long; + u32 rx_runt; + u32 rx_pause_on; + u32 rx_pause_off; + u32 rx_pause_all; + u32 rx_unknown_opcode; + u32 rx_mac_error; + u32 tx_underrun32; + u32 rx_mac_missed; + u32 rx_tcam_dropped; + u32 tdu; + u32 rdu; +}; + +/* Flow Control Settings */ +enum rtl8125_fc_mode { + rtl8125_fc_none = 0, + rtl8125_fc_rx_pause, + rtl8125_fc_tx_pause, + rtl8125_fc_full, + rtl8125_fc_default +}; struct rtl8125_private { void __iomem *mmio_addr; /* memory map physical address */ @@ -1755,7 +2083,9 @@ struct rtl8125_private { unsigned int min_irq_nvecs; //struct msix_entry msix_entries[R8125_MAX_MSIX_VEC]; struct net_device_stats stats; /* statistics of net device */ +#ifdef ENABLE_PTP_SUPPORT spinlock_t lock; /* spin lock flag */ +#endif u32 msg_enable; u32 tx_tcp_csum_cmd; u32 tx_udp_csum_cmd; @@ -1786,8 +2116,8 @@ struct rtl8125_private { struct rtl8125_ring lib_tx_ring[R8125_MAX_TX_QUEUES]; struct rtl8125_ring lib_rx_ring[R8125_MAX_RX_QUEUES]; #endif - struct timer_list esd_timer; - struct timer_list link_timer; + //struct timer_list esd_timer; + //struct timer_list link_timer; struct pci_resource pci_cfg_space; unsigned int esd_flag; unsigned int pci_cfg_is_read; @@ -1815,6 +2145,7 @@ struct rtl8125_private { u8 duplex; u32 speed; u32 advertising; + enum rtl8125_fc_mode fcpause; u16 eeprom_len; u16 cur_page; u32 bios_setting; @@ -1829,10 +2160,15 @@ struct rtl8125_private { unsigned int (*phy_reset_pending)(struct net_device *); unsigned int (*link_ok)(struct net_device *); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - struct work_struct task; + struct work_struct reset_task; + struct work_struct esd_task; + struct work_struct linkchg_task; #else - struct delayed_work task; + struct delayed_work reset_task; + struct delayed_work esd_task; + struct delayed_work linkchg_task; #endif + DECLARE_BITMAP(task_flags, R8125_FLAG_MAX); unsigned features; u8 org_pci_offset_99; @@ -1858,10 +2194,6 @@ struct rtl8125_private { u8 ShortPacketSwChecksum; u8 UseSwPaddingShortPkt; - u16 SwPaddingShortPktLen; - - void *ShortPacketEmptyBuffer; - dma_addr_t ShortPacketEmptyBufferPhy; u8 RequireAdcBiasPatch; u16 AdcBiasPatchIoffset; @@ -1885,13 +2217,16 @@ struct rtl8125_private { u8 HwSuppMagicPktVer; + u8 HwSuppLinkChgWakeUpVer; + u8 HwSuppCheckPhyDisableModeVer; u8 random_mac; - u8 HwSuppGigaForceMode; - + u16 phy_reg_aner; u16 phy_reg_anlpar; + u16 phy_reg_gbsr; + u16 phy_reg_status_2500; u32 HwPcieSNOffset; @@ -1903,6 +2238,20 @@ struct rtl8125_private { u8 HwSuppIntMitiVer; + u8 HwSuppExtendTallyCounterVer; + + u8 check_keep_link_speed; + u8 resume_not_chg_speed; + + u8 HwSuppD0SpeedUpVer; + u8 D0SpeedUpSpeed; + + u8 ring_lib_enabled; + + const char *fw_name; + struct rtl8125_fw *rtl_fw; + u32 ocp_base; + //Dash+++++++++++++++++ u8 HwSuppDashVer; u8 DASH; @@ -1992,8 +2341,7 @@ struct rtl8125_private { //Realwow-------------- #endif //ENABLE_REALWOW_SUPPORT - u32 eee_adv_t; - u8 eee_enabled; + struct ethtool_eee eee; #ifdef ENABLE_R8125_PROCFS //Procfs support @@ -2005,6 +2353,7 @@ struct rtl8125_private { u8 HwSuppPtpVer; u8 EnablePtp; + u8 ptp_master_mode; s64 ptp_adjust; #ifdef ENABLE_PTP_SUPPORT u32 tx_hwtstamp_timeouts; @@ -2023,12 +2372,13 @@ struct rtl8125_private { #ifdef ENABLE_RSS_SUPPORT u32 rss_flags; /* Receive Side Scaling settings */ -#define RTL8125_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */ u8 rss_key[RTL8125_RSS_KEY_SIZE]; -#define RTL8125_MAX_INDIRECTION_TABLE_ENTRIES 128 u8 rss_indir_tbl[RTL8125_MAX_INDIRECTION_TABLE_ENTRIES]; u32 rss_options; #endif + + u8 HwSuppMacMcuVer; + u16 MacMcuPageSize; }; #ifdef ENABLE_LIB_SUPPORT @@ -2094,8 +2444,10 @@ enum mcfg { CFG_METHOD_3, CFG_METHOD_4, CFG_METHOD_5, - CFG_METHOD_MAX, - CFG_METHOD_DEFAULT = 0xFF + CFG_METHOD_6, + CFG_METHOD_7, + CFG_METHOD_DEFAULT, + CFG_METHOD_MAX }; #define LSO_32K 32000 @@ -2127,7 +2479,7 @@ enum mcfg { #define NIC_RAMCODE_VERSION_CFG_METHOD_2 (0x0b11) #define NIC_RAMCODE_VERSION_CFG_METHOD_3 (0x0b33) #define NIC_RAMCODE_VERSION_CFG_METHOD_4 (0x0b17) -#define NIC_RAMCODE_VERSION_CFG_METHOD_5 (0x0b36) +#define NIC_RAMCODE_VERSION_CFG_METHOD_5 (0x0b55) //hwoptimize #define HW_PATCH_SOC_LAN (BIT_0) @@ -2135,15 +2487,15 @@ enum mcfg { static const u16 other_q_intr_mask = (RxOK1 | RxDU1); -void rtl8125_mdio_write(struct rtl8125_private *tp, u32 RegAddr, u32 value); +void rtl8125_mdio_write(struct rtl8125_private *tp, u16 RegAddr, u16 value); void rtl8125_mdio_prot_write(struct rtl8125_private *tp, u32 RegAddr, u32 value); void rtl8125_mdio_prot_direct_write_phy_ocp(struct rtl8125_private *tp, u32 RegAddr, u32 value); -u32 rtl8125_mdio_read(struct rtl8125_private *tp, u32 RegAddr); +u32 rtl8125_mdio_read(struct rtl8125_private *tp, u16 RegAddr); u32 rtl8125_mdio_prot_read(struct rtl8125_private *tp, u32 RegAddr); u32 rtl8125_mdio_prot_direct_read_phy_ocp(struct rtl8125_private *tp, u32 RegAddr); void rtl8125_ephy_write(struct rtl8125_private *tp, int RegAddr, int value); void rtl8125_mac_ocp_write(struct rtl8125_private *tp, u16 reg_addr, u16 value); -u16 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr); +u32 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr); void rtl8125_clear_eth_phy_bit(struct rtl8125_private *tp, u8 addr, u16 mask); void rtl8125_set_eth_phy_bit(struct rtl8125_private *tp, u8 addr, u16 mask); void rtl8125_ocp_write(struct rtl8125_private *tp, u16 addr, u8 len, u32 data); @@ -2151,7 +2503,6 @@ void rtl8125_oob_notify(struct rtl8125_private *tp, u8 cmd); void rtl8125_init_ring_indexes(struct rtl8125_private *tp); int rtl8125_eri_write(struct rtl8125_private *tp, int addr, int len, u32 value, int type); void rtl8125_oob_mutex_lock(struct rtl8125_private *tp); -u32 rtl8125_mdio_read(struct rtl8125_private *tp, u32 RegAddr); u32 rtl8125_ocp_read(struct rtl8125_private *tp, u16 addr, u8 len); u32 rtl8125_ocp_read_with_oob_base_address(struct rtl8125_private *tp, u16 addr, u8 len, u32 base_address); u32 rtl8125_ocp_write_with_oob_base_address(struct rtl8125_private *tp, u16 addr, u8 len, u32 value, u32 base_address); @@ -2203,27 +2554,30 @@ rtl8125_enable_hw_interrupt_v2(struct rtl8125_private *tp, u32 message_id) RTL_W32(tp, IMR_V2_SET_REG_8125, BIT(message_id)); } +int rtl8125_open(struct net_device *dev); +int rtl8125_close(struct net_device *dev); +void rtl8125_hw_config(struct net_device *dev); void rtl8125_hw_set_timer_int_8125(struct rtl8125_private *tp, u32 message_id, u8 timer_intmiti_val); void rtl8125_set_rx_q_num(struct rtl8125_private *tp, unsigned int num_rx_queues); void rtl8125_set_tx_q_num(struct rtl8125_private *tp, unsigned int num_tx_queues); -int rtl8125_set_real_num_queue(struct rtl8125_private *tp); void rtl8125_hw_start(struct net_device *dev); void rtl8125_hw_reset(struct net_device *dev); void rtl8125_tx_clear(struct rtl8125_private *tp); void rtl8125_rx_clear(struct rtl8125_private *tp); int rtl8125_init_ring(struct net_device *dev); void rtl8125_hw_set_rx_packet_filter(struct net_device *dev); +void rtl8125_enable_hw_linkchg_interrupt(struct rtl8125_private *tp); +int rtl8125_dump_tally_counter(struct rtl8125_private *tp, dma_addr_t paddr); -#ifdef ENABLE_LIB_SUPPORT -void rtl8125_lib_reset_prepare(struct rtl8125_private *tp); -void rtl8125_lib_reset_complete(struct rtl8125_private *tp); -#else +#ifndef ENABLE_LIB_SUPPORT static inline void rtl8125_lib_reset_prepare(struct rtl8125_private *tp) { } static inline void rtl8125_lib_reset_complete(struct rtl8125_private *tp) { } #endif #define HW_SUPPORT_CHECK_PHY_DISABLE_MODE(_M) ((_M)->HwSuppCheckPhyDisableModeVer > 0 ) #define HW_HAS_WRITE_PHY_MCU_RAM_CODE(_M) (((_M)->HwHasWrRamCodeToMicroP == TRUE) ? 1 : 0) +#define HW_SUPPORT_D0_SPEED_UP(_M) ((_M)->HwSuppD0SpeedUpVer > 0) +#define HW_SUPPORT_MAC_MCU(_M) ((_M)->HwSuppMacMcuVer > 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) #define netdev_mc_count(dev) ((dev)->mc_count) diff --git a/r8125/r8125_dash.h b/r8125/r8125_dash.h index a2060a1..f86d425 100644 --- a/r8125/r8125_dash.h +++ b/r8125/r8125_dash.h @@ -5,7 +5,7 @@ # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2020 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free diff --git a/r8125/r8125_firmware.c b/r8125/r8125_firmware.c new file mode 100644 index 0000000..ac4ea62 --- /dev/null +++ b/r8125/r8125_firmware.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +################################################################################ +# +# r8168 is the Linux device driver released for Realtek Gigabit Ethernet +# controllers with PCI-Express interface. +# +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Author: +# Realtek NIC software team +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ + +/************************************************************************************ + * This product is covered by one or more of the following patents: + * US6,570,884, US6,115,776, and US6,327,625. + ***********************************************************************************/ + +#include +#include +#include + +#include "r8125_firmware.h" + +enum rtl_fw_opcode { + PHY_READ = 0x0, + PHY_DATA_OR = 0x1, + PHY_DATA_AND = 0x2, + PHY_BJMPN = 0x3, + PHY_MDIO_CHG = 0x4, + PHY_CLEAR_READCOUNT = 0x7, + PHY_WRITE = 0x8, + PHY_READCOUNT_EQ_SKIP = 0x9, + PHY_COMP_EQ_SKIPN = 0xa, + PHY_COMP_NEQ_SKIPN = 0xb, + PHY_WRITE_PREVIOUS = 0xc, + PHY_SKIPN = 0xd, + PHY_DELAY_MS = 0xe, +}; + +struct fw_info { + u32 magic; + char version[RTL8125_VER_SIZE]; + __le32 fw_start; + __le32 fw_len; + u8 chksum; +} __packed; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0) +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) +#endif +#define FW_OPCODE_SIZE sizeof_field(struct rtl8125_fw_phy_action, code[0]) + +static bool rtl8125_fw_format_ok(struct rtl8125_fw *rtl_fw) +{ + const struct firmware *fw = rtl_fw->fw; + struct fw_info *fw_info = (struct fw_info *)fw->data; + struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action; + + if (fw->size < FW_OPCODE_SIZE) + return false; + + if (!fw_info->magic) { + size_t i, size, start; + u8 checksum = 0; + + if (fw->size < sizeof(*fw_info)) + return false; + + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + if (checksum != 0) + return false; + + start = le32_to_cpu(fw_info->fw_start); + if (start > fw->size) + return false; + + size = le32_to_cpu(fw_info->fw_len); + if (size > (fw->size - start) / FW_OPCODE_SIZE) + return false; + + strscpy(rtl_fw->version, fw_info->version, RTL8125_VER_SIZE); + + pa->code = (__le32 *)(fw->data + start); + pa->size = size; + } else { + if (fw->size % FW_OPCODE_SIZE) + return false; + + strscpy(rtl_fw->version, rtl_fw->fw_name, RTL8125_VER_SIZE); + + pa->code = (__le32 *)fw->data; + pa->size = fw->size / FW_OPCODE_SIZE; + } + + return true; +} + +static bool rtl8125_fw_data_ok(struct rtl8125_fw *rtl_fw) +{ + struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action; + size_t index; + + for (index = 0; index < pa->size; index++) { + u32 action = le32_to_cpu(pa->code[index]); + u32 val = action & 0x0000ffff; + u32 regno = (action & 0x0fff0000) >> 16; + + switch (action >> 28) { + case PHY_READ: + case PHY_DATA_OR: + case PHY_DATA_AND: + case PHY_CLEAR_READCOUNT: + case PHY_WRITE: + case PHY_WRITE_PREVIOUS: + case PHY_DELAY_MS: + break; + + case PHY_MDIO_CHG: + if (val > 1) + goto out; + break; + + case PHY_BJMPN: + if (regno > index) + goto out; + break; + case PHY_READCOUNT_EQ_SKIP: + if (index + 2 >= pa->size) + goto out; + break; + case PHY_COMP_EQ_SKIPN: + case PHY_COMP_NEQ_SKIPN: + case PHY_SKIPN: + if (index + 1 + regno >= pa->size) + goto out; + break; + + default: + dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action); + return false; + } + } + + return true; +out: + dev_err(rtl_fw->dev, "Out of range of firmware\n"); + return false; +} + +void rtl8125_fw_write_firmware(struct rtl8125_private *tp, struct rtl8125_fw *rtl_fw) +{ + struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action; + rtl8125_fw_write_t fw_write = rtl_fw->phy_write; + rtl8125_fw_read_t fw_read = rtl_fw->phy_read; + int predata = 0, count = 0; + size_t index; + + for (index = 0; index < pa->size; index++) { + u32 action = le32_to_cpu(pa->code[index]); + u32 data = action & 0x0000ffff; + u32 regno = (action & 0x0fff0000) >> 16; + enum rtl_fw_opcode opcode = action >> 28; + + if (!action) + break; + + switch (opcode) { + case PHY_READ: + predata = fw_read(tp, regno); + count++; + break; + case PHY_DATA_OR: + predata |= data; + break; + case PHY_DATA_AND: + predata &= data; + break; + case PHY_BJMPN: + index -= (regno + 1); + break; + case PHY_MDIO_CHG: + if (data) { + fw_write = rtl_fw->mac_mcu_write; + fw_read = rtl_fw->mac_mcu_read; + } else { + fw_write = rtl_fw->phy_write; + fw_read = rtl_fw->phy_read; + } + + break; + case PHY_CLEAR_READCOUNT: + count = 0; + break; + case PHY_WRITE: + fw_write(tp, regno, data); + break; + case PHY_READCOUNT_EQ_SKIP: + if (count == data) + index++; + break; + case PHY_COMP_EQ_SKIPN: + if (predata == data) + index += regno; + break; + case PHY_COMP_NEQ_SKIPN: + if (predata != data) + index += regno; + break; + case PHY_WRITE_PREVIOUS: + fw_write(tp, regno, predata); + break; + case PHY_SKIPN: + index += regno; + break; + case PHY_DELAY_MS: + mdelay(data); + break; + } + } +} + +void rtl8125_fw_release_firmware(struct rtl8125_fw *rtl_fw) +{ + release_firmware(rtl_fw->fw); +} + +int rtl8125_fw_request_firmware(struct rtl8125_fw *rtl_fw) +{ + int rc; + + rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); + if (rc < 0) + goto out; + + if (!rtl8125_fw_format_ok(rtl_fw) || !rtl8125_fw_data_ok(rtl_fw)) { + release_firmware(rtl_fw->fw); + rc = -EINVAL; + goto out; + } + + return 0; +out: + dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n", + rtl_fw->fw_name, rc); + return rc; +} diff --git a/r8125/r8125_firmware.h b/r8125/r8125_firmware.h new file mode 100644 index 0000000..1961be5 --- /dev/null +++ b/r8125/r8125_firmware.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +################################################################################ +# +# r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet +# controllers with PCI-Express interface. +# +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Author: +# Realtek NIC software team +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ + +/************************************************************************************ + * This product is covered by one or more of the following patents: + * US6,570,884, US6,115,776, and US6,327,625. + ***********************************************************************************/ + +#ifndef _LINUX_rtl8125_FIRMWARE_H +#define _LINUX_rtl8125_FIRMWARE_H + +#include +#include + +struct rtl8125_private; +typedef void (*rtl8125_fw_write_t)(struct rtl8125_private *tp, u16 reg, u16 val); +typedef u32 (*rtl8125_fw_read_t)(struct rtl8125_private *tp, u16 reg); + +#define RTL8125_VER_SIZE 32 + +struct rtl8125_fw { + rtl8125_fw_write_t phy_write; + rtl8125_fw_read_t phy_read; + rtl8125_fw_write_t mac_mcu_write; + rtl8125_fw_read_t mac_mcu_read; + const struct firmware *fw; + const char *fw_name; + struct device *dev; + + char version[RTL8125_VER_SIZE]; + + struct rtl8125_fw_phy_action { + __le32 *code; + size_t size; + } phy_action; +}; + +int rtl8125_fw_request_firmware(struct rtl8125_fw *rtl_fw); +void rtl8125_fw_release_firmware(struct rtl8125_fw *rtl_fw); +void rtl8125_fw_write_firmware(struct rtl8125_private *tp, struct rtl8125_fw *rtl_fw); + +#endif /* _LINUX_rtl8125_FIRMWARE_H */ diff --git a/r8125/r8125_n.c b/r8125/r8125_n.c index 42d4a0f..9f15289 100644 --- a/r8125/r8125_n.c +++ b/r8125/r8125_n.c @@ -5,7 +5,7 @@ # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2020 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free @@ -37,20 +37,14 @@ */ #include - -//The vmkernel network api is from 2.6.24,not the default 2.6.18 -#ifndef LINUX_VERSION_CODE #include -#undef LINUX_VERSION_CODE -#define LINUX_VERSION_CODE KERNEL_VERSION(2,6,24) -#endif - #include #include #include #include #include #include +#include #include #include #include @@ -63,8 +57,6 @@ #include #include -#include - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) #include @@ -91,21 +83,35 @@ #include "r8125.h" #include "rtl_eeprom.h" #include "rtltool.h" +#include "r8125_firmware.h" #ifdef ENABLE_R8125_PROCFS #include #include #endif -#ifdef ENABLE_LIB_SUPPORT -#include -#endif +#define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" +#define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static const int multicast_filter_limit = 32; -#define _R(NAME,MAC,RCR,MASK, JumFrameSz) \ +static const struct { + const char *name; + const char *fw_name; +} rtl_chip_fw_infos[] = { + /* PCI-E devices. */ + [CFG_METHOD_2] = {"RTL8125A" }, + [CFG_METHOD_3] = {"RTL8125A", FIRMWARE_8125A_3}, + [CFG_METHOD_4] = {"RTL8125B", }, + [CFG_METHOD_5] = {"RTL8125B", FIRMWARE_8125B_2}, + [CFG_METHOD_6] = {"RTL8168KB", FIRMWARE_8125A_3}, + [CFG_METHOD_7] = {"RTL8168KB", FIRMWARE_8125B_2}, + [CFG_METHOD_DEFAULT] = {"Unknown", }, +}; + +#define _R(NAME,MAC,RCR,MASK,JumFrameSz) \ { .name = NAME, .mcfg = MAC, .RCR_Cfg = RCR, .RxConfigMask = MASK, .jumbo_frame_sz = JumFrameSz } static const struct { @@ -129,16 +135,28 @@ static const struct { _R("RTL8125B", CFG_METHOD_4, - BIT_30 | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), + BIT_30 | RxCfg_pause_slot_en | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), 0xff7e5880, Jumbo_Frame_9k), _R("RTL8125B", CFG_METHOD_5, + BIT_30 | RxCfg_pause_slot_en | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), + 0xff7e5880, + Jumbo_Frame_9k), + + _R("RTL8168KB", + CFG_METHOD_6, BIT_30 | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), 0xff7e5880, Jumbo_Frame_9k), + _R("RTL8168KB", + CFG_METHOD_7, + BIT_30 | RxCfg_pause_slot_en | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), + 0xff7e5880, + Jumbo_Frame_9k), + _R("Unknown", CFG_METHOD_DEFAULT, (RX_DMA_BURST << RxCfgDMAShift), @@ -147,12 +165,14 @@ static const struct { }; #undef _R + #ifndef PCI_VENDOR_ID_DLINK #define PCI_VENDOR_ID_DLINK 0x1186 #endif static struct pci_device_id rtl8125_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8125), }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8162), }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x3000), }, {0,}, }; @@ -161,15 +181,10 @@ MODULE_DEVICE_TABLE(pci, rtl8125_pci_tbl); static int rx_copybreak = 0; static int use_dac = 1; - -//Maybe timer_count issue has been repaired in 9.004.01 -#ifndef __VMKLNX__ -static int timer_count = 0x0700; //0x2600 is default, 0x0700 for single thread speed issue -static int timer_count_v2 = (0x0700 / 0x100); -#else -static int timer_count = 0x2600; //0x2600 is default, 0x0700 for single thread speed issue +static int timer_count = 0x2600; static int timer_count_v2 = (0x2600 / 0x100); -#endif +static int enable_tx_csum = 1; +static int enable_tso = 0; static struct { u32 msg_enable; @@ -220,26 +235,109 @@ static int tx_no_close_enable = 1; #else static int tx_no_close_enable = 0; #endif +#ifdef ENABLE_PTP_MASTER_MODE +static int enable_ptp_master_mode = 1; +#else +static int enable_ptp_master_mode = 0; +#endif +#ifdef DISABLE_PM_SUPPORT +static int disable_pm_support = 1; +#else +static int disable_pm_support = 0; +#endif -//************************************************************************ -//Port to ESXi from here -#if !defined(__VMKLNX__) +MODULE_AUTHOR("Realtek and the Linux r8125 crew "); +MODULE_DESCRIPTION("Realtek RTL8125 2.5Gigabit Ethernet driver"); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) -static inline void eth_copy_and_sum (struct sk_buff *dest, - const unsigned char *src, - int len, int base) -{ - memcpy (dest->data, src, len); -} -#endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) -#endif //#if !defined(__VMKLNX__) +module_param(speed_mode, uint, 0); +MODULE_PARM_DESC(speed_mode, "force phy operation. Deprecated by ethtool (8)."); + +module_param(duplex_mode, uint, 0); +MODULE_PARM_DESC(duplex_mode, "force phy operation. Deprecated by ethtool (8)."); + +module_param(autoneg_mode, uint, 0); +MODULE_PARM_DESC(autoneg_mode, "force phy operation. Deprecated by ethtool (8)."); + +module_param(advertising_mode, uint, 0); +MODULE_PARM_DESC(advertising_mode, "force phy operation. Deprecated by ethtool (8)."); + +module_param(aspm, int, 0); +MODULE_PARM_DESC(aspm, "Enable ASPM."); + +module_param(s5wol, int, 0); +MODULE_PARM_DESC(s5wol, "Enable Shutdown Wake On Lan."); + +module_param(s5_keep_curr_mac, int, 0); +MODULE_PARM_DESC(s5_keep_curr_mac, "Enable Shutdown Keep Current MAC Address."); + +module_param(rx_copybreak, int, 0); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); + +module_param(use_dac, int, 0); +MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); + + +/**************************************************************************************************/ +//Add by GanFan, to customize compability settings +module_param(enable_tx_csum, int, 0); +MODULE_PARM_DESC(enable_tx_csum, "Enable or disable TX checksum for compatibility of virual NIC."); + +module_param(enable_tso, int, 0); +MODULE_PARM_DESC(enable_tso, "Enable or disable TCP Segmentation Offload (TSO) ."); +/**************************************************************************************************/ + +module_param(timer_count, int, 0); +MODULE_PARM_DESC(timer_count, "Timer Interrupt Interval."); + +module_param(eee_enable, int, 0); +MODULE_PARM_DESC(eee_enable, "Enable Energy Efficient Ethernet."); + +module_param(hwoptimize, ulong, 0); +MODULE_PARM_DESC(hwoptimize, "Enable HW optimization function."); + +module_param(s0_magic_packet, int, 0); +MODULE_PARM_DESC(s0_magic_packet, "Enable S0 Magic Packet."); -//Add by GanFan for ESXi +module_param(tx_no_close_enable, int, 0); +MODULE_PARM_DESC(tx_no_close_enable, "Enable TX No Close."); + +module_param(enable_ptp_master_mode, int, 0); +MODULE_PARM_DESC(enable_ptp_master_mode, "Enable PTP Master Mode."); + +module_param(disable_pm_support, int, 0); +MODULE_PARM_DESC(disable_pm_support, "Disable PM support."); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) +module_param_named(debug, debug.msg_enable, int, 0); +MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); +#endif//LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + +MODULE_LICENSE("GPL"); +#ifdef ENABLE_USE_FIRMWARE_FILE +MODULE_FIRMWARE(FIRMWARE_8125A_3); +MODULE_FIRMWARE(FIRMWARE_8125B_2); +#endif + +MODULE_VERSION(RTL8125_VERSION); + + +/*****************************************************************************/ +// Backport Functions // +/*****************************************************************************/ +#if defined(__VMKLNX__) + +#include + +//Backport 2.6.24 +#undef LINUX_VERSION_CODE +#define LINUX_VERSION_CODE KERNEL_VERSION(2,6,24) -#ifdef __VMKLNX__ +#ifndef SET_ETHTOOL_OPS +#define SET_ETHTOOL_OPS(netdev,ops) \ + ( (netdev)->ethtool_ops = (ops) ) +#endif //SET_ETHTOOL_OPS -//extern bitreverse for symbol unresolved +//Port #define CRCPOLY_LE 0xedb88320 u32 crc32_le(u32 crc, unsigned char const *p, size_t len) @@ -265,8 +363,156 @@ u32 bitreverse(u32 x) #define ether_crc(length, data) bitreverse(crc32_le(~0, data, length)) -//VM Kernel version is 2.6 without pci_enable_msix_range -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) + +//It's sad that VMKernel doesn't support line partner advertisement, so we have to backport rtl8125_gset_xmii to 9.005.06 +static void rtl8125_gset_xmii(struct net_device *dev, +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) + struct ethtool_cmd *cmd +#else + struct ethtool_link_ksettings *cmd +#endif + ) +{ + struct rtl8125_private *tp = netdev_priv(dev); + u16 status; + u8 autoneg, duplex; + u32 speed = 0; + u16 bmcr; + u32 supported, advertising; + + supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause; + + advertising = ADVERTISED_TP; + + rtl8125_mdio_write(tp, 0x1F, 0x0000); + bmcr = rtl8125_mdio_read(tp, MII_BMCR); + + if (bmcr & BMCR_ANENABLE) { + advertising |= ADVERTISED_Autoneg; + autoneg = AUTONEG_ENABLE; + + if (tp->phy_auto_nego_reg & ADVERTISE_10HALF) + advertising |= ADVERTISED_10baseT_Half; + if (tp->phy_auto_nego_reg & ADVERTISE_10FULL) + advertising |= ADVERTISED_10baseT_Full; + if (tp->phy_auto_nego_reg & ADVERTISE_100HALF) + advertising |= ADVERTISED_100baseT_Half; + if (tp->phy_auto_nego_reg & ADVERTISE_100FULL) + advertising |= ADVERTISED_100baseT_Full; + if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL) + advertising |= ADVERTISED_1000baseT_Full; + if (tp->phy_2500_ctrl_reg & RTK_ADVERTISE_2500FULL) + advertising |= ADVERTISED_2500baseX_Full; + } else { + autoneg = AUTONEG_DISABLE; + } + + status = RTL_R16(tp, PHYstatus); + + if (status & LinkStatus) { + /*link on*/ + if (status & _2500bpsF) + speed = SPEED_2500; + else if (status & _1000bpsF) + speed = SPEED_1000; + else if (status & _100bps) + speed = SPEED_100; + else if (status & _10bps) + speed = SPEED_10; + + if (status & TxFlowCtrl) + advertising |= ADVERTISED_Asym_Pause; + + if (status & RxFlowCtrl) + advertising |= ADVERTISED_Pause; + + duplex = ((status & (_1000bpsF | _2500bpsF)) || (status & FullDup)) ? + DUPLEX_FULL : DUPLEX_HALF; + } else { + /*link down*/ + speed = SPEED_UNKNOWN; + duplex = DUPLEX_UNKNOWN; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) + cmd->supported = supported; + cmd->advertising = advertising; + cmd->autoneg = autoneg; + cmd->speed = speed; + cmd->duplex = duplex; + cmd->port = PORT_TP; +#else + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + advertising); + cmd->base.autoneg = autoneg; + cmd->base.speed = speed; + cmd->base.duplex = duplex; + cmd->base.port = PORT_TP; +#endif +} + +//EEE type backport +/** + * ethtool_adv_to_mmd_eee_adv_t + * @adv: the ethtool advertisement settings + * + * A small helper function that translates ethtool advertisement settings + * to EEE advertisements for the MMD EEE Advertisement (7.60) and + * MMD EEE Link Partner Ability (7.61) registers. + */ +static inline u16 ethtool_adv_to_mmd_eee_adv_t(u32 adv) +{ + u16 reg = 0; + + if (adv & ADVERTISED_100baseT_Full) + reg |= MDIO_EEE_100TX; + if (adv & ADVERTISED_1000baseT_Full) + reg |= MDIO_EEE_1000T; + if (adv & ADVERTISED_10000baseT_Full) + reg |= MDIO_EEE_10GT; + if (adv & ADVERTISED_1000baseKX_Full) + reg |= MDIO_EEE_1000KX; + if (adv & ADVERTISED_10000baseKX4_Full) + reg |= MDIO_EEE_10GKX4; + if (adv & ADVERTISED_10000baseKR_Full) + reg |= MDIO_EEE_10GKR; + + return reg; +} + + +static inline u32 mmd_eee_adv_to_ethtool_adv_t(u16 eee_adv) +{ + u32 adv = 0; + + if (eee_adv & MDIO_EEE_100TX) + adv |= ADVERTISED_100baseT_Full; + if (eee_adv & MDIO_EEE_1000T) + adv |= ADVERTISED_1000baseT_Full; + if (eee_adv & MDIO_EEE_10GT) + adv |= ADVERTISED_10000baseT_Full; + if (eee_adv & MDIO_EEE_1000KX) + adv |= ADVERTISED_1000baseKX_Full; + if (eee_adv & MDIO_EEE_10GKX4) + adv |= ADVERTISED_10000baseKX4_Full; + if (eee_adv & MDIO_EEE_10GKR) + adv |= ADVERTISED_10000baseKR_Full; + + return adv; +} + +//PCIe MSIX backport int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec, int maxvec) { @@ -289,12 +535,8 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, return nvec; } -#endif - - -//Multi-queue R/W is not supported -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) +//Multi-queue R/W is not supported by VMKernel int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) { return 0; @@ -304,8 +546,9 @@ int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq) { return 0; } -#endif //#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + +//Checksum offloading backport. unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum) { @@ -379,6 +622,7 @@ unsigned int skb_checksum(const struct sk_buff *skb, int offset, return csum; } + int r8125_skb_checksum_help(struct sk_buff *skb) { unsigned int csum; @@ -410,7 +654,153 @@ int r8125_skb_checksum_help(struct sk_buff *skb) return ret; } -//The struct skbuff definition has no pkt_type member when __VMKLNX__ is defined, so we need detail it. +static inline +__be16 get_protocol(struct sk_buff *skb); + +static bool rtl8125_skb_pad(struct sk_buff *skb); + +static bool +rtl8125_tso_csum(struct sk_buff *skb, + struct net_device *dev, + u32 *opts) +{ + struct rtl8125_private *tp = netdev_priv(dev); + unsigned long large_send = 0; + u32 csum_cmd = 0; + u8 sw_calc_csum = false; + + if (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) { + u32 mss = skb_shinfo(skb)->gso_size; + + /* TCP Segmentation Offload (or TCP Large Send) */ + if (mss) { + u32 transport_offset = (u32)skb_transport_offset(skb); + assert((transport_offset%2) == 0); + switch (get_protocol(skb)) { + case __constant_htons(ETH_P_IP): + if (transport_offset <= GTTCPHO_MAX) { + opts[0] |= GiantSendv4; + opts[0] |= transport_offset << GTTCPHO_SHIFT; + opts[1] |= min(mss, MSS_MAX) << 18; + large_send = 1; + } + break; + case __constant_htons(ETH_P_IPV6): + if (transport_offset <= GTTCPHO_MAX) { + opts[0] |= GiantSendv6; + opts[0] |= transport_offset << GTTCPHO_SHIFT; + opts[1] |= min(mss, MSS_MAX) << 18; + large_send = 1; + } + break; + default: + if (unlikely(net_ratelimit())) + dprintk("tso proto=%x!\n", skb->protocol); + break; + } + + if (large_send == 0) + return false; + + return true; + } + } + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + const struct iphdr *ip = skb->nh.iph; + + if (dev->features & NETIF_F_IP_CSUM) { + if (ip->protocol == IPPROTO_TCP) + csum_cmd = tp->tx_ip_csum_cmd | tp->tx_tcp_csum_cmd; + else if (ip->protocol == IPPROTO_UDP) + csum_cmd = tp->tx_ip_csum_cmd | tp->tx_udp_csum_cmd; + else if (ip->protocol == IPPROTO_IP) + csum_cmd = tp->tx_ip_csum_cmd; + } + if (csum_cmd == 0) { + sw_calc_csum = true; + } + + + } + + if (skb->len < ETH_ZLEN) { + if (tp->UseSwPaddingShortPkt || + (tp->ShortPacketSwChecksum && csum_cmd != 0)) { + if (!rtl8125_skb_pad(skb)) + { + WARN_ON(1); /* we need a WARN() */ + return false; + } + if (csum_cmd != 0) + sw_calc_csum = true; + } + } + + if (sw_calc_csum) { + r8125_skb_checksum_help(skb); + } else + opts[1] |= csum_cmd; + + return true; +} + + +//Unresolved symbol skb_pad +/** + * skb_pad - zero pad the tail of an skb + * @skb: buffer to pad + * @pad: space to pad + * + * Ensure that a buffer is followed by a padding area that is zero + * filled. Used by network drivers which may DMA or transfer data + * beyond the buffer end onto the wire. + * + * May return error in out of memory cases. The skb is freed on error. + */ + +int skb_pad(struct sk_buff *skb, int pad) +{ + int err; + int ntail; + + /* If the skbuff is non linear tailroom is always zero.. */ + if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) { + memset(skb->data+skb->len, 0, pad); + return 0; + } + + ntail = skb->data_len + pad - (skb->end - skb->tail); + if (likely(skb_cloned(skb) || ntail > 0)) { + err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC); + if (unlikely(err)) + goto free_skb; + } + + /* FIXME: The use of this function with non-linear skb's really needs + * to be audited. + */ + err = skb_linearize(skb); + if (unlikely(err)) + goto free_skb; + + memset(skb->data + skb->len, 0, pad); + return 0; + +free_skb: + kfree_skb(skb); + return err; +} + +//Unresolved symbol : synchronize_net +/* Synchronize with packet receive processing. */ +void synchronize_net(void) +{ + might_sleep(); + synchronize_rcu(); +} + +//Multicast backport, VMKernel pkt_type not defined in skbuff struct __skbuff_mhead { __u8 pkt_type:3, @@ -431,79 +821,99 @@ bool isMulticastType(__u8 mhead) return head.pkt_type == PACKET_MULTICAST; } +//PCI power management backport from 2.6.32 +static void +rtl8125_set_pci_pme(struct rtl8125_private *tp, int set) +{ + struct pci_dev *pdev = tp->pci_dev; + u16 pmc; + int pm_cap; -#endif //#ifdef __VMKLNX__ -//End of porting -//************************************************************************ - - -MODULE_AUTHOR("Realtek and the Linux r8125 crew "); -MODULE_DESCRIPTION("Realtek RTL8125 2.5Gigabit Ethernet driver"); - -module_param(speed_mode, uint, 0); -MODULE_PARM_DESC(speed_mode, "force phy operation. Deprecated by ethtool (8)."); - -module_param(duplex_mode, uint, 0); -MODULE_PARM_DESC(duplex_mode, "force phy operation. Deprecated by ethtool (8)."); - -module_param(autoneg_mode, uint, 0); -MODULE_PARM_DESC(autoneg_mode, "force phy operation. Deprecated by ethtool (8)."); - -module_param(advertising_mode, uint, 0); -MODULE_PARM_DESC(advertising_mode, "force phy operation. Deprecated by ethtool (8)."); + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (!pm_cap) + return; -module_param(aspm, int, 0); -MODULE_PARM_DESC(aspm, "Enable ASPM."); + pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pmc); + pmc |= PCI_PM_CTRL_PME_STATUS; + if (set) + pmc |= PCI_PM_CTRL_PME_ENABLE; + else + pmc &= ~PCI_PM_CTRL_PME_ENABLE; + pci_write_config_word(pdev, pm_cap + PCI_PM_CTRL, pmc); +} -module_param(s5wol, int, 0); -MODULE_PARM_DESC(s5wol, "Enable Shutdown Wake On Lan."); -module_param(s5_keep_curr_mac, int, 0); -MODULE_PARM_DESC(s5_keep_curr_mac, "Enable Shutdown Keep Current MAC Address."); +bool pci_pme_capable(struct pci_dev *dev, pci_power_t state) +{ + int pm_cap = pci_find_capability(dev, PCI_CAP_ID_PM); + if (pm_cap == 0) + return false; + u16 value=0; + int pm=0; + pm = pci_find_capability(dev, PCI_CAP_ID_PM); + pci_read_config_word(dev, pm + PCI_PM_PMC, &value); + value &= PCI_PM_CAP_PME_MASK; + value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; + return !!(value & (1 << state)); +} -module_param(rx_copybreak, int, 0); -MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); +static void __pci_set_master(struct pci_dev *dev, bool enable) +{ + u16 old_cmd, cmd; -module_param(use_dac, int, 0); -MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); + pci_read_config_word(dev, PCI_COMMAND, &old_cmd); + if (enable) + cmd = old_cmd | PCI_COMMAND_MASTER; + else + cmd = old_cmd & ~PCI_COMMAND_MASTER; + if (cmd != old_cmd) { + dev_dbg(&dev->dev, "%s bus mastering\n", + enable ? "enabling" : "disabling"); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + dev->is_busmaster = enable; +} -module_param(timer_count, int, 0); -MODULE_PARM_DESC(timer_count, "Timer Interrupt Interval."); +/** + * pci_clear_master - disables bus-mastering for device dev + * @dev: the PCI device to disable + */ +void pci_clear_master(struct pci_dev *dev) +{ + __pci_set_master(dev, false); +} -module_param(eee_enable, int, 0); -MODULE_PARM_DESC(eee_enable, "Enable Energy Efficient Ethernet."); +int pci_wake_from_d3(struct pci_dev *dev, bool enable) +{ + return pci_pme_capable(dev, PCI_D3cold) ? + pci_enable_wake(dev, PCI_D3cold, enable) : + pci_enable_wake(dev, PCI_D3hot, enable); +} -module_param(hwoptimize, ulong, 0); -MODULE_PARM_DESC(hwoptimize, "Enable HW optimization function."); -module_param(s0_magic_packet, int, 0); -MODULE_PARM_DESC(s0_magic_packet, "Enable S0 Magic Packet."); +#endif //#if defined(__VMKLNX__) -module_param(tx_no_close_enable, int, 0); -MODULE_PARM_DESC(tx_no_close_enable, "Enable TX No Close."); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) -module_param_named(debug, debug.msg_enable, int, 0); -MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); -#endif//LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) +/****************************Backport End Here********************************/ -MODULE_LICENSE("GPL"); -MODULE_VERSION(RTL8125_VERSION); +/* #if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) static void rtl8125_esd_timer(unsigned long __opaque); #else static void rtl8125_esd_timer(struct timer_list *t); #endif +*/ +/* #if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) static void rtl8125_link_timer(unsigned long __opaque); #else static void rtl8125_link_timer(struct timer_list *t); #endif +*/ -static int rtl8125_open(struct net_device *dev); -static int rtl8125_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t rtl8125_start_xmit(struct sk_buff *skb, struct net_device *dev); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) static irqreturn_t rtl8125_interrupt(int irq, void *dev_instance, struct pt_regs *regs); #else @@ -514,8 +924,6 @@ static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance, struct pt #else static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance); #endif -void rtl8125_hw_config(struct net_device *dev); -static int rtl8125_close(struct net_device *dev); static void rtl8125_set_rx_mode(struct net_device *dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) static void rtl8125_tx_timeout(struct net_device *dev, unsigned int txqueue); @@ -524,7 +932,8 @@ static void rtl8125_tx_timeout(struct net_device *dev); #endif static struct net_device_stats *rtl8125_get_stats(struct net_device *dev); static int rtl8125_rx_interrupt(struct net_device *, struct rtl8125_private *, struct rtl8125_rx_ring *, napi_budget); -static int rtl8125_tx_interrupt(struct rtl8125_tx_ring *ring); +static int rtl8125_tx_interrupt(struct rtl8125_tx_ring *ring, int budget); +static int rtl8125_tx_interrupt_with_vector(struct rtl8125_private *tp, const int message_id, int budget); static int rtl8125_change_mtu(struct net_device *dev, int new_mtu); static void rtl8125_down(struct net_device *dev); @@ -534,6 +943,8 @@ static void rtl8125_desc_addr_fill(struct rtl8125_private *); static void rtl8125_tx_desc_init(struct rtl8125_private *tp); static void rtl8125_rx_desc_init(struct rtl8125_private *tp); +static u32 mdio_direct_read_phy_ocp(struct rtl8125_private *tp, u16 RegAddr); +static u16 rtl8125_get_hw_phy_mcu_code_ver(struct rtl8125_private *tp); static void rtl8125_phy_power_up(struct net_device *dev); static void rtl8125_phy_power_down(struct net_device *dev); static int rtl8125_set_speed(struct net_device *dev, u8 autoneg, u32 speed, u8 duplex, u32 adv); @@ -544,6 +955,26 @@ static bool rtl8125_clear_phy_mcu_patch_request(struct rtl8125_private *tp); static int rtl8125_poll(napi_ptr napi, napi_budget budget); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void rtl8125_reset_task(void *_data); +static void rtl8125_esd_task(void *_data); +static void rtl8125_linkchg_task(void *_data); +#else +static void rtl8125_reset_task(struct work_struct *work); +static void rtl8125_esd_task(struct work_struct *work); +static void rtl8125_linkchg_task(struct work_struct *work); +#endif +static void rtl8125_schedule_reset_work(struct rtl8125_private *tp); +static void rtl8125_schedule_esd_work(struct rtl8125_private *tp); +static void rtl8125_schedule_linkchg_work(struct rtl8125_private *tp); +static void rtl8125_init_all_schedule_work(struct rtl8125_private *tp); +static void rtl8125_cancel_all_schedule_work(struct rtl8125_private *tp); + +static inline struct device *tp_to_dev(struct rtl8125_private *tp) +{ + return &tp->pci_dev->dev; +} + #if ((LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) && \ LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,00))) void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst, @@ -668,7 +1099,7 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits) #endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) && !defined (__VMKLNX__) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) && !defined(__VMKLNX__) static inline void eth_copy_and_sum (struct sk_buff *dest, const unsigned char *src, int len, int base) @@ -813,21 +1244,50 @@ static inline struct mii_ioctl_data *if_mii(struct ifreq *rq) } #endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) -struct rtl8125_counters { - u64 tx_packets; - u64 rx_packets; - u64 tx_errors; - u32 rx_errors; - u16 rx_missed; - u16 align_errors; - u32 tx_one_collision; - u32 tx_multi_collision; - u64 rx_unicast; - u64 rx_broadcast; - u32 rx_multicast; - u16 tx_aborted; - u16 tx_underun; -}; +static u32 rtl8125_read_thermal_sensor(struct rtl8125_private *tp) +{ + u16 ts_digout; + + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_7: + ts_digout = mdio_direct_read_phy_ocp(tp, 0xBD84); + ts_digout &= 0x3ff; + break; + default: + ts_digout = 0xffff; + break; + } + + return ts_digout; +} + +int rtl8125_dump_tally_counter(struct rtl8125_private *tp, dma_addr_t paddr) +{ + u32 cmd; + u32 WaitCnt; + int retval = -1; + + RTL_W32(tp, CounterAddrHigh, (u64)paddr >> 32); + cmd = (u64)paddr & DMA_BIT_MASK(32); + RTL_W32(tp, CounterAddrLow, cmd); + RTL_W32(tp, CounterAddrLow, cmd | CounterDump); + + WaitCnt = 0; + while (RTL_R32(tp, CounterAddrLow) & CounterDump) { + udelay(10); + + WaitCnt++; + if (WaitCnt > 20) + break; + } + + if (WaitCnt <= 20) + retval = 0; + + return retval; +} #ifdef ENABLE_R8125_PROCFS /**************************************************************************** @@ -843,11 +1303,11 @@ static int proc_get_driver_variable(struct seq_file *m, void *v) { struct net_device *dev = m->private; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; seq_puts(m, "\nDump Driver Variable\n"); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + seq_puts(m, "Variable\tValue\n----------\t-----\n"); seq_printf(m, "MODULENAME\t%s\n", MODULENAME); seq_printf(m, "driver version\t%s\n", RTL8125_VERSION); @@ -924,14 +1384,16 @@ static int proc_get_driver_variable(struct seq_file *m, void *v) seq_printf(m, "aspm\t0x%x\n", aspm); seq_printf(m, "s5wol\t0x%x\n", s5wol); seq_printf(m, "s5_keep_curr_mac\t0x%x\n", s5_keep_curr_mac); - seq_printf(m, "eee_enable\t0x%x\n", tp->eee_enabled); + seq_printf(m, "eee_enable\t0x%x\n", tp->eee.eee_enabled); seq_printf(m, "hwoptimize\t0x%lx\n", hwoptimize); seq_printf(m, "proc_init_num\t0x%x\n", proc_init_num); seq_printf(m, "s0_magic_packet\t0x%x\n", s0_magic_packet); seq_printf(m, "HwSuppMagicPktVer\t0x%x\n", tp->HwSuppMagicPktVer); + seq_printf(m, "HwSuppLinkChgWakeUpVer\t0x%x\n", tp->HwSuppLinkChgWakeUpVer); + seq_printf(m, "HwSuppD0SpeedUpVer\t0x%x\n", tp->HwSuppD0SpeedUpVer); + seq_printf(m, "D0SpeedUpSpeed\t0x%x\n", tp->D0SpeedUpSpeed); seq_printf(m, "HwSuppCheckPhyDisableModeVer\t0x%x\n", tp->HwSuppCheckPhyDisableModeVer); seq_printf(m, "HwPkgDet\t0x%x\n", tp->HwPkgDet); - seq_printf(m, "HwSuppGigaForceMode\t0x%x\n", tp->HwSuppGigaForceMode); seq_printf(m, "HwSuppTxNoCloseVer\t0x%x\n", tp->HwSuppTxNoCloseVer); seq_printf(m, "EnableTxNoClose\t0x%x\n", tp->EnableTxNoClose); seq_printf(m, "NextHwDesCloPtr0\t0x%x\n", tp->tx_ring[0].NextHwDesCloPtr); @@ -946,8 +1408,12 @@ static int proc_get_driver_variable(struct seq_file *m, void *v) seq_printf(m, "tot_tx_rings\t0x%x\n", rtl8125_tot_tx_rings(tp)); seq_printf(m, "EnableRss\t0x%x\n", tp->EnableRss); seq_printf(m, "EnablePtp\t0x%x\n", tp->EnablePtp); + seq_printf(m, "ptp_master_mode\t0x%x\n", tp->ptp_master_mode); seq_printf(m, "min_irq_nvecs\t0x%x\n", tp->min_irq_nvecs); seq_printf(m, "irq_nvecs\t0x%x\n", tp->irq_nvecs); + seq_printf(m, "ring_lib_enabled\t0x%x\n", tp->ring_lib_enabled); + seq_printf(m, "HwSuppIsrVer\t0x%x\n", tp->HwSuppIsrVer); + seq_printf(m, "HwCurrIsrVer\t0x%x\n", tp->HwCurrIsrVer); #ifdef ENABLE_PTP_SUPPORT seq_printf(m, "tx_hwtstamp_timeouts\t0x%x\n", tp->tx_hwtstamp_timeouts); seq_printf(m, "tx_hwtstamp_skipped\t0x%x\n", tp->tx_hwtstamp_skipped); @@ -958,7 +1424,8 @@ static int proc_get_driver_variable(struct seq_file *m, void *v) seq_printf(m, "perm_addr\t%pM\n", dev->perm_addr); #endif seq_printf(m, "dev_addr\t%pM\n", dev->dev_addr); - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); seq_putc(m, '\n'); return 0; @@ -970,52 +1437,67 @@ static int proc_get_tally_counter(struct seq_file *m, void *v) struct rtl8125_private *tp = netdev_priv(dev); struct rtl8125_counters *counters; dma_addr_t paddr; - u32 cmd; - u32 WaitCnt; - unsigned long flags; seq_puts(m, "\nDump Tally Counter\n"); - //ASSERT_RTNL(); + rtnl_lock(); counters = tp->tally_vaddr; paddr = tp->tally_paddr; if (!counters) { seq_puts(m, "\nDump Tally Counter Fail\n"); - return 0; + goto out_unlock; } - spin_lock_irqsave(&tp->lock, flags); - RTL_W32(tp, CounterAddrHigh, (u64)paddr >> 32); - cmd = (u64)paddr & DMA_BIT_MASK(32); - RTL_W32(tp, CounterAddrLow, cmd); - RTL_W32(tp, CounterAddrLow, cmd | CounterDump); - - WaitCnt = 0; - while (RTL_R32(tp, CounterAddrLow) & CounterDump) { - udelay(10); - - WaitCnt++; - if (WaitCnt > 20) - break; - } - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_dump_tally_counter(tp, paddr); seq_puts(m, "Statistics\tValue\n----------\t-----\n"); seq_printf(m, "tx_packets\t%lld\n", le64_to_cpu(counters->tx_packets)); seq_printf(m, "rx_packets\t%lld\n", le64_to_cpu(counters->rx_packets)); seq_printf(m, "tx_errors\t%lld\n", le64_to_cpu(counters->tx_errors)); - seq_printf(m, "rx_missed\t%lld\n", le64_to_cpu(counters->rx_missed)); - seq_printf(m, "align_errors\t%lld\n", le64_to_cpu(counters->align_errors)); - seq_printf(m, "tx_one_collision\t%lld\n", le64_to_cpu(counters->tx_one_collision)); - seq_printf(m, "tx_multi_collision\t%lld\n", le64_to_cpu(counters->tx_multi_collision)); + seq_printf(m, "rx_errors\t%d\n", le32_to_cpu(counters->rx_errors)); + seq_printf(m, "rx_missed\t%d\n", le16_to_cpu(counters->rx_missed)); + seq_printf(m, "align_errors\t%d\n", le16_to_cpu(counters->align_errors)); + seq_printf(m, "tx_one_collision\t%d\n", le32_to_cpu(counters->tx_one_collision)); + seq_printf(m, "tx_multi_collision\t%d\n", le32_to_cpu(counters->tx_multi_collision)); seq_printf(m, "rx_unicast\t%lld\n", le64_to_cpu(counters->rx_unicast)); seq_printf(m, "rx_broadcast\t%lld\n", le64_to_cpu(counters->rx_broadcast)); - seq_printf(m, "rx_multicast\t%lld\n", le64_to_cpu(counters->rx_multicast)); - seq_printf(m, "tx_aborted\t%lld\n", le64_to_cpu(counters->tx_aborted)); - seq_printf(m, "tx_underun\t%lld\n", le64_to_cpu(counters->tx_underun)); + seq_printf(m, "rx_multicast\t%d\n", le32_to_cpu(counters->rx_multicast)); + seq_printf(m, "tx_aborted\t%d\n", le16_to_cpu(counters->tx_aborted)); + seq_printf(m, "tx_underrun\t%d\n", le16_to_cpu(counters->tx_underrun)); + + seq_printf(m, "tx_octets\t%lld\n", le64_to_cpu(counters->tx_octets)); + seq_printf(m, "rx_octets\t%lld\n", le64_to_cpu(counters->rx_octets)); + seq_printf(m, "rx_multicast64\t%lld\n", le64_to_cpu(counters->rx_multicast64)); + seq_printf(m, "tx_unicast64\t%lld\n", le64_to_cpu(counters->tx_unicast64)); + seq_printf(m, "tx_broadcast64\t%lld\n", le64_to_cpu(counters->tx_broadcast64)); + seq_printf(m, "tx_multicast64\t%lld\n", le64_to_cpu(counters->tx_multicast64)); + seq_printf(m, "tx_pause_on\t%d\n", le32_to_cpu(counters->tx_pause_on)); + seq_printf(m, "tx_pause_off\t%d\n", le32_to_cpu(counters->tx_pause_off)); + seq_printf(m, "tx_pause_all\t%d\n", le32_to_cpu(counters->tx_pause_all)); + seq_printf(m, "tx_deferred\t%d\n", le32_to_cpu(counters->tx_deferred)); + seq_printf(m, "tx_late_collision\t%d\n", le32_to_cpu(counters->tx_late_collision)); + seq_printf(m, "tx_all_collision\t%d\n", le32_to_cpu(counters->tx_all_collision)); + seq_printf(m, "tx_aborted32\t%d\n", le32_to_cpu(counters->tx_aborted32)); + seq_printf(m, "align_errors32\t%d\n", le32_to_cpu(counters->align_errors32)); + seq_printf(m, "rx_frame_too_long\t%d\n", le32_to_cpu(counters->rx_frame_too_long)); + seq_printf(m, "rx_runt\t%d\n", le32_to_cpu(counters->rx_runt)); + seq_printf(m, "rx_pause_on\t%d\n", le32_to_cpu(counters->rx_pause_on)); + seq_printf(m, "rx_pause_off\t%d\n", le32_to_cpu(counters->rx_pause_off)); + seq_printf(m, "rx_pause_all\t%d\n", le32_to_cpu(counters->rx_pause_all)); + seq_printf(m, "rx_unknown_opcode\t%d\n", le32_to_cpu(counters->rx_unknown_opcode)); + seq_printf(m, "rx_mac_error\t%d\n", le32_to_cpu(counters->rx_mac_error)); + seq_printf(m, "tx_underrun32\t%d\n", le32_to_cpu(counters->tx_underrun32)); + seq_printf(m, "rx_mac_missed\t%d\n", le32_to_cpu(counters->rx_mac_missed)); + seq_printf(m, "rx_tcam_dropped\t%d\n", le32_to_cpu(counters->rx_tcam_dropped)); + seq_printf(m, "tdu\t%d\n", le32_to_cpu(counters->tdu)); + seq_printf(m, "rdu\t%d\n", le32_to_cpu(counters->rdu)); seq_putc(m, '\n'); + +out_unlock: + rtnl_unlock(); + return 0; } @@ -1026,12 +1508,12 @@ static int proc_get_registers(struct seq_file *m, void *v) u8 byte_rd; struct rtl8125_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - unsigned long flags; seq_puts(m, "\nDump MAC Registers\n"); seq_puts(m, "Offset\tValue\n------\t-----\n"); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + for (n = 0; n < max;) { seq_printf(m, "\n0x%02x:\t", n); @@ -1040,7 +1522,8 @@ static int proc_get_registers(struct seq_file *m, void *v) seq_printf(m, "%02x ", byte_rd); } } - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); seq_putc(m, '\n'); return 0; @@ -1052,12 +1535,12 @@ static int proc_get_pcie_phy(struct seq_file *m, void *v) int i, n, max = R8125_EPHY_REGS_SIZE/2; u16 word_rd; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; seq_puts(m, "\nDump PCIE PHY\n"); seq_puts(m, "\nOffset\tValue\n------\t-----\n "); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + for (n = 0; n < max;) { seq_printf(m, "\n0x%02x:\t", n); @@ -1066,7 +1549,8 @@ static int proc_get_pcie_phy(struct seq_file *m, void *v) seq_printf(m, "%04x ", word_rd); } } - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); seq_putc(m, '\n'); return 0; @@ -1078,12 +1562,12 @@ static int proc_get_eth_phy(struct seq_file *m, void *v) int i, n, max = R8125_PHY_REGS_SIZE/2; u16 word_rd; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; seq_puts(m, "\nDump Ethernet PHY\n"); seq_puts(m, "\nOffset\tValue\n------\t-----\n "); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + seq_puts(m, "\n####################page 0##################\n "); rtl8125_mdio_write(tp, 0x1f, 0x0000); for (n = 0; n < max;) { @@ -1094,7 +1578,8 @@ static int proc_get_eth_phy(struct seq_file *m, void *v) seq_printf(m, "%04x ", word_rd); } } - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); seq_putc(m, '\n'); return 0; @@ -1106,12 +1591,12 @@ static int proc_get_extended_registers(struct seq_file *m, void *v) int i, n, max = R8125_ERI_REGS_SIZE; u32 dword_rd; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; seq_puts(m, "\nDump Extended Registers\n"); seq_puts(m, "\nOffset\tValue\n------\t-----\n "); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + for (n = 0; n < max;) { seq_printf(m, "\n0x%02x:\t", n); @@ -1120,7 +1605,8 @@ static int proc_get_extended_registers(struct seq_file *m, void *v) seq_printf(m, "%08x ", dword_rd); } } - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); seq_putc(m, '\n'); return 0; @@ -1132,12 +1618,12 @@ static int proc_get_pci_registers(struct seq_file *m, void *v) int i, n, max = R8125_PCI_REGS_SIZE; u32 dword_rd; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; seq_puts(m, "\nDump PCI Registers\n"); seq_puts(m, "\nOffset\tValue\n------\t-----\n "); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + for (n = 0; n < max;) { seq_printf(m, "\n0x%03x:\t", n); @@ -1154,7 +1640,46 @@ static int proc_get_pci_registers(struct seq_file *m, void *v) pci_read_config_dword(tp->pci_dev, n, &dword_rd); seq_printf(m, "\n0x%03x:\t%08x ", n, dword_rd); - spin_unlock_irqrestore(&tp->lock, flags); + rtnl_unlock(); + + seq_putc(m, '\n'); + return 0; +} + +static int proc_get_temperature(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8125_private *tp = netdev_priv(dev); + u16 ts_digout, tj, fah; + + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_7: + seq_puts(m, "\nChip Temperature\n"); + break; + default: + seq_puts(m, "\nThis Chip Does Not Support Dump Temperature\n"); + break; + } + + rtnl_lock(); + ts_digout = rtl8125_read_thermal_sensor(tp); + rtnl_unlock(); + +//Fix a silly bug here * (9/5) :) + tj = ts_digout / 2; + if (ts_digout <= 512) { + tj = ts_digout / 2; + seq_printf(m, "Cel:%d\n", tj); + fah = tj * 9/5 + 32; + seq_printf(m, "Fah:%d\n", fah); + } else { + tj = (512 - ((ts_digout / 2) - 512)) / 2; + seq_printf(m, "Cel:-%d\n", tj); + fah = tj * 9/5 + 32; + seq_printf(m, "Fah:-%d\n", fah); + } seq_putc(m, '\n'); return 0; @@ -1167,13 +1692,13 @@ static int proc_get_driver_variable(char *page, char **start, { struct net_device *dev = data; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; int len = 0; len += snprintf(page + len, count - len, "\nDump Driver Driver\n"); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + len += snprintf(page + len, count - len, "Variable\tValue\n----------\t-----\n"); @@ -1258,9 +1783,11 @@ static int proc_get_driver_variable(char *page, char **start, "proc_init_num\t0x%x\n" "s0_magic_packet\t0x%x\n" "HwSuppMagicPktVer\t0x%x\n" + "HwSuppLinkChgWakeUpVer\t0x%x\n" + "HwSuppD0SpeedUpVer\t0x%x\n" + "D0SpeedUpSpeed\t0x%x\n" "HwSuppCheckPhyDisableModeVer\t0x%x\n" "HwPkgDet\t0x%x\n" - "HwSuppGigaForceMode\t0x%x\n" "HwSuppTxNoCloseVer\t0x%x\n" "EnableTxNoClose\t0x%x\n" "NextHwDesCloPtr0\t0x%x\n" @@ -1271,12 +1798,16 @@ static int proc_get_driver_variable(char *page, char **start, "RxDescLength\t0x%x\n" "num_rx_rings\t0x%x\n" "num_tx_rings\t0x%x\n" -// "tot_rx_rings\t0x%x\n" -// "tot_tx_rings\t0x%x\n" + //"tot_rx_rings\t0x%x\n" + //"tot_tx_rings\t0x%x\n" "EnableRss\t0x%x\n" "EnablePtp\t0x%x\n" + "ptp_master_mode\t0x%x\n" "min_irq_nvecs\t0x%x\n" "irq_nvecs\t0x%x\n" + "ring_lib_enabled\t0x%x\n" + "HwSuppIsrVer\t0x%x\n" + "HwCurrIsrVer\t0x%x\n" #ifdef ENABLE_PTP_SUPPORT "tx_hwtstamp_timeouts\t0x%x\n" "tx_hwtstamp_skipped\t0x%x\n" @@ -1362,14 +1893,16 @@ static int proc_get_driver_variable(char *page, char **start, aspm, s5wol, s5_keep_curr_mac, - tp->eee_enabled, + tp->eee.eee_enabled, hwoptimize, proc_init_num, s0_magic_packet, tp->HwSuppMagicPktVer, + tp->HwSuppLinkChgWakeUpVer, + tp->HwSuppD0SpeedUpVer, + tp->D0SpeedUpSpeed, tp->HwSuppCheckPhyDisableModeVer, tp->HwPkgDet, - tp->HwSuppGigaForceMode, tp->HwSuppTxNoCloseVer, tp->EnableTxNoClose, tp->tx_ring[0].NextHwDesCloPtr, @@ -1380,12 +1913,16 @@ static int proc_get_driver_variable(char *page, char **start, tp->RxDescLength, tp->num_rx_rings, tp->num_tx_rings, -// tp->tot_rx_rings, -// tp->tot_tx_rings, + //tp->tot_rx_rings, + //tp->tot_tx_rings, tp->EnableRss, tp->EnablePtp, + tp->ptp_master_mode, tp->min_irq_nvecs, tp->irq_nvecs, + tp->ring_lib_enabled, + tp->HwSuppIsrVer, + tp->HwCurrIsrVer, #ifdef ENABLE_PTP_SUPPORT tp->tx_hwtstamp_timeouts, tp->tx_hwtstamp_skipped, @@ -1397,7 +1934,8 @@ static int proc_get_driver_variable(char *page, char **start, #endif dev->dev_addr ); - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); len += snprintf(page + len, count - len, "\n"); @@ -1413,39 +1951,22 @@ static int proc_get_tally_counter(char *page, char **start, struct rtl8125_private *tp = netdev_priv(dev); struct rtl8125_counters *counters; dma_addr_t paddr; - u32 cmd; - u32 WaitCnt; - unsigned long flags; int len = 0; len += snprintf(page + len, count - len, "\nDump Tally Counter\n"); - //ASSERT_RTNL(); + rtnl_lock(); counters = tp->tally_vaddr; paddr = tp->tally_paddr; if (!counters) { len += snprintf(page + len, count - len, "\nDump Tally Counter Fail\n"); - goto out; + goto out_unlock; } - spin_lock_irqsave(&tp->lock, flags); - RTL_W32(tp, CounterAddrHigh, (u64)paddr >> 32); - cmd = (u64)paddr & DMA_BIT_MASK(32); - RTL_W32(tp, CounterAddrLow, cmd); - RTL_W32(tp, CounterAddrLow, cmd | CounterDump); - - WaitCnt = 0; - while (RTL_R32(tp, CounterAddrLow) & CounterDump) { - udelay(10); - - WaitCnt++; - if (WaitCnt > 20) - break; - } - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_dump_tally_counter(tp, paddr); len += snprintf(page + len, count - len, "Statistics\tValue\n----------\t-----\n"); @@ -1454,31 +1975,89 @@ static int proc_get_tally_counter(char *page, char **start, "tx_packets\t%lld\n" "rx_packets\t%lld\n" "tx_errors\t%lld\n" - "rx_missed\t%lld\n" - "align_errors\t%lld\n" - "tx_one_collision\t%lld\n" - "tx_multi_collision\t%lld\n" + "rx_errors\t%d\n" + "rx_missed\t%d\n" + "align_errors\t%d\n" + "tx_one_collision\t%d\n" + "tx_multi_collision\t%d\n" "rx_unicast\t%lld\n" "rx_broadcast\t%lld\n" - "rx_multicast\t%lld\n" - "tx_aborted\t%lld\n" - "tx_underun\t%lld\n", + "rx_multicast\t%d\n" + "tx_aborted\t%d\n" + "tx_underrun\t%d\n" + + "tx_octets\t%lld\n" + "rx_octets\t%lld\n" + "rx_multicast64\t%lld\n" + "tx_unicast64\t%lld\n" + "tx_broadcast64\t%lld\n" + "tx_multicast64\t%lld\n" + "tx_pause_on\t%d\n" + "tx_pause_off\t%d\n" + "tx_pause_all\t%d\n" + "tx_deferred\t%d\n" + "tx_late_collision\t%d\n" + "tx_all_collision\t%d\n" + "tx_aborted32\t%d\n" + "align_errors32\t%d\n" + "rx_frame_too_long\t%d\n" + "rx_runt\t%d\n" + "rx_pause_on\t%d\n" + "rx_pause_off\t%d\n" + "rx_pause_all\t%d\n" + "rx_unknown_opcode\t%d\n" + "rx_mac_error\t%d\n" + "tx_underrun32\t%d\n" + "rx_mac_missed\t%d\n" + "rx_tcam_dropped\t%d\n" + "tdu\t%d\n" + "rdu\t%d\n", le64_to_cpu(counters->tx_packets), le64_to_cpu(counters->rx_packets), le64_to_cpu(counters->tx_errors), - le64_to_cpu(counters->rx_missed), - le64_to_cpu(counters->align_errors), - le64_to_cpu(counters->tx_one_collision), - le64_to_cpu(counters->tx_multi_collision), + le32_to_cpu(counters->rx_errors), + le16_to_cpu(counters->rx_missed), + le16_to_cpu(counters->align_errors), + le32_to_cpu(counters->tx_one_collision), + le32_to_cpu(counters->tx_multi_collision), le64_to_cpu(counters->rx_unicast), le64_to_cpu(counters->rx_broadcast), - le64_to_cpu(counters->rx_multicast), - le64_to_cpu(counters->tx_aborted), - le64_to_cpu(counters->tx_underun) + le32_to_cpu(counters->rx_multicast), + le16_to_cpu(counters->tx_aborted), + le16_to_cpu(counters->tx_underrun), + + le64_to_cpu(counters->tx_octets), + le64_to_cpu(counters->rx_octets), + le64_to_cpu(counters->rx_multicast64), + le64_to_cpu(counters->tx_unicast64), + le64_to_cpu(counters->tx_broadcast64), + le64_to_cpu(counters->tx_multicast64), + le32_to_cpu(counters->tx_pause_on), + le32_to_cpu(counters->tx_pause_off), + le32_to_cpu(counters->tx_pause_all), + le32_to_cpu(counters->tx_deferred), + le32_to_cpu(counters->tx_late_collision), + le32_to_cpu(counters->tx_all_collision), + le32_to_cpu(counters->tx_aborted32), + le32_to_cpu(counters->align_errors32), + le32_to_cpu(counters->rx_frame_too_long), + le32_to_cpu(counters->rx_runt), + le32_to_cpu(counters->rx_pause_on), + le32_to_cpu(counters->rx_pause_off), + le32_to_cpu(counters->rx_pause_all), + le32_to_cpu(counters->rx_unknown_opcode), + le32_to_cpu(counters->rx_mac_error), + le32_to_cpu(counters->tx_underrun32), + le32_to_cpu(counters->rx_mac_missed), + le32_to_cpu(counters->rx_tcam_dropped), + le32_to_cpu(counters->tdu), + le32_to_cpu(counters->rdu) ); len += snprintf(page + len, count - len, "\n"); -out: +out_unlock: + rtnl_unlock(); + *eof = 1; return len; } @@ -1492,14 +2071,14 @@ static int proc_get_registers(char *page, char **start, u8 byte_rd; struct rtl8125_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - unsigned long flags; int len = 0; len += snprintf(page + len, count - len, "\nDump MAC Registers\n" "Offset\tValue\n------\t-----\n"); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + for (n = 0; n < max;) { len += snprintf(page + len, count - len, "\n0x%02x:\t", @@ -1512,7 +2091,8 @@ static int proc_get_registers(char *page, char **start, byte_rd); } } - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); len += snprintf(page + len, count - len, "\n"); @@ -1528,14 +2108,14 @@ static int proc_get_pcie_phy(char *page, char **start, int i, n, max = R8125_EPHY_REGS_SIZE/2; u16 word_rd; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; int len = 0; len += snprintf(page + len, count - len, "\nDump PCIE PHY\n" "Offset\tValue\n------\t-----\n"); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + for (n = 0; n < max;) { len += snprintf(page + len, count - len, "\n0x%02x:\t", @@ -1548,7 +2128,8 @@ static int proc_get_pcie_phy(char *page, char **start, word_rd); } } - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); len += snprintf(page + len, count - len, "\n"); @@ -1564,14 +2145,14 @@ static int proc_get_eth_phy(char *page, char **start, int i, n, max = R8125_PHY_REGS_SIZE/2; u16 word_rd; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; int len = 0; len += snprintf(page + len, count - len, "\nDump Ethernet PHY\n" "Offset\tValue\n------\t-----\n"); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + len += snprintf(page + len, count - len, "\n####################page 0##################\n"); rtl8125_mdio_write(tp, 0x1f, 0x0000); @@ -1587,7 +2168,8 @@ static int proc_get_eth_phy(char *page, char **start, word_rd); } } - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); len += snprintf(page + len, count - len, "\n"); @@ -1603,14 +2185,14 @@ static int proc_get_extended_registers(char *page, char **start, int i, n, max = R8125_ERI_REGS_SIZE; u32 dword_rd; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; int len = 0; len += snprintf(page + len, count - len, "\nDump Extended Registers\n" "Offset\tValue\n------\t-----\n"); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + for (n = 0; n < max;) { len += snprintf(page + len, count - len, "\n0x%02x:\t", @@ -1623,10 +2205,11 @@ static int proc_get_extended_registers(char *page, char **start, dword_rd); } } - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); len += snprintf(page + len, count - len, "\n"); -//out: + *eof = 1; return len; } @@ -1639,14 +2222,14 @@ static int proc_get_pci_registers(char *page, char **start, int i, n, max = R8125_PCI_REGS_SIZE; u32 dword_rd; struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; int len = 0; len += snprintf(page + len, count - len, "\nDump PCI Registers\n" "Offset\tValue\n------\t-----\n"); - spin_lock_irqsave(&tp->lock, flags); + rtnl_lock(); + for (n = 0; n < max;) { len += snprintf(page + len, count - len, "\n0x%03x:\t", @@ -1672,7 +2255,64 @@ static int proc_get_pci_registers(char *page, char **start, "\n0x%03x:\t%08x ", n, dword_rd); - spin_unlock_irqrestore(&tp->lock, flags); + + rtnl_unlock(); + + len += snprintf(page + len, count - len, "\n"); + + *eof = 1; + return len; +} + +static int proc_get_temperature(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct rtl8125_private *tp = netdev_priv(dev); + u16 ts_digout, tj, fah; + int len = 0; + + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_7: + len += snprintf(page + len, count - len, + "\nChip Temperature\n"); + break; + default: + len += snprintf(page + len, count - len, + "\nThis Chip Does Not Support Dump Temperature\n"); + break; + } + + rtnl_lock(); + ts_digout = rtl8125_read_thermal_sensor(tp); + rtnl_unlock(); + + +//Fix a silly bug here * (9/5) :) +// tj = ts_digout / 2; + if (ts_digout <= 512) { + tj = ts_digout / 2; + len += snprintf(page + len, count - len, + "Cel:%d\n", + tj); + fah = tj * 9/5 + 32; + len += snprintf(page + len, count - len, + "Fah:%d\n", + fah); + + } else { + tj = (512 - ((ts_digout / 2) - 512)) / 2; + len += snprintf(page + len, count - len, + "Cel:-%d\n", + tj); + fah = tj * 9/5 + 32; + len += snprintf(page + len, count - len, + "Fah:-%d\n", + fah); + } len += snprintf(page + len, count - len, "\n"); @@ -1742,6 +2382,7 @@ static const struct rtl8125_proc_file rtl8125_proc_files[] = { { "eth_phy", &proc_get_eth_phy }, { "ext_regs", &proc_get_extended_registers }, { "pci_regs", &proc_get_pci_registers }, + { "temp", &proc_get_temperature }, { "", NULL } }; @@ -1909,8 +2550,8 @@ static void rtl8125_mdio_real_write_phy_ocp(struct rtl8125_private *tp, } static void mdio_real_write(struct rtl8125_private *tp, - u32 RegAddr, - u32 value) + u16 RegAddr, + u16 value) { if (RegAddr == 0x1F) { tp->cur_page = value; @@ -1920,8 +2561,8 @@ static void mdio_real_write(struct rtl8125_private *tp, } void rtl8125_mdio_write(struct rtl8125_private *tp, - u32 RegAddr, - u32 value) + u16 RegAddr, + u16 value) { if (tp->rtk_enable_diag) return; @@ -1999,13 +2640,13 @@ static u32 rtl8125_mdio_real_read_phy_ocp(struct rtl8125_private *tp, } static u32 mdio_real_read(struct rtl8125_private *tp, - u32 RegAddr) + u16 RegAddr) { return rtl8125_mdio_real_read_phy_ocp(tp, tp->cur_page, RegAddr); } u32 rtl8125_mdio_read(struct rtl8125_private *tp, - u32 RegAddr) + u16 RegAddr) { if (tp->rtk_enable_diag) return 0xffffffff; @@ -2096,7 +2737,7 @@ void rtl8125_mac_ocp_write(struct rtl8125_private *tp, u16 reg_addr, u16 value) RTL_W32(tp, MACOCP, data32); } -u16 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr) +u32 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr) { u32 data32; u16 data16 = 0; @@ -2114,6 +2755,23 @@ u16 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr) return data16; } +#ifdef ENABLE_USE_FIRMWARE_FILE +static void mac_mcu_write(struct rtl8125_private *tp, u16 reg, u16 value) +{ + if (reg == 0x1f) { + tp->ocp_base = value << 4; + return; + } + + rtl8125_mac_ocp_write(tp, tp->ocp_base + reg, value); +} + +static u32 mac_mcu_read(struct rtl8125_private *tp, u16 reg) +{ + return rtl8125_mac_ocp_read(tp, tp->ocp_base + reg); +} +#endif + static void ClearAndSetMcuAccessRegBit( struct rtl8125_private *tp, @@ -2203,6 +2861,8 @@ void rtl8125_oob_mutex_lock(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: default: ocp_reg_mutex_oob = 0x110; ocp_reg_mutex_ib = 0x114; @@ -2252,6 +2912,8 @@ void rtl8125_oob_mutex_unlock(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: default: ocp_reg_mutex_oob = 0x110; ocp_reg_mutex_ib = 0x114; @@ -2747,6 +3409,8 @@ rtl8125_enable_rxdvgate(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) | BIT_3); mdelay(2); break; @@ -2763,6 +3427,8 @@ rtl8125_disable_rxdvgate(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) & ~BIT_3); mdelay(2); break; @@ -2821,34 +3487,29 @@ rtl8125_is_in_phy_disable_mode(struct net_device *dev) return in_phy_disable_mode; } -static void -rtl8125_enable_phy_disable_mode(struct net_device *dev) +static bool +rtl8125_stop_all_request(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); + int i; - switch (tp->HwSuppCheckPhyDisableModeVer) { - case 3: - RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) | BIT_5); - break; - } - - dprintk("enable phy disable mode.\n"); -} + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); -static void -rtl8125_disable_phy_disable_mode(struct net_device *dev) -{ - struct rtl8125_private *tp = netdev_priv(dev); + switch (tp->mcfg) { + case CFG_METHOD_2: + case CFG_METHOD_3: + case CFG_METHOD_6: + for (i = 0; i < 20; i++) { + udelay(10); + if (!(RTL_R8(tp, ChipCmd) & StopReq)) break; + } - switch (tp->HwSuppCheckPhyDisableModeVer) { - case 3: - RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) & ~BIT_5); + if (i == 20) + return 0; break; } - mdelay(1); - - dprintk("disable phy disable mode.\n"); + return 1; } void @@ -2857,16 +3518,25 @@ rtl8125_wait_txrx_fifo_empty(struct net_device *dev) struct rtl8125_private *tp = netdev_priv(dev); int i; + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_7: + rtl8125_stop_all_request(dev); + break; + } + switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: for (i = 0; i < 3000; i++) { udelay(50); if ((RTL_R8(tp, MCUCmd_reg) & (Txfifo_empty | Rxfifo_empty)) == (Txfifo_empty | Rxfifo_empty)) break; - } break; } @@ -2874,11 +3544,11 @@ rtl8125_wait_txrx_fifo_empty(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: for (i = 0; i < 3000; i++) { udelay(50); if ((RTL_R16(tp, IntrMitigate) & (BIT_0 | BIT_1 | BIT_8)) == (BIT_0 | BIT_1 | BIT_8)) break; - } break; } @@ -2904,8 +3574,26 @@ rtl8125_disable_dash2_interrupt(struct rtl8125_private *tp) if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) { RTL_CMAC_W8(tp, CMAC_IBIMR0, 0); } -} +} +#endif + +void +rtl8125_enable_hw_linkchg_interrupt(struct rtl8125_private *tp) +{ + switch (tp->HwCurrIsrVer) { + case 2: + RTL_W32(tp, IMR_V2_SET_REG_8125, ISRIMR_V2_LINKCHG); + break; + case 1: + RTL_W32(tp, tp->imr_reg[0], LinkChg | RTL_R32(tp, tp->imr_reg[0])); + break; + } + +#ifdef ENABLE_DASH_SUPPORT + if (tp->DASH) + rtl8125_enable_dash2_interrupt(tp); #endif +} static inline void rtl8125_enable_hw_interrupt(struct rtl8125_private *tp) @@ -2914,7 +3602,7 @@ rtl8125_enable_hw_interrupt(struct rtl8125_private *tp) case 2: RTL_W32(tp, IMR_V2_SET_REG_8125, tp->intr_mask); break; - case 1: { + case 1: RTL_W32(tp, tp->imr_reg[0], tp->intr_mask); if (R8125_MULTI_RX_Q(tp)) { @@ -2922,7 +3610,7 @@ rtl8125_enable_hw_interrupt(struct rtl8125_private *tp) for (i=1; inum_rx_rings; i++) RTL_W16(tp, tp->imr_reg[i], other_q_intr_mask); } - } + break; } #ifdef ENABLE_DASH_SUPPORT @@ -3025,17 +3713,11 @@ rtl8125_nic_reset(struct net_device *dev) rtl8125_enable_rxdvgate(dev); + rtl8125_stop_all_request(dev); + rtl8125_wait_txrx_fifo_empty(dev); - switch (tp->mcfg) { - case CFG_METHOD_2: - case CFG_METHOD_3: - case CFG_METHOD_4: - case CFG_METHOD_5: - default: - mdelay(2); - break; - } + mdelay(2); /* Soft reset the chip. */ RTL_W8(tp, ChipCmd, CmdReset); @@ -3074,6 +3756,8 @@ rtl8125_hw_clear_timer_int(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W32(tp, TIMER_INT0_8125, 0x0000); RTL_W32(tp, TIMER_INT1_8125, 0x0000); RTL_W32(tp, TIMER_INT2_8125, 0x0000); @@ -3162,11 +3846,26 @@ rtl8125_xmii_link_ok(struct net_device *dev) return retval; } +static int +rtl8125_wait_phy_reset_complete(struct rtl8125_private *tp) +{ + int i, val; + + for (i = 0; i < 2500; i++) { + val = rtl8125_mdio_read(tp, MII_BMCR) & BMCR_RESET; + if (!val) + return 0; + + mdelay(1); + } + + return -1; +} + static void rtl8125_xmii_reset_enable(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - int i, val = 0; if (rtl8125_is_in_phy_disable_mode(dev)) { return; @@ -3181,15 +3880,7 @@ rtl8125_xmii_reset_enable(struct net_device *dev) mdio_direct_write_phy_ocp(tp, 0xA5D4, mdio_direct_read_phy_ocp(tp, 0xA5D4) & ~(RTK_ADVERTISE_2500FULL)); rtl8125_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); - for (i = 0; i < 2500; i++) { - val = rtl8125_mdio_read(tp, MII_BMCR) & BMCR_RESET; - - if (!val) { - return; - } - - mdelay(1); - } + if (rtl8125_wait_phy_reset_complete(tp) == 0) return; if (netif_msg_link(tp)) printk(KERN_ERR "%s: PHY reset failed.\n", dev->name); @@ -3200,7 +3891,7 @@ rtl8125_init_ring_indexes(struct rtl8125_private *tp) { int i; - for (i = 0; i < tp->num_tx_rings; i++) { + for (i = 0; i < tp->HwSuppNumTxQueues; i++) { struct rtl8125_tx_ring *ring = &tp->tx_ring[i]; ring->dirty_tx = ring->cur_tx = 0; ring->NextHwDesCloPtr = 0; @@ -3209,7 +3900,7 @@ rtl8125_init_ring_indexes(struct rtl8125_private *tp) ring->priv = tp; } - for (i = 0; i < tp->num_rx_rings; i++) { + for (i = 0; i < tp->HwSuppNumRxQueues; i++) { struct rtl8125_rx_ring *ring = &tp->rx_ring[i]; ring->dirty_rx = ring->cur_rx = 0; ring->index = i; @@ -3241,6 +3932,8 @@ rtl8125_issue_offset_99_event(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xE09A, rtl8125_mac_ocp_read(tp, 0xE09A) | BIT_0); break; } @@ -3272,11 +3965,13 @@ static int rtl8125_enable_eee_plus(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xE080, rtl8125_mac_ocp_read(tp, 0xE080)|BIT_1); break; default: -// dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support EEEPlus\n"); +// dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support EEEPlus\n"); ret = -EOPNOTSUPP; break; } @@ -3294,11 +3989,13 @@ static int rtl8125_disable_eee_plus(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xE080, rtl8125_mac_ocp_read(tp, 0xE080)&~BIT_1); break; default: -// dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support EEEPlus\n"); +// dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support EEEPlus\n"); ret = -EOPNOTSUPP; break; } @@ -3307,96 +4004,140 @@ static int rtl8125_disable_eee_plus(struct rtl8125_private *tp) } static void -rtl8125_wakeup_all_tx_queue(struct net_device *dev) +rtl8125_link_on_patch(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - int i; - for (i=0; inum_tx_rings; i++) - netif_wake_subqueue(dev, i); -} + rtl8125_hw_config(dev); -static void -rtl8125_stop_all_tx_queue(struct net_device *dev) -{ - struct rtl8125_private *tp = netdev_priv(dev); - int i; + if ((tp->mcfg == CFG_METHOD_2) && + netif_running(dev)) { + if (RTL_R16(tp, PHYstatus)&FullDup) + RTL_W32(tp, TxConfig, (RTL_R32(tp, TxConfig) | (BIT_24 | BIT_25)) & ~BIT_19); + else + RTL_W32(tp, TxConfig, (RTL_R32(tp, TxConfig) | BIT_25) & ~(BIT_19 | BIT_24)); + } + + if ((tp->mcfg == CFG_METHOD_2 || + tp->mcfg == CFG_METHOD_3 || + tp->mcfg == CFG_METHOD_4 || + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) && + (RTL_R8(tp, PHYstatus) & _10bps)) + rtl8125_enable_eee_plus(tp); + + rtl8125_hw_start(dev); - for (i=0; inum_tx_rings; i++) - netif_stop_subqueue(dev, i); + netif_carrier_on(dev); + + netif_tx_wake_all_queues(dev); + + tp->phy_reg_aner = rtl8125_mdio_read(tp, MII_EXPANSION); + tp->phy_reg_anlpar = rtl8125_mdio_read(tp, MII_LPA); + tp->phy_reg_gbsr = rtl8125_mdio_read(tp, MII_STAT1000); + tp->phy_reg_status_2500 = mdio_direct_read_phy_ocp(tp, 0xA5D6); } static void -rtl8125_check_link_status(struct net_device *dev) +rtl8125_link_down_patch(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - int link_status_on; - link_status_on = tp->link_ok(dev); + tp->phy_reg_aner = 0; + tp->phy_reg_anlpar = 0; + tp->phy_reg_gbsr = 0; + tp->phy_reg_status_2500 = 0; + + if (tp->mcfg == CFG_METHOD_2 || + tp->mcfg == CFG_METHOD_3 || + tp->mcfg == CFG_METHOD_4 || + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) + rtl8125_disable_eee_plus(tp); + + netif_tx_stop_all_queues(dev); - if (netif_carrier_ok(dev) != link_status_on) { - if (link_status_on) { - rtl8125_hw_config(dev); + netif_carrier_off(dev); - if ((tp->mcfg == CFG_METHOD_2) && - netif_running(dev)) { - if (RTL_R16(tp, PHYstatus)&FullDup) - RTL_W32(tp, TxConfig, (RTL_R32(tp, TxConfig) | (BIT_24 | BIT_25)) & ~BIT_19); - else - RTL_W32(tp, TxConfig, (RTL_R32(tp, TxConfig) | BIT_25) & ~(BIT_19 | BIT_24)); - } + rtl8125_hw_reset(dev); - if ((tp->mcfg == CFG_METHOD_2 || - tp->mcfg == CFG_METHOD_3 || - tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) && - (RTL_R8(tp, PHYstatus) & _10bps)) - rtl8125_enable_eee_plus(tp); + rtl8125_tx_clear(tp); - rtl8125_hw_start(dev); + rtl8125_rx_clear(tp); - netif_carrier_on(dev); + rtl8125_init_ring(dev); - rtl8125_wakeup_all_tx_queue(dev); + rtl8125_enable_hw_linkchg_interrupt(tp); - rtl8125_mdio_write(tp, 0x1F, 0x0000); - tp->phy_reg_anlpar = rtl8125_mdio_read(tp, MII_LPA); + //rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); - if (netif_msg_ifup(tp)) - printk(KERN_INFO PFX "%s: link up\n", dev->name); - } else { - if (netif_msg_ifdown(tp)) - printk(KERN_INFO PFX "%s: link down\n", dev->name); +#ifdef ENABLE_DASH_SUPPORT + if (tp->DASH) { + NICChkTypeEnableDashInterrupt(tp); + } +#endif +} - tp->phy_reg_anlpar = 0; +static void +_rtl8125_check_link_status(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); - if (tp->mcfg == CFG_METHOD_2 || - tp->mcfg == CFG_METHOD_3 || - tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) - rtl8125_disable_eee_plus(tp); + if (tp->link_ok(dev)) { + rtl8125_link_on_patch(dev); - rtl8125_stop_all_tx_queue(dev); + if (netif_msg_ifup(tp)) + printk(KERN_INFO PFX "%s: link up\n", dev->name); + } else { + if (netif_msg_ifdown(tp)) + printk(KERN_INFO PFX "%s: link down\n", dev->name); - netif_carrier_off(dev); + rtl8125_link_down_patch(dev); + } +} - rtl8125_hw_reset(dev); +static void +rtl8125_check_link_status(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); - rtl8125_tx_clear(tp); + _rtl8125_check_link_status(dev); - rtl8125_rx_clear(tp); + tp->resume_not_chg_speed = 0; +} - rtl8125_init_ring(dev); +static void +rtl8125_link_option_giga(u8 *aut, + u32 *spd, + u8 *dup, + u32 *adv) +{ + if ((*spd != SPEED_1000) && + (*spd != SPEED_100) && + (*spd != SPEED_10)) + *spd = SPEED_1000; - rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); + if ((*dup != DUPLEX_FULL) && (*dup != DUPLEX_HALF)) + *dup = DUPLEX_FULL; -#ifdef ENABLE_DASH_SUPPORT - if (tp->DASH) { - NICChkTypeEnableDashInterrupt(tp); - } -#endif - } - } + if ((*aut != AUTONEG_ENABLE) && (*aut != AUTONEG_DISABLE)) + *aut = AUTONEG_ENABLE; + + *adv &= (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); + if (*adv == 0) + *adv = (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); } static void @@ -3442,7 +4183,9 @@ rtl8125_enable_ocp_phy_power_saving(struct net_device *dev) if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) { val = mdio_direct_read_phy_ocp(tp, 0xC416); if (val != 0x0050) { rtl8125_set_phy_mcu_patch_request(tp); @@ -3463,7 +4206,9 @@ rtl8125_disable_ocp_phy_power_saving(struct net_device *dev) if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) { val = mdio_direct_read_phy_ocp(tp, 0xC416); if (val != 0x0500) { rtl8125_set_phy_mcu_patch_request(tp); @@ -3495,6 +4240,8 @@ rtl8125_disable_pci_offset_99(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xE032, rtl8125_mac_ocp_read(tp, 0xE032) & ~(BIT_0 | BIT_1)); break; } @@ -3504,6 +4251,8 @@ rtl8125_disable_pci_offset_99(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_csi_fun0_write_byte(tp, 0x99, 0x00); break; } @@ -3519,6 +4268,8 @@ rtl8125_enable_pci_offset_99(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_csi_fun0_write_byte(tp, 0x99, tp->org_pci_offset_99); break; } @@ -3528,11 +4279,13 @@ rtl8125_enable_pci_offset_99(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: csi_tmp = rtl8125_mac_ocp_read(tp, 0xE032); csi_tmp &= ~(BIT_0 | BIT_1); - if (!(tp->org_pci_offset_99 & (BIT_5 | BIT_6))) + if (tp->org_pci_offset_99 & (BIT_5 | BIT_6)) csi_tmp |= BIT_1; - if (!(tp->org_pci_offset_99 & BIT_2)) + if (tp->org_pci_offset_99 & BIT_2) csi_tmp |= BIT_0; rtl8125_mac_ocp_write(tp, 0xE032, csi_tmp); break; @@ -3549,6 +4302,8 @@ rtl8125_init_pci_offset_99(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xCDD0, 0x9003); csi_tmp = rtl8125_mac_ocp_read(tp, 0xE034); csi_tmp |= (BIT_15 | BIT_14); @@ -3587,6 +4342,8 @@ rtl8125_disable_pci_offset_180(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: csi_tmp = rtl8125_mac_ocp_read(tp, 0xE092); csi_tmp &= 0xFF00; rtl8125_mac_ocp_write(tp, 0xE092, csi_tmp); @@ -3604,6 +4361,8 @@ rtl8125_enable_pci_offset_180(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: csi_tmp = rtl8125_mac_ocp_read(tp, 0xE094); csi_tmp &= 0x00FF; rtl8125_mac_ocp_write(tp, 0xE094, csi_tmp); @@ -3615,6 +4374,8 @@ rtl8125_enable_pci_offset_180(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: csi_tmp = rtl8125_mac_ocp_read(tp, 0xE092); csi_tmp &= 0xFF00; csi_tmp |= BIT_2; @@ -3642,23 +4403,21 @@ rtl8125_set_pci_99_180_exit_driver_para(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: - rtl8125_issue_offset_99_event(tp); - break; - } - - switch (tp->mcfg) { - case CFG_METHOD_2: - case CFG_METHOD_3: - case CFG_METHOD_4: - case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: + if (tp->org_pci_offset_99 & BIT_2) + rtl8125_issue_offset_99_event(tp); rtl8125_disable_pci_offset_99(tp); break; } + switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_disable_pci_offset_180(tp); break; } @@ -3690,6 +4449,26 @@ rtl8125_disable_exit_l1_mask(struct rtl8125_private *tp) ClearMcuAccessRegBit(tp, 0xC0AC, (BIT_7 | BIT_8 | BIT_9 | BIT_10 | BIT_11 | BIT_12)); } +static void +rtl8125_enable_extend_tally_couter(struct rtl8125_private *tp) +{ + switch (tp->HwSuppExtendTallyCounterVer) { + case 1: + SetMcuAccessRegBit(tp, 0xEA84, (BIT_1 | BIT_0)); + break; + } +} + +static void +rtl8125_disable_extend_tally_couter(struct rtl8125_private *tp) +{ + switch (tp->HwSuppExtendTallyCounterVer) { + case 1: + ClearMcuAccessRegBit(tp, 0xEA84, (BIT_1 | BIT_0)); + break; + } +} + static void rtl8125_hw_d3_para(struct net_device *dev) { @@ -3702,6 +4481,8 @@ rtl8125_hw_d3_para(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W8(tp, 0xF1, RTL_R8(tp, 0xF1) & ~BIT_7); rtl8125_enable_cfg9346_write(tp); RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~BIT_7); @@ -3721,6 +4502,8 @@ rtl8125_hw_d3_para(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xEA18, 0x0064); break; } @@ -3731,10 +4514,14 @@ rtl8125_hw_d3_para(struct net_device *dev) if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) rtl8125_disable_ocp_phy_power_saving(dev); rtl8125_disable_rxdvgate(dev); + + rtl8125_disable_extend_tally_couter(tp); } static void @@ -3760,6 +4547,32 @@ rtl8125_disable_magic_packet(struct net_device *dev) } } +static void +rtl8125_enable_linkchg_wakeup(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + switch (tp->HwSuppLinkChgWakeUpVer) { + case 3: + RTL_W8(tp, Config3, RTL_R8(tp, Config3) | LinkUp); + ClearAndSetMcuAccessRegBit(tp, 0xE0C6, (BIT_5 | BIT_3 | BIT_2), (BIT_4 | BIT_1 | BIT_0)); + break; + } +} + +static void +rtl8125_disable_linkchg_wakeup(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + switch (tp->HwSuppLinkChgWakeUpVer) { + case 3: + RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~LinkUp); + ClearMcuAccessRegBit(tp, 0xE0C6, (BIT_5 | BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0)); + break; + } +} + #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) static u32 @@ -3769,6 +4582,9 @@ rtl8125_get_hw_wol(struct rtl8125_private *tp) u32 csi_tmp; u32 wol_opts = 0; + if (disable_pm_support) + goto out; + options = RTL_R8(tp, Config1); if (!(options & PMEnable)) goto out; @@ -3797,6 +4613,41 @@ rtl8125_get_hw_wol(struct rtl8125_private *tp) return wol_opts; } +static void +rtl8125_enable_d0_speedup(struct rtl8125_private *tp) +{ + if (FALSE == HW_SUPPORT_D0_SPEED_UP(tp)) return; + if (tp->D0SpeedUpSpeed == D0_SPEED_UP_SPEED_DISABLE) return; + + if (tp->HwSuppD0SpeedUpVer == 1) { + u16 mac_ocp_data; + + RTL_W8(tp, 0xD0, RTL_R8(tp, 0xD0) | BIT_3); + + //speed up speed + mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xE10A); + mac_ocp_data &= ~(BIT_10 | BIT_9 | BIT_8 | BIT_7); + if (tp->D0SpeedUpSpeed == D0_SPEED_UP_SPEED_2500) { + mac_ocp_data |= BIT_7; + } + rtl8125_mac_ocp_write(tp, 0xE10A, mac_ocp_data); + + //speed up flowcontrol + mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xE860); + mac_ocp_data |= (BIT_15 | BIT_14); + rtl8125_mac_ocp_write(tp, 0xE860, mac_ocp_data); + } +} + +static void +rtl8125_disable_d0_speedup(struct rtl8125_private *tp) +{ + if (FALSE == HW_SUPPORT_D0_SPEED_UP(tp)) return; + + if (tp->HwSuppD0SpeedUpVer == 1) + RTL_W8(tp, 0xD0, RTL_R8(tp, 0xD0) & ~BIT_7); +} + static void rtl8125_set_hw_wol(struct net_device *dev, u32 wolopts) { @@ -3827,114 +4678,228 @@ rtl8125_set_hw_wol(struct net_device *dev, u32 wolopts) break; } - rtl8125_enable_cfg9346_write(tp); + rtl8125_enable_cfg9346_write(tp); + + for (i = 0; i < tmp; i++) { + u8 options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; + if (wolopts & cfg[i].opt) + options |= cfg[i].mask; + RTL_W8(tp, cfg[i].reg, options); + } + + switch (tp->HwSuppLinkChgWakeUpVer) { + case 3: + if (wolopts & WAKE_PHY) + rtl8125_enable_linkchg_wakeup(dev); + else + rtl8125_disable_linkchg_wakeup(dev); + break; + } + + rtl8125_disable_cfg9346_write(tp); +} + +static void +rtl8125_phy_restart_nway(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + if (rtl8125_is_in_phy_disable_mode(dev)) return; + + rtl8125_mdio_write(tp, 0x1F, 0x0000); + rtl8125_mdio_write(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); +} + +static void +rtl8125_phy_setup_force_mode(struct net_device *dev, u32 speed, u8 duplex) +{ + struct rtl8125_private *tp = netdev_priv(dev); + u16 bmcr_true_force = 0; + + if (rtl8125_is_in_phy_disable_mode(dev)) return; + + if ((speed == SPEED_10) && (duplex == DUPLEX_HALF)) { + bmcr_true_force = BMCR_SPEED10; + } else if ((speed == SPEED_10) && (duplex == DUPLEX_FULL)) { + bmcr_true_force = BMCR_SPEED10 | BMCR_FULLDPLX; + } else if ((speed == SPEED_100) && (duplex == DUPLEX_HALF)) { + bmcr_true_force = BMCR_SPEED100; + } else if ((speed == SPEED_100) && (duplex == DUPLEX_FULL)) { + bmcr_true_force = BMCR_SPEED100 | BMCR_FULLDPLX; + } else { + netif_err(tp, drv, dev, "Failed to set phy force mode!\n"); + return; + } + + rtl8125_mdio_write(tp, 0x1F, 0x0000); + rtl8125_mdio_write(tp, MII_BMCR, bmcr_true_force); +} + +//Backport to 2.6.34 + +#if !defined(__VMKLNX__) +static void +rtl8125_set_pci_pme(struct rtl8125_private *tp, int set) +{ + struct pci_dev *pdev = tp->pci_dev; + u16 pmc; + + if (!pdev->pm_cap) + return; + + pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &pmc); + pmc |= PCI_PM_CTRL_PME_STATUS; + if (set) + pmc |= PCI_PM_CTRL_PME_ENABLE; + else + pmc &= ~PCI_PM_CTRL_PME_ENABLE; + pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, pmc); +} +#endif //#if !defined(__VMKLNX__) + +static void +rtl8125_set_wol_link_speed(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + int auto_nego; + int giga_ctrl; + int ctrl_2500; + u32 adv; + u16 anlpar; + u16 gbsr; + u16 status_2500; + u16 aner; + + if (tp->autoneg != AUTONEG_ENABLE) + goto exit; + + rtl8125_mdio_write(tp, 0x1F, 0x0000); + + auto_nego = rtl8125_mdio_read(tp, MII_ADVERTISE); + auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL + | ADVERTISE_100HALF | ADVERTISE_100FULL); + + giga_ctrl = rtl8125_mdio_read(tp, MII_CTRL1000); + giga_ctrl &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + + ctrl_2500 = mdio_direct_read_phy_ocp(tp, 0xA5D4); + ctrl_2500 &= ~(RTK_ADVERTISE_2500FULL); + + aner = anlpar = gbsr = status_2500 = 0; + if (tp->link_ok(dev)) { + aner = rtl8125_mdio_read(tp, MII_EXPANSION); + anlpar = rtl8125_mdio_read(tp, MII_LPA); + gbsr = rtl8125_mdio_read(tp, MII_STAT1000); + status_2500 = mdio_direct_read_phy_ocp(tp, 0xA5D6); + } else { + if (netif_running(dev)) { + aner = tp->phy_reg_aner; + anlpar = tp->phy_reg_anlpar; + gbsr = tp->phy_reg_gbsr; + status_2500 = tp->phy_reg_status_2500; + } + } + + if ((aner | anlpar | gbsr | status_2500) == 0) { + int auto_nego_tmp = 0; + adv = tp->advertising; + if ((adv & ADVERTISED_10baseT_Half) && (anlpar & LPA_10HALF)) + auto_nego_tmp |= ADVERTISE_10HALF; + if ((adv & ADVERTISED_10baseT_Full) && (anlpar & LPA_10FULL)) + auto_nego_tmp |= ADVERTISE_10FULL; + if ((adv & ADVERTISED_100baseT_Half) && (anlpar & LPA_100HALF)) + auto_nego_tmp |= ADVERTISE_100HALF; + if ((adv & ADVERTISED_100baseT_Full) && (anlpar & LPA_100FULL)) + auto_nego_tmp |= ADVERTISE_100FULL; + + if (auto_nego_tmp == 0) goto exit; + + auto_nego |= auto_nego_tmp; + goto skip_check_lpa; + } + if (!(aner & EXPANSION_NWAY)) goto exit; + + adv = tp->advertising; + if ((adv & ADVERTISED_10baseT_Half) && (anlpar & LPA_10HALF)) + auto_nego |= ADVERTISE_10HALF; + else if ((adv & ADVERTISED_10baseT_Full) && (anlpar & LPA_10FULL)) + auto_nego |= ADVERTISE_10FULL; + else if ((adv & ADVERTISED_100baseT_Half) && (anlpar & LPA_100HALF)) + auto_nego |= ADVERTISE_100HALF; + else if ((adv & ADVERTISED_100baseT_Full) && (anlpar & LPA_100FULL)) + auto_nego |= ADVERTISE_100FULL; + else if (adv & ADVERTISED_1000baseT_Half && (gbsr & LPA_1000HALF)) + giga_ctrl |= ADVERTISE_1000HALF; + else if (adv & ADVERTISED_1000baseT_Full && (gbsr & LPA_1000FULL)) + giga_ctrl |= ADVERTISE_1000FULL; + else if (adv & ADVERTISED_2500baseX_Full && (status_2500 & RTK_LPA_ADVERTISE_2500FULL)) + ctrl_2500 |= RTK_ADVERTISE_2500FULL; + else + goto exit; - for (i = 0; i < tmp; i++) { - u8 options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; - if (wolopts & cfg[i].opt) - options |= cfg[i].mask; - RTL_W8(tp, cfg[i].reg, options); - } +skip_check_lpa: + if (tp->DASH) + auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); - rtl8125_disable_cfg9346_write(tp); -} +#ifdef CONFIG_DOWN_SPEED_100 + auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); +#endif -static void -rtl8125_phy_restart_nway(struct net_device *dev) -{ - struct rtl8125_private *tp = netdev_priv(dev); + rtl8125_mdio_write(tp, MII_ADVERTISE, auto_nego); + rtl8125_mdio_write(tp, MII_CTRL1000, giga_ctrl); + mdio_direct_write_phy_ocp(tp, 0xA5D4, ctrl_2500); - if (rtl8125_is_in_phy_disable_mode(dev)) return; + rtl8125_phy_restart_nway(dev); - rtl8125_mdio_write(tp, 0x1F, 0x0000); - rtl8125_mdio_write(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); +exit: + return; } -static void -rtl8125_phy_setup_force_mode(struct net_device *dev, u32 speed, u8 duplex) +static bool +rtl8125_keep_wol_link_speed(struct net_device *dev, u8 from_suspend) { struct rtl8125_private *tp = netdev_priv(dev); - u16 bmcr_true_force = 0; - - if (rtl8125_is_in_phy_disable_mode(dev)) return; - if ((speed == SPEED_10) && (duplex == DUPLEX_HALF)) { - bmcr_true_force = BMCR_SPEED10; - } else if ((speed == SPEED_10) && (duplex == DUPLEX_FULL)) { - bmcr_true_force = BMCR_SPEED10 | BMCR_FULLDPLX; - } else if ((speed == SPEED_100) && (duplex == DUPLEX_HALF)) { - bmcr_true_force = BMCR_SPEED100; - } else if ((speed == SPEED_100) && (duplex == DUPLEX_FULL)) { - bmcr_true_force = BMCR_SPEED100 | BMCR_FULLDPLX; - } else if ((speed == SPEED_1000) && (duplex == DUPLEX_FULL) && - tp->HwSuppGigaForceMode) { - bmcr_true_force = BMCR_SPEED1000 | BMCR_FULLDPLX; - } else { - netif_err(tp, drv, dev, "Failed to set phy force mode!\n"); - return; - } + if ((from_suspend && !tp->link_ok(dev)) || + (!from_suspend && tp->resume_not_chg_speed)) + return 1; - rtl8125_mdio_write(tp, 0x1F, 0x0000); - rtl8125_mdio_write(tp, MII_BMCR, bmcr_true_force); + return 0; } - static void -rtl8125_powerdown_pll(struct net_device *dev) +rtl8125_powerdown_pll(struct net_device *dev, u8 from_suspend) { struct rtl8125_private *tp = netdev_priv(dev); + tp->check_keep_link_speed = 0; if (tp->wol_enabled == WOL_ENABLED || tp->DASH || tp->EnableKCPOffload) { - int auto_nego; - int giga_ctrl; - u16 anlpar; - rtl8125_set_hw_wol(dev, tp->wol_opts); if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) { rtl8125_enable_cfg9346_write(tp); RTL_W8(tp, Config2, RTL_R8(tp, Config2) | PMSTS_En); rtl8125_disable_cfg9346_write(tp); } - rtl8125_mdio_write(tp, 0x1F, 0x0000); - auto_nego = rtl8125_mdio_read(tp, MII_ADVERTISE); - auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL - | ADVERTISE_100HALF | ADVERTISE_100FULL); - - if (netif_running(dev)) - anlpar = tp->phy_reg_anlpar; - else - anlpar = rtl8125_mdio_read(tp, MII_LPA); - -#ifdef CONFIG_DOWN_SPEED_100 - auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); -#else - if (anlpar & (LPA_10HALF | LPA_10FULL)) - auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL); - else - auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); -#endif - - if (tp->DASH) - auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); + /* Enable the PME and clear the status */ + rtl8125_set_pci_pme(tp, 1); - giga_ctrl = rtl8125_mdio_read(tp, MII_CTRL1000) & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); - rtl8125_mdio_write(tp, MII_ADVERTISE, auto_nego); - rtl8125_mdio_write(tp, MII_CTRL1000, giga_ctrl); - if (tp->mcfg == CFG_METHOD_2 || - tp->mcfg == CFG_METHOD_3 || - tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { - int ctrl_2500; + if (rtl8125_keep_wol_link_speed(dev, from_suspend)) { + if (tp->wol_opts & WAKE_PHY) + tp->check_keep_link_speed = 1; + } else { + if (HW_SUPPORT_D0_SPEED_UP(tp)) { + rtl8125_enable_d0_speedup(tp); + tp->check_keep_link_speed = 1; + } - ctrl_2500 = mdio_direct_read_phy_ocp(tp, 0xA5D4); - ctrl_2500 &= ~(RTK_ADVERTISE_2500FULL); - mdio_direct_write_phy_ocp(tp, 0xA5D4, ctrl_2500); + rtl8125_set_wol_link_speed(dev); } - rtl8125_phy_restart_nway(dev); RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) | AcceptBroadcast | AcceptMulticast | AcceptMyPhys); @@ -3946,13 +4911,17 @@ rtl8125_powerdown_pll(struct net_device *dev) rtl8125_phy_power_down(dev); - switch (tp->mcfg) { - case CFG_METHOD_2: - case CFG_METHOD_3: - case CFG_METHOD_4: - case CFG_METHOD_5: - RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~BIT_7); - break; + if (!tp->HwIcVerUnknown) { + switch (tp->mcfg) { + case CFG_METHOD_2: + case CFG_METHOD_3: + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: + RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~BIT_7); + break; + } } switch (tp->mcfg) { @@ -3960,6 +4929,8 @@ rtl8125_powerdown_pll(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) & ~BIT_6); break; } @@ -3974,10 +4945,14 @@ static void rtl8125_powerup_pll(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | BIT_7 | BIT_6); break; } + if (tp->resume_not_chg_speed) return; + rtl8125_phy_power_up(dev); } @@ -3988,27 +4963,21 @@ rtl8125_get_wol(struct net_device *dev, { struct rtl8125_private *tp = netdev_priv(dev); u8 options; - unsigned long flags; wol->wolopts = 0; - if (tp->mcfg == CFG_METHOD_DEFAULT) { + if (tp->mcfg == CFG_METHOD_DEFAULT || disable_pm_support) { wol->supported = 0; return; } else { wol->supported = WAKE_ANY; } - spin_lock_irqsave(&tp->lock, flags); - options = RTL_R8(tp, Config1); if (!(options & PMEnable)) - goto out_unlock; + return; wol->wolopts = tp->wol_opts; - -out_unlock: - spin_unlock_irqrestore(&tp->lock, flags); } static int @@ -4016,20 +4985,15 @@ rtl8125_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; - if (tp->mcfg == CFG_METHOD_DEFAULT) + if (tp->mcfg == CFG_METHOD_DEFAULT || disable_pm_support) return -EOPNOTSUPP; - spin_lock_irqsave(&tp->lock, flags); - tp->wol_opts = wol->wolopts; tp->wol_enabled = (tp->wol_opts) ? WOL_ENABLED : WOL_DISABLED; - spin_unlock_irqrestore(&tp->lock, flags); - - device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); + device_set_wakeup_enable(tp_to_dev(tp), wol->wolopts); return 0; } @@ -4039,12 +5003,17 @@ rtl8125_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct rtl8125_private *tp = netdev_priv(dev); + struct rtl8125_fw *rtl_fw = tp->rtl_fw; strcpy(info->driver, MODULENAME); strcpy(info->version, RTL8125_VERSION); strcpy(info->bus_info, pci_name(tp->pci_dev)); info->regdump_len = R8125_REGS_DUMP_SIZE; info->eedump_len = tp->eeprom_len; + BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version)); + if (rtl_fw) + strlcpy(info->fw_version, rtl_fw->version, + sizeof(info->fw_version)); } static int @@ -4054,6 +5023,20 @@ rtl8125_get_regs_len(struct net_device *dev) } #endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) +static void +rtl8125_set_d0_speedup_speed(struct rtl8125_private *tp) +{ + if (FALSE == HW_SUPPORT_D0_SPEED_UP(tp)) return; + + tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_DISABLE; + if (tp->autoneg == AUTONEG_ENABLE) { + if (tp->speed == SPEED_2500) + tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_2500; + else if(tp->speed == SPEED_1000) + tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_1000; + } +} + static int rtl8125_set_speed_xmii(struct net_device *dev, u8 autoneg, @@ -4107,8 +5090,8 @@ rtl8125_set_speed_xmii(struct net_device *dev, ctrl_2500 |= RTK_ADVERTISE_2500FULL; //flow control - if (dev->mtu <= ETH_DATA_LEN) - auto_nego |= ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM; + if (dev->mtu <= ETH_DATA_LEN && tp->fcpause == rtl8125_fc_full) + auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; tp->phy_auto_nego_reg = auto_nego; tp->phy_1000_ctrl_reg = giga_ctrl; @@ -4123,11 +5106,9 @@ rtl8125_set_speed_xmii(struct net_device *dev, mdelay(20); } else { /*true force*/ - if (speed == SPEED_10 || speed == SPEED_100 || - (speed == SPEED_1000 && duplex == DUPLEX_FULL && - tp->HwSuppGigaForceMode)) { + if (speed == SPEED_10 || speed == SPEED_100) rtl8125_phy_setup_force_mode(dev, speed, duplex); - } else + else goto out; } @@ -4136,6 +5117,8 @@ rtl8125_set_speed_xmii(struct net_device *dev, tp->duplex = duplex; tp->advertising = adv; + rtl8125_set_d0_speedup_speed(tp); + rc = 0; out: return rc; @@ -4151,6 +5134,8 @@ rtl8125_set_speed(struct net_device *dev, struct rtl8125_private *tp = netdev_priv(dev); int ret; + if (tp->resume_not_chg_speed) return 0; + ret = tp->set_speed(dev, autoneg, speed, duplex, adv); return ret; @@ -4166,9 +5151,7 @@ rtl8125_set_settings(struct net_device *dev, #endif ) { - struct rtl8125_private *tp = netdev_priv(dev); int ret; - unsigned long flags; u8 autoneg; u32 speed; u8 duplex; @@ -4189,13 +5172,17 @@ rtl8125_set_settings(struct net_device *dev, cmd->link_modes.supported); ethtool_convert_link_mode_to_legacy_u32(&advertising, cmd->link_modes.advertising); + if (test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + cmd->link_modes.supported)) + supported |= ADVERTISED_2500baseX_Full; + if (test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + cmd->link_modes.advertising)) + advertising |= ADVERTISED_2500baseX_Full; #endif if (advertising & ~supported) return -EINVAL; - spin_lock_irqsave(&tp->lock, flags); ret = rtl8125_set_speed(dev, autoneg, speed, duplex, advertising); - spin_unlock_irqrestore(&tp->lock, flags); return ret; } @@ -4204,17 +5191,14 @@ rtl8125_set_settings(struct net_device *dev, static u32 rtl8125_get_tx_csum(struct net_device *dev) { - struct rtl8125_private *tp = netdev_priv(dev); +// struct rtl8125_private *tp = netdev_priv(dev); u32 ret; - unsigned long flags; - spin_lock_irqsave(&tp->lock, flags); #if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) ret = ((dev->features & NETIF_F_IP_CSUM) != 0); #else ret = ((dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) != 0); #endif //LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) - spin_unlock_irqrestore(&tp->lock, flags); return ret; } @@ -4224,11 +5208,8 @@ rtl8125_get_rx_csum(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); u32 ret; - unsigned long flags; - spin_lock_irqsave(&tp->lock, flags); ret = tp->cp_cmd & RxChkSum; - spin_unlock_irqrestore(&tp->lock, flags); return ret; } @@ -4238,13 +5219,10 @@ rtl8125_set_tx_csum(struct net_device *dev, u32 data) { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; if (tp->mcfg == CFG_METHOD_DEFAULT) return -EOPNOTSUPP; - spin_lock_irqsave(&tp->lock, flags); - #if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) if (data) dev->features |= NETIF_F_IP_CSUM; @@ -4257,8 +5235,6 @@ rtl8125_set_tx_csum(struct net_device *dev, dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); #endif //LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) - spin_unlock_irqrestore(&tp->lock, flags); - return 0; } @@ -4267,13 +5243,10 @@ rtl8125_set_rx_csum(struct net_device *dev, u32 data) { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; if (tp->mcfg == CFG_METHOD_DEFAULT) return -EOPNOTSUPP; - spin_lock_irqsave(&tp->lock, flags); - if (data) tp->cp_cmd |= RxChkSum; else @@ -4281,8 +5254,6 @@ rtl8125_set_rx_csum(struct net_device *dev, RTL_W16(tp, CPlusCmd, tp->cp_cmd); - spin_unlock_irqrestore(&tp->lock, flags); - return 0; } #endif //LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) @@ -4308,9 +5279,6 @@ rtl8125_rx_desc_opts2(struct rtl8125_private *tp, return desc->opts2; } -#ifdef CONFIG_R8125_VLAN - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) static void rtl8125_clear_rx_desc_opts2(struct rtl8125_private *tp, struct RxDesc *desc) @@ -4320,26 +5288,25 @@ rtl8125_clear_rx_desc_opts2(struct rtl8125_private *tp, else desc->opts2 = 0; } -#endif + +#ifdef CONFIG_R8125_VLAN static inline u32 rtl8125_tx_vlan_tag(struct rtl8125_private *tp, struct sk_buff *skb) { - u32 tag; - #if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) - tag = (tp->vlgrp && vlan_tx_tag_present(skb)) ? - TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; + return (tp->vlgrp && vlan_tx_tag_present(skb)) ? + TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; #elif LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) - tag = (vlan_tx_tag_present(skb)) ? - TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; + return (vlan_tx_tag_present(skb)) ? + TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; #else - tag = (skb_vlan_tag_present(skb)) ? - TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00; + return (skb_vlan_tag_present(skb)) ? + TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00; #endif - return tag; + return 0; } #if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) @@ -4349,23 +5316,22 @@ rtl8125_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; - spin_lock_irqsave(&tp->lock, flags); tp->vlgrp = grp; if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) { if (tp->vlgrp) { tp->rtl8125_rx_config |= (EnableInnerVlan | EnableOuterVlan); - RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) | (EnableInnerVlan | EnableOuterVlan)) + RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) | (EnableInnerVlan | EnableOuterVlan)); } else { tp->rtl8125_rx_config &= ~(EnableInnerVlan | EnableOuterVlan); - RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) & ~(EnableInnerVlan | EnableOuterVlan)) + RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) & ~(EnableInnerVlan | EnableOuterVlan)); } } - spin_unlock_irqrestore(&tp->lock, flags); } #endif @@ -4376,16 +5342,13 @@ rtl8125_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; - spin_lock_irqsave(&tp->lock, flags); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) if (tp->vlgrp) tp->vlgrp->vlan_devices[vid] = NULL; #else vlan_group_set_device(tp->vlgrp, vid, NULL); #endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) - spin_unlock_irqrestore(&tp->lock, flags); } #endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) @@ -4439,10 +5402,6 @@ rtl8125_rx_vlan_skb(struct rtl8125_private *tp, static netdev_features_t rtl8125_fix_features(struct net_device *dev, netdev_features_t features) { - struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); if (dev->mtu > MSS_MAX) features &= ~NETIF_F_ALL_TSO; if (dev->mtu > ETH_DATA_LEN) { @@ -4452,7 +5411,6 @@ static netdev_features_t rtl8125_fix_features(struct net_device *dev, #ifndef CONFIG_R8125_VLAN features &= ~NETIF_F_ALL_CSUM; #endif - spin_unlock_irqrestore(&tp->lock, flags); return features; } @@ -4464,15 +5422,21 @@ static int rtl8125_hw_set_features(struct net_device *dev, u32 rx_config; rx_config = RTL_R32(tp, RxConfig); - if (features & NETIF_F_RXALL) + if (features & NETIF_F_RXALL) { + tp->rtl8125_rx_config |= (AcceptErr | AcceptRunt); rx_config |= (AcceptErr | AcceptRunt); - else + } else { + tp->rtl8125_rx_config &= ~(AcceptErr | AcceptRunt); rx_config &= ~(AcceptErr | AcceptRunt); + } - if (dev->features & NETIF_F_HW_VLAN_RX) + if (features & NETIF_F_HW_VLAN_RX) { + tp->rtl8125_rx_config |= (EnableInnerVlan | EnableOuterVlan); rx_config |= (EnableInnerVlan | EnableOuterVlan); - else + } else { + tp->rtl8125_rx_config &= ~(EnableInnerVlan | EnableOuterVlan); rx_config &= ~(EnableInnerVlan | EnableOuterVlan); + } RTL_W32(tp, RxConfig, rx_config); @@ -4490,21 +5454,18 @@ static int rtl8125_hw_set_features(struct net_device *dev, static int rtl8125_set_features(struct net_device *dev, netdev_features_t features) { - struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; - features &= NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX; - spin_lock_irqsave(&tp->lock, flags); - if (features ^ dev->features) - rtl8125_hw_set_features(dev, features); - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_hw_set_features(dev, features); return 0; } #endif +//Backport to 2.6.24 +#if !defined(__VMKLNX__) + static void rtl8125_gset_xmii(struct net_device *dev, #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) struct ethtool_cmd *cmd @@ -4514,12 +5475,17 @@ static void rtl8125_gset_xmii(struct net_device *dev, ) { struct rtl8125_private *tp = netdev_priv(dev); + u16 aner = tp->phy_reg_aner; + u16 anlpar = tp->phy_reg_anlpar; + u16 gbsr = tp->phy_reg_gbsr; + u16 status_2500 = tp->phy_reg_status_2500; + u32 lpa_adv = 0; u16 status; u8 autoneg, duplex; u32 speed = 0; u16 bmcr; u32 supported, advertising; - unsigned long flags; + u8 report_lpa = 0; supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -4532,12 +5498,13 @@ static void rtl8125_gset_xmii(struct net_device *dev, SUPPORTED_Pause | SUPPORTED_Asym_Pause; + if (tp->mcfg == CFG_METHOD_6 || tp->mcfg == CFG_METHOD_7) + supported &= ~SUPPORTED_2500baseX_Full; + advertising = ADVERTISED_TP; - spin_lock_irqsave(&tp->lock, flags); rtl8125_mdio_write(tp, 0x1F, 0x0000); bmcr = rtl8125_mdio_read(tp, MII_BMCR); - spin_unlock_irqrestore(&tp->lock, flags); if (bmcr & BMCR_ANENABLE) { advertising |= ADVERTISED_Autoneg; @@ -4560,8 +5527,10 @@ static void rtl8125_gset_xmii(struct net_device *dev, } status = RTL_R16(tp, PHYstatus); + if (netif_running(dev) && (status & LinkStatus)) + report_lpa = 1; - if (status & LinkStatus) { + if (report_lpa) { /*link on*/ if (status & _2500bpsF) speed = SPEED_2500; @@ -4580,10 +5549,33 @@ static void rtl8125_gset_xmii(struct net_device *dev, duplex = ((status & (_1000bpsF | _2500bpsF)) || (status & FullDup)) ? DUPLEX_FULL : DUPLEX_HALF; + + /*link partner*/ + if (aner & EXPANSION_NWAY) + lpa_adv |= ADVERTISED_Autoneg; + if (anlpar & LPA_10HALF) + lpa_adv |= ADVERTISED_10baseT_Half; + if (anlpar & LPA_10FULL) + lpa_adv |= ADVERTISED_10baseT_Full; + if (anlpar & LPA_100HALF) + lpa_adv |= ADVERTISED_100baseT_Half; + if (anlpar & LPA_100FULL) + lpa_adv |= ADVERTISED_100baseT_Full; + if (anlpar & LPA_PAUSE_CAP) + lpa_adv |= ADVERTISED_Pause; + if (anlpar & LPA_PAUSE_ASYM) + lpa_adv |= ADVERTISED_Asym_Pause; + if (gbsr & LPA_1000HALF) + lpa_adv |= ADVERTISED_1000baseT_Half; + if (gbsr & LPA_1000FULL) + lpa_adv |= ADVERTISED_1000baseT_Full; + if (status_2500 & RTK_LPA_ADVERTISE_2500FULL) + lpa_adv |= ADVERTISED_2500baseX_Full; } else { /*link down*/ speed = SPEED_UNKNOWN; duplex = DUPLEX_UNKNOWN; + lpa_adv = 0; } #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) @@ -4593,17 +5585,50 @@ static void rtl8125_gset_xmii(struct net_device *dev, cmd->speed = speed; cmd->duplex = duplex; cmd->port = PORT_TP; + cmd->lp_advertising = lpa_adv; #else ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, supported); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, advertising); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, + lpa_adv); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) + if (supported & SUPPORTED_2500baseX_Full) { + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, + cmd->link_modes.supported, 0); + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + cmd->link_modes.supported, 1); + } + if (advertising & ADVERTISED_2500baseX_Full) { + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, + cmd->link_modes.advertising, 0); + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + cmd->link_modes.advertising, 1); + } + if (report_lpa) { + if (lpa_adv & ADVERTISED_2500baseX_Full) { + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, + cmd->link_modes.lp_advertising, 0); + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + cmd->link_modes.lp_advertising, 1); + } + if (status_2500 & RTK_LPA_ADVERTISE_5000FULL) + linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, + cmd->link_modes.lp_advertising, 1); + if (status_2500 & RTK_LPA_ADVERTISE_10000FULL) + linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + cmd->link_modes.lp_advertising, 1); + } +#endif cmd->base.autoneg = autoneg; cmd->base.speed = speed; cmd->base.duplex = duplex; cmd->base.port = PORT_TP; #endif } +#endif //#if !defined(__VMKLNX__) + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) static int @@ -4629,14 +5654,12 @@ static void rtl8125_get_regs(struct net_device *dev, struct ethtool_regs *regs, void __iomem *ioaddr = tp->mmio_addr; unsigned int i; u8 *data = p; - unsigned long flags; if (regs->len < R8125_REGS_DUMP_SIZE) return /* -EINVAL */; memset(p, 0, regs->len); - spin_lock_irqsave(&tp->lock, flags); for (i = 0; i < R8125_MAC_REGS_SIZE; i++) *data++ = readb(ioaddr + i); data = (u8*)p + 256; @@ -4659,6 +5682,8 @@ static void rtl8125_get_regs(struct net_device *dev, struct ethtool_regs *regs, case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: default: for (i = 0; i < R8125_ERI_REGS_SIZE; i+=4) { *(u32*)data = rtl8125_eri_read(tp, i , 4, ERIAR_ExGMAC); @@ -4666,7 +5691,43 @@ static void rtl8125_get_regs(struct net_device *dev, struct ethtool_regs *regs, } break; } - spin_unlock_irqrestore(&tp->lock, flags); +} + +static void rtl8125_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + pause->autoneg = (tp->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + if (tp->fcpause == rtl8125_fc_rx_pause) + pause->rx_pause = 1; + else if (tp->fcpause == rtl8125_fc_tx_pause) + pause->tx_pause = 1; + else if (tp->fcpause == rtl8125_fc_full) { + pause->rx_pause = 1; + pause->tx_pause = 1; + } +} + +static int rtl8125_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct rtl8125_private *tp = netdev_priv(dev); + enum rtl8125_fc_mode newfc; + + if (pause->tx_pause || pause->rx_pause) + newfc = rtl8125_fc_full; + else + newfc = rtl8125_fc_none; + + if (tp->fcpause != newfc) { + tp->fcpause = newfc; + + rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); + } + + return 0; + } static u32 @@ -4687,6 +5748,7 @@ rtl8125_set_msglevel(struct net_device *dev, } static const char rtl8125_gstrings[][ETH_GSTRING_LEN] = { + /* legacy */ "tx_packets", "rx_packets", "tx_errors", @@ -4700,6 +5762,34 @@ static const char rtl8125_gstrings[][ETH_GSTRING_LEN] = { "multicast", "tx_aborted", "tx_underrun", + + /* extended */ + "tx_octets", + "rx_octets", + "rx_multicast64", + "tx_unicast64", + "tx_broadcast64", + "tx_multicast64", + "tx_pause_on", + "tx_pause_off", + "tx_pause_all", + "tx_deferred", + "tx_late_collision", + "tx_all_collision", + "tx_aborted32", + "align_errors32", + "rx_frame_too_long", + "rx_runt", + "rx_pause_on", + "rx_pause_off", + "rx_pause_all", + "rx_unknown_opcode", + "rx_mac_error", + "tx_underrun32", + "rx_mac_missed", + "rx_tcam_dropped", + "tdu", + "rdu", }; #endif //#LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) @@ -4731,9 +5821,6 @@ rtl8125_get_ethtool_stats(struct net_device *dev, struct rtl8125_private *tp = netdev_priv(dev); struct rtl8125_counters *counters; dma_addr_t paddr; - u32 cmd; - u32 WaitCnt; - unsigned long flags; ASSERT_RTNL(); @@ -4742,21 +5829,7 @@ rtl8125_get_ethtool_stats(struct net_device *dev, if (!counters) return; - spin_lock_irqsave(&tp->lock, flags); - RTL_W32(tp, CounterAddrHigh, (u64)paddr >> 32); - cmd = (u64)paddr & DMA_BIT_MASK(32); - RTL_W32(tp, CounterAddrLow, cmd); - RTL_W32(tp, CounterAddrLow, cmd | CounterDump); - - WaitCnt = 0; - while (RTL_R32(tp, CounterAddrLow) & CounterDump) { - udelay(10); - - WaitCnt++; - if (WaitCnt > 20) - break; - } - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_dump_tally_counter(tp, paddr); data[0] = le64_to_cpu(counters->tx_packets); data[1] = le64_to_cpu(counters->rx_packets); @@ -4770,7 +5843,34 @@ rtl8125_get_ethtool_stats(struct net_device *dev, data[9] = le64_to_cpu(counters->rx_broadcast); data[10] = le32_to_cpu(counters->rx_multicast); data[11] = le16_to_cpu(counters->tx_aborted); - data[12] = le16_to_cpu(counters->tx_underun); + data[12] = le16_to_cpu(counters->tx_underrun); + + data[13] = le64_to_cpu(counters->tx_octets); + data[14] = le64_to_cpu(counters->rx_octets); + data[15] = le64_to_cpu(counters->rx_multicast64); + data[16] = le64_to_cpu(counters->tx_unicast64); + data[17] = le64_to_cpu(counters->tx_broadcast64); + data[18] = le64_to_cpu(counters->tx_multicast64); + data[19] = le32_to_cpu(counters->tx_pause_on); + data[20] = le32_to_cpu(counters->tx_pause_off); + data[21] = le32_to_cpu(counters->tx_pause_all); + data[22] = le32_to_cpu(counters->tx_deferred); + data[23] = le32_to_cpu(counters->tx_late_collision); + data[24] = le32_to_cpu(counters->tx_all_collision); + data[25] = le32_to_cpu(counters->tx_aborted32); + data[26] = le32_to_cpu(counters->align_errors32); + data[27] = le32_to_cpu(counters->rx_frame_too_long); + data[28] = le32_to_cpu(counters->rx_runt); + data[29] = le32_to_cpu(counters->rx_pause_on); + data[30] = le32_to_cpu(counters->rx_pause_off); + data[31] = le32_to_cpu(counters->rx_pause_all); + data[32] = le32_to_cpu(counters->rx_unknown_opcode); + data[33] = le32_to_cpu(counters->rx_mac_error); + data[34] = le32_to_cpu(counters->tx_underrun32); + data[35] = le32_to_cpu(counters->rx_mac_missed); + data[36] = le32_to_cpu(counters->rx_tcam_dropped); + data[37] = le32_to_cpu(counters->tdu); + data[38] = le32_to_cpu(counters->rdu); } static void @@ -4780,7 +5880,7 @@ rtl8125_get_strings(struct net_device *dev, { switch (stringset) { case ETH_SS_STATS: - memcpy(data, *rtl8125_gstrings, sizeof(rtl8125_gstrings)); + memcpy(data, rtl8125_gstrings, sizeof(rtl8125_gstrings)); break; } } @@ -4803,10 +5903,10 @@ static int rtl_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u16 tmp; if (tp->eeprom_type == EEPROM_TYPE_NONE) { - dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Detect none EEPROM\n"); + dev_printk(KERN_DEBUG, tp_to_dev(tp), "Detect none EEPROM\n"); return -EOPNOTSUPP; } else if (eeprom->len == 0 || (eeprom->offset+eeprom->len) > tp->eeprom_len) { - dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Invalid parameter\n"); + dev_printk(KERN_DEBUG, tp_to_dev(tp), "Invalid parameter\n"); return -EINVAL; } @@ -4815,6 +5915,8 @@ static int rtl_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: default: VPD_addr = 0xD2; VPD_data = 0xD4; @@ -4898,17 +6000,22 @@ static int _kc_ethtool_op_set_sg(struct net_device *dev, u32 data) static int rtl8125_enable_eee(struct rtl8125_private *tp) { + struct ethtool_eee *eee = &tp->eee; + u16 eee_adv_t = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); int ret; ret = 0; switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: + case CFG_METHOD_6: + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, eee->tx_lpi_timer); + SetMcuAccessRegBit(tp, 0xE040, (BIT_1|BIT_0)); SetMcuAccessRegBit(tp, 0xEB62, (BIT_2|BIT_1)); SetEthPhyOcpBit(tp, 0xA432, BIT_4); - SetEthPhyOcpBit(tp, 0xA5D0, tp->eee_adv_t); + SetEthPhyOcpBit(tp, 0xA5D0, eee_adv_t); ClearEthPhyOcpBit(tp, 0xA6D4, BIT_0); ClearEthPhyOcpBit(tp, 0xA6D8, BIT_4); @@ -4917,17 +6024,23 @@ static int rtl8125_enable_eee(struct rtl8125_private *tp) break; case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, eee->tx_lpi_timer); + SetMcuAccessRegBit(tp, 0xE040, (BIT_1|BIT_0)); - SetEthPhyOcpBit(tp, 0xA5D0, tp->eee_adv_t); - ClearEthPhyOcpBit(tp, 0xA6D4, BIT_0); + SetEthPhyOcpBit(tp, 0xA5D0, eee_adv_t); + if (eee->advertised & SUPPORTED_2500baseX_Full) + SetEthPhyOcpBit(tp, 0xA6D4, BIT_0); + else + ClearEthPhyOcpBit(tp, 0xA6D4, BIT_0); ClearEthPhyOcpBit(tp, 0xA6D8, BIT_4); ClearEthPhyOcpBit(tp, 0xA428, BIT_7); ClearEthPhyOcpBit(tp, 0xA4A2, BIT_9); break; default: -// dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support EEE\n"); +// dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support EEE\n"); ret = -EOPNOTSUPP; break; } @@ -4938,6 +6051,8 @@ static int rtl8125_enable_eee(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_set_phy_mcu_patch_request(tp); ClearMcuAccessRegBit(tp, 0xE052, BIT_0); ClearEthPhyOcpBit(tp, 0xA442, BIT_12 | BIT_13); @@ -4957,6 +6072,7 @@ static int rtl8125_disable_eee(struct rtl8125_private *tp) switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: + case CFG_METHOD_6: ClearMcuAccessRegBit(tp, 0xE040, (BIT_1|BIT_0)); ClearMcuAccessRegBit(tp, 0xEB62, (BIT_2|BIT_1)); @@ -4970,6 +6086,7 @@ static int rtl8125_disable_eee(struct rtl8125_private *tp) break; case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: ClearMcuAccessRegBit(tp, 0xE040, (BIT_1|BIT_0)); ClearEthPhyOcpBit(tp, 0xA5D0, (BIT_2 | BIT_1)); @@ -4980,7 +6097,7 @@ static int rtl8125_disable_eee(struct rtl8125_private *tp) ClearEthPhyOcpBit(tp, 0xA4A2, BIT_9); break; default: -// dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support EEE\n"); +// dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support EEE\n"); ret = -EOPNOTSUPP; break; } @@ -4991,6 +6108,8 @@ static int rtl8125_disable_eee(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_set_phy_mcu_patch_request(tp); ClearMcuAccessRegBit(tp, 0xE052, BIT_0); ClearEthPhyOcpBit(tp, 0xA442, BIT_12 | BIT_13); @@ -5005,15 +6124,10 @@ static int rtl8125_disable_eee(struct rtl8125_private *tp) static int rtl_nway_reset(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; int ret, bmcr; - spin_lock_irqsave(&tp->lock, flags); - - if (unlikely(tp->rtk_enable_diag)) { - spin_unlock_irqrestore(&tp->lock, flags); + if (unlikely(tp->rtk_enable_diag)) return -EBUSY; - } /* if autoneg is off, it's an error */ rtl8125_mdio_write(tp, 0x1F, 0x0000); @@ -5027,30 +6141,50 @@ static int rtl_nway_reset(struct net_device *dev) ret = -EINVAL; } - spin_unlock_irqrestore(&tp->lock, flags); - return ret; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) +static u32 +rtl8125_tx_lpi_timer_to_us(struct rtl8125_private *tp , u32 tx_lpi_timer) +{ + u32 to_us; + u16 status; + + //2.5G : tx_lpi_timer * 3.2ns + //Giga: tx_lpi_timer * 8ns + //100M : tx_lpi_timer * 80ns + to_us = tx_lpi_timer * 80; + status = RTL_R16(tp, PHYstatus); + if (status & LinkStatus) { + /*link on*/ + if (status & _2500bpsF) + to_us = (tx_lpi_timer * 32) / 10; + else if (status & _1000bpsF) + to_us = tx_lpi_timer * 8; + } + + //ns to us + to_us /= 1000; + + return to_us; +} + static int -rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *eee) +rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) { struct rtl8125_private *tp = netdev_priv(net); - u32 lp, adv, supported = 0; - unsigned long flags; + struct ethtool_eee *eee = &tp->eee; + u32 lp, adv, tx_lpi_timer, supported = 0; u16 val; - spin_lock_irqsave(&tp->lock, flags); - - if (unlikely(tp->rtk_enable_diag)) { - spin_unlock_irqrestore(&tp->lock, flags); + if (unlikely(tp->rtk_enable_diag)) return -EBUSY; - } /* Get Supported EEE */ - val = mdio_direct_read_phy_ocp(tp, 0xA5C4); - supported = mmd_eee_cap_to_ethtool_sup_t(val); + //val = mdio_direct_read_phy_ocp(tp, 0xA5C4); + //supported = mmd_eee_cap_to_ethtool_sup_t(val); + supported = eee->supported; /* Get advertisement EEE */ val = mdio_direct_read_phy_ocp(tp, 0xA5D0); @@ -5060,60 +6194,106 @@ rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *eee) val = mdio_direct_read_phy_ocp(tp, 0xA5D2); lp = mmd_eee_adv_to_ethtool_adv_t(val); + /* Get EEE Tx LPI timer*/ + tx_lpi_timer = RTL_R16(tp, EEE_TXIDLE_TIMER_8125); + val = rtl8125_mac_ocp_read(tp, 0xE040); val &= BIT_1 | BIT_0; - spin_unlock_irqrestore(&tp->lock, flags); - - eee->eee_enabled = !!val; - eee->eee_active = !!(supported & adv & lp); - eee->supported = supported; - eee->advertised = adv; - eee->lp_advertised = lp; + edata->eee_enabled = !!val; + edata->eee_active = !!(supported & adv & lp); + edata->supported = supported; + edata->advertised = adv; + edata->lp_advertised = lp; + edata->tx_lpi_enabled = edata->eee_enabled; + edata->tx_lpi_timer = rtl8125_tx_lpi_timer_to_us(tp, tx_lpi_timer); return 0; } static int -rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *eee) +rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata) { struct rtl8125_private *tp = netdev_priv(net); - unsigned long flags; + struct ethtool_eee *eee = &tp->eee; + u32 advertising; + int rc = 0; if (!HW_HAS_WRITE_PHY_MCU_RAM_CODE(tp) || tp->DASH) return -EOPNOTSUPP; - spin_lock_irqsave(&tp->lock, flags); - if (unlikely(tp->rtk_enable_diag)) { - spin_unlock_irqrestore(&tp->lock, flags); - return -EBUSY; + dev_printk(KERN_WARNING, tp_to_dev(tp), "Diag Enabled\n"); + rc = -EBUSY; + goto out; } - tp->eee_enabled = eee->eee_enabled; - - //Disable for eee compablity issue - tp->eee_adv_t = ethtool_adv_to_mmd_eee_adv_t(0); //eee->advertised); - - tp->eee_enabled = 0; + if (tp->autoneg != AUTONEG_ENABLE) { + dev_printk(KERN_WARNING, tp_to_dev(tp), "EEE requires autoneg\n"); + rc = -EINVAL; + goto out; + } - if (tp->eee_enabled) { - rtl8125_enable_eee(tp); - } else { - rtl8125_disable_eee(tp); + if (edata->tx_lpi_enabled) { + if (edata->tx_lpi_timer > tp->max_jumbo_frame_size || + edata->tx_lpi_timer < ETH_MIN_MTU) { + dev_printk(KERN_WARNING, tp_to_dev(tp), "Valid LPI timer range is %d to %d. \n", + ETH_MIN_MTU, tp->max_jumbo_frame_size); + rc = -EINVAL; + goto out; + } + } + + advertising = tp->advertising; + if (!edata->advertised) { + edata->advertised = advertising & eee->supported; + } else if (edata->advertised & ~advertising) { + dev_printk(KERN_WARNING, tp_to_dev(tp), "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", + edata->advertised, advertising); + rc = -EINVAL; + goto out; + } + + if (edata->advertised & ~eee->supported) { + dev_printk(KERN_WARNING, tp_to_dev(tp), "EEE advertised %x must be a subset of support %x\n", + edata->advertised, eee->supported); + rc = -EINVAL; + goto out; } - spin_unlock_irqrestore(&tp->lock, flags); + //tp->eee.eee_enabled = edata->eee_enabled; + //tp->eee_adv_t = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + + dev_printk(KERN_WARNING, tp_to_dev(tp), "EEE tx_lpi_timer %x must be a subset of support %x\n", + edata->tx_lpi_timer, eee->tx_lpi_timer); + + eee->advertised = edata->advertised; + eee->tx_lpi_enabled = edata->tx_lpi_enabled; + eee->tx_lpi_timer = edata->tx_lpi_timer; + eee->eee_enabled = edata->eee_enabled; + + if (eee->eee_enabled) + rtl8125_enable_eee(tp); + else + rtl8125_disable_eee(tp); rtl_nway_reset(net); - return 0; + return rc; + +out: + + return rc; } #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) +#if defined(__VMKLNX__) static struct ethtool_ops rtl8125_ethtool_ops = { +#else +static const struct ethtool_ops rtl8125_ethtool_ops = { +#endif .get_drvinfo = rtl8125_get_drvinfo, .get_regs_len = rtl8125_get_regs_len, .get_link = ethtool_op_get_link, @@ -5123,6 +6303,10 @@ static struct ethtool_ops rtl8125_ethtool_ops = { #else .get_link_ksettings = rtl8125_get_settings, .set_link_ksettings = rtl8125_set_settings, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .get_pauseparam = rtl8125_get_pauseparam, + .set_pauseparam = rtl8125_set_pauseparam, #endif .get_msglevel = rtl8125_get_msglevel, .set_msglevel = rtl8125_set_msglevel, @@ -5184,19 +6368,20 @@ static struct ethtool_ops rtl8125_ethtool_ops = { static int rtl8125_enable_green_feature(struct rtl8125_private *tp) { u16 gphy_val; - unsigned long flags; switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: mdio_direct_write_phy_ocp(tp, 0xA436, 0x8011); SetEthPhyOcpBit(tp, 0xA438, BIT_15); rtl8125_mdio_write(tp, 0x00, 0x9200); break; default: - dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support Green Feature\n"); + dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support Green Feature\n"); break; } @@ -5206,19 +6391,20 @@ static int rtl8125_enable_green_feature(struct rtl8125_private *tp) static int rtl8125_disable_green_feature(struct rtl8125_private *tp) { u16 gphy_val; - unsigned long flags; switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: mdio_direct_write_phy_ocp(tp, 0xA436, 0x8011); ClearEthPhyOcpBit(tp, 0xA438, BIT_15); rtl8125_mdio_write(tp, 0x00, 0x9200); break; default: - dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support Green Feature\n"); + dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support Green Feature\n"); break; } @@ -5231,6 +6417,7 @@ static void rtl8125_get_mac_version(struct rtl8125_private *tp) { u32 reg,val32; u32 ICVerID; + struct pci_dev *pdev = tp->pci_dev; val32 = RTL_R32(tp, TxConfig); reg = val32 & 0x7c800000; @@ -5268,6 +6455,13 @@ static void rtl8125_get_mac_version(struct rtl8125_private *tp) tp->efuse_ver = EFUSE_NOT_SUPPORT; break; } + + if (pdev->subsystem_vendor == 0x8162) { + if (tp->mcfg == CFG_METHOD_3) + tp->mcfg = CFG_METHOD_6; + else if (tp->mcfg == CFG_METHOD_5) + tp->mcfg = CFG_METHOD_7; + } } static void @@ -5313,6 +6507,7 @@ rtl8125_clear_phy_ups_reg(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: ClearEthPhyOcpBit(tp, 0xA466, BIT_0); break; }; @@ -5327,7 +6522,9 @@ rtl8125_is_ups_resume(struct net_device *dev) if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) return (rtl8125_mac_ocp_read(tp, 0xD42C) & BIT_8); return 0; @@ -5341,7 +6538,9 @@ rtl8125_clear_ups_resume_bit(struct net_device *dev) if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) rtl8125_mac_ocp_write(tp, 0xD408, rtl8125_mac_ocp_read(tp, 0xD408) & ~(BIT_8)); } @@ -5355,7 +6554,9 @@ rtl8125_wait_phy_ups_resume(struct net_device *dev, u16 PhyState) if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) { do { TmpPhyState = mdio_direct_read_phy_ocp(tp, 0xA420); TmpPhyState &= 0x7; @@ -5396,8 +6597,7 @@ rtl8125_exit_oob(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: - case CFG_METHOD_4: - case CFG_METHOD_5: + case CFG_METHOD_6: rtl8125_dash2_disable_txrx(dev); break; } @@ -5419,6 +6619,8 @@ rtl8125_exit_oob(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xC0BC, 0x00FF); break; } @@ -5431,6 +6633,8 @@ rtl8125_exit_oob(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_disable_now_is_oob(tp); data16 = rtl8125_mac_ocp_read(tp, 0xE8DE) & ~BIT_14; @@ -5451,6 +6655,8 @@ rtl8125_exit_oob(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: if (rtl8125_is_ups_resume(dev)) { rtl8125_wait_phy_ups_resume(dev, 2); rtl8125_clear_ups_resume_bit(dev); @@ -5458,13 +6664,13 @@ rtl8125_exit_oob(struct net_device *dev) } break; }; - - tp->phy_reg_anlpar = 0; } void rtl8125_hw_disable_mac_mcu_bps(struct net_device *dev) { + u16 regAddr; + struct rtl8125_private *tp = netdev_priv(dev); switch (tp->mcfg) { @@ -5472,6 +6678,8 @@ rtl8125_hw_disable_mac_mcu_bps(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_enable_cfg9346_write(tp); RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~BIT_0); RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~BIT_7); @@ -5484,29 +6692,83 @@ rtl8125_hw_disable_mac_mcu_bps(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: - rtl8125_mac_ocp_write(tp, 0xFC38, 0x0000); + case CFG_METHOD_6: + case CFG_METHOD_7: + rtl8125_mac_ocp_write(tp, 0xFC48, 0x0000); + break; + } + + switch (tp->mcfg) { + case CFG_METHOD_2: + case CFG_METHOD_3: + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: + for (regAddr = 0xFC28; regAddr < 0xFC48; regAddr += 2) { + rtl8125_mac_ocp_write(tp, regAddr, 0x0000); + } + + mdelay(3); + + rtl8125_mac_ocp_write(tp, 0xFC26, 0x0000); break; } +} + +#ifndef ENABLE_USE_FIRMWARE_FILE +static void +rtl8125_switch_mac_mcu_ram_code_page(struct rtl8125_private *tp, u16 page) +{ + u16 tmpUshort; + + page &= (BIT_1 | BIT_0); + tmpUshort = rtl8125_mac_ocp_read(tp, 0xE446); + tmpUshort &= ~(BIT_1 | BIT_0); + tmpUshort |= page; + rtl8125_mac_ocp_write(tp, 0xE446, tmpUshort); +} + +static void +_rtl8125_write_mac_mcu_ram_code(struct rtl8125_private *tp, const u16 *entry, u16 entry_cnt) +{ + u16 i; + + for (i = 0; i < entry_cnt; i++) { + rtl8125_mac_ocp_write(tp, 0xF800 + i * 2, entry[i]); + } +} - switch (tp->mcfg) { - case CFG_METHOD_2: - case CFG_METHOD_3: - case CFG_METHOD_4: - case CFG_METHOD_5: - rtl8125_mac_ocp_write(tp, 0xFC28, 0x0000); - rtl8125_mac_ocp_write(tp, 0xFC2A, 0x0000); - rtl8125_mac_ocp_write(tp, 0xFC2C, 0x0000); - rtl8125_mac_ocp_write(tp, 0xFC2E, 0x0000); - rtl8125_mac_ocp_write(tp, 0xFC30, 0x0000); - rtl8125_mac_ocp_write(tp, 0xFC32, 0x0000); - rtl8125_mac_ocp_write(tp, 0xFC34, 0x0000); - rtl8125_mac_ocp_write(tp, 0xFC36, 0x0000); - mdelay(3); - rtl8125_mac_ocp_write(tp, 0xFC26, 0x0000); - break; +static void +_rtl8125_write_mac_mcu_ram_code_with_page(struct rtl8125_private *tp, const u16 *entry, u16 entry_cnt, u16 page_size) +{ + u16 i; + u16 offset; + + if (page_size == 0) return; + + for (i = 0; i < entry_cnt; i++) { + offset = i % page_size; + if (offset == 0) { + u16 page = (i / page_size); + rtl8125_switch_mac_mcu_ram_code_page(tp, page); + } + rtl8125_mac_ocp_write(tp, 0xF800 + offset * 2, entry[i]); } } +static void +rtl8125_write_mac_mcu_ram_code(struct rtl8125_private *tp, const u16 *entry, u16 entry_cnt) +{ + if (FALSE == HW_SUPPORT_MAC_MCU(tp)) return; + if (entry == NULL || entry_cnt == 0) return; + + if (tp->MacMcuPageSize > 0) + _rtl8125_write_mac_mcu_ram_code_with_page(tp, entry, entry_cnt, tp->MacMcuPageSize); + else + _rtl8125_write_mac_mcu_ram_code(tp, entry, entry_cnt); +} + static void rtl8125_set_mac_mcu_8125a_1(struct net_device *dev) { @@ -5517,49 +6779,55 @@ static void rtl8125_set_mac_mcu_8125a_2(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - u16 i; static const u16 mcu_patch_code_8125a_2[] = { - 0xE008, 0xE01E, 0xE02E, 0xE054, 0xE057, 0xE059, 0xE0C2, 0xE0CB, 0x9996, - 0x49D1, 0xF005, 0x49D4, 0xF10A, 0x49D8, 0xF108, 0xC00F, 0x7100, 0x209C, - 0x249C, 0xC009, 0x9900, 0xE004, 0xC006, 0x1900, 0x9900, 0xC602, 0xBE00, - 0x5A48, 0xE0C2, 0x0004, 0xE10A, 0xC60F, 0x73C4, 0x49B3, 0xF106, 0x73C2, - 0xC608, 0xB406, 0xC609, 0xFF80, 0xC605, 0xB406, 0xC605, 0xFF80, 0x0544, - 0x0568, 0xE906, 0xCDE8, 0xC724, 0xC624, 0x9EE2, 0x1E01, 0x9EE0, 0x76E0, - 0x49E0, 0xF1FE, 0x76E6, 0x486D, 0x4868, 0x9EE4, 0x1E03, 0x9EE0, 0x76E0, - 0x49E0, 0xF1FE, 0xC615, 0x9EE2, 0x1E01, 0x9EE0, 0x76E0, 0x49E0, 0xF1FE, - 0x76E6, 0x486F, 0x9EE4, 0x1E03, 0x9EE0, 0x76E0, 0x49E0, 0xF1FE, 0x7196, - 0xC702, 0xBF00, 0x5A44, 0xEB0E, 0x0070, 0x00C3, 0x1BC0, 0xC602, 0xBE00, - 0x0E26, 0xC602, 0xBE00, 0x0EBA, 0x1501, 0xF02A, 0x1500, 0xF15D, 0xC661, - 0x75C8, 0x49D5, 0xF00A, 0x49D6, 0xF008, 0x49D7, 0xF006, 0x49D8, 0xF004, - 0x75D2, 0x49D9, 0xF150, 0xC553, 0x77A0, 0x75C8, 0x4855, 0x4856, 0x4857, - 0x4858, 0x48DA, 0x48DB, 0x49FE, 0xF002, 0x485A, 0x49FF, 0xF002, 0x485B, - 0x9DC8, 0x75D2, 0x4859, 0x9DD2, 0xC643, 0x75C0, 0x49D4, 0xF033, 0x49D0, - 0xF137, 0xE030, 0xC63A, 0x75C8, 0x49D5, 0xF00E, 0x49D6, 0xF00C, 0x49D7, - 0xF00A, 0x49D8, 0xF008, 0x75D2, 0x49D9, 0xF005, 0xC62E, 0x75C0, 0x49D7, - 0xF125, 0xC528, 0x77A0, 0xC627, 0x75C8, 0x4855, 0x4856, 0x4857, 0x4858, - 0x48DA, 0x48DB, 0x49FE, 0xF002, 0x485A, 0x49FF, 0xF002, 0x485B, 0x9DC8, - 0x75D2, 0x4859, 0x9DD2, 0xC616, 0x75C0, 0x4857, 0x9DC0, 0xC613, 0x75C0, - 0x49DA, 0xF003, 0x49D0, 0xF107, 0xC60B, 0xC50E, 0x48D9, 0x9DC0, 0x4859, - 0x9DC0, 0xC608, 0xC702, 0xBF00, 0x3AE0, 0xE860, 0xB400, 0xB5D4, 0xE908, - 0xE86C, 0x1200, 0xC409, 0x6780, 0x48F1, 0x8F80, 0xC404, 0xC602, 0xBE00, - 0x10AA, 0xC010, 0xEA7C, 0xC602, 0xBE00, 0x0000 + 0xE010, 0xE026, 0xE036, 0xE05C, 0xE05E, 0xE060, 0xE0C9, 0xE0D2, 0xE0D4, + 0xE0DF, 0xE0EA, 0xE0FB, 0xE101, 0xE106, 0xE10B, 0xE10D, 0x9996, 0x49D1, + 0xF005, 0x49D4, 0xF10A, 0x49D8, 0xF108, 0xC00F, 0x7100, 0x209C, 0x249C, + 0xC009, 0x9900, 0xE004, 0xC006, 0x1900, 0x9900, 0xC602, 0xBE00, 0x5A48, + 0xE0C2, 0x0004, 0xE10A, 0xC60F, 0x73C4, 0x49B3, 0xF106, 0x73C2, 0xC608, + 0xB406, 0xC609, 0xFF80, 0xC605, 0xB406, 0xC605, 0xFF80, 0x0544, 0x0568, + 0xE906, 0xCDE8, 0xC724, 0xC624, 0x9EE2, 0x1E01, 0x9EE0, 0x76E0, 0x49E0, + 0xF1FE, 0x76E6, 0x486D, 0x4868, 0x9EE4, 0x1E03, 0x9EE0, 0x76E0, 0x49E0, + 0xF1FE, 0xC615, 0x9EE2, 0x1E01, 0x9EE0, 0x76E0, 0x49E0, 0xF1FE, 0x76E6, + 0x486F, 0x9EE4, 0x1E03, 0x9EE0, 0x76E0, 0x49E0, 0xF1FE, 0x7196, 0xC702, + 0xBF00, 0x5A44, 0xEB0E, 0x0070, 0x00C3, 0xC602, 0xBE00, 0x0000, 0xC602, + 0xBE00, 0x0EBA, 0x1501, 0xF02A, 0x1500, 0xF15D, 0xC661, 0x75C8, 0x49D5, + 0xF00A, 0x49D6, 0xF008, 0x49D7, 0xF006, 0x49D8, 0xF004, 0x75D2, 0x49D9, + 0xF150, 0xC553, 0x77A0, 0x75C8, 0x4855, 0x4856, 0x4857, 0x4858, 0x48DA, + 0x48DB, 0x49FE, 0xF002, 0x485A, 0x49FF, 0xF002, 0x485B, 0x9DC8, 0x75D2, + 0x4859, 0x9DD2, 0xC643, 0x75C0, 0x49D4, 0xF033, 0x49D0, 0xF137, 0xE030, + 0xC63A, 0x75C8, 0x49D5, 0xF00E, 0x49D6, 0xF00C, 0x49D7, 0xF00A, 0x49D8, + 0xF008, 0x75D2, 0x49D9, 0xF005, 0xC62E, 0x75C0, 0x49D7, 0xF125, 0xC528, + 0x77A0, 0xC627, 0x75C8, 0x4855, 0x4856, 0x4857, 0x4858, 0x48DA, 0x48DB, + 0x49FE, 0xF002, 0x485A, 0x49FF, 0xF002, 0x485B, 0x9DC8, 0x75D2, 0x4859, + 0x9DD2, 0xC616, 0x75C0, 0x4857, 0x9DC0, 0xC613, 0x75C0, 0x49DA, 0xF003, + 0x49D0, 0xF107, 0xC60B, 0xC50E, 0x48D9, 0x9DC0, 0x4859, 0x9DC0, 0xC608, + 0xC702, 0xBF00, 0x3AE0, 0xE860, 0xB400, 0xB5D4, 0xE908, 0xE86C, 0x1200, + 0xC409, 0x6780, 0x48F1, 0x8F80, 0xC404, 0xC602, 0xBE00, 0x10AA, 0xC010, + 0xEA7C, 0xC602, 0xBE00, 0x0000, 0x740A, 0x4846, 0x4847, 0x9C0A, 0xC607, + 0x74C0, 0x48C6, 0x9CC0, 0xC602, 0xBE00, 0x13FE, 0xE054, 0x72CA, 0x4826, + 0x4827, 0x9ACA, 0xC607, 0x72C0, 0x48A6, 0x9AC0, 0xC602, 0xBE00, 0x07DC, + 0xE054, 0xC60F, 0x74C4, 0x49CC, 0xF109, 0xC60C, 0x74CA, 0x48C7, 0x9CCA, + 0xC609, 0x74C0, 0x4846, 0x9CC0, 0xC602, 0xBE00, 0x2480, 0xE092, 0xE0C0, + 0xE054, 0x7420, 0x48C0, 0x9C20, 0x7444, 0xC602, 0xBE00, 0x12F8, 0x1BFF, + 0x46EB, 0x1BFF, 0xC102, 0xB900, 0x0D5A, 0x1BFF, 0x46EB, 0x1BFF, 0xC102, + 0xB900, 0x0E2A, 0xC602, 0xBE00, 0x0000, 0xC602, 0xBE00, 0x0000 }; rtl8125_hw_disable_mac_mcu_bps(dev); - for (i = 0; i < ARRAY_SIZE(mcu_patch_code_8125a_2); i++) { - rtl8125_mac_ocp_write(tp, 0xF800 + i * 2, mcu_patch_code_8125a_2[i]); - } + rtl8125_write_mac_mcu_ram_code(tp, mcu_patch_code_8125a_2, ARRAY_SIZE(mcu_patch_code_8125a_2)); rtl8125_mac_ocp_write(tp, 0xFC26, 0x8000); rtl8125_mac_ocp_write(tp, 0xFC2A, 0x0540); - rtl8125_mac_ocp_write(tp, 0xFC2E, 0x0E24); rtl8125_mac_ocp_write(tp, 0xFC30, 0x0EB8); rtl8125_mac_ocp_write(tp, 0xFC32, 0x3A5C); rtl8125_mac_ocp_write(tp, 0xFC34, 0x10A8); + rtl8125_mac_ocp_write(tp, 0xFC40, 0x0D54); + rtl8125_mac_ocp_write(tp, 0xFC42, 0x0E24); - rtl8125_mac_ocp_write(tp, 0xFC48, 0x007A); + rtl8125_mac_ocp_write(tp, 0xFC48, 0x3072); } static void @@ -5572,26 +6840,27 @@ static void rtl8125_set_mac_mcu_8125b_2(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - u16 i; static const u16 mcu_patch_code_8125b_2[] = { - 0xE008, 0xE013, 0xE01E, 0xE02F, 0xE035, 0xE04F, 0xE053, 0xE055, 0x740A, - 0x4846, 0x4847, 0x9C0A, 0xC607, 0x74C0, 0x48C6, 0x9CC0, 0xC602, 0xBE00, - 0x13F0, 0xE054, 0x72CA, 0x4826, 0x4827, 0x9ACA, 0xC607, 0x72C0, 0x48A6, - 0x9AC0, 0xC602, 0xBE00, 0x081C, 0xE054, 0xC60F, 0x74C4, 0x49CC, 0xF109, - 0xC60C, 0x74CA, 0x48C7, 0x9CCA, 0xC609, 0x74C0, 0x4846, 0x9CC0, 0xC602, - 0xBE00, 0x2494, 0xE092, 0xE0C0, 0xE054, 0x7420, 0x48C0, 0x9C20, 0x7444, - 0xC602, 0xBE00, 0x12DC, 0x733A, 0x21B5, 0x25BC, 0x1304, 0xF111, 0x1B12, - 0x1D2A, 0x3168, 0x3ADA, 0x31AB, 0x1A00, 0x9AC0, 0x1300, 0xF1FB, 0x7620, - 0x236E, 0x276F, 0x1A3C, 0x22A1, 0x41B5, 0x9EE2, 0x76E4, 0x486F, 0x9EE4, - 0xC602, 0xBE00, 0x4A26, 0x733A, 0x49BB, 0xC602, 0xBE00, 0x47A2, 0xC602, - 0xBE00, 0x0000, 0xC602, 0xBE00, 0x0000 + 0xE010, 0xE01B, 0xE026, 0xE037, 0xE03D, 0xE057, 0xE05B, 0xE05F, 0xE061, + 0xE063, 0xE065, 0xE067, 0xE069, 0xE06B, 0xE06D, 0xE06F, 0x740A, 0x4846, + 0x4847, 0x9C0A, 0xC607, 0x74C0, 0x48C6, 0x9CC0, 0xC602, 0xBE00, 0x13F0, + 0xE054, 0x72CA, 0x4826, 0x4827, 0x9ACA, 0xC607, 0x72C0, 0x48A6, 0x9AC0, + 0xC602, 0xBE00, 0x081C, 0xE054, 0xC60F, 0x74C4, 0x49CC, 0xF109, 0xC60C, + 0x74CA, 0x48C7, 0x9CCA, 0xC609, 0x74C0, 0x4846, 0x9CC0, 0xC602, 0xBE00, + 0x2494, 0xE092, 0xE0C0, 0xE054, 0x7420, 0x48C0, 0x9C20, 0x7444, 0xC602, + 0xBE00, 0x12DC, 0x733A, 0x21B5, 0x25BC, 0x1304, 0xF111, 0x1B12, 0x1D2A, + 0x3168, 0x3ADA, 0x31AB, 0x1A00, 0x9AC0, 0x1300, 0xF1FB, 0x7620, 0x236E, + 0x276F, 0x1A3C, 0x22A1, 0x41B5, 0x9EE2, 0x76E4, 0x486F, 0x9EE4, 0xC602, + 0xBE00, 0x4A26, 0x733A, 0x49BB, 0xC602, 0xBE00, 0x47A2, 0x48C1, 0x48C2, + 0xC5C3, 0xBD00, 0x0A52, 0xC602, 0xBE00, 0x0000, 0xC602, 0xBE00, 0x0000, + 0xC602, 0xBE00, 0x0000, 0xC602, 0xBE00, 0x0000, 0xC602, 0xBE00, 0x0000, + 0xC602, 0xBE00, 0x0000, 0xC602, 0xBE00, 0x0000, 0xC602, 0xBE00, 0x0000, + 0xC602, 0xBE00, 0x0000 }; rtl8125_hw_disable_mac_mcu_bps(dev); - for (i = 0; i < ARRAY_SIZE(mcu_patch_code_8125b_2); i++) { - rtl8125_mac_ocp_write(tp, 0xF800 + i * 2, mcu_patch_code_8125b_2[i]); - } + rtl8125_write_mac_mcu_ram_code(tp, mcu_patch_code_8125b_2, ARRAY_SIZE(mcu_patch_code_8125b_2)); rtl8125_mac_ocp_write(tp, 0xFC26, 0x8000); @@ -5601,6 +6870,7 @@ rtl8125_set_mac_mcu_8125b_2(struct net_device *dev) rtl8125_mac_ocp_write(tp, 0xFC2E, 0x12DA); rtl8125_mac_ocp_write(tp, 0xFC30, 0x4A20); rtl8125_mac_ocp_write(tp, 0xFC32, 0x47A0); + //rtl8125_mac_ocp_write(tp, 0xFC34, 0x0A46); rtl8125_mac_ocp_write(tp, 0xFC48, 0x003F); } @@ -5617,16 +6887,50 @@ rtl8125_hw_mac_mcu_config(struct net_device *dev) rtl8125_set_mac_mcu_8125a_1(dev); break; case CFG_METHOD_3: + case CFG_METHOD_6: rtl8125_set_mac_mcu_8125a_2(dev); break; case CFG_METHOD_4: rtl8125_set_mac_mcu_8125b_1(dev); break; case CFG_METHOD_5: + case CFG_METHOD_7: rtl8125_set_mac_mcu_8125b_2(dev); break; } } +#endif + +#ifdef ENABLE_USE_FIRMWARE_FILE +static void rtl8125_release_firmware(struct rtl8125_private *tp) +{ + if (tp->rtl_fw) { + rtl8125_fw_release_firmware(tp->rtl_fw); + kfree(tp->rtl_fw); + tp->rtl_fw = NULL; + } +} + +void rtl8125_apply_firmware(struct rtl8125_private *tp) +{ + /* TODO: release firmware if rtl_fw_write_firmware signals failure. */ + if (tp->rtl_fw) { + rtl8125_fw_write_firmware(tp, tp->rtl_fw); + /* At least one firmware doesn't reset tp->ocp_base. */ + tp->ocp_base = OCP_STD_PHY_BASE; + + /* PHY soft reset may still be in progress */ + //phy_read_poll_timeout(tp->phydev, MII_BMCR, val, + // !(val & BMCR_RESET), + // 50000, 600000, true); + rtl8125_wait_phy_reset_complete(tp); + + tp->hw_ram_code_ver = rtl8125_get_hw_phy_mcu_code_ver(tp); + tp->sw_ram_code_ver = tp->hw_ram_code_ver; + tp->HwHasWrRamCodeToMicroP = TRUE; + } +} +#endif static void rtl8125_hw_init(struct net_device *dev) @@ -5639,6 +6943,8 @@ rtl8125_hw_init(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_enable_cfg9346_write(tp); RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~BIT_0); RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~BIT_7); @@ -5653,17 +6959,24 @@ rtl8125_hw_init(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xD40A, rtl8125_mac_ocp_read( tp, 0xD40A) & ~(BIT_4)); break; } - rtl8125_hw_mac_mcu_config(dev); +#ifndef ENABLE_USE_FIRMWARE_FILE + if (!tp->rtl_fw) + rtl8125_hw_mac_mcu_config(dev); +#endif /*disable ocp phy power saving*/ if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) rtl8125_disable_ocp_phy_power_saving(dev); //Set PCIE uncorrectable error status mask pcie 0x108 @@ -5671,8 +6984,22 @@ rtl8125_hw_init(struct net_device *dev) csi_tmp |= BIT_20; rtl8125_csi_write(tp, 0x108, csi_tmp); + rtl8125_enable_cfg9346_write(tp); + rtl8125_disable_linkchg_wakeup(dev); + rtl8125_disable_cfg9346_write(tp); + rtl8125_disable_magic_packet(dev); + rtl8125_disable_d0_speedup(tp); + rtl8125_set_pci_pme(tp, 0); if (s0_magic_packet == 1) rtl8125_enable_magic_packet(dev); + +#ifdef ENABLE_USE_FIRMWARE_FILE + if (tp->rtl_fw && + !tp->resume_not_chg_speed && + !(HW_DASH_SUPPORT_TYPE_3(tp) && + tp->HwPkgDet == 0x06)) + rtl8125_apply_firmware(tp); +#endif } static void @@ -5709,6 +7036,7 @@ rtl8125_hw_ephy_config(struct net_device *dev) rtl8125_ephy_write(tp, 0x63, 0xAB62); break; case CFG_METHOD_3: + case CFG_METHOD_6: rtl8125_ephy_write(tp, 0x04, 0xD000); rtl8125_ephy_write(tp, 0x0A, 0x8653); rtl8125_ephy_write(tp, 0x23, 0xAB66); @@ -5775,46 +7103,47 @@ rtl8125_hw_ephy_config(struct net_device *dev) rtl8125_ephy_write(tp, 0x5B, 0x1EA0); break; case CFG_METHOD_5: + case CFG_METHOD_7: rtl8125_ephy_write(tp, 0x0B, 0xA908); - rtl8125_ephy_write(tp, 0x1E, 0x20EB); + rtl8125_ephy_write(tp, 0x22, 0x0023); + rtl8125_ephy_write(tp, 0x1E, 0x28EB); rtl8125_ephy_write(tp, 0x4B, 0xA908); - rtl8125_ephy_write(tp, 0x5E, 0x20EB); - - ClearAndSetPCIePhyBit(tp, - 0x22, - (BIT_5 | BIT_4), - BIT_5 - ); - ClearAndSetPCIePhyBit(tp, - 0x62, - (BIT_5 | BIT_4), - BIT_5 - ); + rtl8125_ephy_write(tp, 0x62, 0x0023); + rtl8125_ephy_write(tp, 0x5E, 0x28EB); break; } } -static int -rtl8125_check_hw_phy_mcu_code_ver(struct net_device *dev) +static u16 +rtl8125_get_hw_phy_mcu_code_ver(struct rtl8125_private *tp) { - struct rtl8125_private *tp = netdev_priv(dev); - int ram_code_ver_match = 0; + u16 hw_ram_code_ver = ~0; switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: mdio_direct_write_phy_ocp(tp, 0xA436, 0x801E); - tp->hw_ram_code_ver = mdio_direct_read_phy_ocp(tp, 0xA438); - break; - default: - tp->hw_ram_code_ver = ~0; + hw_ram_code_ver = mdio_direct_read_phy_ocp(tp, 0xA438); break; } - if ( tp->hw_ram_code_ver == tp->sw_ram_code_ver) { + return hw_ram_code_ver; +} + +static int +rtl8125_check_hw_phy_mcu_code_ver(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + int ram_code_ver_match = 0; + + tp->hw_ram_code_ver = rtl8125_get_hw_phy_mcu_code_ver(tp); + + if (tp->hw_ram_code_ver == tp->sw_ram_code_ver) { ram_code_ver_match = 1; tp->HwHasWrRamCodeToMicroP = TRUE; } @@ -5822,6 +7151,55 @@ rtl8125_check_hw_phy_mcu_code_ver(struct net_device *dev) return ram_code_ver_match; } +bool +rtl8125_set_phy_mcu_patch_request(struct rtl8125_private *tp) +{ + u16 gphy_val; + u16 WaitCount; + bool bSuccess = TRUE; + + SetEthPhyOcpBit(tp, 0xB820, BIT_4); + + WaitCount = 0; + do { + gphy_val = mdio_direct_read_phy_ocp(tp, 0xB800); + udelay(100); + WaitCount++; + } while (!(gphy_val & BIT_6) && (WaitCount < 1000)); + + if (!(gphy_val & BIT_6) && (WaitCount == 1000)) bSuccess = FALSE; + + if (!bSuccess) + dprintk("rtl8125_set_phy_mcu_patch_request fail.\n"); + + return bSuccess; +} + +bool +rtl8125_clear_phy_mcu_patch_request(struct rtl8125_private *tp) +{ + u16 gphy_val; + u16 WaitCount; + bool bSuccess = TRUE; + + ClearEthPhyOcpBit(tp, 0xB820, BIT_4); + + WaitCount = 0; + do { + gphy_val = mdio_direct_read_phy_ocp(tp, 0xB800); + udelay(100); + WaitCount++; + } while ((gphy_val & BIT_6) && (WaitCount < 1000)); + + if ((gphy_val & BIT_6) && (WaitCount == 1000)) bSuccess = FALSE; + + if (!bSuccess) + dprintk("rtl8125_clear_phy_mcu_patch_request fail.\n"); + + return bSuccess; +} + +#ifndef ENABLE_USE_FIRMWARE_FILE static void rtl8125_write_hw_phy_mcu_code_ver(struct net_device *dev) { @@ -5832,6 +7210,8 @@ rtl8125_write_hw_phy_mcu_code_ver(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: mdio_direct_write_phy_ocp(tp, 0xA436, 0x801E); mdio_direct_write_phy_ocp(tp, 0xA438, tp->sw_ram_code_ver); tp->hw_ram_code_ver = tp->sw_ram_code_ver; @@ -5849,12 +7229,14 @@ rtl8125_acquire_phy_mcu_patch_key_lock(struct rtl8125_private *tp) PatchKey = 0x8600; break; case CFG_METHOD_3: + case CFG_METHOD_6: PatchKey = 0x8601; break; case CFG_METHOD_4: PatchKey = 0x3700; break; case CFG_METHOD_5: + case CFG_METHOD_7: PatchKey = 0x3701; break; default: @@ -5874,6 +7256,8 @@ rtl8125_release_phy_mcu_patch_key_lock(struct rtl8125_private *tp) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: mdio_direct_write_phy_ocp(tp, 0xA436, 0x0000); mdio_direct_write_phy_ocp(tp, 0xA438, 0x0000); ClearEthPhyOcpBit(tp, 0xB82E, BIT_0); @@ -5885,46 +7269,6 @@ rtl8125_release_phy_mcu_patch_key_lock(struct rtl8125_private *tp) } } -static -bool -rtl8125_wait_phy_mcu_patch_request_ready(struct rtl8125_private *tp) -{ - u16 gphy_val; - u16 WaitCount; - bool bSuccess = TRUE; - - WaitCount = 0; - do { - gphy_val = mdio_direct_read_phy_ocp(tp, 0xB800); - gphy_val &= BIT_6; - udelay(100); - WaitCount++; - } while(gphy_val != BIT_6 && WaitCount < 1000); - - if (gphy_val != BIT_6 && WaitCount == 1000) bSuccess = FALSE; - - if (!bSuccess) - dprintk("rtl8125_wait_phy_mcu_patch_request_ready fail.\n"); - - return bSuccess; -} - -bool -rtl8125_set_phy_mcu_patch_request(struct rtl8125_private *tp) -{ - SetEthPhyOcpBit(tp, 0xB820, BIT_4); - - return rtl8125_wait_phy_mcu_patch_request_ready(tp); -} - -bool -rtl8125_clear_phy_mcu_patch_request(struct rtl8125_private *tp) -{ - ClearEthPhyOcpBit(tp, 0xB820, BIT_4); - - return rtl8125_wait_phy_mcu_patch_request_ready(tp); -} - static void rtl8125_set_phy_mcu_ram_code(struct net_device *dev, const u16 *ramcode, u16 codesize) { @@ -5950,6 +7294,69 @@ rtl8125_set_phy_mcu_ram_code(struct net_device *dev, const u16 *ramcode, u16 cod return; } +static void +rtl8125_enable_phy_disable_mode(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + switch (tp->HwSuppCheckPhyDisableModeVer) { + case 3: + RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) | BIT_5); + break; + } + + dprintk("enable phy disable mode.\n"); +} + +static void +rtl8125_disable_phy_disable_mode(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + switch (tp->HwSuppCheckPhyDisableModeVer) { + case 3: + RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) & ~BIT_5); + break; + } + + mdelay(1); + + dprintk("disable phy disable mode.\n"); +} + +static void +rtl8125_set_hw_phy_before_init_phy_mcu(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + u16 PhyRegValue; + + switch (tp->mcfg) { + case CFG_METHOD_4: + mdio_direct_write_phy_ocp(tp, 0xBF86, 0x9000); + + SetEthPhyOcpBit(tp, 0xC402, BIT_10); + ClearEthPhyOcpBit(tp, 0xC402, BIT_10); + + PhyRegValue = mdio_direct_read_phy_ocp(tp, 0xBF86); + PhyRegValue &= (BIT_1 | BIT_0); + if (PhyRegValue != 0) + dprintk("PHY watch dog not clear, value = 0x%x \n", PhyRegValue); + + mdio_direct_write_phy_ocp(tp, 0xBD86, 0x1010); + mdio_direct_write_phy_ocp(tp, 0xBD88, 0x1010); + + ClearAndSetEthPhyOcpBit(tp, + 0xBD4E, + BIT_11 | BIT_10, + BIT_11); + ClearAndSetEthPhyOcpBit(tp, + 0xBF46, + BIT_11 | BIT_10 | BIT_9 | BIT_8, + BIT_10 | BIT_9 | BIT_8); + break; + } +} + static void rtl8125_real_set_phy_mcu_8125a_1(struct net_device *dev) { @@ -7996,166 +9403,249 @@ static const u16 phy_mcu_ram_code_8125b_2[] = { 0xa436, 0x8024, 0xa438, 0x3701, 0xa436, 0xB82E, 0xa438, 0x0001, 0xb820, 0x0090, 0xa436, 0xA016, 0xa438, 0x0000, 0xa436, 0xA012, 0xa438, 0x0000, 0xa436, 0xA014, 0xa438, 0x1800, 0xa438, 0x8010, - 0xa438, 0x1800, 0xa438, 0x801a, 0xa438, 0x1800, 0xa438, 0x8024, - 0xa438, 0x1800, 0xa438, 0x802f, 0xa438, 0x1800, 0xa438, 0x8051, - 0xa438, 0x1800, 0xa438, 0x8057, 0xa438, 0x1800, 0xa438, 0x8063, - 0xa438, 0x1800, 0xa438, 0x8068, 0xa438, 0xd093, 0xa438, 0xd1c4, + 0xa438, 0x1800, 0xa438, 0x801a, 0xa438, 0x1800, 0xa438, 0x803f, + 0xa438, 0x1800, 0xa438, 0x8045, 0xa438, 0x1800, 0xa438, 0x8067, + 0xa438, 0x1800, 0xa438, 0x806d, 0xa438, 0x1800, 0xa438, 0x8079, + 0xa438, 0x1800, 0xa438, 0x807e, 0xa438, 0xd093, 0xa438, 0xd1c4, 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd704, 0xa438, 0x5fbc, 0xa438, 0xd504, 0xa438, 0xc9f1, 0xa438, 0x1800, 0xa438, 0x0fc9, 0xa438, 0xbb50, 0xa438, 0xd505, 0xa438, 0xa202, 0xa438, 0xd504, 0xa438, 0x8c0f, 0xa438, 0xd500, 0xa438, 0x1000, 0xa438, 0x1519, - 0xa438, 0x1800, 0xa438, 0x1548, 0xa438, 0x2f70, 0xa438, 0x802a, - 0xa438, 0x2f73, 0xa438, 0x156a, 0xa438, 0x1800, 0xa438, 0x155c, - 0xa438, 0xd505, 0xa438, 0xa202, 0xa438, 0xd500, 0xa438, 0x1800, - 0xa438, 0x1551, 0xa438, 0xc0c1, 0xa438, 0xc0c0, 0xa438, 0xd05a, - 0xa438, 0xd1ba, 0xa438, 0xd701, 0xa438, 0x2529, 0xa438, 0x022a, - 0xa438, 0xd0a7, 0xa438, 0xd1b9, 0xa438, 0xa208, 0xa438, 0x1000, - 0xa438, 0x080e, 0xa438, 0xd701, 0xa438, 0x408b, 0xa438, 0x1000, - 0xa438, 0x0a65, 0xa438, 0xf003, 0xa438, 0x1000, 0xa438, 0x0a6b, - 0xa438, 0xd701, 0xa438, 0x1000, 0xa438, 0x0920, 0xa438, 0x1000, - 0xa438, 0x0915, 0xa438, 0x1000, 0xa438, 0x0909, 0xa438, 0x228f, - 0xa438, 0x8038, 0xa438, 0x9801, 0xa438, 0xd71e, 0xa438, 0x5d61, - 0xa438, 0xd701, 0xa438, 0x1800, 0xa438, 0x022a, 0xa438, 0x2005, - 0xa438, 0x091a, 0xa438, 0x3bd9, 0xa438, 0x0919, 0xa438, 0x1800, - 0xa438, 0x0916, 0xa438, 0x1000, 0xa438, 0x14c5, 0xa438, 0xd703, - 0xa438, 0x3181, 0xa438, 0x8061, 0xa438, 0x60ad, 0xa438, 0x1000, - 0xa438, 0x135c, 0xa438, 0xd703, 0xa438, 0x5fba, 0xa438, 0x1800, - 0xa438, 0x0cc7, 0xa438, 0xd096, 0xa438, 0xd1a9, 0xa438, 0xd503, - 0xa438, 0x1800, 0xa438, 0x0c94, 0xa436, 0xA026, 0xa438, 0xffff, - 0xa436, 0xA024, 0xa438, 0x0c93, 0xa436, 0xA022, 0xa438, 0x0cc5, - 0xa436, 0xA020, 0xa438, 0x0915, 0xa436, 0xA006, 0xa438, 0x020a, - 0xa436, 0xA004, 0xa438, 0x155b, 0xa436, 0xA002, 0xa438, 0x1542, - 0xa436, 0xA000, 0xa438, 0x0fc7, 0xa436, 0xA008, 0xa438, 0x7f00, - 0xa436, 0xA016, 0xa438, 0x0010, 0xa436, 0xA012, 0xa438, 0x0000, - 0xa436, 0xA014, 0xa438, 0x1800, 0xa438, 0x8010, 0xa438, 0x1800, - 0xa438, 0x801d, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, + 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd75e, 0xa438, 0x5fae, + 0xa438, 0x9b50, 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd75e, + 0xa438, 0x7fae, 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd707, + 0xa438, 0x40a7, 0xa438, 0xd719, 0xa438, 0x4071, 0xa438, 0x1800, + 0xa438, 0x1557, 0xa438, 0xd719, 0xa438, 0x2f70, 0xa438, 0x803b, + 0xa438, 0x2f73, 0xa438, 0x156a, 0xa438, 0x5e70, 0xa438, 0x1800, + 0xa438, 0x155d, 0xa438, 0xd505, 0xa438, 0xa202, 0xa438, 0xd500, + 0xa438, 0xffed, 0xa438, 0xd709, 0xa438, 0x4054, 0xa438, 0xa788, + 0xa438, 0xd70b, 0xa438, 0x1800, 0xa438, 0x172a, 0xa438, 0xc0c1, + 0xa438, 0xc0c0, 0xa438, 0xd05a, 0xa438, 0xd1ba, 0xa438, 0xd701, + 0xa438, 0x2529, 0xa438, 0x022a, 0xa438, 0xd0a7, 0xa438, 0xd1b9, + 0xa438, 0xa208, 0xa438, 0x1000, 0xa438, 0x080e, 0xa438, 0xd701, + 0xa438, 0x408b, 0xa438, 0x1000, 0xa438, 0x0a65, 0xa438, 0xf003, + 0xa438, 0x1000, 0xa438, 0x0a6b, 0xa438, 0xd701, 0xa438, 0x1000, + 0xa438, 0x0920, 0xa438, 0x1000, 0xa438, 0x0915, 0xa438, 0x1000, + 0xa438, 0x0909, 0xa438, 0x228f, 0xa438, 0x804e, 0xa438, 0x9801, + 0xa438, 0xd71e, 0xa438, 0x5d61, 0xa438, 0xd701, 0xa438, 0x1800, + 0xa438, 0x022a, 0xa438, 0x2005, 0xa438, 0x091a, 0xa438, 0x3bd9, + 0xa438, 0x0919, 0xa438, 0x1800, 0xa438, 0x0916, 0xa438, 0x1000, + 0xa438, 0x14c5, 0xa438, 0xd703, 0xa438, 0x3181, 0xa438, 0x8077, + 0xa438, 0x60ad, 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd703, + 0xa438, 0x5fba, 0xa438, 0x1800, 0xa438, 0x0cc7, 0xa438, 0xd096, + 0xa438, 0xd1a9, 0xa438, 0xd503, 0xa438, 0x1800, 0xa438, 0x0c94, + 0xa438, 0xa802, 0xa438, 0xa301, 0xa438, 0xa801, 0xa438, 0xc004, + 0xa438, 0xd710, 0xa438, 0x4000, 0xa438, 0x1800, 0xa438, 0x1e79, + 0xa436, 0xA026, 0xa438, 0x1e78, 0xa436, 0xA024, 0xa438, 0x0c93, + 0xa436, 0xA022, 0xa438, 0x0cc5, 0xa436, 0xA020, 0xa438, 0x0915, + 0xa436, 0xA006, 0xa438, 0x020a, 0xa436, 0xA004, 0xa438, 0x1726, + 0xa436, 0xA002, 0xa438, 0x1542, 0xa436, 0xA000, 0xa438, 0x0fc7, + 0xa436, 0xA008, 0xa438, 0xff00, 0xa436, 0xA016, 0xa438, 0x0010, + 0xa436, 0xA012, 0xa438, 0x0000, 0xa436, 0xA014, 0xa438, 0x1800, + 0xa438, 0x8010, 0xa438, 0x1800, 0xa438, 0x801d, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, - 0xa438, 0x802c, 0xa438, 0xd700, 0xa438, 0x6090, 0xa438, 0x60d1, - 0xa438, 0xc95c, 0xa438, 0xf007, 0xa438, 0x60b1, 0xa438, 0xc95a, - 0xa438, 0xf004, 0xa438, 0xc956, 0xa438, 0xf002, 0xa438, 0xc94e, - 0xa438, 0x1800, 0xa438, 0x00cd, 0xa438, 0xd700, 0xa438, 0x6090, - 0xa438, 0x60d1, 0xa438, 0xc95c, 0xa438, 0xf007, 0xa438, 0x60b1, - 0xa438, 0xc95a, 0xa438, 0xf004, 0xa438, 0xc956, 0xa438, 0xf002, - 0xa438, 0xc94e, 0xa438, 0x1000, 0xa438, 0x022a, 0xa438, 0x1800, - 0xa438, 0x0132, 0xa436, 0xA08E, 0xa438, 0xffff, 0xa436, 0xA08C, - 0xa438, 0xffff, 0xa436, 0xA08A, 0xa438, 0xffff, 0xa436, 0xA088, - 0xa438, 0xffff, 0xa436, 0xA086, 0xa438, 0xffff, 0xa436, 0xA084, - 0xa438, 0xffff, 0xa436, 0xA082, 0xa438, 0x012f, 0xa436, 0xA080, - 0xa438, 0x00cc, 0xa436, 0xA090, 0xa438, 0x0103, 0xa436, 0xA016, - 0xa438, 0x0020, 0xa436, 0xA012, 0xa438, 0x0000, 0xa436, 0xA014, - 0xa438, 0x1800, 0xa438, 0x8010, 0xa438, 0x1800, 0xa438, 0x8020, - 0xa438, 0x1800, 0xa438, 0x802a, 0xa438, 0x1800, 0xa438, 0x8035, - 0xa438, 0x1800, 0xa438, 0x803c, 0xa438, 0x1800, 0xa438, 0x803c, + 0xa438, 0x802c, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0xd700, + 0xa438, 0x6090, 0xa438, 0x60d1, 0xa438, 0xc95c, 0xa438, 0xf007, + 0xa438, 0x60b1, 0xa438, 0xc95a, 0xa438, 0xf004, 0xa438, 0xc956, + 0xa438, 0xf002, 0xa438, 0xc94e, 0xa438, 0x1800, 0xa438, 0x00cd, + 0xa438, 0xd700, 0xa438, 0x6090, 0xa438, 0x60d1, 0xa438, 0xc95c, + 0xa438, 0xf007, 0xa438, 0x60b1, 0xa438, 0xc95a, 0xa438, 0xf004, + 0xa438, 0xc956, 0xa438, 0xf002, 0xa438, 0xc94e, 0xa438, 0x1000, + 0xa438, 0x022a, 0xa438, 0x1800, 0xa438, 0x0132, 0xa436, 0xA08E, + 0xa438, 0xffff, 0xa436, 0xA08C, 0xa438, 0xffff, 0xa436, 0xA08A, + 0xa438, 0xffff, 0xa436, 0xA088, 0xa438, 0xffff, 0xa436, 0xA086, + 0xa438, 0xffff, 0xa436, 0xA084, 0xa438, 0xffff, 0xa436, 0xA082, + 0xa438, 0x012f, 0xa436, 0xA080, 0xa438, 0x00cc, 0xa436, 0xA090, + 0xa438, 0x0103, 0xa436, 0xA016, 0xa438, 0x0020, 0xa436, 0xA012, + 0xa438, 0x0000, 0xa436, 0xA014, 0xa438, 0x1800, 0xa438, 0x8010, + 0xa438, 0x1800, 0xa438, 0x8020, 0xa438, 0x1800, 0xa438, 0x802a, + 0xa438, 0x1800, 0xa438, 0x8035, 0xa438, 0x1800, 0xa438, 0x803c, 0xa438, 0x1800, 0xa438, 0x803c, 0xa438, 0x1800, 0xa438, 0x803c, - 0xa438, 0xd107, 0xa438, 0xd042, 0xa438, 0xa404, 0xa438, 0x1000, - 0xa438, 0x09df, 0xa438, 0xd700, 0xa438, 0x5fb4, 0xa438, 0x8280, - 0xa438, 0xd700, 0xa438, 0x6065, 0xa438, 0xd125, 0xa438, 0xf002, - 0xa438, 0xd12b, 0xa438, 0xd040, 0xa438, 0x1800, 0xa438, 0x077f, - 0xa438, 0x0cf0, 0xa438, 0x0c50, 0xa438, 0xd104, 0xa438, 0xd040, - 0xa438, 0x1000, 0xa438, 0x0aa8, 0xa438, 0xd700, 0xa438, 0x5fb4, - 0xa438, 0x1800, 0xa438, 0x0a2e, 0xa438, 0xcb9b, 0xa438, 0xd110, - 0xa438, 0xd040, 0xa438, 0x1000, 0xa438, 0x0b7b, 0xa438, 0x1000, - 0xa438, 0x09df, 0xa438, 0xd700, 0xa438, 0x5fb4, 0xa438, 0x1800, - 0xa438, 0x081b, 0xa438, 0x1000, 0xa438, 0x09df, 0xa438, 0xd704, - 0xa438, 0x7fb8, 0xa438, 0xa718, 0xa438, 0x1800, 0xa438, 0x074e, - 0xa436, 0xA10E, 0xa438, 0xffff, 0xa436, 0xA10C, 0xa438, 0xffff, - 0xa436, 0xA10A, 0xa438, 0xffff, 0xa436, 0xA108, 0xa438, 0xffff, - 0xa436, 0xA106, 0xa438, 0x074d, 0xa436, 0xA104, 0xa438, 0x0818, - 0xa436, 0xA102, 0xa438, 0x0a2c, 0xa436, 0xA100, 0xa438, 0x077e, - 0xa436, 0xA110, 0xa438, 0x000f, 0xa436, 0xb87c, 0xa438, 0x8625, - 0xa436, 0xb87e, 0xa438, 0xaf86, 0xa438, 0x3daf, 0xa438, 0x8689, - 0xa438, 0xaf88, 0xa438, 0x69af, 0xa438, 0x8887, 0xa438, 0xaf88, - 0xa438, 0x9caf, 0xa438, 0x889c, 0xa438, 0xaf88, 0xa438, 0x9caf, - 0xa438, 0x889c, 0xa438, 0xbf86, 0xa438, 0x49d7, 0xa438, 0x0040, - 0xa438, 0x0277, 0xa438, 0x7daf, 0xa438, 0x2727, 0xa438, 0x0000, - 0xa438, 0x7205, 0xa438, 0x0000, 0xa438, 0x7208, 0xa438, 0x0000, - 0xa438, 0x71f3, 0xa438, 0x0000, 0xa438, 0x71f6, 0xa438, 0x0000, - 0xa438, 0x7229, 0xa438, 0x0000, 0xa438, 0x722c, 0xa438, 0x0000, - 0xa438, 0x7217, 0xa438, 0x0000, 0xa438, 0x721a, 0xa438, 0x0000, - 0xa438, 0x721d, 0xa438, 0x0000, 0xa438, 0x7211, 0xa438, 0x0000, - 0xa438, 0x7220, 0xa438, 0x0000, 0xa438, 0x7214, 0xa438, 0x0000, - 0xa438, 0x722f, 0xa438, 0x0000, 0xa438, 0x7223, 0xa438, 0x0000, - 0xa438, 0x7232, 0xa438, 0x0000, 0xa438, 0x7226, 0xa438, 0xf8f9, - 0xa438, 0xfae0, 0xa438, 0x85b3, 0xa438, 0x3802, 0xa438, 0xad27, - 0xa438, 0x02ae, 0xa438, 0x03af, 0xa438, 0x8830, 0xa438, 0x1f66, - 0xa438, 0xef65, 0xa438, 0xbfc2, 0xa438, 0x1f1a, 0xa438, 0x96f7, + 0xa438, 0x1800, 0xa438, 0x803c, 0xa438, 0xd107, 0xa438, 0xd042, + 0xa438, 0xa404, 0xa438, 0x1000, 0xa438, 0x09df, 0xa438, 0xd700, + 0xa438, 0x5fb4, 0xa438, 0x8280, 0xa438, 0xd700, 0xa438, 0x6065, + 0xa438, 0xd125, 0xa438, 0xf002, 0xa438, 0xd12b, 0xa438, 0xd040, + 0xa438, 0x1800, 0xa438, 0x077f, 0xa438, 0x0cf0, 0xa438, 0x0c50, + 0xa438, 0xd104, 0xa438, 0xd040, 0xa438, 0x1000, 0xa438, 0x0aa8, + 0xa438, 0xd700, 0xa438, 0x5fb4, 0xa438, 0x1800, 0xa438, 0x0a2e, + 0xa438, 0xcb9b, 0xa438, 0xd110, 0xa438, 0xd040, 0xa438, 0x1000, + 0xa438, 0x0b7b, 0xa438, 0x1000, 0xa438, 0x09df, 0xa438, 0xd700, + 0xa438, 0x5fb4, 0xa438, 0x1800, 0xa438, 0x081b, 0xa438, 0x1000, + 0xa438, 0x09df, 0xa438, 0xd704, 0xa438, 0x7fb8, 0xa438, 0xa718, + 0xa438, 0x1800, 0xa438, 0x074e, 0xa436, 0xA10E, 0xa438, 0xffff, + 0xa436, 0xA10C, 0xa438, 0xffff, 0xa436, 0xA10A, 0xa438, 0xffff, + 0xa436, 0xA108, 0xa438, 0xffff, 0xa436, 0xA106, 0xa438, 0x074d, + 0xa436, 0xA104, 0xa438, 0x0818, 0xa436, 0xA102, 0xa438, 0x0a2c, + 0xa436, 0xA100, 0xa438, 0x077e, 0xa436, 0xA110, 0xa438, 0x000f, + 0xa436, 0xb87c, 0xa438, 0x8625, 0xa436, 0xb87e, 0xa438, 0xaf86, + 0xa438, 0x3daf, 0xa438, 0x8689, 0xa438, 0xaf88, 0xa438, 0x69af, + 0xa438, 0x8887, 0xa438, 0xaf88, 0xa438, 0x9caf, 0xa438, 0x889c, + 0xa438, 0xaf88, 0xa438, 0x9caf, 0xa438, 0x889c, 0xa438, 0xbf86, + 0xa438, 0x49d7, 0xa438, 0x0040, 0xa438, 0x0277, 0xa438, 0x7daf, + 0xa438, 0x2727, 0xa438, 0x0000, 0xa438, 0x7205, 0xa438, 0x0000, + 0xa438, 0x7208, 0xa438, 0x0000, 0xa438, 0x71f3, 0xa438, 0x0000, + 0xa438, 0x71f6, 0xa438, 0x0000, 0xa438, 0x7229, 0xa438, 0x0000, + 0xa438, 0x722c, 0xa438, 0x0000, 0xa438, 0x7217, 0xa438, 0x0000, + 0xa438, 0x721a, 0xa438, 0x0000, 0xa438, 0x721d, 0xa438, 0x0000, + 0xa438, 0x7211, 0xa438, 0x0000, 0xa438, 0x7220, 0xa438, 0x0000, + 0xa438, 0x7214, 0xa438, 0x0000, 0xa438, 0x722f, 0xa438, 0x0000, + 0xa438, 0x7223, 0xa438, 0x0000, 0xa438, 0x7232, 0xa438, 0x0000, + 0xa438, 0x7226, 0xa438, 0xf8f9, 0xa438, 0xfae0, 0xa438, 0x85b3, + 0xa438, 0x3802, 0xa438, 0xad27, 0xa438, 0x02ae, 0xa438, 0x03af, + 0xa438, 0x8830, 0xa438, 0x1f66, 0xa438, 0xef65, 0xa438, 0xbfc2, + 0xa438, 0x1f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, + 0xa438, 0x00da, 0xa438, 0xf605, 0xa438, 0xbfc2, 0xa438, 0x2f1a, + 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, 0xa438, 0x00db, + 0xa438, 0xf605, 0xa438, 0xef02, 0xa438, 0x1f11, 0xa438, 0x0d42, + 0xa438, 0xbf88, 0xa438, 0x4202, 0xa438, 0x6e7d, 0xa438, 0xef02, + 0xa438, 0x1b03, 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, + 0xa438, 0x4502, 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1a03, + 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4802, + 0xa438, 0x6e7d, 0xa438, 0xbfc2, 0xa438, 0x3f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, 0xa438, 0x00da, 0xa438, 0xf605, - 0xa438, 0xbfc2, 0xa438, 0x2f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, + 0xa438, 0xbfc2, 0xa438, 0x4f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, 0xa438, 0x00db, 0xa438, 0xf605, 0xa438, 0xef02, - 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4202, + 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4b02, 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1b03, 0xa438, 0x1f11, - 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4502, 0xa438, 0x6e7d, + 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4e02, 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1a03, 0xa438, 0x1f11, 0xa438, 0x0d42, - 0xa438, 0xbf88, 0xa438, 0x4802, 0xa438, 0x6e7d, 0xa438, 0xbfc2, - 0xa438, 0x3f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, - 0xa438, 0x00da, 0xa438, 0xf605, 0xa438, 0xbfc2, 0xa438, 0x4f1a, - 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, 0xa438, 0x00db, - 0xa438, 0xf605, 0xa438, 0xef02, 0xa438, 0x1f11, 0xa438, 0x0d42, - 0xa438, 0xbf88, 0xa438, 0x4b02, 0xa438, 0x6e7d, 0xa438, 0xef02, - 0xa438, 0x1b03, 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, - 0xa438, 0x4e02, 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1a03, - 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x5102, - 0xa438, 0x6e7d, 0xa438, 0xef56, 0xa438, 0xd020, 0xa438, 0x1f11, - 0xa438, 0xbf88, 0xa438, 0x5402, 0xa438, 0x6e7d, 0xa438, 0xbf88, - 0xa438, 0x5702, 0xa438, 0x6e7d, 0xa438, 0xbf88, 0xa438, 0x5a02, - 0xa438, 0x6e7d, 0xa438, 0xe185, 0xa438, 0xa0ef, 0xa438, 0x0348, - 0xa438, 0x0a28, 0xa438, 0x05ef, 0xa438, 0x201b, 0xa438, 0x01ad, - 0xa438, 0x2735, 0xa438, 0x1f44, 0xa438, 0xe085, 0xa438, 0x88e1, - 0xa438, 0x8589, 0xa438, 0xbf88, 0xa438, 0x5d02, 0xa438, 0x6e7d, - 0xa438, 0xe085, 0xa438, 0x8ee1, 0xa438, 0x858f, 0xa438, 0xbf88, - 0xa438, 0x6002, 0xa438, 0x6e7d, 0xa438, 0xe085, 0xa438, 0x94e1, - 0xa438, 0x8595, 0xa438, 0xbf88, 0xa438, 0x6302, 0xa438, 0x6e7d, - 0xa438, 0xe085, 0xa438, 0x9ae1, 0xa438, 0x859b, 0xa438, 0xbf88, - 0xa438, 0x6602, 0xa438, 0x6e7d, 0xa438, 0xaf88, 0xa438, 0x3cbf, - 0xa438, 0x883f, 0xa438, 0x026e, 0xa438, 0x9cad, 0xa438, 0x2835, - 0xa438, 0x1f44, 0xa438, 0xe08f, 0xa438, 0xf8e1, 0xa438, 0x8ff9, - 0xa438, 0xbf88, 0xa438, 0x5d02, 0xa438, 0x6e7d, 0xa438, 0xe08f, - 0xa438, 0xfae1, 0xa438, 0x8ffb, 0xa438, 0xbf88, 0xa438, 0x6002, - 0xa438, 0x6e7d, 0xa438, 0xe08f, 0xa438, 0xfce1, 0xa438, 0x8ffd, - 0xa438, 0xbf88, 0xa438, 0x6302, 0xa438, 0x6e7d, 0xa438, 0xe08f, - 0xa438, 0xfee1, 0xa438, 0x8fff, 0xa438, 0xbf88, 0xa438, 0x6602, - 0xa438, 0x6e7d, 0xa438, 0xaf88, 0xa438, 0x3ce1, 0xa438, 0x85a1, - 0xa438, 0x1b21, 0xa438, 0xad37, 0xa438, 0x341f, 0xa438, 0x44e0, - 0xa438, 0x858a, 0xa438, 0xe185, 0xa438, 0x8bbf, 0xa438, 0x885d, - 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x8590, 0xa438, 0xe185, - 0xa438, 0x91bf, 0xa438, 0x8860, 0xa438, 0x026e, 0xa438, 0x7de0, - 0xa438, 0x8596, 0xa438, 0xe185, 0xa438, 0x97bf, 0xa438, 0x8863, - 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x859c, 0xa438, 0xe185, - 0xa438, 0x9dbf, 0xa438, 0x8866, 0xa438, 0x026e, 0xa438, 0x7dae, - 0xa438, 0x401f, 0xa438, 0x44e0, 0xa438, 0x858c, 0xa438, 0xe185, - 0xa438, 0x8dbf, 0xa438, 0x885d, 0xa438, 0x026e, 0xa438, 0x7de0, - 0xa438, 0x8592, 0xa438, 0xe185, 0xa438, 0x93bf, 0xa438, 0x8860, - 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x8598, 0xa438, 0xe185, - 0xa438, 0x99bf, 0xa438, 0x8863, 0xa438, 0x026e, 0xa438, 0x7de0, - 0xa438, 0x859e, 0xa438, 0xe185, 0xa438, 0x9fbf, 0xa438, 0x8866, - 0xa438, 0x026e, 0xa438, 0x7dae, 0xa438, 0x0ce1, 0xa438, 0x85b3, - 0xa438, 0x3904, 0xa438, 0xac2f, 0xa438, 0x04ee, 0xa438, 0x85b3, - 0xa438, 0x00af, 0xa438, 0x39d9, 0xa438, 0x22ac, 0xa438, 0xeaf0, - 0xa438, 0xacf6, 0xa438, 0xf0ac, 0xa438, 0xfaf0, 0xa438, 0xacf8, - 0xa438, 0xf0ac, 0xa438, 0xfcf0, 0xa438, 0xad00, 0xa438, 0xf0ac, - 0xa438, 0xfef0, 0xa438, 0xacf0, 0xa438, 0xf0ac, 0xa438, 0xf4f0, - 0xa438, 0xacf2, 0xa438, 0xf0ac, 0xa438, 0xb0f0, 0xa438, 0xacae, - 0xa438, 0xf0ac, 0xa438, 0xacf0, 0xa438, 0xacaa, 0xa438, 0xa100, - 0xa438, 0x0ce1, 0xa438, 0x8ff7, 0xa438, 0xbf88, 0xa438, 0x8402, - 0xa438, 0x6e7d, 0xa438, 0xaf26, 0xa438, 0xe9e1, 0xa438, 0x8ff6, + 0xa438, 0xbf88, 0xa438, 0x5102, 0xa438, 0x6e7d, 0xa438, 0xef56, + 0xa438, 0xd020, 0xa438, 0x1f11, 0xa438, 0xbf88, 0xa438, 0x5402, + 0xa438, 0x6e7d, 0xa438, 0xbf88, 0xa438, 0x5702, 0xa438, 0x6e7d, + 0xa438, 0xbf88, 0xa438, 0x5a02, 0xa438, 0x6e7d, 0xa438, 0xe185, + 0xa438, 0xa0ef, 0xa438, 0x0348, 0xa438, 0x0a28, 0xa438, 0x05ef, + 0xa438, 0x201b, 0xa438, 0x01ad, 0xa438, 0x2735, 0xa438, 0x1f44, + 0xa438, 0xe085, 0xa438, 0x88e1, 0xa438, 0x8589, 0xa438, 0xbf88, + 0xa438, 0x5d02, 0xa438, 0x6e7d, 0xa438, 0xe085, 0xa438, 0x8ee1, + 0xa438, 0x858f, 0xa438, 0xbf88, 0xa438, 0x6002, 0xa438, 0x6e7d, + 0xa438, 0xe085, 0xa438, 0x94e1, 0xa438, 0x8595, 0xa438, 0xbf88, + 0xa438, 0x6302, 0xa438, 0x6e7d, 0xa438, 0xe085, 0xa438, 0x9ae1, + 0xa438, 0x859b, 0xa438, 0xbf88, 0xa438, 0x6602, 0xa438, 0x6e7d, + 0xa438, 0xaf88, 0xa438, 0x3cbf, 0xa438, 0x883f, 0xa438, 0x026e, + 0xa438, 0x9cad, 0xa438, 0x2835, 0xa438, 0x1f44, 0xa438, 0xe08f, + 0xa438, 0xf8e1, 0xa438, 0x8ff9, 0xa438, 0xbf88, 0xa438, 0x5d02, + 0xa438, 0x6e7d, 0xa438, 0xe08f, 0xa438, 0xfae1, 0xa438, 0x8ffb, + 0xa438, 0xbf88, 0xa438, 0x6002, 0xa438, 0x6e7d, 0xa438, 0xe08f, + 0xa438, 0xfce1, 0xa438, 0x8ffd, 0xa438, 0xbf88, 0xa438, 0x6302, + 0xa438, 0x6e7d, 0xa438, 0xe08f, 0xa438, 0xfee1, 0xa438, 0x8fff, + 0xa438, 0xbf88, 0xa438, 0x6602, 0xa438, 0x6e7d, 0xa438, 0xaf88, + 0xa438, 0x3ce1, 0xa438, 0x85a1, 0xa438, 0x1b21, 0xa438, 0xad37, + 0xa438, 0x341f, 0xa438, 0x44e0, 0xa438, 0x858a, 0xa438, 0xe185, + 0xa438, 0x8bbf, 0xa438, 0x885d, 0xa438, 0x026e, 0xa438, 0x7de0, + 0xa438, 0x8590, 0xa438, 0xe185, 0xa438, 0x91bf, 0xa438, 0x8860, + 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x8596, 0xa438, 0xe185, + 0xa438, 0x97bf, 0xa438, 0x8863, 0xa438, 0x026e, 0xa438, 0x7de0, + 0xa438, 0x859c, 0xa438, 0xe185, 0xa438, 0x9dbf, 0xa438, 0x8866, + 0xa438, 0x026e, 0xa438, 0x7dae, 0xa438, 0x401f, 0xa438, 0x44e0, + 0xa438, 0x858c, 0xa438, 0xe185, 0xa438, 0x8dbf, 0xa438, 0x885d, + 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x8592, 0xa438, 0xe185, + 0xa438, 0x93bf, 0xa438, 0x8860, 0xa438, 0x026e, 0xa438, 0x7de0, + 0xa438, 0x8598, 0xa438, 0xe185, 0xa438, 0x99bf, 0xa438, 0x8863, + 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x859e, 0xa438, 0xe185, + 0xa438, 0x9fbf, 0xa438, 0x8866, 0xa438, 0x026e, 0xa438, 0x7dae, + 0xa438, 0x0ce1, 0xa438, 0x85b3, 0xa438, 0x3904, 0xa438, 0xac2f, + 0xa438, 0x04ee, 0xa438, 0x85b3, 0xa438, 0x00af, 0xa438, 0x39d9, + 0xa438, 0x22ac, 0xa438, 0xeaf0, 0xa438, 0xacf6, 0xa438, 0xf0ac, + 0xa438, 0xfaf0, 0xa438, 0xacf8, 0xa438, 0xf0ac, 0xa438, 0xfcf0, + 0xa438, 0xad00, 0xa438, 0xf0ac, 0xa438, 0xfef0, 0xa438, 0xacf0, + 0xa438, 0xf0ac, 0xa438, 0xf4f0, 0xa438, 0xacf2, 0xa438, 0xf0ac, + 0xa438, 0xb0f0, 0xa438, 0xacae, 0xa438, 0xf0ac, 0xa438, 0xacf0, + 0xa438, 0xacaa, 0xa438, 0xa100, 0xa438, 0x0ce1, 0xa438, 0x8ff7, 0xa438, 0xbf88, 0xa438, 0x8402, 0xa438, 0x6e7d, 0xa438, 0xaf26, - 0xa438, 0xf520, 0xa438, 0xac86, 0xa438, 0xbf88, 0xa438, 0x3f02, - 0xa438, 0x6e9c, 0xa438, 0xad28, 0xa438, 0x03af, 0xa438, 0x3324, - 0xa438, 0xad38, 0xa438, 0x03af, 0xa438, 0x32e6, 0xa438, 0xaf32, - 0xa438, 0xfb00, 0xa436, 0xb87c, 0xa438, 0x8ff6, 0xa436, 0xb87e, - 0xa438, 0x0705, 0xa436, 0xb87c, 0xa438, 0x8ff8, 0xa436, 0xb87e, - 0xa438, 0x19cc, 0xa436, 0xb87c, 0xa438, 0x8ffa, 0xa436, 0xb87e, - 0xa438, 0x28e3, 0xa436, 0xb87c, 0xa438, 0x8ffc, 0xa436, 0xb87e, - 0xa438, 0x1047, 0xa436, 0xb87c, 0xa438, 0x8ffe, 0xa436, 0xb87e, - 0xa438, 0x0a45, 0xa436, 0xb85e, 0xa438, 0x271E, 0xa436, 0xb860, - 0xa438, 0x3846, 0xa436, 0xb862, 0xa438, 0x26E6, 0xa436, 0xb864, - 0xa438, 0x32E3, 0xa436, 0xb886, 0xa438, 0xffff, 0xa436, 0xb888, - 0xa438, 0xffff, 0xa436, 0xb88a, 0xa438, 0xffff, 0xa436, 0xb88c, - 0xa438, 0xffff, 0xa436, 0xb838, 0xa438, 0x000f, 0xb820, 0x0010, + 0xa438, 0xe9e1, 0xa438, 0x8ff6, 0xa438, 0xbf88, 0xa438, 0x8402, + 0xa438, 0x6e7d, 0xa438, 0xaf26, 0xa438, 0xf520, 0xa438, 0xac86, + 0xa438, 0xbf88, 0xa438, 0x3f02, 0xa438, 0x6e9c, 0xa438, 0xad28, + 0xa438, 0x03af, 0xa438, 0x3324, 0xa438, 0xad38, 0xa438, 0x03af, + 0xa438, 0x32e6, 0xa438, 0xaf32, 0xa438, 0xfb00, 0xa436, 0xb87c, + 0xa438, 0x8ff6, 0xa436, 0xb87e, 0xa438, 0x0705, 0xa436, 0xb87c, + 0xa438, 0x8ff8, 0xa436, 0xb87e, 0xa438, 0x19cc, 0xa436, 0xb87c, + 0xa438, 0x8ffa, 0xa436, 0xb87e, 0xa438, 0x28e3, 0xa436, 0xb87c, + 0xa438, 0x8ffc, 0xa436, 0xb87e, 0xa438, 0x1047, 0xa436, 0xb87c, + 0xa438, 0x8ffe, 0xa436, 0xb87e, 0xa438, 0x0a45, 0xa436, 0xb85e, + 0xa438, 0x271E, 0xa436, 0xb860, 0xa438, 0x3846, 0xa436, 0xb862, + 0xa438, 0x26E6, 0xa436, 0xb864, 0xa438, 0x32E3, 0xa436, 0xb886, + 0xa438, 0xffff, 0xa436, 0xb888, 0xa438, 0xffff, 0xa436, 0xb88a, + 0xa438, 0xffff, 0xa436, 0xb88c, 0xa438, 0xffff, 0xa436, 0xb838, + 0xa438, 0x000f, 0xb820, 0x0010, 0xa436, 0x846e, 0xa438, 0xaf84, + 0xa438, 0x86af, 0xa438, 0x8690, 0xa438, 0xaf86, 0xa438, 0xa4af, + 0xa438, 0x86a4, 0xa438, 0xaf86, 0xa438, 0xa4af, 0xa438, 0x86a4, + 0xa438, 0xaf86, 0xa438, 0xa4af, 0xa438, 0x86a4, 0xa438, 0xee82, + 0xa438, 0x5f00, 0xa438, 0x0284, 0xa438, 0x90af, 0xa438, 0x0441, + 0xa438, 0xf8e0, 0xa438, 0x8ff3, 0xa438, 0xa000, 0xa438, 0x0502, + 0xa438, 0x84a4, 0xa438, 0xae06, 0xa438, 0xa001, 0xa438, 0x0302, + 0xa438, 0x84c8, 0xa438, 0xfc04, 0xa438, 0xf8f9, 0xa438, 0xef59, + 0xa438, 0xe080, 0xa438, 0x15ad, 0xa438, 0x2702, 0xa438, 0xae03, + 0xa438, 0xaf84, 0xa438, 0xc3bf, 0xa438, 0x53ca, 0xa438, 0x0252, + 0xa438, 0xc8ad, 0xa438, 0x2807, 0xa438, 0x0285, 0xa438, 0x2cee, + 0xa438, 0x8ff3, 0xa438, 0x01ef, 0xa438, 0x95fd, 0xa438, 0xfc04, + 0xa438, 0xf8f9, 0xa438, 0xfaef, 0xa438, 0x69bf, 0xa438, 0x53ca, + 0xa438, 0x0252, 0xa438, 0xc8ac, 0xa438, 0x2822, 0xa438, 0xd480, + 0xa438, 0x00bf, 0xa438, 0x8684, 0xa438, 0x0252, 0xa438, 0xa9bf, + 0xa438, 0x8687, 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x868a, + 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x868d, 0xa438, 0x0252, + 0xa438, 0xa9ee, 0xa438, 0x8ff3, 0xa438, 0x00af, 0xa438, 0x8526, + 0xa438, 0xe08f, 0xa438, 0xf4e1, 0xa438, 0x8ff5, 0xa438, 0xe28f, + 0xa438, 0xf6e3, 0xa438, 0x8ff7, 0xa438, 0x1b45, 0xa438, 0xac27, + 0xa438, 0x0eee, 0xa438, 0x8ff4, 0xa438, 0x00ee, 0xa438, 0x8ff5, + 0xa438, 0x0002, 0xa438, 0x852c, 0xa438, 0xaf85, 0xa438, 0x26e0, + 0xa438, 0x8ff4, 0xa438, 0xe18f, 0xa438, 0xf52c, 0xa438, 0x0001, + 0xa438, 0xe48f, 0xa438, 0xf4e5, 0xa438, 0x8ff5, 0xa438, 0xef96, + 0xa438, 0xfefd, 0xa438, 0xfc04, 0xa438, 0xf8f9, 0xa438, 0xef59, + 0xa438, 0xbf53, 0xa438, 0x2202, 0xa438, 0x52c8, 0xa438, 0xa18b, + 0xa438, 0x02ae, 0xa438, 0x03af, 0xa438, 0x85da, 0xa438, 0xbf57, + 0xa438, 0x7202, 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xf8e5, + 0xa438, 0x8ff9, 0xa438, 0xbf57, 0xa438, 0x7502, 0xa438, 0x52c8, + 0xa438, 0xe48f, 0xa438, 0xfae5, 0xa438, 0x8ffb, 0xa438, 0xbf57, + 0xa438, 0x7802, 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfce5, + 0xa438, 0x8ffd, 0xa438, 0xbf57, 0xa438, 0x7b02, 0xa438, 0x52c8, + 0xa438, 0xe48f, 0xa438, 0xfee5, 0xa438, 0x8fff, 0xa438, 0xbf57, + 0xa438, 0x6c02, 0xa438, 0x52c8, 0xa438, 0xa102, 0xa438, 0x13ee, + 0xa438, 0x8ffc, 0xa438, 0x80ee, 0xa438, 0x8ffd, 0xa438, 0x00ee, + 0xa438, 0x8ffe, 0xa438, 0x80ee, 0xa438, 0x8fff, 0xa438, 0x00af, + 0xa438, 0x8599, 0xa438, 0xa101, 0xa438, 0x0cbf, 0xa438, 0x534c, + 0xa438, 0x0252, 0xa438, 0xc8a1, 0xa438, 0x0303, 0xa438, 0xaf85, + 0xa438, 0x77bf, 0xa438, 0x5322, 0xa438, 0x0252, 0xa438, 0xc8a1, + 0xa438, 0x8b02, 0xa438, 0xae03, 0xa438, 0xaf86, 0xa438, 0x64e0, + 0xa438, 0x8ff8, 0xa438, 0xe18f, 0xa438, 0xf9bf, 0xa438, 0x8684, + 0xa438, 0x0252, 0xa438, 0xa9e0, 0xa438, 0x8ffa, 0xa438, 0xe18f, + 0xa438, 0xfbbf, 0xa438, 0x8687, 0xa438, 0x0252, 0xa438, 0xa9e0, + 0xa438, 0x8ffc, 0xa438, 0xe18f, 0xa438, 0xfdbf, 0xa438, 0x868a, + 0xa438, 0x0252, 0xa438, 0xa9e0, 0xa438, 0x8ffe, 0xa438, 0xe18f, + 0xa438, 0xffbf, 0xa438, 0x868d, 0xa438, 0x0252, 0xa438, 0xa9af, + 0xa438, 0x867f, 0xa438, 0xbf53, 0xa438, 0x2202, 0xa438, 0x52c8, + 0xa438, 0xa144, 0xa438, 0x3cbf, 0xa438, 0x547b, 0xa438, 0x0252, + 0xa438, 0xc8e4, 0xa438, 0x8ff8, 0xa438, 0xe58f, 0xa438, 0xf9bf, + 0xa438, 0x547e, 0xa438, 0x0252, 0xa438, 0xc8e4, 0xa438, 0x8ffa, + 0xa438, 0xe58f, 0xa438, 0xfbbf, 0xa438, 0x5481, 0xa438, 0x0252, + 0xa438, 0xc8e4, 0xa438, 0x8ffc, 0xa438, 0xe58f, 0xa438, 0xfdbf, + 0xa438, 0x5484, 0xa438, 0x0252, 0xa438, 0xc8e4, 0xa438, 0x8ffe, + 0xa438, 0xe58f, 0xa438, 0xffbf, 0xa438, 0x5322, 0xa438, 0x0252, + 0xa438, 0xc8a1, 0xa438, 0x4448, 0xa438, 0xaf85, 0xa438, 0xa7bf, + 0xa438, 0x5322, 0xa438, 0x0252, 0xa438, 0xc8a1, 0xa438, 0x313c, + 0xa438, 0xbf54, 0xa438, 0x7b02, 0xa438, 0x52c8, 0xa438, 0xe48f, + 0xa438, 0xf8e5, 0xa438, 0x8ff9, 0xa438, 0xbf54, 0xa438, 0x7e02, + 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfae5, 0xa438, 0x8ffb, + 0xa438, 0xbf54, 0xa438, 0x8102, 0xa438, 0x52c8, 0xa438, 0xe48f, + 0xa438, 0xfce5, 0xa438, 0x8ffd, 0xa438, 0xbf54, 0xa438, 0x8402, + 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfee5, 0xa438, 0x8fff, + 0xa438, 0xbf53, 0xa438, 0x2202, 0xa438, 0x52c8, 0xa438, 0xa131, + 0xa438, 0x03af, 0xa438, 0x85a7, 0xa438, 0xd480, 0xa438, 0x00bf, + 0xa438, 0x8684, 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x8687, + 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x868a, 0xa438, 0x0252, + 0xa438, 0xa9bf, 0xa438, 0x868d, 0xa438, 0x0252, 0xa438, 0xa9ef, + 0xa438, 0x95fd, 0xa438, 0xfc04, 0xa438, 0xf0d1, 0xa438, 0x2af0, + 0xa438, 0xd12c, 0xa438, 0xf0d1, 0xa438, 0x44f0, 0xa438, 0xd146, + 0xa438, 0xbf86, 0xa438, 0xa102, 0xa438, 0x52c8, 0xa438, 0xbf86, + 0xa438, 0xa102, 0xa438, 0x52c8, 0xa438, 0xd101, 0xa438, 0xaf06, + 0xa438, 0xa570, 0xa438, 0xce42, 0xa436, 0xb818, 0xa438, 0x043d, + 0xa436, 0xb81a, 0xa438, 0x06a3, 0xa436, 0xb81c, 0xa438, 0xffff, + 0xa436, 0xb81e, 0xa438, 0xffff, 0xa436, 0xb850, 0xa438, 0xffff, + 0xa436, 0xb852, 0xa438, 0xffff, 0xa436, 0xb878, 0xa438, 0xffff, + 0xa436, 0xb884, 0xa438, 0xffff, 0xa436, 0xb832, 0xa438, 0x0003, 0xa436, 0x0000, 0xa438, 0x0000, 0xa436, 0xB82E, 0xa438, 0x0000, 0xa436, 0x8024, 0xa438, 0x0000, 0xb820, 0x0000, 0xa436, 0x801E, - 0xa438, 0x0016, 0xFFFF, 0xFFFF + 0xa438, 0x0020, 0xFFFF, 0xFFFF }; static void @@ -8220,12 +9710,14 @@ rtl8125_init_hw_phy_mcu(struct net_device *dev) rtl8125_set_phy_mcu_8125a_1(dev); break; case CFG_METHOD_3: + case CFG_METHOD_6: rtl8125_set_phy_mcu_8125a_2(dev); break; case CFG_METHOD_4: rtl8125_set_phy_mcu_8125b_1(dev); break; case CFG_METHOD_5: + case CFG_METHOD_7: rtl8125_set_phy_mcu_8125b_2(dev); break; } @@ -8239,6 +9731,7 @@ rtl8125_init_hw_phy_mcu(struct net_device *dev) tp->HwHasWrRamCodeToMicroP = TRUE; } +#endif static void rtl8125_enable_phy_aldps(struct rtl8125_private *tp) @@ -8443,9 +9936,6 @@ rtl8125_hw_phy_config_8125a_2(struct net_device *dev) ); - RTL_W16(tp, EEE_TXIDLE_TIMER_8125, dev->mtu + ETH_HLEN + 0x20); - - mdio_direct_write_phy_ocp(tp, 0xB87C, 0x80A2); mdio_direct_write_phy_ocp(tp, 0xB87E, 0x0153); mdio_direct_write_phy_ocp(tp, 0xB87C, 0x809C); @@ -8859,9 +10349,6 @@ rtl8125_hw_phy_config_8125b_1(struct net_device *dev) mdio_direct_write_phy_ocp(tp, 0xB87E, 0x050E); - RTL_W16(tp, EEE_TXIDLE_TIMER_8125, dev->mtu + ETH_HLEN + 0x20); - - mdio_direct_write_phy_ocp(tp, 0xA436, 0x816C); mdio_direct_write_phy_ocp(tp, 0xA438, 0xC4A0); mdio_direct_write_phy_ocp(tp, 0xA436, 0x8170); @@ -9051,7 +10538,7 @@ rtl8125_hw_phy_config_8125b_2(struct net_device *dev) ); - RTL_W16(tp, EEE_TXIDLE_TIMER_8125, dev->mtu + ETH_HLEN + 0x20); + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, tp->eee.tx_lpi_timer); mdio_direct_write_phy_ocp(tp, 0xB87C, 0x80F5); mdio_direct_write_phy_ocp(tp, 0xB87E, 0x760E); @@ -9105,55 +10592,30 @@ rtl8125_hw_phy_config_8125b_2(struct net_device *dev) BIT_15 | BIT_13 ); - /* - mdio_direct_write_phy_ocp(tp, 0xBFA0, 0xD70D); - mdio_direct_write_phy_ocp(tp, 0xBFA2, 0x4100); - mdio_direct_write_phy_ocp(tp, 0xBFA4, 0xE868); - mdio_direct_write_phy_ocp(tp, 0xBFA6, 0xDC59); - mdio_direct_write_phy_ocp(tp, 0xB54C, 0x3C18); - ClearEthPhyOcpBit(tp, 0xBFA4, BIT_5); - mdio_direct_write_phy_ocp(tp, 0xA436, 0x817D); - SetEthPhyOcpBit(tp, 0xA438, BIT_12); - */ - - - if (aspm) { - if (HW_HAS_WRITE_PHY_MCU_RAM_CODE(tp)) { - rtl8125_enable_phy_aldps(tp); - } - } -} - -static void -rtl8125_set_hw_phy_before_init_phy_mcu(struct net_device *dev) -{ - struct rtl8125_private *tp = netdev_priv(dev); - u16 PhyRegValue; - - switch (tp->mcfg) { - case CFG_METHOD_4: - mdio_direct_write_phy_ocp(tp, 0xBF86, 0x9000); - - SetEthPhyOcpBit(tp, 0xC402, BIT_10); - ClearEthPhyOcpBit(tp, 0xC402, BIT_10); - PhyRegValue = mdio_direct_read_phy_ocp(tp, 0xBF86); - PhyRegValue &= (BIT_1 | BIT_0); - if (PhyRegValue != 0) - dprintk("PHY watch dog not clear, value = 0x%x \n", PhyRegValue); + mdio_direct_write_phy_ocp(tp, 0xA436, 0x8170); + ClearAndSetEthPhyOcpBit(tp, + 0xA438, + BIT_13 | BIT_10 | BIT_9 | BIT_8, + BIT_15 | BIT_14 | BIT_12 | BIT_11 + ); - mdio_direct_write_phy_ocp(tp, 0xBD86, 0x1010); - mdio_direct_write_phy_ocp(tp, 0xBD88, 0x1010); + /* + mdio_direct_write_phy_ocp(tp, 0xBFA0, 0xD70D); + mdio_direct_write_phy_ocp(tp, 0xBFA2, 0x4100); + mdio_direct_write_phy_ocp(tp, 0xBFA4, 0xE868); + mdio_direct_write_phy_ocp(tp, 0xBFA6, 0xDC59); + mdio_direct_write_phy_ocp(tp, 0xB54C, 0x3C18); + ClearEthPhyOcpBit(tp, 0xBFA4, BIT_5); + mdio_direct_write_phy_ocp(tp, 0xA436, 0x817D); + SetEthPhyOcpBit(tp, 0xA438, BIT_12); + */ - ClearAndSetEthPhyOcpBit(tp, - 0xBD4E, - BIT_11 | BIT_10, - BIT_11); - ClearAndSetEthPhyOcpBit(tp, - 0xBF46, - BIT_11 | BIT_10 | BIT_9 | BIT_8, - BIT_10 | BIT_9 | BIT_8); - break; + + if (aspm) { + if (HW_HAS_WRITE_PHY_MCU_RAM_CODE(tp)) { + rtl8125_enable_phy_aldps(tp); + } } } @@ -9162,25 +10624,33 @@ rtl8125_hw_phy_config(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); + if (tp->resume_not_chg_speed) return; + tp->phy_reset_enable(dev); if (HW_DASH_SUPPORT_TYPE_3(tp) && tp->HwPkgDet == 0x06) return; - rtl8125_set_hw_phy_before_init_phy_mcu(dev); +#ifndef ENABLE_USE_FIRMWARE_FILE + if (!tp->rtl_fw) { + rtl8125_set_hw_phy_before_init_phy_mcu(dev); - rtl8125_init_hw_phy_mcu(dev); + rtl8125_init_hw_phy_mcu(dev); + } +#endif switch (tp->mcfg) { case CFG_METHOD_2: rtl8125_hw_phy_config_8125a_1(dev); break; case CFG_METHOD_3: + case CFG_METHOD_6: rtl8125_hw_phy_config_8125a_2(dev); break; case CFG_METHOD_4: rtl8125_hw_phy_config_8125b_1(dev); break; case CFG_METHOD_5: + case CFG_METHOD_7: rtl8125_hw_phy_config_8125b_2(dev); break; } @@ -9191,6 +10661,8 @@ rtl8125_hw_phy_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: default: rtl8125_mdio_write(tp, 0x1F, 0x0A5B); rtl8125_clear_eth_phy_bit(tp, 0x12, BIT_15); @@ -9201,24 +10673,34 @@ rtl8125_hw_phy_config(struct net_device *dev) /*ocp phy power saving*/ /* if (aspm) { - if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3) + if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || + tp->mcfg == CFG_METHOD_6) rtl8125_enable_ocp_phy_power_saving(dev); } */ rtl8125_mdio_write(tp, 0x1F, 0x0000); - - //Modified for eee compablity issue - tp->eee_enabled = 0; if (HW_HAS_WRITE_PHY_MCU_RAM_CODE(tp)) { - if (tp->eee_enabled == 1) + if (tp->eee.eee_enabled) rtl8125_enable_eee(tp); else rtl8125_disable_eee(tp); } } +static void +rtl8125_up(struct net_device *dev) +{ + rtl8125_hw_init(dev); + rtl8125_hw_reset(dev); + rtl8125_powerup_pll(dev); + rtl8125_hw_ephy_config(dev); + rtl8125_hw_phy_config(dev); + rtl8125_hw_config(dev); +} + +/* static inline void rtl8125_delete_esd_timer(struct net_device *dev, struct timer_list *timer) { del_timer_sync(timer); @@ -9235,7 +10717,9 @@ static inline void rtl8125_request_esd_timer(struct net_device *dev) #endif mod_timer(timer, jiffies + RTL8125_ESD_TIMEOUT); } +*/ +/* static inline void rtl8125_delete_link_timer(struct net_device *dev, struct timer_list *timer) { del_timer_sync(timer); @@ -9253,6 +10737,7 @@ static inline void rtl8125_request_link_timer(struct net_device *dev) #endif mod_timer(timer, jiffies + RTL8125_LINK_TIMEOUT); } +*/ #ifdef CONFIG_NET_POLL_CONTROLLER /* @@ -9294,6 +10779,8 @@ rtl8125_get_bios_setting(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: tp->bios_setting = RTL_R32(tp, TimeInt2); break; } @@ -9309,6 +10796,8 @@ rtl8125_set_bios_setting(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W32(tp, TimeInt2, tp->bios_setting); break; } @@ -9322,28 +10811,28 @@ rtl8125_setup_mqs_reg(struct rtl8125_private *tp) //tx tp->tx_ring[0].tdsar_reg = TxDescStartAddrLow; for (i = 1; i < R8125_MAX_TX_QUEUES; i++) { - tp->tx_ring[i].tdsar_reg = (u16)(TNPDS_Q1_LOW_8125 + (i - 1) * 8); + tp->tx_ring[i].tdsar_reg = (u16)(TNPDS_Q1_LOW_8125 + (i - 1) * 8); } for (i = 0; i < R8125_MAX_TX_QUEUES; i++) { - tp->tx_ring[i].hw_clo_ptr_reg = (u16)(HW_CLO_PTR0_8125 + i * 4); - tp->tx_ring[i].sw_tail_ptr_reg = (u16)(SW_TAIL_PTR0_8125 + i * 4); + tp->tx_ring[i].hw_clo_ptr_reg = (u16)(HW_CLO_PTR0_8125 + i * 4); + tp->tx_ring[i].sw_tail_ptr_reg = (u16)(SW_TAIL_PTR0_8125 + i * 4); } //rx tp->rx_ring[0].rdsar_reg = RxDescAddrLow; for (i = 1; i < R8125_MAX_RX_QUEUES; i++) { - tp->rx_ring[i].rdsar_reg = (u16)(RDSAR_Q1_LOW_8125 + (i - 1) * 8); + tp->rx_ring[i].rdsar_reg = (u16)(RDSAR_Q1_LOW_8125 + (i - 1) * 8); } tp->isr_reg[0] = ISR0_8125; for (i = 1; i < R8125_MAX_QUEUES; i++) { - tp->isr_reg[i] = (u16)(ISR1_8125 + (i - 1) * 4); + tp->isr_reg[i] = (u16)(ISR1_8125 + (i - 1) * 4); } tp->imr_reg[0] = IMR0_8125; for (i = 1; i < R8125_MAX_QUEUES; i++) { - tp->imr_reg[i] = (u16)(IMR1_8125 + (i - 1) * 4); + tp->imr_reg[i] = (u16)(IMR1_8125 + (i - 1) * 4); } } @@ -9355,11 +10844,13 @@ rtl8125_init_software_variable(struct net_device *dev) rtl8125_get_bios_setting(dev); +#ifdef ENABLE_LIB_SUPPORT + tp->ring_lib_enabled = 1; +#endif + switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: - case CFG_METHOD_4: - case CFG_METHOD_5: //tp->HwSuppDashVer = 3; break; default: @@ -9372,6 +10863,8 @@ rtl8125_init_software_variable(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: tp->HwPkgDet = rtl8125_mac_ocp_read(tp, 0xDC00); tp->HwPkgDet = (tp->HwPkgDet >> 3) & 0x07; break; @@ -9385,6 +10878,8 @@ rtl8125_init_software_variable(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: tp->HwSuppNowIsOobVer = 1; break; } @@ -9394,6 +10889,8 @@ rtl8125_init_software_variable(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: tp->HwPcieSNOffset = 0x16C; break; } @@ -9449,6 +10946,8 @@ rtl8125_init_software_variable(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: tp->org_pci_offset_99 = rtl8125_csi_fun0_read_byte(tp, 0x99); tp->org_pci_offset_99 &= ~(BIT_5|BIT_6); break; @@ -9457,10 +10956,12 @@ rtl8125_init_software_variable(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: + case CFG_METHOD_6: tp->org_pci_offset_180 = rtl8125_csi_fun0_read_byte(tp, 0x264); break; case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: tp->org_pci_offset_180 = rtl8125_csi_fun0_read_byte(tp, 0x214); break; } @@ -9474,6 +10975,8 @@ rtl8125_init_software_variable(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: default: tp->use_timer_interrrupt = TRUE; break; @@ -9482,18 +10985,13 @@ rtl8125_init_software_variable(struct net_device *dev) if (timer_count == 0 || tp->mcfg == CFG_METHOD_DEFAULT) tp->use_timer_interrrupt = FALSE; - switch (tp->mcfg) { - default: - - tp->SwPaddingShortPktLen = ETH_ZLEN; - break; - } - switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: tp->HwSuppMagicPktVer = WAKEUP_MAGIC_PACKET_V3; break; default: @@ -9506,7 +11004,19 @@ rtl8125_init_software_variable(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: - tp->HwSuppCheckPhyDisableModeVer = 3; + case CFG_METHOD_6: + case CFG_METHOD_7: + tp->HwSuppLinkChgWakeUpVer = 3; + break; + } + + switch (tp->mcfg) { + case CFG_METHOD_3: + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: + tp->HwSuppD0SpeedUpVer = 1; break; } @@ -9515,7 +11025,9 @@ rtl8125_init_software_variable(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: - tp->HwSuppGigaForceMode = TRUE; + case CFG_METHOD_6: + case CFG_METHOD_7: + tp->HwSuppCheckPhyDisableModeVer = 3; break; } @@ -9524,6 +11036,8 @@ rtl8125_init_software_variable(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: tp->HwSuppTxNoCloseVer = 3; break; } @@ -9534,6 +11048,7 @@ rtl8125_init_software_variable(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: + case CFG_METHOD_6: tp->RequireLSOPatch = TRUE; break; } @@ -9543,12 +11058,14 @@ rtl8125_init_software_variable(struct net_device *dev) tp->sw_ram_code_ver = NIC_RAMCODE_VERSION_CFG_METHOD_2; break; case CFG_METHOD_3: + case CFG_METHOD_6: tp->sw_ram_code_ver = NIC_RAMCODE_VERSION_CFG_METHOD_3; break; case CFG_METHOD_4: tp->sw_ram_code_ver = NIC_RAMCODE_VERSION_CFG_METHOD_4; break; case CFG_METHOD_5: + case CFG_METHOD_7: tp->sw_ram_code_ver = NIC_RAMCODE_VERSION_CFG_METHOD_5; break; } @@ -9560,17 +11077,39 @@ rtl8125_init_software_variable(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_3: + case CFG_METHOD_6: if ((rtl8125_mac_ocp_read(tp, 0xD442) & BIT_5) && - (mdio_direct_read_phy_ocp(tp, 0xD068) & BIT_1) - ) { + (mdio_direct_read_phy_ocp(tp, 0xD068) & BIT_1)) tp->RequirePhyMdiSwapPatch = TRUE; - } + break; + } + + switch (tp->mcfg) { + case CFG_METHOD_2: + case CFG_METHOD_3: + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: + tp->HwSuppMacMcuVer = 2; + break; + } + + switch (tp->mcfg) { + case CFG_METHOD_2: + case CFG_METHOD_3: + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: + tp->MacMcuPageSize = RTL8125_MAC_MCU_PAGE_SIZE; break; } switch (tp->mcfg) { case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: tp->HwSuppNumTxQueues = 2; tp->HwSuppNumRxQueues = 4; break; @@ -9590,6 +11129,7 @@ rtl8125_init_software_variable(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: tp->HwSuppRssVer = 5; tp->HwSuppIndirTblEntries = 128; break; @@ -9622,6 +11162,7 @@ rtl8125_init_software_variable(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: tp->HwSuppPtpVer = 1; break; } @@ -9647,6 +11188,7 @@ rtl8125_init_software_variable(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: tp->HwSuppIsrVer = 2; break; default: @@ -9655,8 +11197,11 @@ rtl8125_init_software_variable(struct net_device *dev) } tp->HwCurrIsrVer = tp->HwSuppIsrVer; - if (tp->HwSuppIsrVer == 2 && !(tp->features & RTL_FEATURE_MSIX)) - tp->HwCurrIsrVer = 1; + if (tp->HwSuppIsrVer == 2) { + if (!(tp->features & RTL_FEATURE_MSIX) || + tp->irq_nvecs < R8125_MIN_MSIX_VEC_8125B) + tp->HwCurrIsrVer = 1; + } if (tp->HwCurrIsrVer < 2 || tp->irq_nvecs < 19) tp->num_tx_rings = 1; @@ -9664,15 +11209,15 @@ rtl8125_init_software_variable(struct net_device *dev) if (tp->HwCurrIsrVer == 2) { int i; - tp->intr_mask = ISRIMR_TOK_Q0; + tp->intr_mask = ISRIMR_V2_LINKCHG | ISRIMR_TOK_Q0; if (tp->num_tx_rings > 1) tp->intr_mask |= ISRIMR_TOK_Q1; for (i = 0; i < tp->num_rx_rings; i++) tp->intr_mask |= ISRIMR_V2_ROK_Q0 << i; } else { - tp->intr_mask = RxDescUnavail | TxOK | RxOK | SWInt; - tp->timer_intr_mask = PCSTimeout; + tp->intr_mask = LinkChg | RxDescUnavail | TxOK | RxOK | SWInt; + tp->timer_intr_mask = LinkChg | PCSTimeout; #ifdef ENABLE_DASH_SUPPORT if (tp->DASH) { @@ -9687,14 +11232,27 @@ rtl8125_init_software_variable(struct net_device *dev) switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: + case CFG_METHOD_6: tp->HwSuppIntMitiVer = 3; break; case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: tp->HwSuppIntMitiVer = 4; break; } + switch (tp->mcfg) { + case CFG_METHOD_2: + case CFG_METHOD_3: + case CFG_METHOD_4: + case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: + tp->HwSuppExtendTallyCounterVer = 1; + break; + } + timer_count_v2 = (timer_count / 0x100); tp->NicCustLedValue = RTL_R16(tp, CustomLED); @@ -9702,12 +11260,16 @@ rtl8125_init_software_variable(struct net_device *dev) tp->wol_opts = rtl8125_get_hw_wol(tp); tp->wol_enabled = (tp->wol_opts) ? WOL_ENABLED : WOL_DISABLED; - rtl8125_link_option((u8*)&autoneg_mode, (u32*)&speed_mode, (u8*)&duplex_mode, (u32*)&advertising_mode); + if (tp->mcfg == CFG_METHOD_6 || tp->mcfg == CFG_METHOD_7) + rtl8125_link_option_giga((u8*)&autoneg_mode, (u32*)&speed_mode, (u8*)&duplex_mode, (u32*)&advertising_mode); + else + rtl8125_link_option((u8*)&autoneg_mode, (u32*)&speed_mode, (u8*)&duplex_mode, (u32*)&advertising_mode); tp->autoneg = autoneg_mode; tp->speed = speed_mode; tp->duplex = duplex_mode; tp->advertising = advertising_mode; + tp->fcpause = rtl8125_fc_full; tp->max_jumbo_frame_size = rtl_chip_info[tp->chipset].jumbo_frame_sz; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) @@ -9716,9 +11278,23 @@ rtl8125_init_software_variable(struct net_device *dev) dev->max_mtu = tp->max_jumbo_frame_size; #endif //LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) - //Modified for eee issue - tp->eee_enabled = 0; //eee_enable; - tp->eee_adv_t = 0; //MDIO_EEE_1000T | MDIO_EEE_100TX; + if (tp->mcfg != CFG_METHOD_DEFAULT) { + struct ethtool_eee *eee = &tp->eee; + + eee->eee_enabled = eee_enable; + eee->supported = SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full; + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + eee->supported |= SUPPORTED_2500baseX_Full; + break; + } + eee->advertised = mmd_eee_adv_to_ethtool_adv_t(MDIO_EEE_1000T | MDIO_EEE_100TX); + eee->tx_lpi_timer = dev->mtu + ETH_HLEN + 0x20; + } + + tp->ptp_master_mode = enable_ptp_master_mode; } static void @@ -9745,6 +11321,7 @@ rtl8125_release_board(struct pci_dev *pdev, iounmap(ioaddr); pci_release_regions(pdev); + pci_clear_mwi(pdev); pci_disable_device(pdev); free_netdev(dev); } @@ -9762,7 +11339,9 @@ rtl8125_get_mac_address(struct net_device *dev) if(tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) { *(u32*)&mac_addr[0] = RTL_R32(tp, BACKUP_ADDR0_8125); *(u16*)&mac_addr[4] = RTL_R16(tp, BACKUP_ADDR1_8125); } @@ -9804,19 +11383,14 @@ rtl8125_set_mac_address(struct net_device *dev, { struct rtl8125_private *tp = netdev_priv(dev); struct sockaddr *addr = p; - unsigned long flags; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - spin_lock_irqsave(&tp->lock, flags); - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); rtl8125_rar_set(tp, dev->dev_addr); - spin_unlock_irqrestore(&tp->lock, flags); - return 0; } @@ -10516,7 +12090,6 @@ rtl8125_do_ioctl(struct net_device *dev, struct rtl8125_private *tp = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(ifr); int ret; - unsigned long flags; ret = 0; switch (cmd) { @@ -10525,19 +12098,15 @@ rtl8125_do_ioctl(struct net_device *dev, break; case SIOCGMIIREG: - spin_lock_irqsave(&tp->lock, flags); rtl8125_mdio_write(tp, 0x1F, 0x0000); data->val_out = rtl8125_mdio_read(tp, data->reg_num); - spin_unlock_irqrestore(&tp->lock, flags); break; case SIOCSMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); rtl8125_mdio_write(tp, 0x1F, 0x0000); rtl8125_mdio_write(tp, data->reg_num, data->val_in); - spin_unlock_irqrestore(&tp->lock, flags); break; #ifdef ETHTOOL_OPS_COMPAT @@ -10611,6 +12180,8 @@ rtl8125_phy_power_up(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_wait_phy_ups_resume(dev, 3); break; }; @@ -10670,9 +12241,12 @@ rtl8125_init_board(struct pci_dev *pdev, goto err_out_free_dev; } - rc = pci_set_mwi(pdev); - if (rc < 0) - goto err_out_disable; + if (pci_set_mwi(pdev) < 0) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + if (netif_msg_drv(&debug)) + dev_info(&pdev->dev, "Mem-Wr-Inval unavailable.\n"); +#endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + } /* save power state before pci_enable_device overwrites it */ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); @@ -10735,8 +12309,6 @@ rtl8125_init_board(struct pci_dev *pdev, } } - pci_set_master(pdev); - /* ioremap MMIO region */ ioaddr = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); if (ioaddr == NULL) { @@ -10780,13 +12352,9 @@ rtl8125_init_board(struct pci_dev *pdev, err_out_free_res: pci_release_regions(pdev); - err_out_mwi: pci_clear_mwi(pdev); - -err_out_disable: pci_disable_device(pdev); - err_out_free_dev: free_netdev(dev); err_out: @@ -10796,24 +12364,10 @@ rtl8125_init_board(struct pci_dev *pdev, } static void -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) -rtl8125_esd_timer(unsigned long __opaque) -#else -rtl8125_esd_timer(struct timer_list *t) -#endif +rtl8125_esd_checker(struct rtl8125_private *tp) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) - struct net_device *dev = (struct net_device *)__opaque; - struct rtl8125_private *tp = netdev_priv(dev); - struct timer_list *timer = &tp->esd_timer; -#else - struct rtl8125_private *tp = from_timer(tp, t, esd_timer); struct net_device *dev = tp->dev; - struct timer_list *timer = t; -#endif struct pci_dev *pdev = tp->pci_dev; - unsigned long timeout = RTL8125_ESD_TIMEOUT; - unsigned long flags; u8 cmd; u16 io_base_l; u16 mem_base_l; @@ -10830,8 +12384,6 @@ rtl8125_esd_timer(struct timer_list *t) u32 pci_sn_l; u32 pci_sn_h; - spin_lock_irqsave(&tp->lock, flags); - tp->esd_flag = 0; pci_read_config_byte(pdev, PCI_COMMAND, &cmd); @@ -10839,6 +12391,12 @@ rtl8125_esd_timer(struct timer_list *t) printk(KERN_ERR "%s: cmd = 0x%02x, should be 0x%02x \n.", dev->name, cmd, tp->pci_cfg_space.cmd); pci_write_config_byte(pdev, PCI_COMMAND, tp->pci_cfg_space.cmd); tp->esd_flag |= BIT_0; + + pci_read_config_byte(pdev, PCI_COMMAND, &cmd); + if (cmd == 0xff) { + printk(KERN_ERR "%s: pci link is down \n.", dev->name); + goto exit; + } } pci_read_config_word(pdev, PCI_BASE_ADDRESS_0, &io_base_l); @@ -10943,25 +12501,44 @@ rtl8125_esd_timer(struct timer_list *t) if (tp->esd_flag != 0) { printk(KERN_ERR "%s: esd_flag = 0x%04x\n.\n", dev->name, tp->esd_flag); - rtl8125_stop_all_tx_queue(dev); + netif_tx_stop_all_queues(dev); netif_carrier_off(dev); rtl8125_hw_reset(dev); rtl8125_tx_clear(tp); rtl8125_rx_clear(tp); rtl8125_init_ring(dev); - rtl8125_hw_init(dev); - rtl8125_powerup_pll(dev); - rtl8125_hw_ephy_config(dev); - rtl8125_hw_phy_config(dev); - rtl8125_hw_config(dev); + rtl8125_up(dev); + rtl8125_enable_hw_linkchg_interrupt(tp); rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); tp->esd_flag = 0; } - spin_unlock_irqrestore(&tp->lock, flags); +exit: + return; +} +/* +static void +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) +rtl8125_esd_timer(unsigned long __opaque) +#else +rtl8125_esd_timer(struct timer_list *t) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) + struct net_device *dev = (struct net_device *)__opaque; + struct rtl8125_private *tp = netdev_priv(dev); + struct timer_list *timer = &tp->esd_timer; +#else + struct rtl8125_private *tp = from_timer(tp, t, esd_timer); + //struct net_device *dev = tp->dev; + struct timer_list *timer = t; +#endif + rtl8125_esd_checker(tp); mod_timer(timer, jiffies + timeout); } +*/ +/* static void #if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) rtl8125_link_timer(unsigned long __opaque) @@ -10978,14 +12555,11 @@ rtl8125_link_timer(struct timer_list *t) struct net_device *dev = tp->dev; struct timer_list *timer = t; #endif - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); rtl8125_check_link_status(dev); - spin_unlock_irqrestore(&tp->lock, flags); mod_timer(timer, jiffies + RTL8125_LINK_TIMEOUT); } +*/ int rtl8125_enable_msix(struct rtl8125_private *tp) @@ -11043,19 +12617,20 @@ static int rtl8125_try_msi(struct rtl8125_private *tp) unsigned msi = 0; int nvecs = 1; + tp->max_irq_nvecs = 1; + tp->min_irq_nvecs = 1; +#ifndef DISABLE_MULTI_MSIX_VECTOR switch (tp->mcfg) { case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_7: tp->max_irq_nvecs = R8125_MAX_MSIX_VEC_8125B; tp->min_irq_nvecs = R8125_MIN_MSIX_VEC_8125B; break; - default: - tp->max_irq_nvecs = 1; - tp->min_irq_nvecs = 1; - break; } +#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) +#if defined(RTL_USE_NEW_INTR_API) if ((nvecs = pci_alloc_irq_vectors(pdev, tp->min_irq_nvecs, tp->max_irq_nvecs, PCI_IRQ_MSIX)) > 0) msi |= RTL_FEATURE_MSIX; else if ((nvecs = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES)) > 0 && @@ -11082,7 +12657,7 @@ static int rtl8125_try_msi(struct rtl8125_private *tp) static void rtl8125_disable_msi(struct pci_dev *pdev, struct rtl8125_private *tp) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) +#if defined(RTL_USE_NEW_INTR_API) if (tp->features & (RTL_FEATURE_MSI | RTL_FEATURE_MSIX)) pci_free_irq_vectors(pdev); #elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13) @@ -11096,7 +12671,7 @@ static void rtl8125_disable_msi(struct pci_dev *pdev, struct rtl8125_private *tp static int rtl8125_get_irq(struct pci_dev *pdev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) +#if defined(RTL_USE_NEW_INTR_API) return pci_irq_vector(pdev, 0); #else return pdev->irq; @@ -11132,6 +12707,7 @@ static const struct net_device_ops rtl8125_netdev_ops = { }; #endif + #ifdef CONFIG_R8125_NAPI static int rtl8125_poll(napi_ptr napi, napi_budget budget) @@ -11141,28 +12717,20 @@ static int rtl8125_poll(napi_ptr napi, napi_budget budget) RTL_GET_NETDEV(tp) unsigned int work_to_do = RTL_NAPI_QUOTA(budget, dev); unsigned int work_done = 0; - unsigned long flags; int i; for (i = 0; i < tp->num_rx_rings; i++) work_done += rtl8125_rx_interrupt(dev, tp, &tp->rx_ring[i], budget); - spin_lock_irqsave(&tp->lock, flags); for (i = 0; i < tp->num_tx_rings; i++) - rtl8125_tx_interrupt(&tp->tx_ring[i]); - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_tx_interrupt(&tp->tx_ring[i], budget); RTL_NAPI_QUOTA_UPDATE(dev, work_done, budget); if (work_done < work_to_do) { #ifdef ENABLE_DASH_SUPPORT - if (tp->DASH) { - struct net_device *dev = tp->dev; - - spin_lock_irqsave(&tp->lock, flags); - HandleDashInterrupt(dev); - spin_unlock_irqrestore(&tp->lock, flags); - } + if (tp->DASH) + HandleDashInterrupt(tp->dev); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) @@ -11184,18 +12752,6 @@ static int rtl8125_poll(napi_ptr napi, napi_budget budget) return RTL_NAPI_RETURN_VALUE; } -static int -rtl8125_tx_interrupt_with_vector(struct rtl8125_private *tp, const int message_id) -{ - int count = 0; - if (message_id == 16) - count += rtl8125_tx_interrupt(&tp->tx_ring[0]); - else if (message_id == 18) - count += rtl8125_tx_interrupt(&tp->tx_ring[1]); - - return count; -} - #if 0 static int rtl8125_poll_msix_ring(napi_ptr napi, napi_budget budget) { @@ -11204,26 +12760,18 @@ static int rtl8125_poll_msix_ring(napi_ptr napi, napi_budget budget) RTL_GET_NETDEV(tp) unsigned int work_to_do = RTL_NAPI_QUOTA(budget, dev); unsigned int work_done = 0; - unsigned long flags; const int message_id = r8125napi->index; work_done += rtl8125_rx_interrupt(dev, tp, &tp->rx_ring[message_id], budget); - spin_lock_irqsave(&tp->lock, flags); - rtl8125_tx_interrupt_with_vector(tp, message_id); - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_tx_interrupt_with_vector(tp, message_id, budget); RTL_NAPI_QUOTA_UPDATE(dev, work_done, budget); if (work_done < work_to_do) { #ifdef ENABLE_DASH_SUPPORT - if (tp->DASH && message_id == 0) { - struct net_device *dev = tp->dev; - - spin_lock_irqsave(&tp->lock, flags); - HandleDashInterrupt(dev); - spin_unlock_irqrestore(&tp->lock, flags); - } + if (tp->DASH && message_id == 0) + HandleDashInterrupt(tp->dev); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) @@ -11253,15 +12801,12 @@ static int rtl8125_poll_msix_tx(napi_ptr napi, napi_budget budget) RTL_GET_NETDEV(tp) unsigned int work_to_do = RTL_NAPI_QUOTA(budget, dev); unsigned int work_done = 0; - unsigned long flags; const int message_id = r8125napi->index; //suppress unused variable (void)(dev); - spin_lock_irqsave(&tp->lock, flags); - rtl8125_tx_interrupt_with_vector(tp, message_id); - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_tx_interrupt_with_vector(tp, message_id, budget); RTL_NAPI_QUOTA_UPDATE(dev, work_done, budget); @@ -11296,7 +12841,7 @@ static int rtl8125_poll_msix_other(napi_ptr napi, napi_budget budget) //suppress unused variable (void)(dev); (void)(work_to_do); - + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) RTL_NETIF_RX_COMPLETE(dev, napi, work_to_do); #else @@ -11401,6 +12946,23 @@ static void rtl8125_init_napi(struct rtl8125_private *tp) } } +static int +rtl8125_set_real_num_queue(struct rtl8125_private *tp) +{ + int retval = 0; + + retval = netif_set_real_num_tx_queues(tp->dev, tp->num_tx_rings); + if (retval < 0) + goto exit; + + retval = netif_set_real_num_rx_queues(tp->dev, tp->num_rx_rings); + if (retval < 0) + goto exit; + +exit: + return retval; +} + static int __devinit rtl8125_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -11439,9 +13001,9 @@ rtl8125_init_one(struct pci_dev *pdev, dev_err(&pdev->dev, "Can't allocate interrupt\n"); goto err_out_1; } - +#ifdef ENABLE_PTP_SUPPORT spin_lock_init(&tp->lock); - +#endif rtl8125_init_software_variable(dev); RTL_NET_DEVICE_OPS(rtl8125_netdev_ops); @@ -11471,8 +13033,25 @@ rtl8125_init_one(struct pci_dev *pdev, * enable them. Use at own risk! */ tp->cp_cmd |= RTL_R16(tp, CPlusCmd); + if (tp->mcfg != CFG_METHOD_DEFAULT) { - dev->features |= NETIF_F_IP_CSUM; + + /* Add by GanFan, to set net features according to parameters + * In ESXi,use 'esxcli system module parameters set (or list) ' command + * e.g. esxcli system module parameter set -m r8125 -p "enable_tso=0" + */ +#if defined (__VMKLNX__) + if (enable_tx_csum) + dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + else + dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM) ; + + if (enable_tso) + dev->features |= NETIF_F_TSO | NETIF_F_TSO6; + else + dev->features &= (NETIF_F_TSO | NETIF_F_TSO6); +#endif //#if defined (__VMKLNX__) + #if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) tp->cp_cmd |= RxChkSum; #else @@ -11500,13 +13079,6 @@ rtl8125_init_one(struct pci_dev *pdev, #endif //LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) #endif //LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) -//Disable all buggy checksums -#ifdef __VMKLNX__ - dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - tp->cp_cmd &= ~RxChkSum; - netif_set_gso_max_size(dev, LSO_64K); -#endif //#ifdef __VMKLNX__ - #ifdef ENABLE_RSS_SUPPORT if (tp->EnableRss) { @@ -11524,9 +13096,16 @@ rtl8125_init_one(struct pci_dev *pdev, #ifdef ENABLE_LIB_SUPPORT ATOMIC_INIT_NOTIFIER_HEAD(&tp->lib_nh); #endif + rtl8125_init_all_schedule_work(tp); + + rc = rtl8125_set_real_num_queue(tp); + if (rc < 0) + goto err_out; rtl8125_exit_oob(dev); + rtl8125_powerup_pll(dev); + rtl8125_hw_init(dev); rtl8125_hw_reset(dev); @@ -11539,6 +13118,8 @@ rtl8125_init_one(struct pci_dev *pdev, rtl8125_get_mac_address(dev); + tp->fw_name = rtl_chip_fw_infos[tp->mcfg].fw_name; + tp->tally_vaddr = dma_alloc_coherent(&pdev->dev, sizeof(*tp->tally_vaddr), &tp->tally_paddr, GFP_KERNEL); if (!tp->tally_vaddr) { @@ -11594,6 +13175,10 @@ rtl8125_remove_one(struct pci_dev *pdev) assert(dev != NULL); assert(tp != NULL); + set_bit(R8125_FLAG_DOWN, tp->task_flags); + + rtl8125_cancel_all_schedule_work(tp); + #ifdef CONFIG_R8125_NAPI rtl8125_del_napi(tp); #endif @@ -11611,6 +13196,11 @@ rtl8125_remove_one(struct pci_dev *pdev) } rtl8125_release_board(pdev, dev); + +#ifdef ENABLE_USE_FIRMWARE_FILE + rtl8125_release_firmware(tp); +#endif + pci_set_drvdata(pdev, NULL); } @@ -11632,12 +13222,12 @@ static void rtl8125_free_irq(struct rtl8125_private *tp) struct r8125_napi *r8125napi = &tp->r8125napi[i]; if (irq->requested) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) + irq->requested = 0; +#if defined(RTL_USE_NEW_INTR_API) pci_free_irq(tp->pci_dev, i, r8125napi); #else free_irq(irq->vector, r8125napi); #endif - irq->requested = 0; } } } @@ -11651,7 +13241,7 @@ static int rtl8125_alloc_irq(struct rtl8125_private *tp) int i = 0; const int len = sizeof(tp->irq_tbl[0].name); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) +#if defined(RTL_USE_NEW_INTR_API) for (i=0; iirq_nvecs; i++) { irq = &tp->irq_tbl[i]; if (tp->features & RTL_FEATURE_MSIX && @@ -11671,6 +13261,10 @@ static int rtl8125_alloc_irq(struct rtl8125_private *tp) irq->requested = 1; } #else + unsigned long irq_flags = 0; +#ifdef ENABLE_LIB_SUPPORT + irq_flags |= IRQF_NO_SUSPEND; +#endif if (tp->features & RTL_FEATURE_MSIX && tp->HwCurrIsrVer == 2) { for (i=0; iirq_nvecs; i++) { @@ -11678,7 +13272,7 @@ static int rtl8125_alloc_irq(struct rtl8125_private *tp) irq->handler = rtl8125_interrupt_msix; r8125napi = &tp->r8125napi[i]; snprintf(irq->name, len, "%s-%d", dev->name, i); - rc = request_irq(irq->vector, irq->handler, 0, irq->name, r8125napi); + rc = request_irq(irq->vector, irq->handler, irq_flags, irq->name, r8125napi); if (rc) break; @@ -11692,7 +13286,8 @@ static int rtl8125_alloc_irq(struct rtl8125_private *tp) snprintf(irq->name, len, "%s-0", dev->name); if (!(tp->features & RTL_FEATURE_MSIX)) irq->vector = dev->irq; - rc = request_irq(irq->vector, irq->handler, (tp->features & (RTL_FEATURE_MSI | RTL_FEATURE_MSIX)) ? 0 : SA_SHIRQ, irq->name, r8125napi); + irq_flags |= (tp->features & (RTL_FEATURE_MSI | RTL_FEATURE_MSIX)) ? 0 : SA_SHIRQ; + rc = request_irq(irq->vector, irq->handler, irq_flags, irq->name, r8125napi); if (rc == 0) irq->requested = 1; @@ -11774,40 +13369,41 @@ static void rtl8125_free_rx_desc(struct rtl8125_private *tp) static void rtl8125_free_alloc_resources(struct rtl8125_private *tp) { - struct pci_dev *pdev = tp->pci_dev; - rtl8125_free_rx_desc(tp); rtl8125_free_tx_desc(tp); - - if (tp->ShortPacketEmptyBuffer != NULL) { - dma_free_coherent(&pdev->dev, ETH_ZLEN, tp->ShortPacketEmptyBuffer, - tp->ShortPacketEmptyBufferPhy); - tp->ShortPacketEmptyBuffer = NULL; - } } -int rtl8125_set_real_num_queue(struct rtl8125_private *tp) +#ifdef ENABLE_USE_FIRMWARE_FILE +static void rtl8125_request_firmware(struct rtl8125_private *tp) { - int retval = 0; + struct rtl8125_fw *rtl_fw; - retval = netif_set_real_num_tx_queues(tp->dev, tp->num_tx_rings); - if (retval < 0) - goto exit; + /* firmware loaded already or no firmware available */ + if (tp->rtl_fw || !tp->fw_name) + return; - retval = netif_set_real_num_rx_queues(tp->dev, tp->num_rx_rings); - if (retval < 0) - goto exit; + rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL); + if (!rtl_fw) + return; -exit: - return retval; + rtl_fw->phy_write = rtl8125_mdio_write; + rtl_fw->phy_read = rtl8125_mdio_read; + rtl_fw->mac_mcu_write = mac_mcu_write; + rtl_fw->mac_mcu_read = mac_mcu_read; + rtl_fw->fw_name = tp->fw_name; + rtl_fw->dev = tp_to_dev(tp); + + if (rtl8125_fw_request_firmware(rtl_fw)) + kfree(rtl_fw); + else + tp->rtl_fw = rtl_fw; } +#endif -static int rtl8125_open(struct net_device *dev) +int rtl8125_open(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - struct pci_dev *pdev = tp->pci_dev; - unsigned long flags; int retval; retval = -ENOMEM; @@ -11823,20 +13419,11 @@ static int rtl8125_open(struct net_device *dev) if (rtl8125_alloc_tx_desc(tp) < 0 || rtl8125_alloc_rx_desc(tp) < 0) goto err_free_all_allocated_mem; - if (tp->UseSwPaddingShortPkt) { - tp->ShortPacketEmptyBuffer = dma_alloc_coherent(&pdev->dev, SHORT_PACKET_PADDING_BUF_SIZE, - &tp->ShortPacketEmptyBufferPhy, GFP_KERNEL); - if (!tp->ShortPacketEmptyBuffer) - goto err_free_all_allocated_mem; - - memset(tp->ShortPacketEmptyBuffer, 0x0, SHORT_PACKET_PADDING_BUF_SIZE); - } - retval = rtl8125_init_ring(dev); if (retval < 0) goto err_free_all_allocated_mem; - retval = rtl8125_set_real_num_queue(tp); + retval = rtl8125_alloc_irq(tp); if (retval < 0) goto err_free_all_allocated_mem; @@ -11851,49 +13438,39 @@ static int rtl8125_open(struct net_device *dev) dev->dev_addr[4], dev->dev_addr[5], dev->irq); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - INIT_WORK(&tp->task, NULL, dev); -#else - INIT_DELAYED_WORK(&tp->task, NULL); -#endif - -#ifdef CONFIG_R8125_NAPI - rtl8125_enable_napi(tp); -#endif - - spin_lock_irqsave(&tp->lock, flags); - - rtl8125_exit_oob(dev); - - rtl8125_hw_init(dev); - - rtl8125_hw_reset(dev); - - rtl8125_powerup_pll(dev); +#ifdef ENABLE_USE_FIRMWARE_FILE + rtl8125_request_firmware(tp); +#endif + pci_set_master(tp->pci_dev); - rtl8125_hw_ephy_config(dev); +#ifdef CONFIG_R8125_NAPI + rtl8125_enable_napi(tp); +#endif - rtl8125_hw_phy_config(dev); + rtl8125_exit_oob(dev); - rtl8125_hw_config(dev); + rtl8125_up(dev); #ifdef ENABLE_PTP_SUPPORT if (tp->EnablePtp) rtl8125_ptp_init(tp); #endif + clear_bit(R8125_FLAG_DOWN, tp->task_flags); - rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); + if (tp->resume_not_chg_speed) + rtl8125_check_link_status(dev); + else + rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); - spin_unlock_irqrestore(&tp->lock, flags); + if (tp->esd_flag == 0) { + //rtl8125_request_esd_timer(dev); - retval = rtl8125_alloc_irq(tp); - if (retval < 0) - goto err_free_all_allocated_mem; + rtl8125_schedule_esd_work(tp); + } - if (tp->esd_flag == 0) - rtl8125_request_esd_timer(dev); + //rtl8125_request_link_timer(dev); - rtl8125_request_link_timer(dev); + rtl8125_enable_hw_linkchg_interrupt(tp); out: @@ -12000,14 +13577,7 @@ rtl8125_hw_set_rx_packet_filter(struct net_device *dev) static void rtl8125_set_rx_mode(struct net_device *dev) { - struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); - rtl8125_hw_set_rx_packet_filter(dev); - - spin_unlock_irqrestore(&tp->lock, flags); } void @@ -12056,6 +13626,8 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W8(tp, 0xF1, RTL_R8(tp, 0xF1) & ~BIT_7); RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~BIT_7); RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~BIT_0); @@ -12068,6 +13640,8 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~BIT_1); break; } @@ -12077,6 +13651,8 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: //IntMITI_0-IntMITI_31 for (i=0xA00; i<0xB00; i+=4) RTL_W32(tp, i, 0x00000000); @@ -12089,6 +13665,8 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xC0B6); mac_ocp_data &= BIT_0; rtl8125_mac_ocp_write(tp, 0xC0B6, mac_ocp_data); @@ -12097,6 +13675,8 @@ rtl8125_hw_config(struct net_device *dev) rtl8125_tally_counter_addr_fill(tp); + rtl8125_enable_extend_tally_couter(tp); + rtl8125_desc_addr_fill(tp); /* Set DMA burst size and Interframe Gap Time */ @@ -12109,7 +13689,9 @@ rtl8125_hw_config(struct net_device *dev) if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { + tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_6 || + tp->mcfg == CFG_METHOD_7) { set_offset70F(tp, 0x27); set_offset79(tp, 0x50); @@ -12134,24 +13716,28 @@ rtl8125_hw_config(struct net_device *dev) mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xE614); mac_ocp_data &= ~( BIT_10 | BIT_9 | BIT_8); - if (tp->mcfg == CFG_METHOD_4 || tp->mcfg == CFG_METHOD_5) { + if (tp->mcfg == CFG_METHOD_4 || tp->mcfg == CFG_METHOD_5 || + tp->mcfg == CFG_METHOD_7) mac_ocp_data |= ((2 & 0x07) << 8); - } else { - if (tp->DASH && !(rtl8125_csi_fun0_read_byte(tp, 0x79) & BIT_0)) - mac_ocp_data |= ((3 & 0x07) << 8); - else - mac_ocp_data |= ((4 & 0x07) << 8); - } + else + mac_ocp_data |= ((3 & 0x07) << 8); rtl8125_mac_ocp_write(tp, 0xE614, mac_ocp_data); rtl8125_set_tx_q_num(tp, rtl8125_tot_tx_rings(tp)); mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xE63E); mac_ocp_data &= ~(BIT_5 | BIT_4); - if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3) + if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || + tp->mcfg == CFG_METHOD_6) mac_ocp_data |= ((0x02 & 0x03) << 4); rtl8125_mac_ocp_write(tp, 0xE63E, mac_ocp_data); + mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xC0B4); + mac_ocp_data &= ~BIT_0; + rtl8125_mac_ocp_write(tp, 0xC0B4, mac_ocp_data); + mac_ocp_data |= BIT_0; + rtl8125_mac_ocp_write(tp, 0xC0B4, mac_ocp_data); + mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xC0B4); mac_ocp_data |= (BIT_3|BIT_2); rtl8125_mac_ocp_write(tp, 0xC0B4, mac_ocp_data); @@ -12168,7 +13754,7 @@ rtl8125_hw_config(struct net_device *dev) mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xE056); mac_ocp_data &= ~(BIT_7 | BIT_6 | BIT_5 | BIT_4); - mac_ocp_data |= (BIT_4 | BIT_5); + //mac_ocp_data |= (BIT_4 | BIT_5); rtl8125_mac_ocp_write(tp, 0xE056, mac_ocp_data); RTL_W8(tp, TDFNR, 0x10); @@ -12184,17 +13770,14 @@ rtl8125_hw_config(struct net_device *dev) mac_ocp_data |= (BIT_0); rtl8125_mac_ocp_write(tp, 0xEA1C, mac_ocp_data); - mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xE0C0); - mac_ocp_data &= ~(BIT_14 | BIT_11 | BIT_10 | BIT_9 | BIT_8 | BIT_3 | BIT_2 | BIT_1 | BIT_0); - mac_ocp_data |= (BIT_14 | BIT_10 | BIT_1 | BIT_0); - rtl8125_mac_ocp_write(tp, 0xE0C0, mac_ocp_data); + rtl8125_mac_ocp_write(tp, 0xE0C0, 0x4000); - SetMcuAccessRegBit(tp, 0xE052, (BIT_6|BIT_5|BIT_3)); - ClearMcuAccessRegBit(tp, 0xE052, BIT_7); + SetMcuAccessRegBit(tp, 0xE052, (BIT_6 | BIT_5)); + ClearMcuAccessRegBit(tp, 0xE052, BIT_3 | BIT_7); mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xD430); mac_ocp_data &= ~(BIT_11 | BIT_10 | BIT_9 | BIT_8 | BIT_7 | BIT_6 | BIT_5 | BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0); - mac_ocp_data |= 0x47F; + mac_ocp_data |= 0x45F; rtl8125_mac_ocp_write(tp, 0xD430, mac_ocp_data); //rtl8125_mac_ocp_write(tp, 0xE0C0, 0x4F87); @@ -12203,8 +13786,9 @@ rtl8125_hw_config(struct net_device *dev) else RTL_W8(tp, 0xD0, (RTL_R8(tp, 0xD0) & ~BIT_6) | BIT_7); - if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3) - RTL_W8(tp, 0xD3, RTL_R8(tp, 0xD3) | BIT_0); + if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || + tp->mcfg == CFG_METHOD_6) + RTL_W8(tp, MCUCmd_reg, RTL_R8(tp, MCUCmd_reg) | BIT_0); rtl8125_disable_eee_plus(tp); @@ -12249,6 +13833,8 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: rtl8125_mac_ocp_write(tp, 0xE098, 0xC302); break; } @@ -12258,6 +13844,8 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: if (aspm) { rtl8125_init_pci_offset_99(tp); } @@ -12268,6 +13856,8 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: if (aspm) { rtl8125_init_pci_offset_180(tp); } @@ -12288,7 +13878,9 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_2: case CFG_METHOD_3: case CFG_METHOD_4: - case CFG_METHOD_5: { + case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: { int timeout; for (timeout = 0; timeout < 10; timeout++) { if ((rtl8125_mac_ocp_read(tp, 0xE00E) & BIT_13)==0) @@ -12339,6 +13931,8 @@ rtl8125_hw_config(struct net_device *dev) case CFG_METHOD_3: case CFG_METHOD_4: case CFG_METHOD_5: + case CFG_METHOD_6: + case CFG_METHOD_7: if (aspm) { RTL_W8(tp, Config5, RTL_R8(tp, Config5) | BIT_0); RTL_W8(tp, Config2, RTL_R8(tp, Config2) | BIT_7); @@ -12372,7 +13966,6 @@ rtl8125_change_mtu(struct net_device *dev, { struct rtl8125_private *tp = netdev_priv(dev); int ret = 0; - unsigned long flags; #if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) if (new_mtu < ETH_MIN_MTU) @@ -12381,39 +13974,33 @@ rtl8125_change_mtu(struct net_device *dev, new_mtu = tp->max_jumbo_frame_size; #endif //LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) - spin_lock_irqsave(&tp->lock, flags); dev->mtu = new_mtu; - spin_unlock_irqrestore(&tp->lock, flags); if (!netif_running(dev)) goto out; rtl8125_down(dev); - spin_lock_irqsave(&tp->lock, flags); - rtl8125_set_rxbufsize(tp, dev); ret = rtl8125_init_ring(dev); - if (ret < 0) { - spin_unlock_irqrestore(&tp->lock, flags); + if (ret < 0) goto err_out; - } #ifdef CONFIG_R8125_NAPI rtl8125_enable_napi(tp); #endif//CONFIG_R8125_NAPI - rtl8125_stop_all_tx_queue(dev); - netif_carrier_off(dev); + //netif_tx_stop_all_queues(dev); + //netif_carrier_off(dev); rtl8125_hw_config(dev); - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_enable_hw_linkchg_interrupt(tp); rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); - mod_timer(&tp->esd_timer, jiffies + RTL8125_ESD_TIMEOUT); - mod_timer(&tp->link_timer, jiffies + RTL8125_LINK_TIMEOUT); + //mod_timer(&tp->esd_timer, jiffies + RTL8125_ESD_TIMEOUT); + //mod_timer(&tp->link_timer, jiffies + RTL8125_LINK_TIMEOUT); out: #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) netdev_update_features(dev); @@ -12445,7 +14032,7 @@ rtl8125_mark_to_asic_v3(struct RxDescV3 *descv3, { u32 eor = le32_to_cpu(descv3->RxDescNormalDDWord4.opts1) & RingEnd; - descv3->RxDescNormalDDWord4.opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz); + WRITE_ONCE(descv3->RxDescNormalDDWord4.opts1, cpu_to_le32(DescOwn | eor | rx_buf_sz)); } void @@ -12458,7 +14045,7 @@ rtl8125_mark_to_asic(struct rtl8125_private *tp, else { u32 eor = le32_to_cpu(desc->opts1) & RingEnd; - desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz); + WRITE_ONCE(desc->opts1, cpu_to_le32(DescOwn | eor | rx_buf_sz)); } } @@ -12502,9 +14089,9 @@ rtl8125_alloc_rx_skb(struct rtl8125_private *tp, skb_reserve(skb, RTK_RX_ALIGN); - mapping = dma_map_single(&tp->pci_dev->dev, skb->data, rx_buf_sz, + mapping = dma_map_single(tp_to_dev(tp), skb->data, rx_buf_sz, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { + if (unlikely(dma_mapping_error(tp_to_dev(tp), mapping))) { if (unlikely(net_ratelimit())) netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n"); goto err_out; @@ -12728,93 +14315,147 @@ rtl8125_tx_clear(struct rtl8125_private *tp) } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -static void rtl8125_schedule_work(struct net_device *dev, void (*task)(void *)) +static void rtl8125_schedule_reset_work(struct rtl8125_private *tp) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) - struct rtl8125_private *tp = netdev_priv(dev); + set_bit(R8125_FLAG_TASK_RESET_PENDING, tp->task_flags); + schedule_delayed_work(&tp->reset_task, 4); +#endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) +} + +static void rtl8125_schedule_esd_work(struct rtl8125_private *tp) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + set_bit(R8125_FLAG_TASK_ESD_CHECK_PENDING, tp->task_flags); + schedule_delayed_work(&tp->esd_task, RTL8125_ESD_TIMEOUT); +#endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) +} - INIT_WORK(&tp->task, task, dev); - schedule_delayed_work(&tp->task, 4); +static void rtl8125_schedule_linkchg_work(struct rtl8125_private *tp) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + set_bit(R8125_FLAG_TASK_LINKCHG_CHECK_PENDING, tp->task_flags); + schedule_delayed_work(&tp->linkchg_task, 4); #endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) } -#define rtl8125_cancel_schedule_work(a) +#define rtl8125_cancel_schedule_reset_work(a) +#define rtl8125_cancel_schedule_esd_work(a) +#define rtl8125_cancel_schedule_linkchg_work(a) #else -static void rtl8125_schedule_work(struct net_device *dev, work_func_t task) +static void rtl8125_schedule_reset_work(struct rtl8125_private *tp) { - struct rtl8125_private *tp = netdev_priv(dev); + set_bit(R8125_FLAG_TASK_RESET_PENDING, tp->task_flags); + schedule_delayed_work(&tp->reset_task, 4); +} + +static void rtl8125_cancel_schedule_reset_work(struct rtl8125_private *tp) +{ + struct work_struct *work = &tp->reset_task.work; + + if (!work->func) return; - INIT_DELAYED_WORK(&tp->task, task); - schedule_delayed_work(&tp->task, 4); + cancel_delayed_work_sync(&tp->reset_task); } -static void rtl8125_cancel_schedule_work(struct net_device *dev) +static void rtl8125_schedule_esd_work(struct rtl8125_private *tp) { - struct rtl8125_private *tp = netdev_priv(dev); - struct work_struct *work = &tp->task.work; + set_bit(R8125_FLAG_TASK_ESD_CHECK_PENDING, tp->task_flags); + schedule_delayed_work(&tp->esd_task, RTL8125_ESD_TIMEOUT); +} + +static void rtl8125_cancel_schedule_esd_work(struct rtl8125_private *tp) +{ + struct work_struct *work = &tp->esd_task.work; + + if (!work->func) return; + + cancel_delayed_work_sync(&tp->esd_task); +} + +static void rtl8125_schedule_linkchg_work(struct rtl8125_private *tp) +{ + set_bit(R8125_FLAG_TASK_LINKCHG_CHECK_PENDING, tp->task_flags); + schedule_delayed_work(&tp->linkchg_task, RTL8125_ESD_TIMEOUT); +} + +static void rtl8125_cancel_schedule_linkchg_work(struct rtl8125_private *tp) +{ + struct work_struct *work = &tp->linkchg_task.work; if (!work->func) return; - cancel_delayed_work_sync(&tp->task); + cancel_delayed_work_sync(&tp->linkchg_task); } #endif +static void rtl8125_init_all_schedule_work(struct rtl8125_private *tp) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&tp->reset_task, rtl8125_reset_task, dev); + INIT_WORK(&tp->esd_task, rtl8125_esd_task, dev); + INIT_WORK(&tp->linkchg_task, rtl8125_linkchg_task, dev); +#else + INIT_DELAYED_WORK(&tp->reset_task, rtl8125_reset_task); + INIT_DELAYED_WORK(&tp->esd_task, rtl8125_esd_task); + INIT_DELAYED_WORK(&tp->linkchg_task, rtl8125_linkchg_task); +#endif +} + +static void rtl8125_cancel_all_schedule_work(struct rtl8125_private *tp) +{ + rtl8125_cancel_schedule_reset_work(tp); + rtl8125_cancel_schedule_esd_work(tp); + rtl8125_cancel_schedule_linkchg_work(tp); +} + static void -rtl8125_wait_for_quiescence(struct net_device *dev) +rtl8125_wait_for_irq_complete(struct rtl8125_private *tp) { - struct rtl8125_private *tp = netdev_priv(dev); + if (tp->features & RTL_FEATURE_MSIX) { + int i; + for (i = 0; i < tp->irq_nvecs; i++) + synchronize_irq(tp->irq_tbl[i].vector); + } else { + synchronize_irq(tp->dev->irq); + } +} - synchronize_irq(dev->irq); +static void +_rtl8125_wait_for_quiescence(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); /* Wait for any pending NAPI task to complete */ #ifdef CONFIG_R8125_NAPI rtl8125_disable_napi(tp); #endif//CONFIG_R8125_NAPI +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,67) + /* Give a racing hard_start_xmit a few cycles to complete. */ + synchronize_net(); +#endif + rtl8125_irq_mask_and_ack(tp); -#ifdef CONFIG_R8125_NAPI - rtl8125_enable_napi(tp); -#endif//CONFIG_R8125_NAPI + rtl8125_wait_for_irq_complete(tp); } -#if 0 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -static void rtl8125_reinit_task(void *_data) -#else -static void rtl8125_reinit_task(struct work_struct *work) -#endif +static void +rtl8125_wait_for_quiescence(struct net_device *dev) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - struct net_device *dev = _data; -#else - struct rtl8125_private *tp = - container_of(work, struct rtl8125_private, task.work); - struct net_device *dev = tp->dev; -#endif - int ret; + struct rtl8125_private *tp = netdev_priv(dev); - if (netif_running(dev)) { - rtl8125_wait_for_quiescence(dev); - rtl8125_close(dev); - } + //suppress unused variable + (void)(tp); - ret = rtl8125_open(dev); - if (unlikely(ret < 0)) { - if (unlikely(net_ratelimit())) { - struct rtl8125_private *tp = netdev_priv(dev); + _rtl8125_wait_for_quiescence(dev); - if (netif_msg_drv(tp)) { - printk(PFX KERN_ERR - "%s: reinit failure (status = %d)." - " Rescheduling.\n", dev->name, ret); - } - } - rtl8125_schedule_work(dev, rtl8125_reinit_task); - } +#ifdef CONFIG_R8125_NAPI + rtl8125_enable_napi(tp); +#endif//CONFIG_R8125_NAPI } -#endif static int rtl8125_rx_nostuck(struct rtl8125_private *tp) { @@ -12833,15 +14474,18 @@ static void rtl8125_reset_task(void *_data) static void rtl8125_reset_task(struct work_struct *work) { struct rtl8125_private *tp = - container_of(work, struct rtl8125_private, task.work); + container_of(work, struct rtl8125_private, reset_task.work); struct net_device *dev = tp->dev; #endif u32 budget = ~(u32)0; - unsigned long flags; int i; - if (!netif_running(dev)) - return; + rtnl_lock(); + + if (!netif_running(dev) || + test_bit(R8125_FLAG_DOWN, tp->task_flags) || + !test_and_clear_bit(R8125_FLAG_TASK_RESET_PENDING, tp->task_flags)) + goto out_unlock; rtl8125_wait_for_quiescence(dev); @@ -12853,7 +14497,9 @@ static void rtl8125_reset_task(struct work_struct *work) #endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) } - spin_lock_irqsave(&tp->lock, flags); + netif_tx_stop_all_queues(dev); + netif_carrier_off(dev); + rtl8125_hw_reset(dev); rtl8125_tx_clear(tp); @@ -12863,10 +14509,16 @@ static void rtl8125_reset_task(struct work_struct *work) #ifdef ENABLE_PTP_SUPPORT rtl8125_ptp_reset(tp); #endif - rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); - spin_unlock_irqrestore(&tp->lock, flags); + if (tp->resume_not_chg_speed) { + _rtl8125_check_link_status(dev); + + tp->resume_not_chg_speed = 0; + } else { + rtl8125_enable_hw_linkchg_interrupt(tp); + + rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); + } } else { - spin_unlock_irqrestore(&tp->lock, flags); if (unlikely(net_ratelimit())) { struct rtl8125_private *tp = netdev_priv(dev); @@ -12875,9 +14527,65 @@ static void rtl8125_reset_task(struct work_struct *work) "%s: Rx buffers shortage\n", dev->name); } } - rtl8125_schedule_work(dev, rtl8125_reset_task); + rtl8125_schedule_reset_work(tp); } + +out_unlock: + rtnl_unlock(); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void rtl8125_esd_task(void *_data) +{ + struct net_device *dev = _data; + struct rtl8125_private *tp = netdev_priv(dev); +#else +static void rtl8125_esd_task(struct work_struct *work) +{ + struct rtl8125_private *tp = + container_of(work, struct rtl8125_private, esd_task.work); + struct net_device *dev = tp->dev; +#endif + rtnl_lock(); + + if (!netif_running(dev) || + test_bit(R8125_FLAG_DOWN, tp->task_flags) || + !test_and_clear_bit(R8125_FLAG_TASK_ESD_CHECK_PENDING, tp->task_flags)) + goto out_unlock; + + rtl8125_esd_checker(tp); + + rtl8125_schedule_esd_work(tp); + +out_unlock: + rtnl_unlock(); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void rtl8125_linkchg_task(void *_data) +{ + struct net_device *dev = _data; + //struct rtl8125_private *tp = netdev_priv(dev); +#else +static void rtl8125_linkchg_task(struct work_struct *work) +{ + struct rtl8125_private *tp = + container_of(work, struct rtl8125_private, linkchg_task.work); + struct net_device *dev = tp->dev; +#endif + rtnl_lock(); + + if (!netif_running(dev) || + test_bit(R8125_FLAG_DOWN, tp->task_flags) || + !test_and_clear_bit(R8125_FLAG_TASK_LINKCHG_CHECK_PENDING, tp->task_flags)) + goto out_unlock; + + rtl8125_check_link_status(dev); + +out_unlock: + rtnl_unlock(); } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) static void rtl8125_tx_timeout(struct net_device *dev, unsigned int txqueue) @@ -12887,16 +14595,9 @@ rtl8125_tx_timeout(struct net_device *dev) #endif { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); - rtl8125_stop_all_tx_queue(dev); - netif_carrier_off(dev); - rtl8125_hw_reset(dev); - spin_unlock_irqrestore(&tp->lock, flags); /* Let's wait a bit while any (async) irq lands on */ - rtl8125_schedule_work(dev, rtl8125_reset_task); + rtl8125_schedule_reset_work(tp); } static u32 @@ -12914,8 +14615,7 @@ static int rtl8125_xmit_frags(struct rtl8125_private *tp, struct rtl8125_tx_ring *ring, struct sk_buff *skb, - u32 opts1, - u32 opts2) + const u32 *opts) { struct skb_shared_info *info = skb_shinfo(skb); unsigned int cur_frag, entry; @@ -12943,13 +14643,13 @@ rtl8125_xmit_frags(struct rtl8125_private *tp, #endif if (tp->RequireLSOPatch && (cur_frag == nr_frags - 1) && - (opts1 & (GiantSendv4|GiantSendv6)) && + (opts[0] & (GiantSendv4|GiantSendv6)) && PktLenCnt < ETH_FRAME_LEN && len > 1) { len -= 1; - mapping = dma_map_single(&tp->pci_dev->dev, addr, len, DMA_TO_DEVICE); + mapping = dma_map_single(tp_to_dev(tp), addr, len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { + if (unlikely(dma_mapping_error(tp_to_dev(tp), mapping))) { if (unlikely(net_ratelimit())) netif_err(tp, drv, tp->dev, "Failed to map TX fragments DMA!\n"); @@ -12957,13 +14657,13 @@ rtl8125_xmit_frags(struct rtl8125_private *tp, } /* anti gcc 2.95.3 bugware (sic) */ - status = rtl8125_get_txd_opts1(opts1, len, entry); + status = rtl8125_get_txd_opts1(opts[0], len, entry); txd->addr = cpu_to_le64(mapping); ring->tx_skb[entry].len = len; - txd->opts2 = cpu_to_le32(opts2); + txd->opts2 = cpu_to_le32(opts[1]); wmb(); txd->opts1 = cpu_to_le32(status); @@ -12977,9 +14677,9 @@ rtl8125_xmit_frags(struct rtl8125_private *tp, LsoPatchEnabled = TRUE; } - mapping = dma_map_single(&tp->pci_dev->dev, addr, len, DMA_TO_DEVICE); + mapping = dma_map_single(tp_to_dev(tp), addr, len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { + if (unlikely(dma_mapping_error(tp_to_dev(tp), mapping))) { if (unlikely(net_ratelimit())) netif_err(tp, drv, tp->dev, "Failed to map TX fragments DMA!\n"); @@ -12987,7 +14687,7 @@ rtl8125_xmit_frags(struct rtl8125_private *tp, } /* anti gcc 2.95.3 bugware (sic) */ - status = rtl8125_get_txd_opts1(opts1, len, entry); + status = rtl8125_get_txd_opts1(opts[0], len, entry); if (cur_frag == (nr_frags - 1) || LsoPatchEnabled == TRUE) { //ring->tx_skb[entry].skb = skb; status |= LastFrag; @@ -12997,7 +14697,7 @@ rtl8125_xmit_frags(struct rtl8125_private *tp, ring->tx_skb[entry].len = len; - txd->opts2 = cpu_to_le32(opts2); + txd->opts2 = cpu_to_le32(opts[1]); wmb(); txd->opts1 = cpu_to_le32(status); @@ -13024,17 +14724,191 @@ __be16 get_protocol(struct sk_buff *skb) else protocol = skb->protocol; - return protocol; -#endif -} + return protocol; +#endif +} + +static inline +u8 rtl8125_get_l4_protocol(struct sk_buff *skb) +{ + int no = skb_network_offset(skb); + struct ipv6hdr *i6h, _i6h; + struct iphdr *ih, _ih; + u8 ip_protocol = IPPROTO_RAW; + + switch (get_protocol(skb)) { + case __constant_htons(ETH_P_IP): + ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih); + if (ih) + ip_protocol = ih->protocol; + break; + case __constant_htons(ETH_P_IPV6): + i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h); + if (i6h) + ip_protocol = i6h->nexthdr; + break; + } + + return ip_protocol; +} + +static bool rtl8125_skb_pad_with_len(struct sk_buff *skb, unsigned int len) +{ + if (skb_padto(skb, len)) + return false; + skb_put(skb, len - skb->len); + return true; +} + +static bool rtl8125_skb_pad(struct sk_buff *skb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) + return rtl8125_skb_pad_with_len(skb, ETH_ZLEN); +#else + return !eth_skb_pad(skb); +#endif +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) +/* msdn_giant_send_check() + * According to the document of microsoft, the TCP Pseudo Header excludes the + * packet length for IPv6 TCP large packets. + */ +static int msdn_giant_send_check(struct sk_buff *skb) +{ + const struct ipv6hdr *ipv6h; + struct tcphdr *th; + int ret; + + ret = skb_cow_head(skb, 0); + if (ret) + return ret; + + ipv6h = ipv6_hdr(skb); + th = tcp_hdr(skb); + + th->check = 0; + th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); + + return ret; +} +#endif + +//A lot of backport here, rewrite this funtion +#if !defined(__VMKLNX__) +#define MIN_PATCH_LEN (47) +static u32 +rtl8125_get_patch_pad_len(struct sk_buff *skb) +{ + u32 pad_len = 0; + int trans_data_len; + u32 hdr_len; + u32 pkt_len = skb->len; + u8 ip_protocol; + bool has_trans = skb_transport_header_was_set(skb); + + if (!(has_trans && (pkt_len < 175))) //128 + MIN_PATCH_LEN + goto no_padding; + + ip_protocol = rtl8125_get_l4_protocol(skb); + if (!(ip_protocol == IPPROTO_TCP || ip_protocol == IPPROTO_UDP)) + goto no_padding; + + trans_data_len = pkt_len - + (skb->transport_header - + skb_headroom(skb)); + if (ip_protocol == IPPROTO_UDP) { + if (trans_data_len > 3 && trans_data_len < MIN_PATCH_LEN) { + u16 dest_port = 0; + + skb_copy_bits(skb, skb->transport_header - skb_headroom(skb) + 2, &dest_port, 2); + dest_port = ntohs(dest_port); + + if (dest_port == 0x13f || + dest_port == 0x140) { + pad_len = MIN_PATCH_LEN - trans_data_len; + goto out; + } + } + } + + hdr_len = 0; + if (ip_protocol == IPPROTO_TCP) + hdr_len = 20; + else if (ip_protocol == IPPROTO_UDP) + hdr_len = 8; + if (trans_data_len < hdr_len) + pad_len = hdr_len - trans_data_len; + +out: + if ((pkt_len + pad_len) < ETH_ZLEN) + pad_len = ETH_ZLEN - pkt_len; + + return pad_len; + +no_padding: + + return 0; +} + + +static bool +rtl8125_tso_csum(struct sk_buff *skb, + struct net_device *dev, + u32 *opts) +{ + struct rtl8125_private *tp = netdev_priv(dev); + unsigned long large_send = 0; + u32 csum_cmd = 0; + u8 sw_calc_csum = false; + u8 check_patch_required = true; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + if (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) + u32 mss = skb_shinfo(skb)->tso_size; +#else + u32 mss = skb_shinfo(skb)->gso_size; +#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) + + /* TCP Segmentation Offload (or TCP Large Send) */ + if (mss) { + u32 transport_offset = (u32)skb_transport_offset(skb); + assert((transport_offset%2) == 0); + switch (get_protocol(skb)) { + case __constant_htons(ETH_P_IP): + if (transport_offset <= GTTCPHO_MAX) { + opts[0] |= GiantSendv4; + opts[0] |= transport_offset << GTTCPHO_SHIFT; + opts[1] |= min(mss, MSS_MAX) << 18; + large_send = 1; + } + break; + case __constant_htons(ETH_P_IPV6): +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + if (msdn_giant_send_check(skb)) + return false; +#endif + if (transport_offset <= GTTCPHO_MAX) { + opts[0] |= GiantSendv6; + opts[0] |= transport_offset << GTTCPHO_SHIFT; + opts[1] |= min(mss, MSS_MAX) << 18; + large_send = 1; + } + break; + default: + if (unlikely(net_ratelimit())) + dprintk("tso proto=%x!\n", skb->protocol); + break; + } + + if (large_send == 0) + return false; -static inline u32 -rtl8125_tx_csum(struct sk_buff *skb, - struct net_device *dev) -{ - struct rtl8125_private *tp = netdev_priv(dev); - u32 csum_cmd = 0; - u8 sw_calc_csum = FALSE; + return true; + } + } +#endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) if (skb->ip_summed == CHECKSUM_PARTIAL) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) @@ -13080,156 +14954,66 @@ rtl8125_tx_csum(struct sk_buff *skb, csum_cmd |= tp->tx_udp_csum_cmd; #endif if (csum_cmd == 0) { - sw_calc_csum = TRUE; + sw_calc_csum = true; + } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) WARN_ON(1); /* we need a WARN() */ #endif + + if (ip_protocol == IPPROTO_TCP) + check_patch_required = false; + } + + if (check_patch_required) { + u32 pad_len = rtl8125_get_patch_pad_len(skb); + + if (pad_len > 0) { + if (!rtl8125_skb_pad_with_len(skb, skb->len + pad_len)) + return false; + + if (csum_cmd != 0) + sw_calc_csum = true; } } - if (tp->ShortPacketSwChecksum && - skb->len < tp->SwPaddingShortPktLen && - csum_cmd != 0) - sw_calc_csum = TRUE; + if (skb->len < ETH_ZLEN) { + if (tp->UseSwPaddingShortPkt || + (tp->ShortPacketSwChecksum && csum_cmd != 0)) { + if (!rtl8125_skb_pad(skb)) + return false; + + if (csum_cmd != 0) + sw_calc_csum = true; + } + } if (sw_calc_csum) { - -#ifdef __VMKLNX__ - r8125_skb_checksum_help(skb); -#else -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) skb_checksum_help(&skb, 0); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) skb_checksum_help(skb, 0); #else skb_checksum_help(skb); #endif -#endif //#ifdef __VMKLNX__ - csum_cmd = 0; - } - - return csum_cmd; -} - -static int -rtl8125_sw_padding_short_pkt(struct rtl8125_private *tp, - struct rtl8125_tx_ring *ring, - struct sk_buff *skb, - u32 opts1, - u32 opts2) -{ - unsigned int entry; - dma_addr_t mapping; - u32 status, len; - void *addr; - struct TxDesc *txd = NULL; - int ret = 0; - - if (skb->len >= tp->SwPaddingShortPktLen) - goto out; - - entry = ring->cur_tx; - - entry = (entry + 1) % NUM_TX_DESC; - - txd = ring->TxDescArray + entry; - len = tp->SwPaddingShortPktLen - skb->len; - addr = tp->ShortPacketEmptyBuffer; - mapping = dma_map_single(&tp->pci_dev->dev, addr, len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { - if (unlikely(net_ratelimit())) - netif_err(tp, drv, tp->dev, - "Failed to map Short Packet Buffer DMA!\n"); - ret = -ENOMEM; - goto out; - } - status = rtl8125_get_txd_opts1(opts1, len, entry); - status |= LastFrag; - - txd->addr = cpu_to_le64(mapping); - - txd->opts2 = cpu_to_le32(opts2); - wmb(); - txd->opts1 = cpu_to_le32(status); -out: - return ret; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) -/* r8169_csum_workaround() - * The hw limites the value the transport offset. When the offset is out of the - * range, calculate the checksum by sw. - */ -static void r8125_csum_workaround(struct rtl8125_private *tp, - struct sk_buff *skb) -{ - if (skb_shinfo(skb)->gso_size) { - netdev_features_t features = tp->dev->features; - struct sk_buff *segs, *nskb; - - features &= ~(NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - segs = skb_gso_segment(skb, features); - if (IS_ERR(segs) || !segs) - goto drop; - - do { - nskb = segs; - segs = segs->next; - nskb->next = NULL; - rtl8125_start_xmit(nskb, tp->dev); - } while (segs); - - dev_consume_skb_any(skb); - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (skb_checksum_help(skb) < 0) - goto drop; - - rtl8125_start_xmit(skb, tp->dev); - } else { - struct net_device_stats *stats; + } else + opts[1] |= csum_cmd; -drop: - stats = &tp->dev->stats; - stats->tx_dropped++; - dev_kfree_skb_any(skb); - } + return true; } -/* msdn_giant_send_check() - * According to the document of microsoft, the TCP Pseudo Header excludes the - * packet length for IPv6 TCP large packets. - */ -static int msdn_giant_send_check(struct sk_buff *skb) -{ - const struct ipv6hdr *ipv6h; - struct tcphdr *th; - int ret; - - ret = skb_cow_head(skb, 0); - if (ret) - return ret; - - ipv6h = ipv6_hdr(skb); - th = tcp_hdr(skb); - - th->check = 0; - th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); - - return ret; -} -#endif +#endif //#if !defined(__VMKLNX__) static bool rtl8125_tx_slots_avail(struct rtl8125_private *tp, - struct rtl8125_tx_ring *ring, - unsigned int nr_frags) + struct rtl8125_tx_ring *ring) { - unsigned int slots_avail = ring->dirty_tx + NUM_TX_DESC - ring->cur_tx; + unsigned int slots_avail = READ_ONCE(ring->dirty_tx) + NUM_TX_DESC + - READ_ONCE(ring->cur_tx); /* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */ - return slots_avail > nr_frags; + return slots_avail > MAX_SKB_FRAGS; } -static int +static netdev_tx_t rtl8125_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -13238,22 +15022,19 @@ rtl8125_start_xmit(struct sk_buff *skb, struct TxDesc *txd; dma_addr_t mapping; u32 len; - u32 opts1; - u32 opts2; - int ret = NETDEV_TX_OK; - unsigned long flags, large_send; + u32 opts[2]; + netdev_tx_t ret = NETDEV_TX_OK; int frags; u8 EnableTxNoClose = tp->EnableTxNoClose; const u16 queue_mapping = skb_get_queue_mapping(skb); struct rtl8125_tx_ring *ring; + bool stop_queue; assert(queue_mapping < tp->num_tx_queues); ring = &tp->tx_ring[queue_mapping]; - spin_lock_irqsave(&tp->lock, flags); - - if (unlikely(!rtl8125_tx_slots_avail(tp, ring, skb_shinfo(skb)->nr_frags))) { + if (unlikely(!rtl8125_tx_slots_avail(tp, ring))) { if (netif_msg_drv(tp)) { printk(KERN_ERR "%s: BUG! Tx Ring[%d] full when queue awake!\n", @@ -13277,88 +15058,29 @@ rtl8125_start_xmit(struct sk_buff *skb, } } - opts1 = DescOwn; - opts2 = rtl8125_tx_vlan_tag(tp, skb); - - large_send = 0; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) - if (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) - u32 mss = skb_shinfo(skb)->tso_size; -#else - u32 mss = skb_shinfo(skb)->gso_size; -#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) - - /* TCP Segmentation Offload (or TCP Large Send) */ - if (mss) { - u32 transport_offset = (u32)skb_transport_offset(skb); - assert((transport_offset%2) == 0); - switch (get_protocol(skb)) { - case __constant_htons(ETH_P_IP): - if (transport_offset <= GTTCPHO_MAX) { - opts1 |= GiantSendv4; - opts1 |= transport_offset << GTTCPHO_SHIFT; - opts2 |= min(mss, MSS_MAX) << 18; - large_send = 1; - } - break; - case __constant_htons(ETH_P_IPV6): -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) - if (msdn_giant_send_check(skb)) { - spin_unlock_irqrestore(&tp->lock, flags); - r8125_csum_workaround(tp, skb); - goto out; - } -#endif - if (transport_offset <= GTTCPHO_MAX) { - opts1 |= GiantSendv6; - opts1 |= transport_offset << GTTCPHO_SHIFT; - opts2 |= min(mss, MSS_MAX) << 18; - large_send = 1; - } - break; - default: - if (unlikely(net_ratelimit())) - dprintk("tso proto=%x!\n", skb->protocol); - break; - } - - if (large_send == 0) - goto err_dma_0; - } - } -#endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + opts[0] = DescOwn; + opts[1] = rtl8125_tx_vlan_tag(tp, skb); - if (large_send == 0) { - if (skb->ip_summed == CHECKSUM_PARTIAL) { - opts2 |= rtl8125_tx_csum(skb, dev); - } - } + if (unlikely(!rtl8125_tso_csum(skb, dev, opts))) + goto err_dma_0; - frags = rtl8125_xmit_frags(tp, ring, skb, opts1, opts2); + frags = rtl8125_xmit_frags(tp, ring, skb, opts); if (unlikely(frags < 0)) goto err_dma_0; if (frags) { len = skb_headlen(skb); - opts1 |= FirstFrag; + opts[0] |= FirstFrag; } else { len = skb->len; //ring->tx_skb[entry].skb = skb; - if (tp->UseSwPaddingShortPkt && len < tp->SwPaddingShortPktLen) { - if (unlikely(rtl8125_sw_padding_short_pkt(tp, ring, skb, opts1, opts2))) - goto err_dma_1; - opts1 |= FirstFrag; - frags++; - } else { - opts1 |= FirstFrag | LastFrag; - } + opts[0] |= FirstFrag | LastFrag; } - opts1 = rtl8125_get_txd_opts1(opts1, len, entry); - mapping = dma_map_single(&tp->pci_dev->dev, skb->data, len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { + opts[0] = rtl8125_get_txd_opts1(opts[0], len, entry); + mapping = dma_map_single(tp_to_dev(tp), skb->data, len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(tp_to_dev(tp), mapping))) { if (unlikely(net_ratelimit())) netif_err(tp, drv, dev, "Failed to map TX DMA!\n"); goto err_dma_1; @@ -13380,9 +15102,9 @@ rtl8125_start_xmit(struct sk_buff *skb, #endif ring->tx_skb[entry].skb = skb; txd->addr = cpu_to_le64(mapping); - txd->opts2 = cpu_to_le32(opts2); + txd->opts2 = cpu_to_le32(opts[1]); wmb(); - txd->opts1 = cpu_to_le32(opts1); + txd->opts1 = cpu_to_le32(opts[0]); #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) dev->trans_start = jiffies; @@ -13390,23 +15112,37 @@ rtl8125_start_xmit(struct sk_buff *skb, skb_tx_timestamp(skb); #endif //LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) - ring->cur_tx += frags + 1; + /* rtl_tx needs to see descriptor changes before updated tp->cur_tx */ + smp_wmb(); - wmb(); + WRITE_ONCE(ring->cur_tx, ring->cur_tx + frags + 1); + + stop_queue = !rtl8125_tx_slots_avail(tp, ring); + if (unlikely(stop_queue)) { + /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must + * not miss a ring update when it notices a stopped queue. + */ + smp_wmb(); + netif_stop_subqueue(dev, queue_mapping); + } if (EnableTxNoClose) RTL_W16(tp, ring->sw_tail_ptr_reg, ring->cur_tx % MAX_TX_NO_CLOSE_DESC_PTR_V2); else RTL_W16(tp, TPPOLL_8125, BIT(ring->index)); /* set polling bit */ - if (!rtl8125_tx_slots_avail(tp, ring, MAX_SKB_FRAGS)) { - netif_stop_subqueue(dev, queue_mapping); - smp_rmb(); - if (rtl8125_tx_slots_avail(tp, ring, MAX_SKB_FRAGS)) - netif_wake_subqueue(dev, queue_mapping); + if (unlikely(stop_queue)) { + /* Sync with rtl_tx: + * - publish queue status and cur_tx ring index (write barrier) + * - refresh dirty_tx ring index (read barrier). + * May the current thread have a pessimistic view of the ring + * status and forget to wake up queue, a racing rtl_tx thread + * can't. + */ + smp_mb(); + if (rtl8125_tx_slots_avail(tp, ring)) + netif_start_subqueue(dev, queue_mapping); } - - spin_unlock_irqrestore(&tp->lock, flags); out: return ret; err_dma_1: @@ -13414,7 +15150,6 @@ rtl8125_start_xmit(struct sk_buff *skb, rtl8125_tx_clear_range(tp, ring, ring->cur_tx + 1, frags); err_dma_0: RTLDEV->stats.tx_dropped++; - spin_unlock_irqrestore(&tp->lock, flags); dev_kfree_skb_any(skb); ret = NETDEV_TX_OK; goto out; @@ -13422,19 +15157,17 @@ rtl8125_start_xmit(struct sk_buff *skb, netif_stop_subqueue(dev, queue_mapping); ret = NETDEV_TX_BUSY; RTLDEV->stats.tx_dropped++; - - spin_unlock_irqrestore(&tp->lock, flags); goto out; } -static u32 +static inline u32 rtl8125_fast_mod(const u32 input, const u32 ceil) { return input >= ceil ? input % ceil : input; } static int -rtl8125_tx_interrupt(struct rtl8125_tx_ring *ring) +rtl8125_tx_interrupt(struct rtl8125_tx_ring *ring, int budget) { struct rtl8125_private *tp = ring->priv; struct net_device *dev = tp->dev; @@ -13443,29 +15176,27 @@ rtl8125_tx_interrupt(struct rtl8125_tx_ring *ring) u8 EnableTxNoClose = tp->EnableTxNoClose; dirty_tx = ring->dirty_tx; + smp_rmb(); + tx_left = READ_ONCE(ring->cur_tx) - dirty_tx; if (EnableTxNoClose) { + unsigned int tx_desc_closed; u32 NextHwDesCloPtr = RTL_R16(tp, ring->hw_clo_ptr_reg); ring->NextHwDesCloPtr = NextHwDesCloPtr; smp_rmb(); - tx_left = rtl8125_fast_mod(NextHwDesCloPtr - ring->BeginHwDesCloPtr, MAX_TX_NO_CLOSE_DESC_PTR_V2); + tx_desc_closed = rtl8125_fast_mod(NextHwDesCloPtr - ring->BeginHwDesCloPtr, MAX_TX_NO_CLOSE_DESC_PTR_V2); + if(tx_left > tx_desc_closed) tx_left = tx_desc_closed; ring->BeginHwDesCloPtr = NextHwDesCloPtr; - } else { - smp_rmb(); - tx_left = ring->cur_tx - dirty_tx; } while (tx_left > 0) { unsigned int entry = dirty_tx % NUM_TX_DESC; struct ring_info *tx_skb = ring->tx_skb + entry; - u32 len = tx_skb->len; - u32 status; - rmb(); - status = le32_to_cpu(ring->TxDescArray[entry].opts1); - if (!EnableTxNoClose && (status & DescOwn)) + if (!EnableTxNoClose && + (le32_to_cpu(ring->TxDescArray[entry].opts1) & DescOwn)) break; - RTLDEV->stats.tx_bytes += len; + RTLDEV->stats.tx_bytes += tx_skb->len; RTLDEV->stats.tx_packets++; rtl8125_unmap_tx_skb(tp->pci_dev, @@ -13473,11 +15204,7 @@ rtl8125_tx_interrupt(struct rtl8125_tx_ring *ring) ring->TxDescArray + entry); if (tx_skb->skb != NULL) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) - dev_consume_skb_any(tx_skb->skb); -#else - dev_kfree_skb_any(tx_skb->skb); -#endif + RTL_NAPI_CONSUME_SKB_ANY(tx_skb->skb, budget); tx_skb->skb = NULL; } dirty_tx++; @@ -13486,11 +15213,11 @@ rtl8125_tx_interrupt(struct rtl8125_tx_ring *ring) if (ring->dirty_tx != dirty_tx) { count = dirty_tx - ring->dirty_tx; - ring->dirty_tx = dirty_tx; + WRITE_ONCE(ring->dirty_tx, dirty_tx); smp_wmb(); if (__netif_subqueue_stopped(dev, ring->index) && - (rtl8125_tx_slots_avail(tp, ring, MAX_SKB_FRAGS))) { - netif_wake_subqueue(dev, ring->index); + (rtl8125_tx_slots_avail(tp, ring))) { + netif_start_subqueue(dev, ring->index); } smp_rmb(); if (!EnableTxNoClose && (ring->cur_tx != dirty_tx)) { @@ -13501,6 +15228,23 @@ rtl8125_tx_interrupt(struct rtl8125_tx_ring *ring) return count; } +static int +rtl8125_tx_interrupt_with_vector(struct rtl8125_private *tp, + const int message_id, + int budget) +{ + int count = 0; + + if (message_id == 16) + count += rtl8125_tx_interrupt(&tp->tx_ring[0], budget); +#ifdef ENABLE_MULTIPLE_TX_QUEUE + else if (message_id == 18) + count += rtl8125_tx_interrupt(&tp->tx_ring[1], budget); +#endif + + return count; +} + static inline int rtl8125_fragmented_frame(struct rtl8125_private *tp, u32 status) { @@ -13711,47 +15455,63 @@ rtl8125_rx_interrupt(struct net_device *dev, #ifdef ENABLE_PTP_SUPPORT if (tp->EnablePtp) { - struct RxDescV3 *desc_next; u8 desc_type; - u32 status_next; desc_type = rtl8125_rx_desc_type(status); if (desc_type == RXDESC_TYPE_NEXT && rx_left > 0) { + u32 status_next; + struct RxDescV3 *desc_next; unsigned int entry_next; struct sk_buff *skb_next; - cur_rx++; - rx_left--; - entry_next = cur_rx % NUM_RX_DESC; + entry_next = (cur_rx + 1) % NUM_RX_DESC; desc_next = (struct RxDescV3 *)rtl8125_get_rxdesc(tp, ring->RxDescArray, entry_next); + rmb(); status_next = le32_to_cpu(desc_next->RxDescNormalDDWord4.opts1); - if (status_next & DescOwn) - break; + if (unlikely(status_next & DescOwn)) { + udelay(1); + rmb(); + status_next = le32_to_cpu(desc_next->RxDescNormalDDWord4.opts1); + if (unlikely(status_next & DescOwn)) { + if (netif_msg_rx_err(tp)) { + printk(KERN_ERR + "%s: Rx Next Desc ERROR. status = %08x\n", + dev->name, status_next); + } + break; + } + } + cur_rx++; + rx_left--; desc_type = rtl8125_rx_desc_type(status_next); - if (desc_type == RXDESC_TYPE_PTP) { + if (desc_type == RXDESC_TYPE_PTP) rtl8125_rx_ptp_pktstamp(tp, skb, desc_next); - skb_next = ring->Rx_skbuff[entry_next]; - dev_kfree_skb_any(skb_next); - ring->Rx_skbuff[entry_next] = NULL; - } else + else WARN_ON(1); + + rx_buf_phy_addr = ring->RxDescPhyAddr[entry_next]; + dma_unmap_single(tp_to_dev(tp), rx_buf_phy_addr, + tp->rx_buf_sz, DMA_FROM_DEVICE); + skb_next = ring->Rx_skbuff[entry_next]; + dev_kfree_skb_any(skb_next); + ring->Rx_skbuff[entry_next] = NULL; } else WARN_ON(desc_type != RXDESC_TYPE_NORMAL); } #endif - rx_buf_phy_addr = le64_to_cpu(ring->RxDescPhyAddr[entry]); - dma_sync_single_for_cpu(&tp->pci_dev->dev, + rx_buf_phy_addr = ring->RxDescPhyAddr[entry]; + dma_sync_single_for_cpu(tp_to_dev(tp), rx_buf_phy_addr, tp->rx_buf_sz, DMA_FROM_DEVICE); if (rtl8125_try_rx_copy(tp, ring, &skb, pkt_size, desc, tp->rx_buf_sz)) { ring->Rx_skbuff[entry] = NULL; - dma_unmap_single(&tp->pci_dev->dev, rx_buf_phy_addr, + dma_unmap_single(tp_to_dev(tp), rx_buf_phy_addr, tp->rx_buf_sz, DMA_FROM_DEVICE); } else { - dma_sync_single_for_device(&tp->pci_dev->dev, rx_buf_phy_addr, + dma_sync_single_for_device(tp_to_dev(tp), rx_buf_phy_addr, tp->rx_buf_sz, DMA_FROM_DEVICE); } @@ -13765,8 +15525,13 @@ rtl8125_rx_interrupt(struct net_device *dev, skb->dev = dev; skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); - - if (isMulticastType(skb->mhead)) //Port to Esxi + +//Backport VMKernel +#if defined (__VMKLNX__) + if (isMulticastType(skb->mhead)) +#else + if (skb->pkt_type == PACKET_MULTICAST) +#endif RTLDEV->stats.multicast++; if (rtl8125_rx_vlan_skb(tp, desc, skb) < 0) @@ -13809,6 +15574,15 @@ rtl8125_rx_interrupt(struct net_device *dev, return count; } +static bool +rtl8125_linkchg_interrupt(struct rtl8125_private *tp, u32 status) +{ + if (tp->HwCurrIsrVer == 2) + return status & ISRIMR_V2_LINKCHG; + + return status & LinkChg; +} + /* *The interrupt handler does all of the Rx thread work and cleans up after *the Tx thread. @@ -13842,10 +15616,17 @@ static irqreturn_t rtl8125_interrupt(int irq, void *dev_instance) handled = 1; +#if defined(RTL_USE_NEW_INTR_API) + if (!tp->irq_tbl[0].requested) + break; +#endif rtl8125_disable_hw_interrupt(tp); RTL_W32(tp, tp->isr_reg[0], status&~RxFIFOOver); + if (rtl8125_linkchg_interrupt(tp, status)) + rtl8125_schedule_linkchg_work(tp); + #ifdef ENABLE_DASH_SUPPORT if (tp->DASH) { if (HW_DASH_SUPPORT_TYPE_3(tp)) { @@ -13898,8 +15679,8 @@ static irqreturn_t rtl8125_interrupt(int irq, void *dev_instance) rtl8125_rx_interrupt(dev, tp, &tp->rx_ring[0], budget); #endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) - for (i = 0; i < tp->num_tx_queues; i++) - rtl8125_tx_interrupt(&tp->tx_ring[i]); + for (i = 0; i < tp->num_tx_rings; i++) + rtl8125_tx_interrupt(&tp->tx_ring[i], ~(u32)0); #ifdef ENABLE_DASH_SUPPORT if (tp->DASH) { struct net_device *dev = tp->dev; @@ -13934,10 +15715,20 @@ static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance) #endif do { +#if defined(RTL_USE_NEW_INTR_API) + if (!tp->irq_tbl[message_id].requested) + break; +#endif rtl8125_disable_hw_interrupt_v2(tp, message_id); rtl8125_clear_hw_isr_v2(tp, message_id); + //link change + if (message_id == 21) { + rtl8125_schedule_linkchg_work(tp); + break; + } + #ifdef CONFIG_R8125_NAPI if (likely(RTL_NETIF_RX_SCHEDULE_PREP(dev, &r8125napi->napi))) __RTL_NETIF_RX_SCHEDULE(dev, &r8125napi->napi); @@ -13945,15 +15736,15 @@ static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance) printk(KERN_INFO "%s: interrupt message id %d in poll_msix\n", dev->name, message_id); #else + if (message_id < tp->num_rx_rings) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) - rtl8125_rx_interrupt(dev, tp, &tp->rx_ring[message_id], &budget); + rtl8125_rx_interrupt(dev, tp, &tp->rx_ring[message_id], &budget); #else - rtl8125_rx_interrupt(dev, tp, &tp->rx_ring[message_id], budget); + rtl8125_rx_interrupt(dev, tp, &tp->rx_ring[message_id], budget); #endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + } - spin_lock_irqsave(&tp->lock, flags); - rtl8125_tx_interrupt_with_vector(tp, message_id); - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_tx_interrupt_with_vector(tp, message_id, ~(u32)0); rtl8125_enable_hw_interrupt_v2(tp, message_id); #endif @@ -13966,40 +15757,22 @@ static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance) static void rtl8125_down(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; - - rtl8125_delete_esd_timer(dev, &tp->esd_timer); - rtl8125_delete_link_timer(dev, &tp->link_timer); - -#ifdef CONFIG_R8125_NAPI - rtl8125_disable_napi(tp); -#endif//CONFIG_R8125_NAPI + //rtl8125_delete_esd_timer(dev, &tp->esd_timer); - rtl8125_stop_all_tx_queue(dev); + //rtl8125_delete_link_timer(dev, &tp->link_timer); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11) - /* Give a racing hard_start_xmit a few cycles to complete. */ - synchronize_rcu(); /* FIXME: should this be synchronize_irq()? */ -#endif + netif_tx_disable(dev); - spin_lock_irqsave(&tp->lock, flags); + _rtl8125_wait_for_quiescence(dev); netif_carrier_off(dev); rtl8125_hw_reset(dev); - spin_unlock_irqrestore(&tp->lock, flags); - - synchronize_irq(dev->irq); - - spin_lock_irqsave(&tp->lock, flags); - rtl8125_tx_clear(tp); rtl8125_rx_clear(tp); - - spin_unlock_irqrestore(&tp->lock, flags); } static int rtl8125_resource_freed(struct rtl8125_private *tp) @@ -14015,37 +15788,31 @@ static int rtl8125_resource_freed(struct rtl8125_private *tp) return 1; } -static int rtl8125_close(struct net_device *dev) +int rtl8125_close(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; if (!rtl8125_resource_freed(tp)) { - rtl8125_cancel_schedule_work(dev); + set_bit(R8125_FLAG_DOWN, tp->task_flags); rtl8125_down(dev); - spin_lock_irqsave(&tp->lock, flags); + pci_clear_master(tp->pci_dev); + #ifdef ENABLE_PTP_SUPPORT rtl8125_ptp_stop(tp); #endif rtl8125_hw_d3_para(dev); - rtl8125_powerdown_pll(dev); - - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_powerdown_pll(dev, 0); rtl8125_free_irq(tp); rtl8125_free_alloc_resources(tp); } else { - spin_lock_irqsave(&tp->lock, flags); - rtl8125_hw_d3_para(dev); - rtl8125_powerdown_pll(dev); - - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_powerdown_pll(dev, 0); } return 0; @@ -14057,6 +15824,8 @@ static void rtl8125_shutdown(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct rtl8125_private *tp = netdev_priv(dev); + rtnl_lock(); + if (tp->DASH) rtl8125_driver_stop(tp); @@ -14069,6 +15838,18 @@ static void rtl8125_shutdown(struct pci_dev *pdev) rtl8125_close(dev); rtl8125_disable_msi(pdev, tp); + + rtnl_unlock(); + +//ESXi VMKernel hasn't global var system_state +#if !defined(__VMKLNX__) + if (system_state == SYSTEM_POWER_OFF) { + pci_clear_master(tp->pci_dev); + pci_wake_from_d3(pdev, tp->wol_enabled); + pci_set_power_state(pdev, PCI_D3hot); + } +#endif + } #endif @@ -14084,11 +15865,6 @@ net_device_stats *rtl8125_get_stats(struct net_device *dev) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) struct rtl8125_private *tp = netdev_priv(dev); #endif - if (netif_running(dev)) { -// spin_lock_irqsave(&tp->lock, flags); -// spin_unlock_irqrestore(&tp->lock, flags); - } - return &RTLDEV->stats; } @@ -14115,40 +15891,44 @@ rtl8125_suspend(struct pci_dev *pdev, pm_message_t state) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) u32 pci_pm_state = pci_choose_state(pdev, state); #endif - unsigned long flags; - if (!netif_running(dev)) goto out; - rtl8125_cancel_schedule_work(dev); + //rtl8125_cancel_all_schedule_work(tp); - rtl8125_delete_esd_timer(dev, &tp->esd_timer); + //rtl8125_delete_esd_timer(dev, &tp->esd_timer); - rtl8125_delete_link_timer(dev, &tp->link_timer); + //rtl8125_delete_link_timer(dev, &tp->link_timer); - rtl8125_stop_all_tx_queue(dev); + rtnl_lock(); + + set_bit(R8125_FLAG_DOWN, tp->task_flags); + + netif_tx_disable(dev); netif_carrier_off(dev); netif_device_detach(dev); - spin_lock_irqsave(&tp->lock, flags); - #ifdef ENABLE_PTP_SUPPORT rtl8125_ptp_suspend(tp); #endif rtl8125_hw_reset(dev); - rtl8125_hw_d3_para(dev); + pci_clear_master(pdev); - rtl8125_powerdown_pll(dev); + rtl8125_hw_d3_para(dev); - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_powerdown_pll(dev, 1); if (tp->DASH) rtl8125_driver_stop(tp); + + rtnl_unlock(); out: + pci_disable_device(pdev); + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) pci_save_state(pdev, &pci_pm_state); #else @@ -14157,11 +15937,33 @@ rtl8125_suspend(struct pci_dev *pdev, pm_message_t state) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled); #endif - //pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + pci_prepare_to_sleep(pdev); return 0; } +static int +rtl8125_hw_d3_not_power_off(struct net_device *dev) +{ + return rtl8125_check_hw_phy_mcu_code_ver(dev); +} + +static int rtl8125_wait_phy_nway_complete_sleep(struct rtl8125_private *tp) +{ + int i, val; + + for (i = 0; i < 30; i++) { + val = rtl8125_mdio_read(tp, MII_BMSR) & BMSR_ANEGCOMPLETE; + if (val) + return 0; + + msleep(100); + } + + return -1; +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) static int rtl8125_resume(struct pci_dev *pdev) @@ -14177,12 +15979,18 @@ rtl8125_resume(struct device *device) struct net_device *dev = pci_get_drvdata(pdev); #endif struct rtl8125_private *tp = netdev_priv(dev); - unsigned long flags; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) u32 pci_pm_state = PCI_D0; #endif + u32 err; + + rtnl_lock(); - pci_set_power_state(pdev, PCI_D0); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Cannot enable PCI device from suspend\n"); + goto out_unlock; + } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) pci_restore_state(pdev, &pci_pm_state); #else @@ -14190,38 +15998,39 @@ rtl8125_resume(struct device *device) #endif pci_enable_wake(pdev, PCI_D0, 0); - spin_lock_irqsave(&tp->lock, flags); - /* restore last modified mac address */ rtl8125_rar_set(tp, dev->dev_addr); - spin_unlock_irqrestore(&tp->lock, flags); + tp->resume_not_chg_speed = 0; + if (tp->check_keep_link_speed && + //tp->link_ok(dev) && + rtl8125_hw_d3_not_power_off(dev) && + rtl8125_wait_phy_nway_complete_sleep(tp) == 0) + tp->resume_not_chg_speed = 1; if (!netif_running(dev)) - goto out; + goto out_unlock; - spin_lock_irqsave(&tp->lock, flags); + pci_set_master(pdev); rtl8125_exit_oob(dev); - rtl8125_hw_init(dev); - - rtl8125_powerup_pll(dev); - - rtl8125_hw_ephy_config(dev); + rtl8125_up(dev); - rtl8125_hw_phy_config(dev); + clear_bit(R8125_FLAG_DOWN, tp->task_flags); - rtl8125_schedule_work(dev, rtl8125_reset_task); + rtl8125_schedule_reset_work(tp); - spin_unlock_irqrestore(&tp->lock, flags); + rtl8125_schedule_esd_work(tp); + //mod_timer(&tp->esd_timer, jiffies + RTL8125_ESD_TIMEOUT); + //mod_timer(&tp->link_timer, jiffies + RTL8125_LINK_TIMEOUT); +out_unlock: netif_device_attach(dev); - mod_timer(&tp->esd_timer, jiffies + RTL8125_ESD_TIMEOUT); - mod_timer(&tp->link_timer, jiffies + RTL8125_LINK_TIMEOUT); -out: - return 0; + rtnl_unlock(); + + return err; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) @@ -14271,29 +16080,13 @@ rtl8125_init_module(void) rtl8125_proc_module_init(); #endif -#ifdef ENABLE_LIB_SUPPORT - ret = qcom_smmu_register(&rtl8125_pci_driver); -#endif - - if (ret) { - printk(KERN_INFO "%s: r8125 : Failed to register smmu with platform\n", - MODULENAME); - return ret; - } - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) ret = pci_register_driver(&rtl8125_pci_driver); #else ret = pci_module_init(&rtl8125_pci_driver); #endif - if (ret) - goto err_pci_reg; - return ret; -err_pci_reg: -#ifdef ENABLE_LIB_SUPPORT - qcom_smmu_unregister(&rtl8125_pci_driver); -#endif + return ret; } @@ -14301,9 +16094,7 @@ static void __exit rtl8125_cleanup_module(void) { pci_unregister_driver(&rtl8125_pci_driver); -#ifdef ENABLE_LIB_SUPPORT - qcom_smmu_unregister(&rtl8125_pci_driver); -#endif + #ifdef ENABLE_R8125_PROCFS if (rtl8125_proc) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) diff --git a/r8125/r8125_ptp.c b/r8125/r8125_ptp.c new file mode 100644 index 0000000..e1102b7 --- /dev/null +++ b/r8125/r8125_ptp.c @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +################################################################################ +# +# r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet +# controllers with PCI-Express interface. +# +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Author: +# Realtek NIC software team +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ + +/************************************************************************************ + * This product is covered by one or more of the following patents: + * US6,570,884, US6,115,776, and US6,327,625. + ***********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "r8125.h" +#include "r8125_ptp.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) +static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64) +{ + return *(const struct timespec *)&ts64; +} + +static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) +{ + return *(const struct timespec64 *)&ts; +} +#endif + +static int _rtl8125_phc_gettime(struct rtl8125_private *tp, struct timespec64 *ts64) +{ + //get local time + RTL_W16(tp, PTP_TIME_CORRECT_CMD_8125, (PTP_CMD_LATCHED_LOCAL_TIME | PTP_EXEC_CMD)); + + /* nanoseconds */ + //0x6808[29:0] + ts64->tv_nsec = (RTL_R32(tp, PTP_SOFT_CONFIG_Time_NS_8125) & 0x3fffffff) + + tp->ptp_adjust; + + /* seconds */ + //0x680C[47:0] + ts64->tv_sec = RTL_R16(tp, PTP_SOFT_CONFIG_Time_S_8125 + 4); + ts64->tv_sec <<= 32; + ts64->tv_sec |= RTL_R32(tp, PTP_SOFT_CONFIG_Time_S_8125); + + return 0; +} + +static int _rtl8125_phc_settime(struct rtl8125_private *tp, const struct timespec64 *ts64) +{ + /* nanoseconds */ + //0x6808[29:0] + RTL_W32(tp, PTP_SOFT_CONFIG_Time_NS_8125, (ts64->tv_nsec & 0x3fffffff)); + + /* seconds */ + //0x680C[47:0] + RTL_W32(tp, PTP_SOFT_CONFIG_Time_S_8125, ts64->tv_sec); + RTL_W16(tp, PTP_SOFT_CONFIG_Time_S_8125 + 4, (ts64->tv_sec >> 32)); + + //set local time + RTL_W16(tp, PTP_TIME_CORRECT_CMD_8125, (PTP_CMD_SET_LOCAL_TIME | PTP_EXEC_CMD)); + + return 0; +} + +#if 0 +static int _rtl8125_phc_adjtime(struct rtl8125_private *tp, s64 delta) +{ + struct timespec64 now, then = ns_to_timespec64(delta); + u32 nsec; + u64 sec; + + _rtl8125_phc_gettime(tp, &now); + now = timespec64_add(now, then); + + nsec = now.tv_nsec & 0x3fffffff; + sec = now.tv_sec & 0x0000ffffffffffff; + + /* nanoseconds */ + //0x6808[29:0] + RTL_W32(tp, PTP_SOFT_CONFIG_Time_NS_8125, nsec); + + /* seconds */ + //0x680C[47:0] + RTL_W32(tp, PTP_SOFT_CONFIG_Time_S_8125, sec); + RTL_W16(tp, PTP_SOFT_CONFIG_Time_S_8125 + 4, (sec >> 32)); + + //adjust local time + //RTL_W16(tp, PTP_TIME_CORRECT_CMD_8125, (PTP_CMD_DRIFT_LOCAL_TIME | PTP_EXEC_CMD)); + RTL_W16(tp, PTP_TIME_CORRECT_CMD_8125, (PTP_CMD_SET_LOCAL_TIME | PTP_EXEC_CMD)); + + return 0; +} +#endif + +static int rtl8125_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct rtl8125_private *tp = container_of(ptp, struct rtl8125_private, ptp_clock_info); + unsigned long flags; + //int ret = 0; + + //netif_info(tp, drv, tp->dev, "phc adjust time\n"); + + spin_lock_irqsave(&tp->lock, flags); + //ret = _rtl8125_phc_adjtime(tp, delta); + tp->ptp_adjust += delta; + spin_unlock_irqrestore(&tp->lock, flags); + + return 0; +} + +/* +1ppm means every 125MHz plus 125Hz. It also means every 8ns minus 8ns*10^(-6) + +1ns=2^30 sub_ns + +8ns*10^(-6) = 8 * 2^30 sub_ns * 10^(-6) = 2^33 sub_ns * 10^(-6) = 8590 = 0x218E sub_ns + +1ppb means every 125MHz plus 0.125Hz. It also means every 8ns minus 8ns*10^(-9) + +1ns=2^30 sub_ns + +8ns*10^(-9) = 8 * 2^30 sub_ns * 10^(-9) = 2^33 sub_ns * 10^(-9) = 8.59 sub_ns = 9 sub_ns +*/ +static int _rtl8125_phc_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + struct rtl8125_private *tp = container_of(ptp, struct rtl8125_private, ptp_clock_info); + bool negative = false; + u32 sub_ns; + + if (ppb < 0) { + negative = true; + ppb = -ppb; + } + + sub_ns = ppb * 9; + if (negative) { + sub_ns = -sub_ns; + sub_ns &= 0x3fffffff; + sub_ns |= PTP_ADJUST_TIME_NS_NEGATIVE; + } else + sub_ns &= 0x3fffffff; + + /* nanoseconds */ + //0x6808[29:0] + RTL_W32(tp, PTP_SOFT_CONFIG_Time_NS_8125, sub_ns); + + //adjust local time + RTL_W16(tp, PTP_TIME_CORRECT_CMD_8125, (PTP_CMD_DRIFT_LOCAL_TIME | PTP_EXEC_CMD)); + //RTL_W16(tp, PTP_TIME_CORRECT_CMD_8125, (PTP_CMD_SET_LOCAL_TIME | PTP_EXEC_CMD)); + + return 0; +} + +static int rtl8125_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) +{ + //struct rtl8125_private *tp = container_of(ptp, struct rtl8125_private, ptp_clock_info); + + //netif_info(tp, drv, tp->dev, "phc adjust freq\n"); + + if (delta > ptp->max_adj || delta < -ptp->max_adj) + return -EINVAL; + + _rtl8125_phc_adjfreq(ptp, delta); + + return 0; +} + +static int rtl8125_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts64) +{ + struct rtl8125_private *tp = container_of(ptp, struct rtl8125_private, ptp_clock_info); + unsigned long flags; + int ret; + + //netif_info(tp, drv, tp->dev, "phc get ts\n"); + + spin_lock_irqsave(&tp->lock, flags); + ret = _rtl8125_phc_gettime(tp, ts64); + spin_unlock_irqrestore(&tp->lock, flags); + + return ret; +} + +static int rtl8125_phc_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts64) +{ + struct rtl8125_private *tp = container_of(ptp, struct rtl8125_private, ptp_clock_info); + unsigned long flags; + int ret; + + //netif_info(tp, drv, tp->dev, "phc set ts\n"); + + spin_lock_irqsave(&tp->lock, flags); + ret = _rtl8125_phc_settime(tp, ts64); + tp->ptp_adjust = 0; + spin_unlock_irqrestore(&tp->lock, flags); + + return ret; +} + +static int rtl8125_phc_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct rtl8125_private *tp = container_of(ptp, struct rtl8125_private, ptp_clock_info); + unsigned long flags; + u16 ptp_ctrl; + + //netif_info(tp, drv, tp->dev, "phc enable type %x on %d\n", rq->type, on); + + switch (rq->type) { + case PTP_CLK_REQ_PPS: + spin_lock_irqsave(&tp->lock, flags); + ptp_ctrl = RTL_R16(tp, PTP_CTRL_8125); + ptp_ctrl &= ~BIT_15; + if (on) + ptp_ctrl |= BIT_14; + else + ptp_ctrl &= ~BIT_14; + RTL_W16(tp, PTP_CTRL_8125, ptp_ctrl); + spin_unlock_irqrestore(&tp->lock, flags); + return 0; + default: + return -EOPNOTSUPP; + } +} + +int rtl8125_get_ts_info(struct net_device *netdev, + struct ethtool_ts_info *info) +{ + struct rtl8125_private *tp = netdev_priv(netdev); + + /* we always support timestamping disabled */ + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE); + + if (tp->HwSuppPtpVer == 0) + return ethtool_op_get_ts_info(netdev, info); + + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + if (tp->ptp_clock) + info->phc_index = ptp_clock_index(tp->ptp_clock); + else + info->phc_index = -1; + + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); + + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); + + return 0; +} + +static const struct ptp_clock_info rtl_ptp_clock_info = { + .owner = THIS_MODULE, + .n_alarm = 0, + .n_ext_ts = 0, + .n_per_out = 0, + .n_pins = 0, + .pps = 1, + .adjfreq = rtl8125_phc_adjfreq, + .adjtime = rtl8125_phc_adjtime, + .gettime64 = rtl8125_phc_gettime, + .settime64 = rtl8125_phc_settime, + .enable = rtl8125_phc_enable, +}; + +static int rtl8125_get_tx_ptp_pkt_tstamp(struct rtl8125_private *tp, struct timespec64 *ts64) +{ + return _rtl8125_phc_gettime(tp, ts64); +} + +static void rtl8125_ptp_tx_hwtstamp(struct rtl8125_private *tp) +{ + struct sk_buff *skb = tp->ptp_tx_skb; + struct skb_shared_hwtstamps shhwtstamps = {0}; + struct timespec64 ts64; + + RTL_W8(tp, PTP_ISR_8125, PTP_ISR_TOK | PTP_ISR_TER); + + rtl8125_get_tx_ptp_pkt_tstamp(tp, &ts64); + + /* Upper 32 bits contain s, lower 32 bits contain ns. */ + shhwtstamps.hwtstamp = ktime_set(ts64.tv_sec, + ts64.tv_nsec); + + /* Clear the lock early before calling skb_tstamp_tx so that + * applications are not woken up before the lock bit is clear. We use + * a copy of the skb pointer to ensure other threads can't change it + * while we're notifying the stack. + */ + tp->ptp_tx_skb = NULL; + + /* Notify the stack and free the skb after we've unlocked */ + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); +} + +#define RTL8125_PTP_TX_TIMEOUT (HZ * 15) +static void rtl8125_ptp_tx_work(struct work_struct *work) +{ + struct rtl8125_private *tp = container_of(work, struct rtl8125_private, + ptp_tx_work); + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + + if (!tp->ptp_tx_skb) + goto Exit; + + if (time_is_before_jiffies(tp->ptp_tx_start + + RTL8125_PTP_TX_TIMEOUT)) { + dev_kfree_skb_any(tp->ptp_tx_skb); + tp->ptp_tx_skb = NULL; + tp->tx_hwtstamp_timeouts++; + /* Clear the tx valid bit in TSYNCTXCTL register to enable + * interrupt + */ + RTL_W8(tp, PTP_ISR_8125, PTP_ISR_TOK | PTP_ISR_TER); + goto Exit; + } + + if (RTL_R8(tp, PTP_ISR_8125) & (PTP_ISR_TOK)) + rtl8125_ptp_tx_hwtstamp(tp); + else + /* reschedule to check later */ + schedule_work(&tp->ptp_tx_work); + +Exit: + spin_unlock_irqrestore(&tp->lock, flags); +} + +static int rtl8125_hwtstamp_enable(struct rtl8125_private *tp, bool enable) +{ + RTL_W16(tp, PTP_CTRL_8125, 0); + if (enable) { + u16 ptp_ctrl; + struct timespec64 ts64; + + //clear ptp isr + RTL_W8(tp, PTP_ISR_8125, 0xff); + //ptp source 0:gphy 1:mac + rtl8125_mac_ocp_write(tp, 0xDC00, rtl8125_mac_ocp_read(tp, 0xDC00) | BIT_6); + //enable ptp + ptp_ctrl = (BIT_0 | BIT_3 | BIT_4 | BIT_6 | BIT_10 | BIT_12 | BIT_13); + if (tp->ptp_master_mode) { + ptp_ctrl &= ~BIT_13; + ptp_ctrl |= BIT_1; + } + RTL_W16(tp, PTP_CTRL_8125, ptp_ctrl); + + //set system time + /* + if (ktime_to_timespec64_cond(ktime_get_real(), &ts64)) + _rtl8125_phc_settime(tp, timespec64_to_timespec(ts64)); + */ + ktime_get_real_ts64(&ts64); + ts64.tv_nsec += tp->ptp_adjust; + _rtl8125_phc_settime(tp, &ts64); + tp->ptp_adjust = 0; + } + + return 0; +} + +static long rtl8125_ptp_create_clock(struct rtl8125_private *tp) +{ + struct net_device *netdev = tp->dev; + long err; + + if (!IS_ERR_OR_NULL(tp->ptp_clock)) + return 0; + + if (tp->HwSuppPtpVer == 0) { + tp->ptp_clock = NULL; + return -EOPNOTSUPP; + } + + tp->ptp_clock_info = rtl_ptp_clock_info; + snprintf(tp->ptp_clock_info.name, sizeof(tp->ptp_clock_info.name), + "%pm", tp->dev->dev_addr); + tp->ptp_clock_info.max_adj = 119304647; + tp->ptp_clock = ptp_clock_register(&tp->ptp_clock_info, &tp->pci_dev->dev); + if (IS_ERR(tp->ptp_clock)) { + err = PTR_ERR(tp->ptp_clock); + tp->ptp_clock = NULL; + netif_err(tp, drv, tp->dev, "ptp_clock_register failed\n"); + return err; + } else + netif_info(tp, drv, tp->dev, "registered PHC device on %s\n", netdev->name); + + return 0; +} + +void rtl8125_ptp_reset(struct rtl8125_private *tp) +{ + if (!tp->ptp_clock) + return; + + netif_info(tp, drv, tp->dev, "reset PHC clock\n"); + + rtl8125_hwtstamp_enable(tp, false); +} + +void rtl8125_ptp_init(struct rtl8125_private *tp) +{ + /* obtain a PTP device, or re-use an existing device */ + if (rtl8125_ptp_create_clock(tp)) + return; + + /* we have a clock so we can initialize work now */ + INIT_WORK(&tp->ptp_tx_work, rtl8125_ptp_tx_work); + + tp->ptp_adjust = 0; + + /* reset the PTP related hardware bits */ + rtl8125_ptp_reset(tp); + + return; +} + +void rtl8125_ptp_suspend(struct rtl8125_private *tp) +{ + if (!tp->ptp_clock) + return; + + netif_info(tp, drv, tp->dev, "suspend PHC clock\n"); + + rtl8125_hwtstamp_enable(tp, false); + + /* ensure that we cancel any pending PTP Tx work item in progress */ + cancel_work_sync(&tp->ptp_tx_work); +} + +void rtl8125_ptp_stop(struct rtl8125_private *tp) +{ + struct net_device *netdev = tp->dev; + + netif_info(tp, drv, tp->dev, "stop PHC clock\n"); + + /* first, suspend PTP activity */ + rtl8125_ptp_suspend(tp); + + /* disable the PTP clock device */ + if (tp->ptp_clock) { + ptp_clock_unregister(tp->ptp_clock); + tp->ptp_clock = NULL; + netif_info(tp, drv, tp->dev, "removed PHC on %s\n", + netdev->name); + } +} + +static int rtl8125_set_tstamp(struct net_device *netdev, struct ifreq *ifr) +{ + struct rtl8125_private *tp = netdev_priv(netdev); + struct hwtstamp_config config; + bool hwtstamp = 0; + + //netif_info(tp, drv, tp->dev, "ptp set ts\n"); + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + if (config.flags) + return -EINVAL; + + switch (config.tx_type) { + case HWTSTAMP_TX_ON: + hwtstamp = 1; + case HWTSTAMP_TX_OFF: + break; + case HWTSTAMP_TX_ONESTEP_SYNC: + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + hwtstamp = 1; + case HWTSTAMP_FILTER_NONE: + break; + default: + return -ERANGE; + } + + if (tp->hwtstamp_config.tx_type != config.tx_type || + tp->hwtstamp_config.rx_filter != config.rx_filter) { + tp->hwtstamp_config = config; + rtl8125_hwtstamp_enable(tp, hwtstamp); + } + + return copy_to_user(ifr->ifr_data, &config, + sizeof(config)) ? -EFAULT : 0; +} + +static int rtl8125_get_tstamp(struct net_device *netdev, struct ifreq *ifr) +{ + struct rtl8125_private *tp = netdev_priv(netdev); + + //netif_info(tp, drv, tp->dev, "ptp get ts\n"); + + return copy_to_user(ifr->ifr_data, &tp->hwtstamp_config, + sizeof(tp->hwtstamp_config)) ? -EFAULT : 0; +} + +int rtl8125_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct rtl8125_private *tp = netdev_priv(netdev); + int ret; + unsigned long flags; + + //netif_info(tp, drv, tp->dev, "ptp ioctl\n"); + + ret = 0; + switch (cmd) { +#ifdef ENABLE_PTP_SUPPORT + case SIOCSHWTSTAMP: + spin_lock_irqsave(&tp->lock, flags); + ret = rtl8125_set_tstamp(netdev, ifr); + spin_unlock_irqrestore(&tp->lock, flags); + break; + case SIOCGHWTSTAMP: + spin_lock_irqsave(&tp->lock, flags); + ret = rtl8125_get_tstamp(netdev, ifr); + spin_unlock_irqrestore(&tp->lock, flags); + break; +#endif + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +void rtl8125_rx_ptp_pktstamp(struct rtl8125_private *tp, struct sk_buff *skb, + struct RxDescV3 *descv3) +{ + time64_t tv_sec; + long tv_nsec; + + tv_sec = le32_to_cpu(descv3->RxDescTimeStamp.TimeStampHigh) + + ((u64)le32_to_cpu(descv3->RxDescPTPDDWord4.TimeStampHHigh) << 32); + tv_nsec = le32_to_cpu(descv3->RxDescTimeStamp.TimeStampLow) + tp->ptp_adjust; + + skb_hwtstamps(skb)->hwtstamp = ktime_set(tv_sec, tv_nsec); +} diff --git a/r8125/r8125_ptp.h b/r8125/r8125_ptp.h new file mode 100644 index 0000000..a324ff3 --- /dev/null +++ b/r8125/r8125_ptp.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +################################################################################ +# +# r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet +# controllers with PCI-Express interface. +# +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Author: +# Realtek NIC software team +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ + +/************************************************************************************ + * This product is covered by one or more of the following patents: + * US6,570,884, US6,115,776, and US6,327,625. + ***********************************************************************************/ + +#ifndef _LINUX_rtl8125_PTP_H +#define _LINUX_rtl8125_PTP_H + +#include +#include +#include +#include +#include + +struct rtl8125_ptp_info { + s64 time_sec; + u32 time_ns; + u16 ts_info; +}; + +#ifndef _STRUCT_TIMESPEC +#define _STRUCT_TIMESPEC +struct timespec { + __kernel_old_time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; +#endif + +enum PTP_CMD_TYPE { + PTP_CMD_SET_LOCAL_TIME = 0, + PTP_CMD_DRIFT_LOCAL_TIME, + PTP_CMD_LATCHED_LOCAL_TIME, +}; + + +struct rtl8125_private; +struct RxDescV3; + +int rtl8125_get_ts_info(struct net_device *netdev, + struct ethtool_ts_info *info); + +void rtl8125_ptp_reset(struct rtl8125_private *tp); +void rtl8125_ptp_init(struct rtl8125_private *tp); +void rtl8125_ptp_suspend(struct rtl8125_private *tp); +void rtl8125_ptp_stop(struct rtl8125_private *tp); + +int rtl8125_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); + +void rtl8125_rx_ptp_pktstamp(struct rtl8125_private *tp, struct sk_buff *skb, + struct RxDescV3 *descv3); + +#endif /* _LINUX_rtl8125_PTP_H */ diff --git a/r8125/r8125_realwow.h b/r8125/r8125_realwow.h index c42e111..352e327 100644 --- a/r8125/r8125_realwow.h +++ b/r8125/r8125_realwow.h @@ -1,10 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* ################################################################################ # # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2020 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free diff --git a/r8125/r8125_rss.c b/r8125/r8125_rss.c new file mode 100644 index 0000000..78e53f5 --- /dev/null +++ b/r8125/r8125_rss.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +################################################################################ +# +# r8168 is the Linux device driver released for Realtek Gigabit Ethernet +# controllers with PCI-Express interface. +# +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Author: +# Realtek NIC software team +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ + +/************************************************************************************ + * This product is covered by one or more of the following patents: + * US6,570,884, US6,115,776, and US6,327,625. + ***********************************************************************************/ + +#include +#include "r8125.h" + +enum rtl8125_rss_register_content { + /* RSS */ + RSS_CTRL_TCP_IPV4_SUPP = (1 << 0), + RSS_CTRL_IPV4_SUPP = (1 << 1), + RSS_CTRL_TCP_IPV6_SUPP = (1 << 2), + RSS_CTRL_IPV6_SUPP = (1 << 3), + RSS_HALF_SUPP = (1 << 7), + RSS_CTRL_UDP_IPV4_SUPP = (1 << 11), + RSS_CTRL_UDP_IPV6_SUPP = (1 << 12), + RSS_QUAD_CPU_EN = (1 << 16), + RSS_HQ_Q_SUP_R = (1 << 31), +}; + +static int rtl8125_get_rss_hash_opts(struct rtl8125_private *tp, + struct ethtool_rxnfc *cmd) +{ + cmd->data = 0; + + /* Report default options for RSS */ + switch (cmd->flow_type) { + case TCP_V4_FLOW: + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + /* fallthrough */ + case UDP_V4_FLOW: + if (tp->rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + /* fallthrough */ + case IPV4_FLOW: + cmd->data |= RXH_IP_SRC | RXH_IP_DST; + break; + case TCP_V6_FLOW: + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + /* fallthrough */ + case UDP_V6_FLOW: + if (tp->rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6) + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + /* fallthrough */ + case IPV6_FLOW: + cmd->data |= RXH_IP_SRC | RXH_IP_DST; + break; + default: + return -EINVAL; + } + + return 0; +} + +int rtl8125_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, + u32 *rule_locs) +{ + struct rtl8125_private *tp = netdev_priv(dev); + int ret = -EOPNOTSUPP; + + netif_info(tp, drv, tp->dev, "rss get rxnfc\n"); + + if (!(dev->features & NETIF_F_RXHASH)) + return ret; + + switch (cmd->cmd) { + case ETHTOOL_GRXRINGS: + cmd->data = rtl8125_tot_rx_rings(tp); + ret = 0; + break; + case ETHTOOL_GRXFH: + ret = rtl8125_get_rss_hash_opts(tp, cmd); + break; + default: + break; + } + + return ret; +} + +u32 rtl8125_rss_indir_tbl_entries(struct rtl8125_private *tp) +{ + return tp->HwSuppIndirTblEntries; +} + +#define RSS_MASK_BITS_OFFSET (8) +#define RSS_CPU_NUM_OFFSET (16) +#define RTL8125_UDP_RSS_FLAGS (RTL_8125_RSS_FLAG_HASH_UDP_IPV4 | \ + RTL_8125_RSS_FLAG_HASH_UDP_IPV6) +static int _rtl8125_set_rss_hash_opt(struct rtl8125_private *tp) +{ + u32 rss_flags = tp->rss_flags; + u32 hash_mask_len; + u32 rss_ctrl; + + rss_ctrl = ilog2(rtl8125_tot_rx_rings(tp)); + rss_ctrl &= (BIT_0 | BIT_1 | BIT_2); + rss_ctrl <<= RSS_CPU_NUM_OFFSET; + + /* Perform hash on these packet types */ + rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP + | RSS_CTRL_IPV4_SUPP + | RSS_CTRL_IPV6_SUPP + | RSS_CTRL_TCP_IPV6_SUPP; + + if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4) + rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP; + + if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6) + rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP; + + hash_mask_len = ilog2(rtl8125_rss_indir_tbl_entries(tp)); + hash_mask_len &= (BIT_0 | BIT_1 | BIT_2); + rss_ctrl |= hash_mask_len << RSS_MASK_BITS_OFFSET; + + RTL_W32(tp, RSS_CTRL_8125, rss_ctrl); + + return 0; +} + +static int rtl8125_set_rss_hash_opt(struct rtl8125_private *tp, + struct ethtool_rxnfc *nfc) +{ + u32 rss_flags = tp->rss_flags; + + netif_info(tp, drv, tp->dev, "rss set hash\n"); + + /* + * RSS does not support anything other than hashing + * to queues on src and dst IPs and ports + */ + if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3)) + return -EINVAL; + + switch (nfc->flow_type) { + case TCP_V4_FLOW: + case TCP_V6_FLOW: + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST) || + !(nfc->data & RXH_L4_B_0_1) || + !(nfc->data & RXH_L4_B_2_3)) + return -EINVAL; + break; + case UDP_V4_FLOW: + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST)) + return -EINVAL; + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + rss_flags &= ~RTL_8125_RSS_FLAG_HASH_UDP_IPV4; + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + rss_flags |= RTL_8125_RSS_FLAG_HASH_UDP_IPV4; + break; + default: + return -EINVAL; + } + break; + case UDP_V6_FLOW: + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST)) + return -EINVAL; + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + rss_flags &= ~RTL_8125_RSS_FLAG_HASH_UDP_IPV6; + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + rss_flags |= RTL_8125_RSS_FLAG_HASH_UDP_IPV6; + break; + default: + return -EINVAL; + } + break; + case SCTP_V4_FLOW: + case AH_ESP_V4_FLOW: + case AH_V4_FLOW: + case ESP_V4_FLOW: + case SCTP_V6_FLOW: + case AH_ESP_V6_FLOW: + case AH_V6_FLOW: + case ESP_V6_FLOW: + case IP_USER_FLOW: + case ETHER_FLOW: + /* RSS is not supported for these protocols */ + if (nfc->data) { + netif_err(tp, drv, tp->dev, "Command parameters not supported\n"); + return -EINVAL; + } + return 0; + break; + default: + return -EINVAL; + } + + /* if we changed something we need to update flags */ + if (rss_flags != tp->rss_flags) { + u32 rss_ctrl = RTL_R32(tp, RSS_CTRL_8125); + + if ((rss_flags & RTL8125_UDP_RSS_FLAGS) && + !(tp->rss_flags & RTL8125_UDP_RSS_FLAGS)) + netdev_warn(tp->dev, + "enabling UDP RSS: fragmented packets may " + "arrive out of order to the stack above\n"); + + tp->rss_flags = rss_flags; + + /* Perform hash on these packet types */ + rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP + | RSS_CTRL_IPV4_SUPP + | RSS_CTRL_IPV6_SUPP + | RSS_CTRL_TCP_IPV6_SUPP; + + rss_ctrl &= ~(RSS_CTRL_UDP_IPV4_SUPP | + RSS_CTRL_UDP_IPV6_SUPP); + + if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4) + rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP; + + if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6) + rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP; + + RTL_W32(tp, RSS_CTRL_8125, rss_ctrl); + } + + return 0; +} + +int rtl8125_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) +{ + struct rtl8125_private *tp = netdev_priv(dev); + int ret = -EOPNOTSUPP; + + netif_info(tp, drv, tp->dev, "rss set rxnfc\n"); + + if (!(dev->features & NETIF_F_RXHASH)) + return ret; + + switch (cmd->cmd) { + case ETHTOOL_SRXFH: + ret = rtl8125_set_rss_hash_opt(tp, cmd); + break; + default: + break; + } + + return ret; +} + +static u32 _rtl8125_get_rxfh_key_size(struct rtl8125_private *tp) +{ + return sizeof(tp->rss_key); +} + +u32 rtl8125_get_rxfh_key_size(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + netif_info(tp, drv, tp->dev, "rss get key size\n"); + + if (!(dev->features & NETIF_F_RXHASH)) + return 0; + + return _rtl8125_get_rxfh_key_size(tp); +} + +u32 rtl8125_rss_indir_size(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + netif_info(tp, drv, tp->dev, "rss get indir tbl size\n"); + + if (!(dev->features & NETIF_F_RXHASH)) + return 0; + + return rtl8125_rss_indir_tbl_entries(tp); +} + +static void rtl8125_get_reta(struct rtl8125_private *tp, u32 *indir) +{ + int i, reta_size = rtl8125_rss_indir_tbl_entries(tp); + + for (i = 0; i < reta_size; i++) + indir[i] = tp->rss_indir_tbl[i]; +} + +int rtl8125_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, + u8 *hfunc) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + netif_info(tp, drv, tp->dev, "rss get rxfh\n"); + + if (!(dev->features & NETIF_F_RXHASH)) + return -EOPNOTSUPP; + + if (hfunc) + *hfunc = ETH_RSS_HASH_TOP; + + if (indir) + rtl8125_get_reta(tp, indir); + + if (key) + memcpy(key, tp->rss_key, rtl8125_get_rxfh_key_size(dev)); + + return 0; +} + +static u32 rtl8125_rss_key_reg(struct rtl8125_private *tp) +{ + return RSS_KEY_8125; +} + +static u32 rtl8125_rss_indir_tbl_reg(struct rtl8125_private *tp) +{ + return RSS_INDIRECTION_TBL_8125_V2; +} + +static void rtl8125_store_reta(struct rtl8125_private *tp) +{ + u16 indir_tbl_reg = rtl8125_rss_indir_tbl_reg(tp); + u32 i, reta_entries = rtl8125_rss_indir_tbl_entries(tp); + u32 reta = 0; + u8 *indir_tbl = tp->rss_indir_tbl; + + /* Write redirection table to HW */ + for (i = 0; i < reta_entries; i++) { + reta |= indir_tbl[i] << (i & 0x3) * 8; + if ((i & 3) == 3) { + RTL_W32(tp, indir_tbl_reg, reta); + + indir_tbl_reg += 4; + reta = 0; + } + } +} + +static void rtl8125_store_rss_key(struct rtl8125_private *tp) +{ + const u16 rss_key_reg = rtl8125_rss_key_reg(tp); + u32 i, rss_key_size = _rtl8125_get_rxfh_key_size(tp); + u32 *rss_key = (u32*)tp->rss_key; + + /* Write redirection table to HW */ + for (i = 0; i < rss_key_size; i+=4) + RTL_W32(tp, rss_key_reg + i, *rss_key++); +} + +int rtl8125_set_rxfh(struct net_device *dev, const u32 *indir, + const u8 *key, const u8 hfunc) +{ + struct rtl8125_private *tp = netdev_priv(dev); + int i; + u32 reta_entries = rtl8125_rss_indir_tbl_entries(tp); + + netif_info(tp, drv, tp->dev, "rss set rxfh\n"); + + /* We require at least one supported parameter to be changed and no + * change in any of the unsupported parameters + */ + if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) + return -EOPNOTSUPP; + + /* Fill out the redirection table */ + if (indir) { + int max_queues = tp->num_rx_rings; + + /* Verify user input. */ + for (i = 0; i < reta_entries; i++) + if (indir[i] >= max_queues) + return -EINVAL; + + for (i = 0; i < reta_entries; i++) + tp->rss_indir_tbl[i] = indir[i]; + } + + /* Fill out the rss hash key */ + if (key) + memcpy(tp->rss_key, key, rtl8125_get_rxfh_key_size(dev)); + + rtl8125_store_reta(tp); + + rtl8125_store_rss_key(tp); + + return 0; +} + +static u32 rtl8125_get_rx_desc_hash(struct rtl8125_private *tp, + struct RxDescV3 *descv3) +{ + return le32_to_cpu(descv3->RxDescNormalDDWord2.RSSResult); +} + +#define RXS_8125B_RSS_UDP BIT(9) +#define RXS_8125_RSS_IPV4 BIT(10) +#define RXS_8125_RSS_IPV6 BIT(12) +#define RXS_8125_RSS_TCP BIT(13) +#define RTL8125_RXS_RSS_L3_TYPE_MASK (RXS_8125_RSS_IPV4 | RXS_8125_RSS_IPV6) +#define RTL8125_RXS_RSS_L4_TYPE_MASK (RXS_8125_RSS_TCP | RXS_8125B_RSS_UDP) +void rtl8125_rx_hash(struct rtl8125_private *tp, + struct RxDescV3 *descv3, + struct sk_buff *skb) +{ + u16 rss_header_info; + + if (!(tp->dev->features & NETIF_F_RXHASH)) + return; + + rss_header_info = le16_to_cpu(descv3->RxDescNormalDDWord2.HeaderInfo); + + if (!(rss_header_info & RTL8125_RXS_RSS_L3_TYPE_MASK)) + return; + + skb_set_hash(skb, rtl8125_get_rx_desc_hash(tp, descv3), + (RTL8125_RXS_RSS_L4_TYPE_MASK & rss_header_info) ? + PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); +} + +void rtl8125_disable_rss(struct rtl8125_private *tp) +{ + RTL_W32(tp, RSS_CTRL_8125, 0x00); +} + +void _rtl8125_config_rss(struct rtl8125_private *tp) +{ + _rtl8125_set_rss_hash_opt(tp); + + rtl8125_store_reta(tp); + + rtl8125_store_rss_key(tp); +} + +void rtl8125_config_rss(struct rtl8125_private *tp) +{ + if (!tp->EnableRss) { + rtl8125_disable_rss(tp); + return; + } + + _rtl8125_config_rss(tp); +} + +void rtl8125_init_rss(struct rtl8125_private *tp) +{ + int i; + + for (i = 0; i < rtl8125_rss_indir_tbl_entries(tp); i++) + tp->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings); + + netdev_rss_key_fill(tp->rss_key, RTL8125_RSS_KEY_SIZE); +} diff --git a/r8125/r8125_rss.h b/r8125/r8125_rss.h new file mode 100644 index 0000000..90e2809 --- /dev/null +++ b/r8125/r8125_rss.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +################################################################################ +# +# r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet +# controllers with PCI-Express interface. +# +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Author: +# Realtek NIC software team +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ + +/************************************************************************************ + * This product is covered by one or more of the following patents: + * US6,570,884, US6,115,776, and US6,327,625. + ***********************************************************************************/ + +#ifndef _LINUX_rtl8125_RSS_H +#define _LINUX_rtl8125_RSS_H + +#include +#include + +#define RTL8125_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */ +#define RTL8125_MAX_INDIRECTION_TABLE_ENTRIES 128 + +enum rtl8125_rss_flag { + RTL_8125_RSS_FLAG_HASH_UDP_IPV4 = (1 << 0), + RTL_8125_RSS_FLAG_HASH_UDP_IPV6 = (1 << 1), +}; + +struct rtl8125_private; + +int rtl8125_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, + u32 *rule_locs); +int rtl8125_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd); +u32 rtl8125_get_rxfh_key_size(struct net_device *netdev); +u32 rtl8125_rss_indir_size(struct net_device *netdev); +int rtl8125_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, + u8 *hfunc); +int rtl8125_set_rxfh(struct net_device *netdev, const u32 *indir, + const u8 *key, const u8 hfunc); +void rtl8125_rx_hash(struct rtl8125_private *tp, + struct RxDescV3 *descv3, + struct sk_buff *skb); +void _rtl8125_config_rss(struct rtl8125_private *tp); +void rtl8125_config_rss(struct rtl8125_private *tp); +void rtl8125_init_rss(struct rtl8125_private *tp); +u32 rtl8125_rss_indir_tbl_entries(struct rtl8125_private *tp); +void rtl8125_disable_rss(struct rtl8125_private *tp); + +#endif /* _LINUX_rtl8125_RSS_H */ diff --git a/r8125/rtl_eeprom.c b/r8125/rtl_eeprom.c index d2c673c..866ae5f 100644 --- a/r8125/rtl_eeprom.c +++ b/r8125/rtl_eeprom.c @@ -5,7 +5,7 @@ # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2020 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free @@ -34,17 +34,7 @@ #include #include -//The vmkernel network api is from 2.6.24,not the default 2.6.18 -#ifndef LINUX_VERSION_CODE #include -#undef LINUX_VERSION_CODE -#define LINUX_VERSION_CODE KERNEL_VERSION(2,6,24) -#endif -//The vmkernel network api is from 2.6.24,not the default 2.6.18 -#ifdef LINUX_VERSION_CODE -#undef LINUX_VERSION_CODE -#define LINUX_VERSION_CODE KERNEL_VERSION(2,6,24) -#endif #include #include #include diff --git a/r8125/rtl_eeprom.h b/r8125/rtl_eeprom.h index 0e3fa83..b0c4a05 100644 --- a/r8125/rtl_eeprom.h +++ b/r8125/rtl_eeprom.h @@ -5,7 +5,7 @@ # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2020 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free diff --git a/r8125/rtltool.c b/r8125/rtltool.c index 5e307ee..ace717b 100644 --- a/r8125/rtltool.c +++ b/r8125/rtltool.c @@ -5,7 +5,7 @@ # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2020 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free @@ -33,13 +33,7 @@ ***********************************************************************************/ #include -//The vmkernel network api is from 2.6.24,not the default 2.6.18 -#ifndef LINUX_VERSION_CODE #include -#undef LINUX_VERSION_CODE -#define LINUX_VERSION_CODE KERNEL_VERSION(2,6,24) -#endif - #include #include #include @@ -53,7 +47,6 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) { struct rtltool_cmd my_cmd; - unsigned long flags; int ret; if (copy_from_user(&my_cmd, ifr->ifr_data, sizeof(my_cmd))) @@ -103,10 +96,7 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); my_cmd.data = rtl8125_mdio_prot_read(tp, my_cmd.offset); - spin_unlock_irqrestore(&tp->lock, flags); - if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) { ret = -EFAULT; break; @@ -118,19 +108,14 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); rtl8125_mdio_prot_write(tp, my_cmd.offset, my_cmd.data); - spin_unlock_irqrestore(&tp->lock, flags); break; case RTLTOOL_READ_EPHY: if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); my_cmd.data = rtl8125_ephy_read(tp, my_cmd.offset); - spin_unlock_irqrestore(&tp->lock, flags); - if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) { ret = -EFAULT; break; @@ -142,17 +127,13 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); rtl8125_ephy_write(tp, my_cmd.offset, my_cmd.data); - spin_unlock_irqrestore(&tp->lock, flags); break; case RTLTOOL_READ_ERI: my_cmd.data = 0; if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) { - spin_lock_irqsave(&tp->lock, flags); my_cmd.data = rtl8125_eri_read(tp, my_cmd.offset, my_cmd.len, ERIAR_ExGMAC); - spin_unlock_irqrestore(&tp->lock, flags); } else { ret = -EOPNOTSUPP; break; @@ -173,9 +154,7 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) return -EPERM; if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) { - spin_lock_irqsave(&tp->lock, flags); rtl8125_eri_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data, ERIAR_ExGMAC); - spin_unlock_irqrestore(&tp->lock, flags); } else { ret = -EOPNOTSUPP; break; @@ -231,10 +210,7 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); my_cmd.data = rtl8125_eeprom_read_sc(tp, my_cmd.offset); - spin_unlock_irqrestore(&tp->lock, flags); - if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) { ret = -EFAULT; break; @@ -246,21 +222,16 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); rtl8125_eeprom_write_sc(tp, my_cmd.offset, my_cmd.data); - spin_unlock_irqrestore(&tp->lock, flags); break; case RTL_READ_OOB_MAC: if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); rtl8125_oob_mutex_lock(tp); my_cmd.data = rtl8125_ocp_read(tp, my_cmd.offset, 4); rtl8125_oob_mutex_unlock(tp); - spin_unlock_irqrestore(&tp->lock, flags); - if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) { ret = -EFAULT; break; @@ -274,20 +245,16 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (my_cmd.len == 0 || my_cmd.len > 4) return -EOPNOTSUPP; - spin_lock_irqsave(&tp->lock, flags); rtl8125_oob_mutex_lock(tp); rtl8125_ocp_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data); rtl8125_oob_mutex_unlock(tp); - spin_unlock_irqrestore(&tp->lock, flags); break; case RTL_ENABLE_PCI_DIAG: if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); tp->rtk_enable_diag = 1; - spin_unlock_irqrestore(&tp->lock, flags); dprintk("enable rtk diag\n"); break; @@ -296,9 +263,7 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); tp->rtk_enable_diag = 0; - spin_unlock_irqrestore(&tp->lock, flags); dprintk("disable rtk diag\n"); break; @@ -310,10 +275,7 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (my_cmd.offset % 2) return -EOPNOTSUPP; - spin_lock_irqsave(&tp->lock, flags); my_cmd.data = rtl8125_mac_ocp_read(tp, my_cmd.offset); - spin_unlock_irqrestore(&tp->lock, flags); - if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) { ret = -EFAULT; break; @@ -327,19 +289,14 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if ((my_cmd.offset % 2) || (my_cmd.len != 2)) return -EOPNOTSUPP; - spin_lock_irqsave(&tp->lock, flags); rtl8125_mac_ocp_write(tp, my_cmd.offset, (u16)my_cmd.data); - spin_unlock_irqrestore(&tp->lock, flags); break; case RTL_DIRECT_READ_PHY_OCP: if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); my_cmd.data = rtl8125_mdio_prot_direct_read_phy_ocp(tp, my_cmd.offset); - spin_unlock_irqrestore(&tp->lock, flags); - if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) { ret = -EFAULT; break; @@ -351,9 +308,7 @@ int rtl8125_tool_ioctl(struct rtl8125_private *tp, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&tp->lock, flags); rtl8125_mdio_prot_direct_write_phy_ocp(tp, my_cmd.offset, my_cmd.data); - spin_unlock_irqrestore(&tp->lock, flags); break; default: diff --git a/r8125/rtltool.h b/r8125/rtltool.h index aa95875..fc8a10c 100644 --- a/r8125/rtltool.h +++ b/r8125/rtltool.h @@ -5,7 +5,7 @@ # r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet # controllers with PCI-Express interface. # -# Copyright(c) 2020 Realtek Semiconductor Corp. All rights reserved. +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free