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 + -
显示快捷键?