📄 r1000_n.c
字号:
//=========================================================================
//Realtek Ethernet driver for Linux kernel 2.4.x. and 2.6.x
//=========================================================================
#include "r1000.h"
#ifdef MODULE_PARM
static int speed[MAX_UNITS] = {-1,-1,-1,-1,-1,-1,-1,-1};
static int duplex[MAX_UNITS] = {-1,-1,-1,-1,-1,-1,-1,-1};
static int autoneg[MAX_UNITS] = {-1,-1,-1,-1,-1,-1,-1,-1};
#endif //MODULE_PARM
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
/* 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 int multicast_filter_limit = 32;
const static struct {
const char *name;
u8 mcfg; /* depend on documents of Realtek */
u32 RxConfigMask; /* should clear the bits supported by this chip */
} rtl_chip_info[] = {
{ "RTL8169", MCFG_METHOD_1, 0xff7e1880 },
{ "RTL8169S/8110S", MCFG_METHOD_2, 0xff7e1880 },
{ "RTL8169S/8110S", MCFG_METHOD_3, 0xff7e1880 },
{ "RTL8169SB/8110SB", MCFG_METHOD_4, 0xff7e1880 },
{ "RTL8110SC", MCFG_METHOD_5, 0xff7e1880 },
{ "RTL8168B/8111B", MCFG_METHOD_11, 0xff7e1880 },
{ "RTL8168B/8111B", MCFG_METHOD_12, 0xff7e1880 },
{ "RTL8101E", MCFG_METHOD_13, 0xff7e1880 },
{ "RTL8100E", MCFG_METHOD_14, 0xff7e1880 },
{ "RTL8100E", MCFG_METHOD_15, 0xff7e1880 },
{ 0 }
};
static struct pci_device_id r1000_pci_tbl[] __devinitdata = {
{ 0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x10ec, 0x8167, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x10ec, 0x8168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x10ec, 0x8136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{0,}
};
MODULE_DEVICE_TABLE (pci, r1000_pci_tbl);
MODULE_AUTHOR ("Realtek");
MODULE_DESCRIPTION ("Linux device driver for Realtek Ethernet Controllers");
#ifdef MODULE_PARM
MODULE_PARM (speed, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM_DESC(speed,"Link speed");
MODULE_PARM (duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM_DESC(duplex,"Link duplex");
MODULE_PARM (autoneg, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM_DESC(autoneg,"Autonegotiation");
#else //MODULE_PARM
/* Module Parameters are always initialized to -1, so that the driver
* can tell the difference between no user specified value or the
* user asking for the default value.
* The true default values are loaded in when e1000_check_options is called.
*
* This is a GCC extension to ANSI C.
* See the item "Labeled Elements in Initializers" in the section
* "Extensions to the C Language Family" of the GCC documentation.
*/
#define R1000_PARAM_INIT { [0 ... MAX_UNITS] = OPTION_UNSET }
/* All parameters are treated the same, as an integer array of values.
* This macro just reduces the need to repeat the same declaration code
* over and over (plus this helps to avoid typo bugs).
*/
#define R1000_PARAM(X, S) \
static int __devinitdata X[MAX_UNITS+1] = R1000_PARAM_INIT; \
static int num_##X = 0; \
module_param_array(X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, S);
/* Link Speed
* Valid Values: 10Mbps, 100Mbps, and 1000Mbps
* Defaule value: 100Mbps
*/
R1000_PARAM(speed, "Link speed");
/* Link duplex
* Valid Values: half duplex and full duplex
* Defaule value: full duplex
*/
R1000_PARAM(duplex, "Link duplex");
/* Autonegotiation
* Valid Values: enable and disable
* Defaule value: enable
*/
R1000_PARAM(autoneg, "Autonegotiation");
#endif //MODULE_PARM
MODULE_LICENSE("GPL");
static int r1000_open (struct net_device *netdev);
static int r1000_start_xmit (struct sk_buff *skb, struct net_device *netdev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
//typedef int irqreturn_t;
#define IRQ_NONE 0
#define IRQ_HANDLED 1
static void r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
#else
static irqreturn_t r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
#endif
static void r1000_init_ring (struct net_device *netdev);
static void r1000_hw_start (struct net_device *netdev);
static int r1000_close (struct net_device *netdev);
static inline u32 ether_crc (int length, unsigned char *data);
static void r1000_set_rx_mode (struct net_device *netdev);
static void r1000_tx_timeout (struct net_device *netdev);
static struct net_device_stats *r1000_get_stats(struct net_device *netdev);
#ifdef R1000_JUMBO_FRAME_SUPPORT
static int r1000_change_mtu(struct net_device *netdev, int new_mtu);
#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT
static void r1000_hw_PHY_config (struct net_device *netdev);
static void r1000_hw_PHY_reset(struct net_device *netdev);
//static const u16 r1000_intr_mask=LinkChg|RxDescUnavail|RxFIFOOver|TxErr|TxOK|RxErr|RxOK;
static const u16 r1000_intr_mask=LinkChg|RxDescUnavail|TxErr|TxOK|RxErr|RxOK;
static const unsigned int r1000_rx_config=(RX_FIFO_THRESH<<RxCfgFIFOShift)|(RX_DMA_BURST<<RxCfgDMAShift)|0x0000000E;
static int r1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
extern int ethtool_ioctl(struct ifreq *ifr);
extern struct ethtool_ops r1000_ethtool_ops;
static int r1000_set_speed_duplex(unsigned long ioaddr, unsigned int anar, unsigned int gbcr, unsigned int bmcr);
static void r1000_rx_action(struct net_device *netdev);
static void r1000_tx_action(struct net_device *netdev);
#ifdef R1000_BOTTOM_HALVES
static void r1000_rx_interrupt(unsigned long ndev);
static void r1000_tx_interrupt(unsigned long ndev);
#else
static void r1000_rx_interrupt(struct net_device *netdev, struct r1000_private *priv, unsigned long ioaddr);
static void r1000_tx_interrupt (struct net_device *netdev, struct r1000_private *priv, unsigned long ioaddr);
#endif //R1000_BOTTOM_HALVES
#ifdef R1000_DEBUG
unsigned alloc_rxskb_cnt = 0;
#define R1000_ALLOC_RXSKB(bufsize) dev_alloc_skb(bufsize); alloc_rxskb_cnt ++ ;
#define R1000_FREE_RXSKB(skb) kfree_skb(skb); alloc_rxskb_cnt -- ;
#define R1000_NETIF_RX(skb) netif_rx(skb); alloc_rxskb_cnt -- ;
#else
#define R1000_ALLOC_RXSKB(bufsize) dev_alloc_skb(bufsize);
#define R1000_FREE_RXSKB(skb) kfree_skb(skb);
#define R1000_NETIF_RX(skb) netif_rx(skb);
#endif //end #ifdef R1000_DEBUG
//=================================================================
// PHYAR
// bit Symbol
// 31 Flag
// 30-21 reserved
// 20-16 5-bit GMII/MII register address
// 15-0 16-bit GMII/MII register data
//=================================================================
void R1000_WRITE_GMII_REG( unsigned long ioaddr, int RegAddr, int value )
{
int i;
RTL_W32 ( PHYAR, 0x80000000 | (RegAddr&0xFF)<<16 | value);
udelay(1000);
for( i = 2000; i > 0 ; i -- ){
// Check if the RTL8169 has completed writing to the specified MII register
if( ! (RTL_R32(PHYAR)&0x80000000) ){
break;
}
else{
udelay(100);
}// end of if( ! (RTL_R32(PHYAR)&0x80000000) )
}// end of for() loop
}
//=================================================================
int R1000_READ_GMII_REG( unsigned long ioaddr, int RegAddr )
{
int i, value = -1;
RTL_W32 ( PHYAR, 0x0 | (RegAddr&0xFF)<<16 );
udelay(1000);
for( i = 2000; i > 0 ; i -- ){
// Check if the RTL8169 has completed retrieving data from the specified MII register
if( RTL_R32(PHYAR) & 0x80000000 ){
value = (int)( RTL_R32(PHYAR)&0xFFFF );
break;
}
else{
udelay(100);
}// end of if( RTL_R32(PHYAR) & 0x80000000 )
}// end of for() loop
return value;
}
void r1000_phy_timer_t_handler( void *timer_data )
{
struct net_device *netdev = (struct net_device *)timer_data;
struct r1000_private *priv = (struct r1000_private *) (netdev->priv);
unsigned long ioaddr = priv->ioaddr;
assert( priv->mcfg > MCFG_METHOD_1 );
assert( priv->pcfg < PCFG_METHOD_3 );
if( RTL_R8(PHYstatus) & LinkStatus ){
priv->phy_link_down_cnt = 0 ;
}
else{
priv->phy_link_down_cnt ++ ;
if( priv->phy_link_down_cnt >= 12 ){
// If link on 1000, perform phy reset.
if( R1000_READ_GMII_REG( ioaddr, PHY_1000_CTRL_REG ) & PHY_Cap_1000_Full )
{
DBG_PRINT("r1000_hw_PHY_reset\n");
r1000_hw_PHY_reset(netdev);
}
priv->phy_link_down_cnt = 0 ;
}
}
//---------------------------------------------------------------------------
//mod_timer is a more efficient way to update the expire field of an active timer.
//---------------------------------------------------------------------------
// r1000_mod_timer( (&priv->phy_timer_t), 100 );
}
void r1000_timer_handler( void *timer_data )
{
struct net_device *netdev = (struct net_device *)timer_data;
struct r1000_private *priv = (struct r1000_private *) (netdev->priv);
if( (priv->mcfg > MCFG_METHOD_1) && (priv->pcfg < PCFG_METHOD_3) ){
DBG_PRINT("FIX PCS -> r1000_phy_timer_t_handler\n");
priv->phy_link_down_cnt = 0;
r1000_phy_timer_t_handler( timer_data );
}
r1000_mod_timer( (&priv->r1000_timer), priv->expire_time );
}
static int r1000_set_speed_duplex(unsigned long ioaddr, unsigned int anar, unsigned int gbcr, unsigned int bmcr){
unsigned int i = 0;
unsigned int bmsr;
R1000_WRITE_GMII_REG(ioaddr,PHY_AUTO_NEGO_REG,anar);
R1000_WRITE_GMII_REG(ioaddr,PHY_1000_CTRL_REG,gbcr);
R1000_WRITE_GMII_REG(ioaddr,PHY_CTRL_REG,bmcr);
for(i=0;i<10000;i++){
bmsr = R1000_READ_GMII_REG(ioaddr,PHY_STAT_REG);
if(bmsr&PHY_Auto_Neco_Comp)
return 0;
}
return -1;
}
static int __devinit r1000_init_board ( struct pci_dev *pdev, struct net_device **netdev_out, unsigned long *ioaddr_out)
{
unsigned long ioaddr = 0;
struct net_device *netdev;
struct r1000_private *priv;
int rc, i;
#ifndef R1000_USE_IO
unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
#endif
assert (pdev != NULL);
assert (ioaddr_out != NULL);
*ioaddr_out = 0;
*netdev_out = NULL;
// dev zeroed in init_etherdev
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
netdev = init_etherdev (NULL, sizeof (*priv));
#else
netdev = alloc_etherdev (sizeof (*priv));
#endif
if (netdev == NULL) {
printk (KERN_ERR PFX "unable to alloc new ethernet\n");
return -ENOMEM;
}
SET_MODULE_OWNER(netdev);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
SET_NETDEV_DEV(netdev, &pdev->dev);
#endif
priv = netdev->priv;
// enable device (incl. PCI PM wakeup and hotplug setup)
rc = pci_enable_device (pdev);
if (rc)
goto err_out;
#ifndef R1000_USE_IO
mmio_start = pci_resource_start (pdev, 1);
mmio_end = pci_resource_end (pdev, 1);
mmio_flags = pci_resource_flags (pdev, 1);
mmio_len = pci_resource_len (pdev, 1);
// make sure PCI base addr 1 is MMIO
if (!(mmio_flags & IORESOURCE_MEM)) {
printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
// check for weird/broken PCI region reporting
if ( mmio_len < RTL_MIN_IO_SIZE ) {
printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
#endif
rc = pci_request_regions (pdev, netdev->name);
if (rc)
goto err_out;
// enable PCI bus-mastering
pci_set_master (pdev);
#ifdef R1000_USE_IO
ioaddr = pci_resource_start(pdev, 0);
#else
// ioremap MMIO region
ioaddr = (unsigned long)ioremap (mmio_start, mmio_len);
if (ioaddr == 0) {
printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res;
}
#endif
// Soft reset the chip.
RTL_W8 ( ChipCmd, CmdReset);
// Check that the chip has finished the reset.
for (i = 1000; i > 0; i--){
if ( (RTL_R8(ChipCmd) & CmdReset) == 0){
break;
}
else{
udelay (10);
}
}
// identify config method
{
unsigned long val32 = (RTL_R32(TxConfig)&0x7c800000);
if( val32 == 0x38800000)
priv->mcfg = MCFG_METHOD_15;
else if( val32 == 0x30800000)
priv->mcfg = MCFG_METHOD_14;
else if( val32 == 0x34000000)
priv->mcfg = MCFG_METHOD_13;
else if( val32 == 0x38000000)
priv->mcfg = MCFG_METHOD_12;
else if( val32 == 0x30000000)
priv->mcfg = MCFG_METHOD_11;
else if( val32 == 0x18000000)
priv->mcfg = MCFG_METHOD_5;
else if( val32 == 0x10000000 )
priv->mcfg = MCFG_METHOD_4;
else if( val32 == 0x04000000 )
priv->mcfg = MCFG_METHOD_3;
else if( val32 == 0x00800000 )
priv->mcfg = MCFG_METHOD_2;
else if( val32 == 0x00000000 )
priv->mcfg = MCFG_METHOD_1;
else
priv->mcfg = MCFG_METHOD_1;
}
{
unsigned char val8 = (unsigned char)(R1000_READ_GMII_REG(ioaddr,3)&0x000f);
if( val8 == 0x00 ){
priv->pcfg = PCFG_METHOD_1;
}
else if( val8 == 0x01 ){
priv->pcfg = PCFG_METHOD_2;
}
else if( val8 == 0x02 ){
priv->pcfg = PCFG_METHOD_3;
}
else{
priv->pcfg = PCFG_METHOD_3;
}
}
for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--){
if (priv->mcfg == rtl_chip_info[i].mcfg) {
priv->chipset = i;
goto match;
}
}
//if unknown chip, assume array element #0, original RTL-8169 in this case
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8169\n", pdev->slot_name);
#endif
priv->chipset = 0;
match:
*ioaddr_out = ioaddr;
*netdev_out = netdev;
return 0;
#ifndef R1000_USE_IO
err_out_free_res:
pci_release_regions (pdev);
#endif
err_out:
unregister_netdev(netdev);
kfree(netdev);
return rc;
}
int r1000_set_medium(struct net_device *netdev,u16 speed,u8 duplex,u8 autoneg){
struct r1000_private *priv = (struct r1000_private *)(netdev->priv);
unsigned long ioaddr = priv->ioaddr;
unsigned int anar=0,gbcr=0,bmcr=0,ret=0,val=0;
val = R1000_READ_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG );
#ifdef R1000_HW_FLOW_CONTROL_SUPPORT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -