/*
################################################################################
#
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Copyright(c) 2017-2018 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 <http://www.gnu.org/licenses/>.
#
# Author:
# Realtek NIC software team <nicfae@realtek.com>
# 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.
***********************************************************************************/
/*
* This driver is modified from r8169.c in Linux kernel 2.6.18
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/crc32.h>
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/ip.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
#include <linux/ipv6.h>
#include <net/ip6_checksum.h>
#endif
#include <linux/tcp.h>
#include <linux/init.h>
#include <linux/rtnetlink.h>
#include <linux/completion.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
#include <linux/pci-aspm.h>
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,37)
#include <linux/prefetch.h>
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#define dev_printk(A,B,fmt,args...) printk(A fmt,##args)
#else
#include <linux/dma-mapping.h>
#include <linux/moduleparam.h>
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
#include <linux/mdio.h>
#endif
#include <asm/io.h>
#include <asm/irq.h>
#include "r8168.h"
#include "r8168_asf.h"
#include "rtl_eeprom.h"
#include "rtltool.h"
#ifdef ENABLE_R8168_PROCFS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#endif
/* 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) \
{ .name = NAME, .mcfg = MAC, .RCR_Cfg = RCR, .RxConfigMask = MASK, .jumbo_frame_sz = JumFrameSz }
static const struct {
const char *name;
u8 mcfg;
u32 RCR_Cfg;
u32 RxConfigMask; /* Clears the bits supported by this chip */
u32 jumbo_frame_sz;
} rtl_chip_info[] = {
_R("RTL8168B/8111B",
CFG_METHOD_1,
(Reserved2_data << Reserved2_shift) | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_4k),
_R("RTL8168B/8111B",
CFG_METHOD_2,
(Reserved2_data << Reserved2_shift) | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_4k),
_R("RTL8168B/8111B",
CFG_METHOD_3,
(Reserved2_data << Reserved2_shift) | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_4k),
_R("RTL8168C/8111C",
CFG_METHOD_4,
RxCfg_128_int_en | RxCfg_fet_multi_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_6k),
_R("RTL8168C/8111C",
CFG_METHOD_5,
RxCfg_128_int_en | RxCfg_fet_multi_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_6k),
_R("RTL8168C/8111C",
CFG_METHOD_6,
RxCfg_128_int_en | RxCfg_fet_multi_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_6k),
_R("RTL8168CP/8111CP",
CFG_METHOD_7,
RxCfg_128_int_en | RxCfg_fet_multi_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_6k),
_R("RTL8168CP/8111CP",
CFG_METHOD_8,
RxCfg_128_int_en | RxCfg_fet_multi_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_6k),
_R("RTL8168D/8111D",
CFG_METHOD_9,
RxCfg_128_int_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168D/8111D",
CFG_METHOD_10,
RxCfg_128_int_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168DP/8111DP",
CFG_METHOD_11,
RxCfg_128_int_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168DP/8111DP",
CFG_METHOD_12,
RxCfg_128_int_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168DP/8111DP",
CFG_METHOD_13,
RxCfg_128_int_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168E/8111E",
CFG_METHOD_14,
RxCfg_128_int_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168E/8111E",
CFG_METHOD_15,
RxCfg_128_int_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168E-VL/8111E-VL",
CFG_METHOD_16,
RxCfg_128_int_en | RxEarly_off_V1 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e0080,
Jumbo_Frame_9k),
_R("RTL8168E-VL/8111E-VL",
CFG_METHOD_17,
RxCfg_128_int_en | RxEarly_off_V1 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168F/8111F",
CFG_METHOD_18,
RxCfg_128_int_en | RxEarly_off_V1 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168F/8111F",
CFG_METHOD_19,
RxCfg_128_int_en | RxEarly_off_V1 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8411",
CFG_METHOD_20,
RxCfg_128_int_en | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e1880,
Jumbo_Frame_9k),
_R("RTL8168G/8111G",
CFG_METHOD_21,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168G/8111G",
CFG_METHOD_22,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168EP/8111EP",
CFG_METHOD_23,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168GU/8111GU",
CFG_METHOD_24,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168GU/8111GU",
CFG_METHOD_25,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("8411B",
CFG_METHOD_26,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168EP/8111EP",
CFG_METHOD_27,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168EP/8111EP",
CFG_METHOD_28,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168H/8111H",
CFG_METHOD_29,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168H/8111H",
CFG_METHOD_30,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168FP/8111FP",
CFG_METHOD_31,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("RTL8168FP/8111FP",
CFG_METHOD_32,
RxCfg_128_int_en | RxEarly_off_V2 | Rx_Single_fetch_V2 | (RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_9k),
_R("Unknown",
CFG_METHOD_DEFAULT,
(RX_DMA_BURST << RxCfgDMAShift),
0xff7e5880,
Jumbo_Frame_1k)
};
#undef _R
#ifndef PCI_VENDOR_ID_DLINK
#define PCI_VENDOR_ID_DLINK 0x1186
#endif
static struct pci_device_id rtl8168_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161), },
{ PCI_VENDOR_ID_DLINK, 0x4300, 0x1186, 0x4b10,},
{0,},
};
MODULE_DEVICE_TABLE(pci, rtl8168_pci_tbl);
static int rx_copybreak = 0;
static int use_dac = 1;
static int timer_count = 0x2600;
static struct {
u32 msg_enable;
} debug = { -1 };
static unsigned int speed_mode = SPEED_1000;
static unsigned int duplex_mode = DUPLEX_FULL;
static unsigned int autoneg_mode = AUTONEG_ENABLE;
#ifdef CONFIG_ASPM
static int aspm = 1;
#else
static int aspm = 0;
#endif
#ifdef ENABLE_S5WOL
static int s5wol = 1;
#else
static int s5wol = 0;
#endif
#ifdef ENABLE_S5_KEEP_CURR_MAC
static int s5_keep_curr_mac = 1;
#else
static int s5_keep_curr_mac = 0;
#endif
#ifdef ENABLE_EEE
static int eee_enable = 1;
#else
static int eee_enable = 0;
#endif
#ifdef CONFIG_SOC_LAN
static ulong hwoptimize = HW_PATCH_SOC_LAN;
#else
static ulong hwoptimize = 0;
#endif
#ifdef ENABLE_S0_MAGIC_PACKET
static int s0_magic_packet = 1;
#else
static int s0_magic_packet = 0;
#endif
MODULE_AUTHOR("Realtek and the Linux r8168 crew <netdev@vger.kernel.org>");
MODULE_DESCRIPTION("RealTek RTL-8168 Gigabit 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(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.");
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.");
#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");
MODULE_VERSION(RTL8168_VERSION);
static void rtl8168_sleep_rx_enable(struct net_device *dev);
static void rtl8168_dsm(struct net_device *dev, int dev_state);
static void rtl8168_esd_timer(unsigned long __opaque);
static void rtl8168_link_timer(unsigned long __opaque);
static void rtl8168_tx_clear(struct rtl8168_private *tp);
static void rtl8168_rx_clear(struct rtl8168_private *tp);
static int rtl8168_open(struct net_device *dev);
static int rtl8168_start_xmit(struct sk_buff *skb, struct net_device *dev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t rtl8168_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
#else
static irqreturn_t rtl8168_interrupt(int irq, void *dev_instance);
#endif
static void rtl8168_rx_desc_offset0_init(struct rtl8168_private *, int);
static int rtl8168_init_ring(struct net_device *dev);
static void rtl8168_hw_config(struct net_device *dev);
static void rtl8168_hw_start(struct net_device *dev);
static int rtl8168_close(struct net_device *dev);
static void rtl8168_set_rx_mode(struct net_device *dev);
static void rtl8168_tx_timeout(struct net_device *dev);
static struct net_device_stats *rtl8168_get_stats(struct net_device *dev);
static int rtl8168_rx_interrupt(struct net_device *, struct rtl8168_private *, void __iomem *, napi_budget);
static int rtl8168_change_mtu(struct net_device *dev, int new_mtu);
static void rtl8168_down(struct net_device *dev);
static int rtl8168_set_mac_address(struct net_device *dev, void *p);
void rtl8168_rar_set(struct rtl8168_private *tp, uint8_t *addr);
static void rtl8168_desc_addr_fill(struct rtl8168_private *);
static void rtl8168_tx_desc_init(struct rtl8168_private *tp);
static void rtl8168_rx_desc_init(struct rtl8168_private *tp);
static void rtl8168_hw_reset(struct net_device *dev);
static void rtl8168_phy_power_up(struct net_device *dev);
static void rtl8168_phy_power_down(struct net_device *dev);
static int rtl8168_set_speed(struct net_device *dev, u8 autoneg, u32 speed, u8 duplex);
#ifdef CONFIG_R8168_NAPI
static int rtl8168_poll(napi_ptr napi, napi_budget budget);
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#undef ethtool_ops
#define ethtool_ops _kc_ethtool_ops
struct _kc_ethtool_ops {
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
int (*set_settings)(struct net_device *, struct ethtool_cmd *);
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
int (*get_regs_len)(struct net_device *);
void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
void (*get_wol)(struct net_device *, struct ethtool_wolinfo *);
int (*set_wol)(struct net_device *, struct ethtool_wolinfo *);
u32 (*get_msglevel)(struct net_device *);
void (*set_msglevel)(struct net_device *, u32);
int (*nway_reset)(struct net_device *);
u32 (*get_link)(struct net_device *);
int (*get_eeprom_len)(struct net_device *);
int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *);
int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *);
void (*get_pauseparam)(struct net_device *,
struct ethtool_pauseparam*);
int (*set_pauseparam)(struct net_device *,
struct ethtool_pauseparam*);
u32 (*get_rx_csum)(struct net_device *);
int (*set_rx_csum)(struct net_device *, u32);
u32 (*get_tx_csum)(struct net_device *);
int (*set_tx_csum)(struct net_device *, u32);
u32 (*get_sg)(struct net_device *);
int (*set_sg)(struct net_device *, u32);
u32 (*get_tso)(struct net_device *);
int (*set_tso)(struct net_device *, u32);
int (*self_test_count)(struct net_device *);
void (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
void (*get_strings)(struct net_device *, u32 stringset, u8 *);
int (*phys_id)(struct net_device *, u32);
int (*get_stats_count)(struct net_device *);
void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *,
u64 *);
} *ethtool_ops = NULL;
#undef SET_ETHTOOL_OPS
#define SET_ETHTOOL_OPS(netdev, ops) (ethtool_ops = (ops))
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
#ifndef SET_ETHTOOL_OPS
#define SET_ETHTOOL_OPS(netdev,ops) \
( (netdev)->ethtool_ops = (ops) )
#endif //SET_ETHTOOL_OPS
#endif //LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
//#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
#ifndef netif_msg_init
#define netif_msg_init _kc_netif_msg_init
/* copied from linux kernel 2.6.20 include/linux/netdevice.h */
static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits)
{
/* use default */
if (debug_value < 0 || debug_value >= (sizeof(u32) * 8))
return default_msg_enable_bits;
if (debug_value == 0) /* no output */
return 0;
/* set low N bits */
return (1 << debug_value) - 1;
}
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
#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)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
/* copied from linux kernel 2.6.20 /include/linux/time.h */
/* Parameters used to convert the timespec values: */
#define MSEC_PER_SEC 1000L
/* copied from linux kernel 2.6.20 /include/linux/jiffies.h */
/*
* Change timeval to jiffies, trying to avoid the
* most obvious overflows..
*
* And some not so obvious.
*
* Note that we don't want to return MAX_LONG, because
* for various timeout reasons we often end up having
* to wait "jiffies+1" in order to guarantee that we wait
* at _least_ "jiffies" - so "jiffies+1" had better still
* be positive.
*/
#define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
/*
* Convert jiffies to milliseconds and back.
*
* Avoid unnecessary multiplications/divisions in the
* two most common HZ cases:
*/
static inline unsigned int _kc_jiffies_to_msecs(const unsigned long j)
{
#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
return (MSEC_PER_SEC / HZ) * j;
#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
#else
return (j * MSEC_PER_SEC) / HZ;
#endif
}
static inline unsigned long _kc_msecs_to_jiffies(const unsigned int m)
{
if (m > _kc_jiffies_to_msecs(MAX_JIFFY_OFFSET))
return MAX_JIFFY_OFFSET;
#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
return m * (HZ / MSEC_PER_SEC);
#else
return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC;
#endif
}
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
/* copied from linux kernel 2.6.12.6 /include/linux/pm.h */
typedef int __bitwise pci_power_t;
/* copied from linux kernel 2.6.12.6 /include/linux/pci.h */
typedef u32 __bitwise pm_message_t;
#define PCI_D0 ((pci_power_t __force) 0)
#define PCI_D1 ((pci_power_t __force) 1)
#define PCI_D2 ((pci_power_t __force) 2)
#define PCI_D3hot ((pci_power_t __force) 3)
#define PCI_D3cold ((pci_power_t __force) 4)
#define PCI_POWER_ERROR ((pci_power_t __force) -1)
/* copied from linux kernel 2.6.12.6 /drivers/pci/pci.c */
/**
* pci_choose_state - Choose the power state of a PCI device
* @dev: PCI device to be suspended
* @state: target sleep state for the whole system. This is the value
* that is passed to suspend() function.
*
* Returns PCI power state suitable for given device and given system
* message.
*/
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
{
if (!pci_find_capability(dev, PCI_CAP_ID_PM))
return PCI_D0;
switch (state) {
case 0:
return PCI_D0;
case 3:
return PCI_D3hot;
default:
printk("They asked me for state %d\n", state);
// BUG();
}
return PCI_D0;
}
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
/**
* msleep_interruptible - sleep waiting for waitqueue interruptions
* @msecs: Time in milliseconds to sleep for
*/
#define msleep_interruptible _kc_msleep_interruptible
unsigned long _kc_msleep_interruptible(unsigned int msecs)
{
unsigned long timeout = _kc_msecs_to_jiffies(msecs);
while (timeout && !signal_pending(current)) {
set_current_state(TASK_INTERRUPTIBLE);
timeout = schedule_timeout(timeout);
}
return _kc_jiffies_to_msecs(timeout);
}
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
/* copied from linux kernel 2.6.20 include/linux/sched.h */
#ifndef __sched
#define __sched __attribute__((__section__(".sched.text")))
#endif
/* copied from linux kernel 2.6.20 kernel/timer.c */
signed long __sched schedule_timeout_uninterruptible(signed long timeout)
{
__set_current_state(TASK_UNINTERRUPTIBLE);
return schedule_timeout(timeout);
}
/* copied from linux kernel 2.6.20 include/linux/mii.h */
#undef if_mii
#define if_mii _kc_if_mii
static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
{
return (struct mii_ioctl_data *) &rq->ifr_ifru;
}
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
struct rtl8168_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;
};
/* SysFS node */
static int power_saver_flag;
static struct kobject *rt8168_ps_kobj;
static ssize_t show_power_saver(struct kobject *dev,
struct kobj_attribute *attr, char *buf) {
ssize_t ret;
ret = snprintf(buf, PAGE_SIZE, "%u\n", power_saver_flag);
return ret;
}
static ssize_t set_power_saver(struct kobject *dev,
struct kobj_attribute *attr, const char *buf, size_t count) {
sscanf(buf, "%d", &power_saver_flag);
if (!power_saver_flag) {
pr_debug("rt8168_power mode is set to big spender");
aspm = 0;
s5wol = 0;
eee_enable = 0;
} else {
pr_debug("rt8168_power mode is set to no waste");
#ifdef CONFIG_R8168_ASPM
aspm = 1;
#else
aspm = 0;
#endif
#ifdef CONFIG_R8168_S5WOL
s5wol = 1;
#else
s5wol = 0;
#endif
#ifdef ENABLE_EEE
eee_enable = 1;
#else
eee_enable = 0;
#endif
}
return count;
}
static const struct kobj_attribute rt8168_psaver_attr[] = {
__ATTR(mode, S_IRUGO | S_IWUSR | S_IWGRP, show_power_saver, set_power_saver),
};
static int rtl8168_sysfs_register(void)
{
int ret, i;
if (!kernel_kobj) {
pr_err("kernel_kobj is NULL\n");
return -1;
}
rt8168_ps_kobj = kobject_create_and_add("rt8168_power", kernel_kobj);
if (!rt8168_ps_kobj) {
pr_err("unable to create rt8168_power_saver kernel object!\n");
return -1;
}
for (i = 0; i < ARRAY_SIZE(rt8168_psaver_attr); i++) {
ret = sysfs_create_file(rt8168_ps_kobj,
&rt8168_psaver_attr[i].attr);
if (ret)
pr_err("failed to create %s\n",
rt8168_psaver_attr[i].attr.name);
}
return ret;
}
static int rtl8168_sysfs_remove(void)
{
int i;
if (!rt8168_ps_kobj)
return -1;
for (i = 0; i < ARRAY_SIZE(rt8168_psaver_attr); i++)
sysfs_remove_file(rt8168_ps_kobj, &rt8168_psaver_attr[i].attr);
return 0;
}
#ifdef ENABLE_R8168_PROCFS
/****************************************************************************
* -----------------------------PROCFS STUFF-------------------------
*****************************************************************************
*/
static struct proc_dir_entry *rtl8168_proc;
static int proc_init_num = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
static int proc_get_driver_variable(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
struct rtl8168_private *tp = netdev_priv(dev);
unsigned long flags;
seq_puts(m, "\nDump Driver Variable\n");
spin_lock_irqsave(&tp->lock, flags);
seq_puts(m, "Variable\tValue\n----------\t-----\n");
seq_printf(m, "MODULENAME\t%s\n", MODULENAME);
seq_printf(m, "driver version\t%s\n", RTL8168_VERSION);
seq_printf(m, "chipset\t%d\n", tp->chipset);
seq_printf(m, "chipset_name\t%s\n", rtl_chip_info[tp->chipset].name);
seq_printf(m, "mtu\t%d\n", dev->mtu);
seq_printf(m, "NUM_RX_DESC\t0x%x\n", NUM_RX_DESC);
seq_printf(m, "cur_rx\t0x%x\n", tp->cur_rx);
seq_printf(m, "dirty_rx\t0x%x\n", tp->dirty_rx);
seq_printf(m, "NUM_TX_DESC\t0x%x\n", NUM_TX_DESC);
seq_printf(m, "cur_tx\t0x%x\n", tp->cur_tx);
seq_printf(m, "dirty_tx\t0x%x\n", tp->dirty_tx);
seq_printf(m, "rx_buf_sz\t0x%x\n", tp->rx_buf_sz);
seq_printf(m, "esd_flag\t0x%x\n", tp->esd_flag);
seq_printf(m, "pci_cfg_is_read\t0x%x\n", tp->pci_cfg_is_read);
seq_printf(m, "rtl8168_rx_config\t0x%x\n", tp->rtl8168_rx_config);
seq_printf(m, "cp_cmd\t0x%x\n", tp->cp_cmd);
seq_printf(m, "intr_mask\t0x%x\n", tp->intr_mask);
seq_printf(m, "timer_intr_mask\t0x%x\n", tp->timer_intr_mask);
seq_printf(m, "wol_enabled\t0x%x\n", tp->wol_enabled);
seq_printf(m, "wol_opts\t0x%x\n", tp->wol_opts);
seq_printf(m, "efuse_ver\t0x%x\n", tp->efuse_ver);
seq_printf(m, "eeprom_type\t0x%x\n", tp->eeprom_type);
seq_printf(m, "autoneg\t0x%x\n", tp->autoneg);
seq_printf(m, "duplex\t0x%x\n", tp->duplex);
seq_printf(m, "speed\t%d\n", tp->speed);
seq_printf(m, "eeprom_len\t0x%x\n", tp->eeprom_len);
seq_printf(m, "cur_page\t0x%x\n", tp->cur_page);
seq_printf(m, "bios_setting\t0x%x\n", tp->bios_setting);
seq_printf(m, "features\t0x%x\n", tp->features);
seq_printf(m, "org_pci_offset_99\t0x%x\n", tp->org_pci_offset_99);
seq_printf(m, "org_pci_offset_180\t0x%x\n", tp->org_pci_offset_180);
seq_printf(m, "issue_offset_99_event\t0x%x\n", tp->issue_offset_99_event);
seq_printf(m, "org_pci_offset_80\t0x%x\n", tp->org_pci_offset_80);
seq_printf(m, "org_pci_offset_81\t0x%x\n", tp->org_pci_offset_81);
seq_printf(m, "use_timer_interrrupt\t0x%x\n", tp->use_timer_interrrupt);
seq_printf(m, "HwIcVerUnknown\t0x%x\n", tp->HwIcVerUnknown);
seq_printf(m, "NotWrRamCodeToMicroP\t0x%x\n", tp->NotWrRamCodeToMicroP);
seq_printf(m, "NotWrMcuPatchCode\t0x%x\n", tp->NotWrMcuPatchCode);
seq_printf(m, "HwHasWrRamCodeToMicroP\t0x%x\n", tp->HwHasWrRamCodeToMicroP);
seq_printf(m, "sw_ram_code_ver\t0x%x\n", tp->sw_ram_code_ver);
seq_printf(m, "hw_ram_code_ver\t0x%x\n", tp->hw_ram_code_ver);
seq_printf(m, "rtk_enable_diag\t0x%x\n", tp->rtk_enable_diag);
seq_printf(m, "ShortPacketSwChecksum\t0x%x\n", tp->ShortPacketSwChecksum);
seq_printf(m, "UseSwPaddingShortPkt\t0x%x\n", tp->UseSwPaddingShortPkt);
seq_printf(m, "RequireAdcBiasPatch\t0x%x\n", tp->RequireAdcBiasPatch);
seq_printf(m, "AdcBiasPatchIoffset\t0x%x\n", tp->AdcBiasPatchIoffset);
seq_printf(m, "RequireAdjustUpsTxLinkPulseTiming\t0x%x\n", tp->RequireAdjustUpsTxLinkPulseTiming);
seq_printf(m, "SwrCnt1msIni\t0x%x\n", tp->SwrCnt1msIni);
seq_printf(m, "HwSuppNowIsOobVer\t0x%x\n", tp->HwSuppNowIsOobVer);
seq_printf(m, "HwFiberModeVer\t0x%x\n", tp->HwFiberModeVer);
seq_printf(m, "RequiredSecLanDonglePatch\t0x%x\n", tp->RequiredSecLanDonglePatch);
seq_printf(m, "HwSuppDashVer\t0x%x\n", tp->HwSuppDashVer);
seq_printf(m, "DASH\t0x%x\n", tp->DASH);
seq_printf(m, "dash_printer_enabled\t0x%x\n", tp->dash_printer_enabled);
seq_printf(m, "HwSuppKCPOffloadVer\t0x%x\n", tp->HwSuppKCPOffloadVer);
seq_printf(m, "speed_mode\t0x%x\n", speed_mode);
seq_printf(m, "duplex_mode\t0x%x\n", duplex_mode);
seq_printf(m, "autoneg_mode\t0x%x\n", autoneg_mode);
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", eee_enable);
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, "HwSuppCheckPhyDisableModeVer\t0x%x\n", tp->HwSuppCheckPhyDisableModeVer);
seq_printf(m, "HwPkgDet\t0x%x\n", tp->HwPkgDet);
seq_printf(m, "random_mac\t0x%x\n", tp->random_mac);
seq_printf(m, "org_mac_addr\t%pM\n", tp->org_mac_addr);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
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);
seq_putc(m, '\n');
return 0;
}
static int proc_get_tally_counter(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
struct rtl8168_counters *counters;
dma_addr_t paddr;
u32 cmd;
u32 WaitCnt;
unsigned long flags;
seq_puts(m, "\nDump Tally Counter\n");
//ASSERT_RTNL();
counters = tp->tally_vaddr;
paddr = tp->tally_paddr;
if (!counters) {
seq_puts(m, "\nDump Tally Counter Fail\n");
return 0;
}
spin_lock_irqsave(&tp->lock, flags);
RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
cmd = (u64)paddr & DMA_BIT_MASK(32);
RTL_W32(CounterAddrLow, cmd);
RTL_W32(CounterAddrLow, cmd | CounterDump);
WaitCnt = 0;
while (RTL_R32(CounterAddrLow) & CounterDump) {
udelay(10);
WaitCnt++;
if (WaitCnt > 20)
break;
}
spin_unlock_irqrestore(&tp->lock, flags);
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_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_putc(m, '\n');
return 0;
}
static int proc_get_registers(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
int i, n, max = R8168_MAC_REGS_SIZE;
u8 byte_rd;
struct rtl8168_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);
for (n = 0; n < max;) {
seq_printf(m, "\n0x%02x:\t", n);
for (i = 0; i < 16 && n < max; i++, n++) {
byte_rd = readb(ioaddr + n);
seq_printf(m, "%02x ", byte_rd);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
seq_putc(m, '\n');
return 0;
}
static int proc_get_pcie_phy(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
int i, n, max = R8168_EPHY_REGS_SIZE/2;
u16 word_rd;
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
unsigned long flags;
seq_puts(m, "\nDump PCIE PHY\n");
seq_puts(m, "\nOffset\tValue\n------\t-----\n ");
spin_lock_irqsave(&tp->lock, flags);
for (n = 0; n < max;) {
seq_printf(m, "\n0x%02x:\t", n);
for (i = 0; i < 8 && n < max; i++, n++) {
word_rd = rtl8168_ephy_read(ioaddr, n);
seq_printf(m, "%04x ", word_rd);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
seq_putc(m, '\n');
return 0;
}
static int proc_get_eth_phy(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
int i, n, max = R8168_PHY_REGS_SIZE/2;
u16 word_rd;
struct rtl8168_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);
seq_puts(m, "\n####################page 0##################\n ");
mdio_write(tp, 0x1f, 0x0000);
for (n = 0; n < max;) {
seq_printf(m, "\n0x%02x:\t", n);
for (i = 0; i < 8 && n < max; i++, n++) {
word_rd = mdio_read(tp, n);
seq_printf(m, "%04x ", word_rd);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
seq_putc(m, '\n');
return 0;
}
static int proc_get_extended_registers(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
int i, n, max = R8168_ERI_REGS_SIZE;
u32 dword_rd;
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
unsigned long flags;
switch (tp->mcfg) {
case CFG_METHOD_1:
case CFG_METHOD_2:
case CFG_METHOD_3:
/* RTL8168B does not support Extend GMAC */
seq_puts(m, "\nNot Support Dump Extended Registers\n");
return 0;
}
seq_puts(m, "\nDump Extended Registers\n");
seq_puts(m, "\nOffset\tValue\n------\t-----\n ");
spin_lock_irqsave(&tp->lock, flags);
for (n = 0; n < max;) {
seq_printf(m, "\n0x%02x:\t", n);
for (i = 0; i < 4 && n < max; i++, n+=4) {
dword_rd = rtl8168_eri_read(ioaddr, n, 4, ERIAR_ExGMAC);
seq_printf(m, "%08x ", dword_rd);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
seq_putc(m, '\n');
return 0;
}
static int proc_get_pci_registers(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
int i, n, max = R8168_PCI_REGS_SIZE;
u32 dword_rd;
struct rtl8168_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);
for (n = 0; n < max;) {
seq_printf(m, "\n0x%03x:\t", n);
for (i = 0; i < 4 && n < max; i++, n+=4) {
pci_read_config_dword(tp->pci_dev, n, &dword_rd);
seq_printf(m, "%08x ", dword_rd);
}
}
n = 0x110;
pci_read_config_dword(tp->pci_dev, n, &dword_rd);
seq_printf(m, "\n0x%03x:\t%08x ", n, dword_rd);
n = 0x70c;
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);
seq_putc(m, '\n');
return 0;
}
#else
static int proc_get_driver_variable(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
struct rtl8168_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);
len += snprintf(page + len, count - len,
"Variable\tValue\n----------\t-----\n");
len += snprintf(page + len, count - len,
"MODULENAME\t%s\n"
"driver version\t%s\n"
"chipset\t%d\n"
"chipset_name\t%s\n"
"mtu\t%d\n"
"NUM_RX_DESC\t0x%x\n"
"cur_rx\t0x%x\n"
"dirty_rx\t0x%x\n"
"NUM_TX_DESC\t0x%x\n"
"cur_tx\t0x%x\n"
"dirty_tx\t0x%x\n"
"rx_buf_sz\t0x%x\n"
"esd_flag\t0x%x\n"
"pci_cfg_is_read\t0x%x\n"
"rtl8168_rx_config\t0x%x\n"
"cp_cmd\t0x%x\n"
"intr_mask\t0x%x\n"
"timer_intr_mask\t0x%x\n"
"wol_enabled\t0x%x\n"
"wol_opts\t0x%x\n"
"efuse_ver\t0x%x\n"
"eeprom_type\t0x%x\n"
"autoneg\t0x%x\n"
"duplex\t0x%x\n"
"speed\t%d\n"
"eeprom_len\t0x%x\n"
"cur_page\t0x%x\n"
"bios_setting\t0x%x\n"
"features\t0x%x\n"
"org_pci_offset_99\t0x%x\n"
"org_pci_offset_180\t0x%x\n"
"issue_offset_99_event\t0x%x\n"
"org_pci_offset_80\t0x%x\n"
"org_pci_offset_81\t0x%x\n"
"use_timer_interrrupt\t0x%x\n"
"HwIcVerUnknown\t0x%x\n"
"NotWrRamCodeToMicroP\t0x%x\n"
"NotWrMcuPatchCode\t0x%x\n"
"HwHasWrRamCodeToMicroP\t0x%x\n"
"sw_ram_code_ver\t0x%x\n"
"hw_ram_code_ver\t0x%x\n"
"rtk_enable_diag\t0x%x\n"
"ShortPacketSwChecksum\t0x%x\n"
"UseSwPaddingShortPkt\t0x%x\n"
"RequireAdcBiasPatch\t0x%x\n"
"AdcBiasPatchIoffset\t0x%x\n"
"RequireAdjustUpsTxLinkPulseTiming\t0x%x\n"
"SwrCnt1msIni\t0x%x\n"
"HwSuppNowIsOobVer\t0x%x\n"
"HwFiberModeVer\t0x%x\n"
"RequiredSecLanDonglePatch\t0x%x\n"
"HwSuppDashVer\t0x%x\n"
"DASH\t0x%x\n"
"dash_printer_enabled\t0x%x\n"
"HwSuppKCPOffloadVer\t0x%x\n"
"speed_mode\t0x%x\n"
"duplex_mode\t0x%x\n"
"autoneg_mode\t0x%x\n"
"aspm\t0x%x\n"
"s5wol\t0x%x\n"
"s5_keep_curr_mac\t0x%x\n"
"eee_enable\t0x%x\n"
"hwoptimize\t0x%lx\n"
"proc_init_num\t0x%x\n"
"s0_magic_packet\t0x%x\n"
"HwSuppMagicPktVer\t0x%x\n"
"HwSuppCheckPhyDisableModeVer\t0x%x\n"
"HwPkgDet\t0x%x\n"
"random_mac\t0x%x\n"
"org_mac_addr\t%pM\n"
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
"perm_addr\t%pM\n"
#endif
"dev_addr\t%pM\n",
MODULENAME,
RTL8168_VERSION,
tp->chipset,
rtl_chip_info[tp->chipset].name,
dev->mtu,
NUM_RX_DESC,
tp->cur_rx,
tp->dirty_rx,
NUM_TX_DESC,
tp->cur_tx,
tp->dirty_tx,
tp->rx_buf_sz,
tp->esd_flag,
tp->pci_cfg_is_read,
tp->rtl8168_rx_config,
tp->cp_cmd,
tp->intr_mask,
tp->timer_intr_mask,
tp->wol_enabled,
tp->wol_opts,
tp->efuse_ver,
tp->eeprom_type,
tp->autoneg,
tp->duplex,
tp->speed,
tp->eeprom_len,
tp->cur_page,
tp->bios_setting,
tp->features,
tp->org_pci_offset_99,
tp->org_pci_offset_180,
tp->issue_offset_99_event,
tp->org_pci_offset_80,
tp->org_pci_offset_81,
tp->use_timer_interrrupt,
tp->HwIcVerUnknown,
tp->NotWrRamCodeToMicroP,
tp->NotWrMcuPatchCode,
tp->HwHasWrRamCodeToMicroP,
tp->sw_ram_code_ver,
tp->hw_ram_code_ver,
tp->rtk_enable_diag,
tp->ShortPacketSwChecksum,
tp->UseSwPaddingShortPkt,
tp->RequireAdcBiasPatch,
tp->AdcBiasPatchIoffset,
tp->RequireAdjustUpsTxLinkPulseTiming,
tp->SwrCnt1msIni,
tp->HwSuppNowIsOobVer,
tp->HwFiberModeVer,
tp->RequiredSecLanDonglePatch,
tp->HwSuppDashVer,
tp->DASH,
tp->dash_printer_enabled,
tp->HwSuppKCPOffloadVer,
speed_mode,
duplex_mode,
autoneg_mode,
aspm,
s5wol,
s5_keep_curr_mac,
eee_enable,
hwoptimize,
proc_init_num,
s0_magic_packet,
tp->HwSuppMagicPktVer,
tp->HwSuppCheckPhyDisableModeVer,
tp->HwPkgDet,
tp->random_mac,
tp->org_mac_addr,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
dev->perm_addr,
#endif
dev->dev_addr
);
spin_unlock_irqrestore(&tp->lock, flags);
len += snprintf(page + len, count - len, "\n");
*eof = 1;
return len;
}
static int proc_get_tally_counter(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
struct rtl8168_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();
counters = tp->tally_vaddr;
paddr = tp->tally_paddr;
if (!counters) {
len += snprintf(page + len, count - len,
"\nDump Tally Counter Fail\n");
goto out;
}
spin_lock_irqsave(&tp->lock, flags);
RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
cmd = (u64)paddr & DMA_BIT_MASK(32);
RTL_W32(CounterAddrLow, cmd);
RTL_W32(CounterAddrLow, cmd | CounterDump);
WaitCnt = 0;
while (RTL_R32(CounterAddrLow) & CounterDump) {
udelay(10);
WaitCnt++;
if (WaitCnt > 20)
break;
}
spin_unlock_irqrestore(&tp->lock, flags);
len += snprintf(page + len, count - len,
"Statistics\tValue\n----------\t-----\n");
len += snprintf(page + len, count - len,
"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_unicast\t%lld\n"
"rx_broadcast\t%lld\n"
"rx_multicast\t%lld\n"
"tx_aborted\t%lld\n"
"tx_underun\t%lld\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),
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)
);
len += snprintf(page + len, count - len, "\n");
out:
*eof = 1;
return len;
}
static int proc_get_registers(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
int i, n, max = R8168_MAC_REGS_SIZE;
u8 byte_rd;
struct rtl8168_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);
for (n = 0; n < max;) {
len += snprintf(page + len, count - len,
"\n0x%02x:\t",
n);
for (i = 0; i < 16 && n < max; i++, n++) {
byte_rd = readb(ioaddr + n);
len += snprintf(page + len, count - len,
"%02x ",
byte_rd);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
len += snprintf(page + len, count - len, "\n");
*eof = 1;
return len;
}
static int proc_get_pcie_phy(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
int i, n, max = R8168_EPHY_REGS_SIZE/2;
u16 word_rd;
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
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);
for (n = 0; n < max;) {
len += snprintf(page + len, count - len,
"\n0x%02x:\t",
n);
for (i = 0; i < 8 && n < max; i++, n++) {
word_rd = rtl8168_ephy_read(ioaddr, n);
len += snprintf(page + len, count - len,
"%04x ",
word_rd);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
len += snprintf(page + len, count - len, "\n");
*eof = 1;
return len;
}
static int proc_get_eth_phy(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
int i, n, max = R8168_PHY_REGS_SIZE/2;
u16 word_rd;
struct rtl8168_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);
len += snprintf(page + len, count - len,
"\n####################page 0##################\n");
mdio_write(tp, 0x1f, 0x0000);
for (n = 0; n < max;) {
len += snprintf(page + len, count - len,
"\n0x%02x:\t",
n);
for (i = 0; i < 8 && n < max; i++, n++) {
word_rd = mdio_read(tp, n);
len += snprintf(page + len, count - len,
"%04x ",
word_rd);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
len += snprintf(page + len, count - len, "\n");
*eof = 1;
return len;
}
static int proc_get_extended_registers(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
int i, n, max = R8168_ERI_REGS_SIZE;
u32 dword_rd;
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
unsigned long flags;
int len = 0;
switch (tp->mcfg) {
case CFG_METHOD_1:
case CFG_METHOD_2:
case CFG_METHOD_3:
/* RTL8168B does not support Extend GMAC */
len += snprintf(page + len, count - len,
"\nNot Support Dump Extended Registers\n");
goto out;
}
len += snprintf(page + len, count - len,
"\nDump Extended Registers\n"
"Offset\tValue\n------\t-----\n");
spin_lock_irqsave(&tp->lock, flags);
for (n = 0; n < max;) {
len += snprintf(page + len, count - len,
"\n0x%02x:\t",
n);
for (i = 0; i < 4 && n < max; i++, n+=4) {
dword_rd = rtl8168_eri_read(ioaddr, n, 4, ERIAR_ExGMAC);
len += snprintf(page + len, count - len,
"%08x ",
dword_rd);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
len += snprintf(page + len, count - len, "\n");
out:
*eof = 1;
return len;
}
static int proc_get_pci_registers(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
int i, n, max = R8168_PCI_REGS_SIZE;
u32 dword_rd;
struct rtl8168_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);
for (n = 0; n < max;) {
len += snprintf(page + len, count - len,
"\n0x%03x:\t",
n);
for (i = 0; i < 4 && n < max; i++, n+=4) {
pci_read_config_dword(tp->pci_dev, n, &dword_rd);
len += snprintf(page + len, count - len,
"%08x ",
dword_rd);
}
}
n = 0x110;
pci_read_config_dword(tp->pci_dev, n, &dword_rd);
len += snprintf(page + len, count - len,
"\n0x%03x:\t%08x ",
n,
dword_rd);
n = 0x70c;
pci_read_config_dword(tp->pci_dev, n, &dword_rd);
len += snprintf(page + len, count - len,
"\n0x%03x:\t%08x ",
n,
dword_rd);
spin_unlock_irqrestore(&tp->lock, flags);
len += snprintf(page + len, count - len, "\n");
*eof = 1;
return len;
}
#endif
static void rtl8168_proc_module_init(void)
{
//create /proc/net/r8168
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
rtl8168_proc = proc_mkdir(MODULENAME, init_net.proc_net);
#else
rtl8168_proc = proc_mkdir(MODULENAME, proc_net);
#endif
if (!rtl8168_proc)
dprintk("cannot create %s proc entry \n", MODULENAME);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
/*
* seq_file wrappers for procfile show routines.
*/
static int rtl8168_proc_open(struct inode *inode, struct file *file)
{
struct net_device *dev = proc_get_parent_data(inode);
int (*show)(struct seq_file *, void *) = PDE_DATA(inode);
return single_open(file, show, dev);
}
static const struct file_operations rtl8168_proc_fops = {
.open = rtl8168_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
/*
* Table of proc files we need to create.
*/
struct rtl8168_proc_file {
char name[12];
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
int (*show)(struct seq_file *, void *);
#else
int (*show)(char *, char **, off_t, int, int *, void *);
#endif
};
static const struct rtl8168_proc_file rtl8168_proc_files[] = {
{ "driver_var", &proc_get_driver_variable },
{ "tally", &proc_get_tally_counter },
{ "registers", &proc_get_registers },
{ "pcie_phy", &proc_get_pcie_phy },
{ "eth_phy", &proc_get_eth_phy },
{ "ext_regs", &proc_get_extended_registers },
{ "pci_regs", &proc_get_pci_registers },
{ "" }
};
static void rtl8168_proc_init(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
const struct rtl8168_proc_file *f;
struct proc_dir_entry *dir;
if (rtl8168_proc && !tp->proc_dir) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
dir = proc_mkdir_data(dev->name, 0, rtl8168_proc, dev);
if (!dir) {
printk("Unable to initialize /proc/net/%s/%s\n",
MODULENAME, dev->name);
return;
}
tp->proc_dir = dir;
proc_init_num++;
for (f = rtl8168_proc_files; f->name[0]; f++) {
if (!proc_create_data(f->name, S_IFREG | S_IRUGO, dir,
&rtl8168_proc_fops, f->show)) {
printk("Unable to initialize "
"/proc/net/%s/%s/%s\n",
MODULENAME, dev->name, f->name);
return;
}
}
#else
dir = proc_mkdir(dev->name, rtl8168_proc);
if (!dir) {
printk("Unable to initialize /proc/net/%s/%s\n",
MODULENAME, dev->name);
return;
}
tp->proc_dir = dir;
proc_init_num++;
for (f = rtl8168_proc_files; f->name[0]; f++) {
if (!create_proc_read_entry(f->name, S_IFREG | S_IRUGO,
dir, f->show, dev)) {
printk("Unable to initialize "
"/proc/net/%s/%s/%s\n",
MODULENAME, dev->name, f->name);
return;
}
}
#endif
}
}
static void rtl8168_proc_remove(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
if (tp->proc_dir) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
remove_proc_subtree(dev->name, rtl8168_proc);
proc_init_num--;
#else
const struct rtl8168_proc_file *f;
struct rtl8168_private *tp = netdev_priv(dev);
for (f = rtl8168_proc_files; f->name[0]; f++)
remove_proc_entry(f->name, tp->proc_dir);
remove_proc_entry(dev->name, rtl8168_proc);
proc_init_num--;
#endif
tp->proc_dir = NULL;
}
}
#endif //ENABLE_R8168_PROCFS
static inline u16 map_phy_ocp_addr(u16 PageNum, u8 RegNum)
{
u16 OcpPageNum = 0;
u8 OcpRegNum = 0;
u16 OcpPhyAddress = 0;
if ( PageNum == 0 ) {
OcpPageNum = OCP_STD_PHY_BASE_PAGE + ( RegNum / 8 );
OcpRegNum = 0x10 + ( RegNum % 8 );
} else {
OcpPageNum = PageNum;
OcpRegNum = RegNum;
}
OcpPageNum <<= 4;
if ( OcpRegNum < 16 ) {
OcpPhyAddress = 0;
} else {
OcpRegNum -= 16;
OcpRegNum <<= 1;
OcpPhyAddress = OcpPageNum + OcpRegNum;
}
return OcpPhyAddress;
}
static void mdio_write_phy_ocp(struct rtl8168_private *tp,
u16 PageNum,
u32 RegAddr,
u32 value)
{
void __iomem *ioaddr = tp->mmio_addr;
u32 data32;
u16 ocp_addr;
int i;
ocp_addr = map_phy_ocp_addr(PageNum, RegAddr);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
WARN_ON_ONCE(ocp_addr % 2);
#endif
data32 = ocp_addr/2;
data32 <<= OCPR_Addr_Reg_shift;
data32 |= OCPR_Write | value;
RTL_W32(PHYOCP, data32);
for (i = 0; i < 100; i++) {
udelay(1);
if (!(RTL_R32(PHYOCP) & OCPR_Flag))
break;
}
}
static void mdio_real_write(struct rtl8168_private *tp,
u32 RegAddr,
u32 value)
{
void __iomem *ioaddr = tp->mmio_addr;
int i;
if (RegAddr == 0x1F) {
tp->cur_page = value;
}
if (tp->mcfg == CFG_METHOD_11) {
RTL_W32(OCPDR, OCPDR_Write |
(RegAddr & OCPDR_Reg_Mask) << OCPDR_GPHY_Reg_shift |
(value & OCPDR_Data_Mask));
RTL_W32(OCPAR, OCPAR_GPHY_Write);
RTL_W32(EPHY_RXER_NUM, 0);
for (i = 0; i < 100; i++) {
mdelay(1);
if (!(RTL_R32(OCPAR) & OCPAR_Flag))
break;
}
} else if (tp->mcfg == CFG_METHOD_21 || tp->mcfg == CFG_METHOD_22 ||
tp->mcfg == CFG_METHOD_23 || tp->mcfg == CFG_METHOD_24 ||
tp->mcfg == CFG_METHOD_25 || tp->mcfg == CFG_METHOD_26 ||
tp->mcfg == CFG_METHOD_27 || tp->mcfg == CFG_METHOD_28 ||
tp->mcfg == CFG_METHOD_29 || tp->mcfg == CFG_METHOD_30 ||
tp->mcfg == CFG_METHOD_31 || tp->mcfg == CFG_METHOD_32) {
if (RegAddr == 0x1F) {
return;
}
mdio_write_phy_ocp(tp, tp->cur_page, RegAddr, value);
} else {
if (tp->mcfg == CFG_METHOD_12 || tp->mcfg == CFG_METHOD_13)
RTL_W32(0xD0, RTL_R32(0xD0) & ~0x00020000);
RTL_W32(PHYAR, PHYAR_Write |
(RegAddr & PHYAR_Reg_Mask) << PHYAR_Reg_shift |
(value & PHYAR_Data_Mask));
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed writing to the specified MII register */
if (!(RTL_R32(PHYAR) & PHYAR_Flag)) {
udelay(20);
break;
}
}
if (tp->mcfg == CFG_METHOD_12 || tp->mcfg == CFG_METHOD_13)
RTL_W32(0xD0, RTL_R32(0xD0) | 0x00020000);
}
}
void mdio_write(struct rtl8168_private *tp,
u32 RegAddr,
u32 value)
{
if (tp->rtk_enable_diag) return;
mdio_real_write(tp, RegAddr, value);
}
void mdio_prot_write(struct rtl8168_private *tp,
u32 RegAddr,
u32 value)
{
mdio_real_write(tp, RegAddr, value);
}
static u32 mdio_read_phy_ocp(struct rtl8168_private *tp,
u16 PageNum,
u32 RegAddr)
{
void __iomem *ioaddr = tp->mmio_addr;
u32 data32;
u16 ocp_addr;
int i, value = 0;
ocp_addr = map_phy_ocp_addr(PageNum, RegAddr);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
WARN_ON_ONCE(ocp_addr % 2);
#endif
data32 = ocp_addr/2;
data32 <<= OCPR_Addr_Reg_shift;
RTL_W32(PHYOCP, data32);
for (i = 0; i < 100; i++) {
udelay(1);
if (RTL_R32(PHYOCP) & OCPR_Flag)
break;
}
value = RTL_R32(PHYOCP) & OCPDR_Data_Mask;
return value;
}
u32 mdio_read(struct rtl8168_private *tp,
u32 RegAddr)
{
void __iomem *ioaddr = tp->mmio_addr;
int i, value = 0;
if (tp->mcfg==CFG_METHOD_11) {
RTL_W32(OCPDR, OCPDR_Read |
(RegAddr & OCPDR_Reg_Mask) << OCPDR_GPHY_Reg_shift);
RTL_W32(OCPAR, OCPAR_GPHY_Write);
RTL_W32(EPHY_RXER_NUM, 0);
for (i = 0; i < 100; i++) {
mdelay(1);
if (!(RTL_R32(OCPAR) & OCPAR_Flag))
break;
}
mdelay(1);
RTL_W32(OCPAR, OCPAR_GPHY_Read);
RTL_W32(EPHY_RXER_NUM, 0);
for (i = 0; i < 100; i++) {
mdelay(1);
if (RTL_R32(OCPAR) & OCPAR_Flag)
break;
}
value = RTL_R32(OCPDR) & OCPDR_Data_Mask;
} else if (tp->mcfg == CFG_METHOD_21 || tp->mcfg == CFG_METHOD_22 ||
tp->mcfg == CFG_METHOD_23 || tp->mcfg == CFG_METHOD_24 ||
tp->mcfg == CFG_METHOD_25 || tp->mcfg == CFG_METHOD_26 ||
tp->mcfg == CFG_METHOD_27 || tp->mcfg == CFG_METHOD_28 ||
tp->mcfg == CFG_METHOD_29 || tp->mcfg == CFG_METHOD_30 ||
tp->mcfg == CFG_METHOD_31 || tp->mcfg == CFG_METHOD_32) {
value = mdio_read_phy_ocp(tp, tp->cur_page, RegAddr);
} else {
if (tp->mcfg == CFG_METHOD_12 || tp->mcfg == CFG_METHOD_13)
RTL_W32(0xD0, RTL_R32(0xD0) & ~0x00020000);
RTL_W32(PHYAR,
PHYAR_Read | (RegAddr & PHYAR_Reg_Mask) << PHYAR_Reg_shift);
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed retrieving data from the specified MII register */
if (RTL_R32(PHYAR) & PHYAR_Flag) {
value = RTL_R32(PHYAR) & PHYAR_Data_Mask;
udelay(20);
break;
}
}
if (tp->mcfg == CFG_METHOD_12 || tp->mcfg == CFG_METHOD_13)
RTL_W32(0xD0, RTL_R32(0xD0) | 0x00020000);
}
return value;
}
static void ClearAndSetEthPhyBit(struct rtl8168_private *tp, u8 addr, u16 clearmask, u16 setmask)
{
u16 PhyRegValue;
PhyRegValue = mdio_read( tp, addr );
PhyRegValue &= ~clearmask;
PhyRegValue |= setmask;
mdio_write( tp, addr, PhyRegValue);
}
void ClearEthPhyBit(struct rtl8168_private *tp, u8 addr, u16 mask)
{
ClearAndSetEthPhyBit( tp,
addr,
mask,
0
);
}
void SetEthPhyBit(struct rtl8168_private *tp, u8 addr, u16 mask)
{
ClearAndSetEthPhyBit( tp,
addr,
0,
mask
);
}
void mac_ocp_write(struct rtl8168_private *tp, u16 reg_addr, u16 value)
{
void __iomem *ioaddr = tp->mmio_addr;
u32 data32;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
WARN_ON_ONCE(reg_addr % 2);
#endif
data32 = reg_addr/2;
data32 <<= OCPR_Addr_Reg_shift;
data32 += value;
data32 |= OCPR_Write;
RTL_W32(MACOCP, data32);
}
u16 mac_ocp_read(struct rtl8168_private *tp, u16 reg_addr)
{
void __iomem *ioaddr = tp->mmio_addr;
u32 data32;
u16 data16 = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
WARN_ON_ONCE(reg_addr % 2);
#endif
data32 = reg_addr/2;
data32 <<= OCPR_Addr_Reg_shift;
RTL_W32(MACOCP, data32);
data16 = (u16)RTL_R32(MACOCP);
return data16;
}
static u32 real_ocp_read(struct rtl8168_private *tp, u16 addr, u8 len)
{
void __iomem *ioaddr = tp->mmio_addr;
int i, val_shift, shift = 0;
u32 value1 = 0, value2 = 0, mask;
if (len > 4 || len <= 0)
return -1;
while (len > 0) {
val_shift = addr % 4;
addr = addr & ~0x3;
RTL_W32(OCPAR, (0x0F<<12) | (addr&0xFFF));
for (i = 0; i < 20; i++) {
udelay(100);
if (RTL_R32(OCPAR) & OCPAR_Flag)
break;
}
if (len == 1) mask = (0xFF << (val_shift * 8)) & 0xFFFFFFFF;
else if (len == 2) mask = (0xFFFF << (val_shift * 8)) & 0xFFFFFFFF;
else if (len == 3) mask = (0xFFFFFF << (val_shift * 8)) & 0xFFFFFFFF;
else mask = (0xFFFFFFFF << (val_shift * 8)) & 0xFFFFFFFF;
value1 = RTL_R32(OCPDR) & mask;
value2 |= (value1 >> val_shift * 8) << shift * 8;
if (len <= 4 - val_shift) {
len = 0;
} else {
len -= (4 - val_shift);
shift = 4 - val_shift;
addr += 4;
}
}
udelay(20);
return value2;
}
u32 OCP_read_with_oob_base_address(struct rtl8168_private *tp, u16 addr, u8 len, const u32 base_address)
{
void __iomem *ioaddr = tp->mmio_addr;
return rtl8168_eri_read_with_oob_base_address(ioaddr, addr, len, ERIAR_OOB, base_address);
}
u32 OCP_read(struct rtl8168_private *tp, u16 addr, u8 len)
{
u32 value = 0;
if (HW_DASH_SUPPORT_TYPE_2(tp))
value = OCP_read_with_oob_base_address(tp, addr, len, NO_BASE_ADDRESS);
else if (HW_DASH_SUPPORT_TYPE_3(tp))
value = OCP_read_with_oob_base_address(tp, addr, len, RTL8168FP_OOBMAC_BASE);
else
value = real_ocp_read(tp, addr, len);
return value;
}
static int real_ocp_write(struct rtl8168_private *tp, u16 addr, u8 len, u32 value)
{
void __iomem *ioaddr = tp->mmio_addr;
int i, val_shift, shift = 0;
u32 value1 = 0, mask;
if (len > 4 || len <= 0)
return -1;
while (len > 0) {
val_shift = addr % 4;
addr = addr & ~0x3;
if (len == 1) mask = (0xFF << (val_shift * 8)) & 0xFFFFFFFF;
else if (len == 2) mask = (0xFFFF << (val_shift * 8)) & 0xFFFFFFFF;
else if (len == 3) mask = (0xFFFFFF << (val_shift * 8)) & 0xFFFFFFFF;
else mask = (0xFFFFFFFF << (val_shift * 8)) & 0xFFFFFFFF;
value1 = OCP_read(tp, addr, 4) & ~mask;
value1 |= ((value << val_shift * 8) >> shift * 8);
RTL_W32(OCPDR, value1);
RTL_W32(OCPAR, OCPAR_Flag | (0x0F<<12) | (addr&0xFFF));
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed ERI write */
if (!(RTL_R32(OCPAR) & OCPAR_Flag))
break;
}
if (len <= 4 - val_shift) {
len = 0;
} else {
len -= (4 - val_shift);
shift = 4 - val_shift;
addr += 4;
}
}
udelay(20);
return 0;
}
u32 OCP_write_with_oob_base_address(struct rtl8168_private *tp, u16 addr, u8 len, u32 value, const u32 base_address)
{
void __iomem *ioaddr = tp->mmio_addr;
return rtl8168_eri_write_with_oob_base_address(ioaddr, addr, len, value, ERIAR_OOB, base_address);
}
void OCP_write(struct rtl8168_private *tp, u16 addr, u8 len, u32 value)
{
if (HW_DASH_SUPPORT_TYPE_2(tp))
OCP_write_with_oob_base_address(tp, addr, len, value, NO_BASE_ADDRESS);
else if (HW_DASH_SUPPORT_TYPE_3(tp))
OCP_write_with_oob_base_address(tp, addr, len, value, RTL8168FP_OOBMAC_BASE);
else
real_ocp_write(tp, addr, len, value);
}
void OOB_mutex_lock(struct rtl8168_private *tp)
{
u8 reg_16, reg_a0;
u32 wait_cnt_0, wait_Cnt_1;
u16 ocp_reg_mutex_ib;
u16 ocp_reg_mutex_oob;
u16 ocp_reg_mutex_prio;
if (!tp->DASH) return;
switch (tp->mcfg) {
case CFG_METHOD_11:
case CFG_METHOD_12:
ocp_reg_mutex_oob = 0x16;
ocp_reg_mutex_ib = 0x17;
ocp_reg_mutex_prio = 0x9C;
break;
case CFG_METHOD_13:
ocp_reg_mutex_oob = 0x06;
ocp_reg_mutex_ib = 0x07;
ocp_reg_mutex_prio = 0x9C;
break;
case CFG_METHOD_23:
case CFG_METHOD_27:
case CFG_METHOD_28:
case CFG_METHOD_31:
case CFG_METHOD_32:
default:
ocp_reg_mutex_oob = 0x110;
ocp_reg_mutex_ib = 0x114;
ocp_reg_mutex_prio = 0x11C;
break;
}
OCP_write(tp, ocp_reg_mutex_ib, 1, BIT_0);
reg_16 = OCP_read(tp, ocp_reg_mutex_oob, 1);
wait_cnt_0 = 0;
while(reg_16) {
reg_a0 = OCP_read(tp, ocp_reg_mutex_prio, 1);
if (reg_a0) {
OCP_write(tp, ocp_reg_mutex_ib, 1, 0x00);
reg_a0 = OCP_read(tp, ocp_reg_mutex_prio, 1);
wait_Cnt_1 = 0;
while(reg_a0) {
reg_a0 = OCP_read(tp, ocp_reg_mutex_prio, 1);
wait_Cnt_1++;
if (wait_Cnt_1 > 2000)
break;
};
OCP_write(tp, ocp_reg_mutex_ib, 1, BIT_0);
}
reg_16 = OCP_read(tp, ocp_reg_mutex_oob, 1);
wait_cnt_0++;
if (wait_cnt_0 > 2000)
break;
};
}
void OOB_mutex_unlock(struct rtl8168_private *tp)
{
u16 ocp_reg_mutex_ib;
u16 ocp_reg_mutex_oob;
u16 ocp_reg_mutex_prio;
if (!tp->DASH) return;
switch (tp->mcfg) {
case CFG_METHOD_11:
case CFG_METHOD_12:
ocp_reg_mutex_oob = 0x16;
ocp_reg_mutex_ib = 0x17;
ocp_reg_mutex_prio = 0x9C;
break;
case CFG_METHOD_13:
ocp_reg_mutex_oob = 0x06;
ocp_reg_mutex_ib = 0x07;
ocp_reg_mutex_prio = 0x9C;
break;
case CFG_METHOD_23:
case CFG_METHOD_27:
case CFG_METHOD_28:
case CFG_METHOD_31:
case CFG_METHOD_32:
default:
ocp_reg_mutex_oob = 0x110;
ocp_reg_mutex_ib = 0x114;
ocp_reg_mutex_prio = 0x11C;
break;
}
OCP_write(tp, ocp_reg_mutex_prio, 1, BIT_0);
OCP_write(tp, ocp_reg_mutex_ib, 1, 0x00);
}
void OOB_notify(struct rtl8168_private *tp, u8 cmd)
{
void __iomem *ioaddr = tp->mmio_addr;
rtl8168_eri_write(ioaddr, 0xE8, 1, cmd, ERIAR_ExGMAC);
OCP_write(tp, 0x30, 1, 0x01);
}
static int rtl8168_check_dash(struct rtl8168_private *tp)
{
if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) {
if (OCP_read(tp, 0x128, 1) & BIT_0)
return 1;
else
return 0;
} else {
u32 reg;
if (tp->mcfg == CFG_METHOD_13)
reg = 0xb8;
else
reg = 0x10;
if (OCP_read(tp, reg, 2) & 0x00008000)
return 1;
else
return 0;
}
}
void Dash2DisableTx(struct rtl8168_private *tp)
{
if (!tp->DASH) return;
if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) {
u16 WaitCnt;
u8 TmpUchar;
//Disable oob Tx
RTL_CMAC_W8(CMAC_IBCR2, RTL_CMAC_R8(CMAC_IBCR2) & ~( BIT_0 ));
WaitCnt = 0;
//wait oob tx disable
do {
TmpUchar = RTL_CMAC_R8(CMAC_IBISR0);
if ( TmpUchar & ISRIMR_DASH_TYPE2_TX_DISABLE_IDLE ) {
break;
}
udelay( 50 );
WaitCnt++;
} while(WaitCnt < 2000);
//Clear ISRIMR_DASH_TYPE2_TX_DISABLE_IDLE
RTL_CMAC_W8(CMAC_IBISR0, RTL_CMAC_R8(CMAC_IBISR0) | ISRIMR_DASH_TYPE2_TX_DISABLE_IDLE);
}
}
void Dash2EnableTx(struct rtl8168_private *tp)
{
if (!tp->DASH) return;
if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) {
RTL_CMAC_W8(CMAC_IBCR2, RTL_CMAC_R8(CMAC_IBCR2) | BIT_0);
}
}
void Dash2DisableRx(struct rtl8168_private *tp)
{
if (!tp->DASH) return;
if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) {
RTL_CMAC_W8(CMAC_IBCR0, RTL_CMAC_R8(CMAC_IBCR0) & ~( BIT_0 ));
}
}
void Dash2EnableRx(struct rtl8168_private *tp)
{
if (!tp->DASH) return;
if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) {
RTL_CMAC_W8(CMAC_IBCR0, RTL_CMAC_R8(CMAC_IBCR0) | BIT_0);
}
}
static void Dash2DisableTxRx(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) {
Dash2DisableTx( tp );
Dash2DisableRx( tp );
}
}
static void rtl8168_driver_start(struct rtl8168_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
if (!tp->DASH)
return;
if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) {
int timeout;
u32 tmp_value;
OCP_write(tp, 0x180, 1, OOB_CMD_DRIVER_START);
tmp_value = OCP_read(tp, 0x30, 1);
tmp_value |= BIT_0;
OCP_write(tp, 0x30, 1, tmp_value);
for (timeout = 0; timeout < 10; timeout++) {
mdelay(10);
if (OCP_read(tp, 0x124, 1) & BIT_0)
break;
}
} else {
int timeout;
u32 reg;
if (tp->mcfg == CFG_METHOD_13) {
RTL_W8(TwiCmdReg, RTL_R8(TwiCmdReg) | ( BIT_7 ));
}
OOB_notify(tp, OOB_CMD_DRIVER_START);
if (tp->mcfg == CFG_METHOD_13)
reg = 0xB8;
else
reg = 0x10;
for (timeout = 0; timeout < 10; timeout++) {
mdelay(10);
if (OCP_read(tp, reg, 2) & BIT_11)
break;
}
}
}
static void rtl8168_driver_stop(struct rtl8168_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
if (!tp->DASH)
return;
if (HW_DASH_SUPPORT_TYPE_2(tp) || HW_DASH_SUPPORT_TYPE_3(tp)) {
struct net_device *dev = tp->dev;
int timeout;
u32 tmp_value;
Dash2DisableTxRx(dev);
OCP_write(tp, 0x180, 1, OOB_CMD_DRIVER_STOP);
tmp_value = OCP_read(tp, 0x30, 1);
tmp_value |= BIT_0;
OCP_write(tp, 0x30, 1, tmp_value);
for (timeout = 0; timeout < 10; timeout++) {
mdelay(10);
if (!(OCP_read(tp, 0x124, 1) & BIT_0))
break;
}
} else {
int timeout;
u32 reg;
OOB_notify(tp, OOB_CMD_DRIVER_STOP);
if (tp->mcfg == CFG_METHOD_13)
reg = 0xB8;
else
reg = 0x10;
for (timeout = 0; timeout < 10; timeout++) {
mdelay(10);
if ((OCP_read(tp, reg, 2) & BIT_11) == 0)
break;
}
if (tp->mcfg == CFG_METHOD_13) {
RTL_W8(TwiCmdReg, RTL_R8(TwiCmdReg) & ~( BIT_7 ));
}
}
}
void rtl8168_ephy_write(void __iomem *ioaddr, int RegAddr, int value)
{
int i;
RTL_W32(EPHYAR,
EPHYAR_Write |
(RegAddr & EPHYAR_Reg_Mask) << EPHYAR_Reg_shift |
(value & EPHYAR_Data_Mask));
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed EPHY write */
if (!(RTL_R32(EPHYAR) & EPHYAR_Flag))
break;
}
udelay(20);
}
u16 rtl8168_ephy_read(void __iomem *ioaddr, int RegAddr)
{
int i;
u16 value = 0xffff;
RTL_W32(EPHYAR,
EPHYAR_Read | (RegAddr & EPHYAR_Reg_Mask) << EPHYAR_Reg_shift);
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed EPHY read */
if (RTL_R32(EPHYAR) & EPHYAR_Flag) {
value = (u16) (RTL_R32(EPHYAR) & EPHYAR_Data_Mask);
break;
}
}
udelay(20);
return value;
}
static void ClearAndSetPCIePhyBit(struct rtl8168_private *tp, u8 addr, u16 clearmask, u16 setmask)
{
void __iomem *ioaddr = tp->mmio_addr;
u16 EphyValue;
EphyValue = rtl8168_ephy_read( ioaddr, addr );
EphyValue &= ~clearmask;
EphyValue |= setmask;
rtl8168_ephy_write( ioaddr, addr, EphyValue);
}
static void ClearPCIePhyBit(struct rtl8168_private *tp, u8 addr, u16 mask)
{
ClearAndSetPCIePhyBit( tp,
addr,
mask,
0
);
}
static void SetPCIePhyBit( struct rtl8168_private *tp, u8 addr, u16 mask)
{
ClearAndSetPCIePhyBit( tp,
addr,
0,
mask
);
}
static u32
rtl8168_csi_other_fun_read(struct rtl8168_private *tp,
u8 multi_fun_sel_bit,
u32 addr)
{
void __iomem *ioaddr = tp->mmio_addr;
u32 cmd;
int i;
u32 value = 0;
cmd = CSIAR_Read | CSIAR_ByteEn << CSIAR_ByteEn_shift | (addr & CSIAR_Addr_Mask);
if (tp->mcfg != CFG_METHOD_20 && tp->mcfg != CFG_METHOD_23 &&
tp->mcfg != CFG_METHOD_26 && tp->mcfg != CFG_METHOD_27 &&
tp->mcfg != CFG_METHOD_28 && tp->mcfg != CFG_METHOD_31 &&
tp->mcfg != CFG_METHOD_32) {
multi_fun_sel_bit = 0;
}
if ( multi_fun_sel_bit > 7 ) {
return 0xffffffff;
}
cmd |= multi_fun_sel_bit << 16;
RTL_W32(CSIAR, cmd);
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed CSI read */
if (RTL_R32(CSIAR) & CSIAR_Flag) {
value = (u32)RTL_R32(CSIDR);
break;
}
}
udelay(20);
return value;
}
static void
rtl8168_csi_other_fun_write(struct rtl8168_private *tp,
u8 multi_fun_sel_bit,
u32 addr,
u32 value)
{
void __iomem *ioaddr = tp->mmio_addr;
u32 cmd;
int i;
RTL_W32(CSIDR, value);
cmd = CSIAR_Write | CSIAR_ByteEn << CSIAR_ByteEn_shift | (addr & CSIAR_Addr_Mask);
if (tp->mcfg != CFG_METHOD_20 && tp->mcfg != CFG_METHOD_23 &&
tp->mcfg != CFG_METHOD_26 && tp->mcfg != CFG_METHOD_27 &&
tp->mcfg != CFG_METHOD_28 && tp->mcfg != CFG_METHOD_31 &&
tp->mcfg != CFG_METHOD_32) {
multi_fun_sel_bit = 0;
}
if ( multi_fun_sel_bit > 7 ) {
return;
}
cmd |= multi_fun_sel_bit << 16;
RTL_W32(CSIAR, cmd);
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed CSI write */
if (!(RTL_R32(CSIAR) & CSIAR_Flag))
break;
}
udelay(20);
}
static u32
rtl8168_csi_read(struct rtl8168_private *tp,
u32 addr)
{
u8 multi_fun_sel_bit;
if (tp->mcfg == CFG_METHOD_20)
multi_fun_sel_bit = 2;
else if (tp->mcfg == CFG_METHOD_26 || tp->mcfg == CFG_METHOD_31 ||
tp->mcfg == CFG_METHOD_32)
multi_fun_sel_bit = 1;
else
multi_fun_sel_bit = 0;
return rtl8168_csi_other_fun_read(tp, multi_fun_sel_bit, addr);
}
static void
rtl8168_csi_write(struct rtl8168_private *tp,
u32 addr,
u32 value)
{
u8 multi_fun_sel_bit;
if (tp->mcfg == CFG_METHOD_20)
multi_fun_sel_bit = 2;
else if (tp->mcfg == CFG_METHOD_26 || tp->mcfg == CFG_METHOD_31 ||
tp->mcfg == CFG_METHOD_32)
multi_fun_sel_bit = 1;
else
multi_fun_sel_bit = 0;
rtl8168_csi_other_fun_write(tp, multi_fun_sel_bit, addr, value);
}
static u8
rtl8168_csi_fun0_read_byte(struct rtl8168_private *tp,
u32 addr)
{
u8 RetVal = 0;
if (tp->mcfg == CFG_METHOD_20 || tp->mcfg == CFG_METHOD_26 ||
tp->mcfg == CFG_METHOD_31 || tp->mcfg == CFG_METHOD_32) {
u32 TmpUlong;
u16 RegAlignAddr;
u8 ShiftByte;
RegAlignAddr = addr & ~(0x3);
ShiftByte = addr & (0x3);
TmpUlong = rtl8168_csi_other_fun_read(tp, 0, addr);
TmpUlong >>= (8*ShiftByte);
RetVal = (u8)TmpUlong;
} else {
struct pci_dev *pdev = tp->pci_dev;
pci_read_config_byte(pdev, addr, &RetVal);
}
udelay(20);
return RetVal;
}
static void
rtl8168_csi_fun0_write_byte(struct rtl8168_private *tp,
u32 addr,
u8 value)
{
if (tp->mcfg == CFG_METHOD_20 || tp->mcfg == CFG_METHOD_26 ||
tp->mcfg == CFG_METHOD_31 || tp->mcfg == CFG_METHOD_32) {
u32 TmpUlong;
u16 RegAlignAddr;
u8 ShiftByte;
RegAlignAddr = addr & ~(0x3);
ShiftByte = addr & (0x3);
TmpUlong = rtl8168_csi_other_fun_read(tp, 0, RegAlignAddr);
TmpUlong &= ~(0xFF << (8*ShiftByte));
TmpUlong |= (value << (8*ShiftByte));
rtl8168_csi_other_fun_write( tp, 0, RegAlignAddr, TmpUlong );
} else {
struct pci_dev *pdev = tp->pci_dev;
pci_write_config_byte(pdev, addr, value);
}
udelay(20);
}
static void
rtl8168_csi_set_dash_other_fun(struct rtl8168_private *tp,
u16 addr,
u32 clearmask,
u32 setmask,
u8 goto_d3)
{
u8 multi_fun_sel_bit;
u32 TmpUlong;
switch(tp->mcfg) {
case CFG_METHOD_23:
case CFG_METHOD_27:
case CFG_METHOD_28:
for (multi_fun_sel_bit = 1; multi_fun_sel_bit < 4; multi_fun_sel_bit++) {
TmpUlong = rtl8168_csi_other_fun_read(tp, multi_fun_sel_bit, addr);
TmpUlong &= ~clearmask;
TmpUlong |= setmask;
rtl8168_csi_other_fun_write(tp, multi_fun_sel_bit, addr, TmpUlong);
}
break;
case CFG_METHOD_31:
case CFG_METHOD_32:
for (multi_fun_sel_bit = 0; multi_fun_sel_bit < 8; multi_fun_sel_bit++) {
u8 set_other_fun = FALSE;
if (multi_fun_sel_bit == 1) {
set_other_fun = FALSE;
} else if (multi_fun_sel_bit == 0 || multi_fun_sel_bit == 2 || multi_fun_sel_bit == 7) {
if (goto_d3)
set_other_fun = TRUE;
} else if (multi_fun_sel_bit == 3 || multi_fun_sel_bit == 4) {
TmpUlong = rtl8168_csi_other_fun_read(tp, multi_fun_sel_bit, 0xF000);
if (TmpUlong == 0xFFFFFFFF)
set_other_fun = TRUE;
else
set_other_fun = FALSE;
} else { //func 5, 6
if (tp->DASH) {
TmpUlong = mac_ocp_read(tp, 0x184);
if (TmpUlong & BIT_26)
set_other_fun = FALSE;
else
set_other_fun = TRUE;
}
}
if (set_other_fun) {
TmpUlong = rtl8168_csi_other_fun_read(tp, multi_fun_sel_bit, addr);
TmpUlong &= ~clearmask;
TmpUlong |= setmask;
rtl8168_csi_other_fun_write(tp, multi_fun_sel_bit, addr, TmpUlong);
}
}
break;
}
}
u32 rtl8168_eri_read_with_oob_base_address(void __iomem *ioaddr, int addr, int len, int type, const u32 base_address)
{
int i, val_shift, shift = 0;
u32 value1 = 0, value2 = 0, mask;
u32 eri_cmd;
const u32 transformed_base_address = ((base_address & 0x00FFF000) << 6) | (base_address & 0x000FFF);
if (len > 4 || len <= 0)
return -1;
while (len > 0) {
val_shift = addr % ERIAR_Addr_Align;
addr = addr & ~0x3;
eri_cmd = ERIAR_Read |
transformed_base_address |
type << ERIAR_Type_shift |
ERIAR_ByteEn << ERIAR_ByteEn_shift |
(addr & 0x0FFF);
if (addr & 0xF000) {
u32 tmp;
tmp = addr & 0xF000;
tmp >>= 12;
eri_cmd |= (tmp << 20) & 0x00F00000;
}
RTL_W32(ERIAR, eri_cmd);
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed ERI read */
if (RTL_R32(ERIAR) & ERIAR_Flag)
break;
}
if (len == 1) mask = (0xFF << (val_shift * 8)) & 0xFFFFFFFF;
else if (len == 2) mask = (0xFFFF << (val_shift * 8)) & 0xFFFFFFFF;
else if (len == 3) mask = (0xFFFFFF << (val_shift * 8)) & 0xFFFFFFFF;
else mask = (0xFFFFFFFF << (val_shift * 8)) & 0xFFFFFFFF;
value1 = RTL_R32(ERIDR) & mask;
value2 |= (value1 >> val_shift * 8) << shift * 8;
if (len <= 4 - val_shift) {
len = 0;
} else {
len -= (4 - val_shift);
shift = 4 - val_shift;
addr += 4;
}
}
udelay(20);
return value2;
}
u32 rtl8168_eri_read(void __iomem *ioaddr, int addr, int len, int type)
{
return rtl8168_eri_read_with_oob_base_address(ioaddr, addr, len, type, 0);
}
int rtl8168_eri_write_with_oob_base_address(void __iomem *ioaddr, int addr, int len, u32 value, int type, const u32 base_address)
{
int i, val_shift, shift = 0;
u32 value1 = 0, mask;
u32 eri_cmd;
const u32 transformed_base_address = ((base_address & 0x00FFF000) << 6) | (base_address & 0x000FFF);
if (len > 4 || len <= 0)
return -1;
while (len > 0) {
val_shift = addr % ERIAR_Addr_Align;
addr = addr & ~0x3;
if (len == 1) mask = (0xFF << (val_shift * 8)) & 0xFFFFFFFF;
else if (len == 2) mask = (0xFFFF << (val_shift * 8)) & 0xFFFFFFFF;
else if (len == 3) mask = (0xFFFFFF << (val_shift * 8)) & 0xFFFFFFFF;
else mask = (0xFFFFFFFF << (val_shift * 8)) & 0xFFFFFFFF;
value1 = rtl8168_eri_read_with_oob_base_address(ioaddr, addr, 4, type, base_address) & ~mask;
value1 |= ((value << val_shift * 8) >> shift * 8);
RTL_W32(ERIDR, value1);
eri_cmd = ERIAR_Write |
transformed_base_address |
type << ERIAR_Type_shift |
ERIAR_ByteEn << ERIAR_ByteEn_shift |
(addr & 0x0FFF);
if (addr & 0xF000) {
u32 tmp;
tmp = addr & 0xF000;
tmp >>= 12;
eri_cmd |= (tmp << 20) & 0x00F00000;
}
RTL_W32(ERIAR, eri_cmd);
for (i = 0; i < 10; i++) {
udelay(100);
/* Check if the RTL8168 has completed ERI write */
if (!(RTL_R32(ERIAR) & ERIAR_Flag))
break;
}
if (len <= 4 - val_shift) {
len = 0;
} else {
len -= (4 - val_shift);
shift = 4 - val_shift;
addr += 4;
}
}
udelay(20);
return 0;
}
int rtl8168_eri_write(void __iomem *ioaddr, int addr, int len, u32 value, int type)
{
return rtl8168_eri_write_with_oob_base_address(ioaddr, addr, len, value, type, NO_BASE_ADDRESS);
}
static void
rtl8168_enable_rxdvgate(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
switch (tp->mcfg) {
case CFG_METHOD_21:
case CFG_METHOD_22:
case CFG_METHOD_23:
case CFG_METHOD_24:
case CFG_METHOD_25:
case CFG_METHOD_26:
case CFG_METHOD_27:
case CFG_METHOD_28:
case CFG_METHOD_29:
case CFG_METHOD_30:
case CFG_METHOD_31:
case CFG_METHOD_32:
RTL_W8(0xF2, RTL_R8(0xF2) | BIT_3);
mdelay(2);
break;
}
}
static void
rtl8168_disable_rxdvgate(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
switch (tp->mcfg) {
case CFG_METHOD_21:
case CFG_METHOD_22:
case CFG_METHOD_23:
case CFG_METHOD_24:
case CFG_METHOD_25:
case CFG_METHOD_26:
case CFG_METHOD_27:
case CFG_METHOD_28:
case CFG_METHOD_29:
case CFG_METHOD_30:
case CFG_METHOD_31:
case CFG_METHOD_32:
RTL_W8(0xF2, RTL_R8(0xF2) & ~BIT_3);
mdelay(2);
break;
}
}
static u8
rtl8168_is_gpio_low(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
u8 gpio_low = FALSE;
switch (tp->HwSuppCheckPhyDisableModeVer) {
case 1:
case 2:
if (!(mac_ocp_read(tp, 0xDC04) & BIT_9))
gpio_low = TRUE;
break;
case 3:
if (!(mac_ocp_read(tp, 0xDC04) & BIT_13))
gpio_low = TRUE;
break;
}
if (gpio_low)
dprintk("gpio is low.\n");
return gpio_low;
}
static u8
rtl8168_is_phy_disable_mode_enabled(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
u8 phy_disable_mode_enabled = FALSE;
switch (tp->HwSuppCheckPhyDisableModeVer) {
case 1:
if (mac_ocp_read(tp, 0xDC20) & BIT_1)
phy_disable_mode_enabled = TRUE;
break;
case 2:
case 3:
if (RTL_R8(0xF2) & BIT_5)
phy_disable_mode_enabled = TRUE;
break;
}
if (phy_disable_mode_enabled)
dprintk("phy disable mode enabled.\n");
return phy_disable_mode_enabled;
}
static u8
rtl8168_is_in_phy_disable_mode(struct net_device *dev)
{
u8 in_phy_disable_mode = FALSE;
if (rtl8168_is_phy_disable_mode_enabled(dev) && rtl8168_is_gpio_low(dev))
in_phy_disable_mode = TRUE;
if (in_phy_disable_mode)
dprintk("Hardware is in phy disable mode.\n");
return in_phy_disable_mode;
}
static void
rtl8168_enable_phy_disable_mode(struct net_device *dev)
{
struct rtl8168_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
switch (tp->HwSuppCheckPhyDisableModeVer) {
case 1:
mac_ocp_write(tp, 0xDC20, mac_ocp_read(tp, 0xDC20) | BIT_1);
break;
case 2:
case 3:
RTL_W8(0xF2, RTL_R8(0xF2) | BIT_5);
break;
}
|