r1000_n.c
来自「LINUX下面的RTL8169的驱动原码」· C语言 代码 · 共 2,072 行 · 第 1/4 页
C
2,072 行
//======================================================================================================
//======================================================================================================
void r1000_phy_timer_t_handler( void *timer_data )
{
struct net_device *dev = (struct net_device *)timer_data;
struct r1000_private *priv = (struct r1000_private *) (dev->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( dev );
}
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 *dev = (struct net_device *)timer_data;
struct r1000_private *priv = (struct r1000_private *) (dev->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 );
}
#ifdef R1000_DYNAMIC_CONTROL
{
struct r1000_cb_t *rt = &(priv->rt);
if( priv->linkstatus == _1000_Full ){
r1000_callback(rt);
}
}
#endif //end #ifdef R1000_DYNAMIC_CONTROL
r1000_mod_timer( (&priv->r1000_timer), priv->expire_time );
}
//======================================================================================================
//======================================================================================================
static int __devinit r1000_init_board ( struct pci_dev *pdev, struct net_device **dev_out, unsigned long *ioaddr_out)
{
unsigned long ioaddr = 0;
struct net_device *dev;
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;
*dev_out = NULL;
// dev zeroed in init_etherdev
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
dev = init_etherdev (NULL, sizeof (*priv));
#else
dev = alloc_etherdev (sizeof (*priv));
#endif
if (dev == NULL) {
printk (KERN_ERR PFX "unable to alloc new ethernet\n");
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
SET_NETDEV_DEV(dev, &pdev->dev);
#endif
priv = dev->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, dev->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;
*dev_out = dev;
return 0;
#ifndef R1000_USE_IO
err_out_free_res:
pci_release_regions (pdev);
#endif
err_out:
unregister_netdev (dev);
kfree (dev);
return rc;
}
//======================================================================================================
static int __devinit r1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *dev = NULL;
struct r1000_private *priv = NULL;
unsigned long ioaddr = 0;
static int board_idx = -1;
int i;
int option = -1, Cap10_100 = 0, Cap1000 = 0;
int val=0;
assert (pdev != NULL);
assert (ent != NULL);
board_idx++;
i = r1000_init_board (pdev, &dev, &ioaddr);
if (i < 0) {
return i;
}
priv = dev->priv;
assert (ioaddr != NULL);
assert (dev != NULL);
assert (priv != NULL);
// Get MAC address //
for (i = 0; i < MAC_ADDR_LEN ; i++){
dev->dev_addr[i] = RTL_R8( MAC0 + i );
}
dev->open = r1000_open;
dev->hard_start_xmit = r1000_start_xmit;
dev->get_stats = r1000_get_stats;
dev->stop = r1000_close;
dev->tx_timeout = r1000_tx_timeout;
dev->set_multicast_list = r1000_set_rx_mode;
dev->watchdog_timeo = TX_TIMEOUT;
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) ioaddr;
#ifdef R1000_JUMBO_FRAME_SUPPORT
dev->change_mtu = r1000_change_mtu;
#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT
#ifdef R1000_IOCTL_SUPPORT
dev->do_ioctl = r1000_ioctl;
#endif //end #ifdef R1000_IOCTL_SUPPORT
#ifdef R1000_DYNAMIC_CONTROL
priv->rt.dev = dev;
#endif //end #ifdef R1000_DYNAMIC_CONTROL
priv = dev->priv; // private data //
priv->pci_dev = pdev;
priv->ioaddr = ioaddr;
//#ifdef R1000_JUMBO_FRAME_SUPPORT
priv->curr_mtu_size = dev->mtu;
priv->tx_pkt_len = dev->mtu + ETH_HDR_LEN;
priv->rx_pkt_len = dev->mtu + ETH_HDR_LEN;
priv->hw_rx_pkt_len = priv->rx_pkt_len + 8;
//#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT
DBG_PRINT("-------------------------- \n");
DBG_PRINT("dev->mtu = %d \n", dev->mtu);
DBG_PRINT("priv->curr_mtu_size = %d \n", priv->curr_mtu_size);
DBG_PRINT("priv->tx_pkt_len = %d \n", priv->tx_pkt_len);
DBG_PRINT("priv->rx_pkt_len = %d \n", priv->rx_pkt_len);
DBG_PRINT("priv->hw_rx_pkt_len = %d \n", priv->hw_rx_pkt_len);
DBG_PRINT("-------------------------- \n");
spin_lock_init (&priv->lock);
register_netdev (dev);
pci_set_drvdata(pdev, dev); // pdev->driver_data = data;
printk (KERN_DEBUG "%s: Identified chip type is '%s'.\n",dev->name,rtl_chip_info[priv->chipset].name);
printk (KERN_INFO "%s: %s at 0x%lx, "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
"IRQ %d\n",
dev->name,
R1000_DRIVER_NAME,
dev->base_addr,
dev->dev_addr[0], dev->dev_addr[1],
dev->dev_addr[2], dev->dev_addr[3],
dev->dev_addr[4], dev->dev_addr[5],
dev->irq);
// Config PHY
r1000_hw_PHY_config(dev);
DBG_PRINT("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
RTL_W8( 0x82, 0x01 );
if( priv->mcfg < MCFG_METHOD_3 ){
DBG_PRINT("Set PCI Latency=0x40\n");
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
}
if( priv->mcfg == MCFG_METHOD_2 ){
DBG_PRINT("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
RTL_W8( 0x82, 0x01 );
DBG_PRINT("Set PHY Reg 0x0bh = 0x00h\n");
R1000_WRITE_GMII_REG( ioaddr, 0x0b, 0x0000 ); //w 0x0b 15 0 0
}
// if TBI is not endbled
if( !(RTL_R8(PHYstatus) & TBI_Enable) ){
val = R1000_READ_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG );
#ifdef R1000_HW_FLOW_CONTROL_SUPPORT
val |= PHY_Cap_PAUSE | PHY_Cap_ASYM_PAUSE ;
#endif //end #define R1000_HW_FLOW_CONTROL_SUPPORT
option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
// Force Realtek Ethernet Controller in 10/100/1000Mpbs Full/Half-duplex mode.
if( option > 0 ){
printk(KERN_INFO "%s: Force-mode Enabled. \n", dev->name);
Cap10_100 = 0;
Cap1000 = 0;
switch( option ){
case _10_Half:
Cap10_100 = PHY_Cap_10_Half;
Cap1000 = PHY_Cap_Null;
break;
case _10_Full:
Cap10_100 = PHY_Cap_10_Full | PHY_Cap_10_Half;
Cap1000 = PHY_Cap_Null;
break;
case _100_Half:
if(priv->mcfg!=MCFG_METHOD_13)
Cap10_100 = PHY_Cap_100_Half | PHY_Cap_10_Full | PHY_Cap_10_Half;
else
Cap10_100 = 0x0081;
Cap1000 = PHY_Cap_Null;
break;
case _100_Full:
Cap10_100 = PHY_Cap_100_Full | PHY_Cap_100_Half | PHY_Cap_10_Full | PHY_Cap_10_Half;
Cap1000 = PHY_Cap_Null;
break;
case _1000_Full:
Cap10_100 = PHY_Cap_100_Full | PHY_Cap_100_Half | PHY_Cap_10_Full | PHY_Cap_10_Half;
if((priv->mcfg!=MCFG_METHOD_13)&&(priv->mcfg!=MCFG_METHOD_14)&&(priv->mcfg!=MCFG_METHOD_15))
printk("This Realtek NIC doesn't support 1000Mbps\n");
else
Cap1000 = PHY_Cap_1000_Full|PHY_Cap_1000_Half;
break;
default:
break;
}
//flow control enable
R1000_WRITE_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | ( val&0xC1F ) ); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged
R1000_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, Cap1000 );
}
else{
printk(KERN_INFO "%s: Auto-negotiation Enabled.\n", dev->name);
// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
R1000_WRITE_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG,
PHY_Cap_10_Half | PHY_Cap_10_Full | PHY_Cap_100_Half | PHY_Cap_100_Full | ( val&0xC1F ) );
// enable 1000 Full Mode
if((priv->mcfg!=MCFG_METHOD_13)&&(priv->mcfg!=MCFG_METHOD_14)&&(priv->mcfg!=MCFG_METHOD_15))
R1000_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full | PHY_Cap_1000_Half);
}// end of if( option > 0 )
// Enable auto-negotiation and restart auto-nigotiation
R1000_WRITE_GMII_REG( ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego );
udelay(100);
// wait for auto-negotiation process
for( i = 7000; i > 0; i-- ){
//check if auto-negotiation complete
if( R1000_READ_GMII_REG(ioaddr, PHY_STAT_REG) & PHY_Auto_Neco_Comp ){
udelay(100);
option = RTL_R8(PHYstatus);
if( option & _1000Mbps ){
printk(KERN_INFO "%s: 1000Mbps Full-duplex operation.\n", dev->name);
}
else{
printk(KERN_INFO "%s: %sMbps %s-duplex operation.\n", dev->name,
(option & _100Mbps) ? "100" : "10", (option & FullDup) ? "Full" : "Half" );
}
break;
}
else{
udelay(100);
}// end of if( R1000_READ_GMII_REG(ioaddr, 1) & 0x20 )
}// end for-loop to wait for auto-negotiation process
option = RTL_R8(PHYstatus);
if( option & _1000Mbps ){
priv->linkstatus = _1000_Full;
}
else{
if(option & _100Mbps){
priv->linkstatus = (option & FullDup) ? _100_Full : _100_Half;
}
else{
priv->linkstatus = (option & FullDup) ? _10_Full : _10_Half;
}
}
DBG_PRINT("priv->linkstatus = 0x%02x\n", priv->linkstatus);
}// end of TBI is not enabled
else{
udelay(100);
DBG_PRINT("1000Mbps Full-duplex operation, TBI Link %s!\n",(RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed" );
}// end of TBI is not enabled
//show some information after the driver is inserted
if(( priv->mcfg == MCFG_METHOD_11 )||( priv->mcfg == MCFG_METHOD_12 ))
printk("Realtek RTL8168/8111 Family PCI-E Gigabit Ethernet Network Adapter\n");
else if((priv->mcfg==MCFG_METHOD_13)||(priv->mcfg==MCFG_METHOD_14)||(priv->mcfg==MCFG_METHOD_15))
printk("Realtek RTL8139/810x Family Fast Ethernet Network Adapter\n");
else
printk("Realtek RTL8169/8110 Family Gigabit Ethernet Network Adapter\n");
printk("Driver version:%s\n",R1000_VERSION);
printk("Released date:%s\n",RELEASE_DATE);
if(RTL_R8(PHYstatus) & LinkStatus){
printk("Link Status:%s\n","Linked");
if(RTL_R8(PHYstatus) & _1000Mbps)
printk("Link Speed:1000Mbps\n");
else if(RTL_R8(PHYstatus) & _100Mbps)
printk("Link Speed:100Mbps\n");
else if(RTL_R8(PHYstatus) & _10Mbps)
printk("Link Speed:10Mbps\n");
printk("Duplex mode:%s\n",RTL_R8(PHYstatus)&FullDup?"Full-Duplex":"Half-Duplex");
}else{
printk("Link Status:%s\n","Not Linked");
}
#ifdef R1000_USE_IO
printk("I/O Base:0x%X(I/O port)\n",(unsigned int)(priv->ioaddr));
#else
printk("I/O Base:0x%X(I/O memory)\n",(unsigned int)(priv->ioaddr));
#endif //R1000_USE_IO
printk("IRQ:%d\n",dev->irq);
return 0;
}
//======================================================================================================
static void __devexit r1000_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
assert (dev != NULL);
assert (priv != NULL);
unregister_netdev (dev);
#ifdef R1000_USE_IO
#else
iounmap ((void *)(dev->base_addr));
#endif
pci_release_regions (pdev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
kfree (dev);
#else
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?