⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 r1000_n.c

📁 REALTEC RTL8618 8111 Driver for linux 版权归周立发
💻 C
📖 第 1 页 / 共 4 页
字号:
	val |= PHY_Cap_PAUSE | PHY_Cap_ASYM_PAUSE ;
#endif //end #define R1000_HW_FLOW_CONTROL_SUPPORT

	bmcr = PHY_Restart_Auto_Nego|PHY_Enable_Auto_Nego;

	if(autoneg==AUTONEG_ENABLE){
		priv->autoneg = AUTONEG_ENABLE;
		anar = PHY_Cap_10_Half|PHY_Cap_10_Full|PHY_Cap_100_Half|PHY_Cap_100_Full;
		gbcr = PHY_Cap_1000_Half|PHY_Cap_1000_Full;
	}else{
		priv->autoneg = AUTONEG_DISABLE;
		if(speed==SPEED_1000){
			priv->speed = SPEED_1000;
			priv->duplex = DUPLEX_FULL;

			anar = PHY_Cap_10_Half|PHY_Cap_10_Full|PHY_Cap_100_Half|PHY_Cap_100_Full;
			if((priv->mcfg==MCFG_METHOD_13)||(priv->mcfg==MCFG_METHOD_14)||(priv->mcfg==MCFG_METHOD_15))
				gbcr = PHY_Cap_Null;
			else
				gbcr = PHY_Cap_1000_Half|PHY_Cap_1000_Full;
		}else if((speed==SPEED_100)&&(duplex==DUPLEX_FULL)){
			priv->speed = SPEED_100;
			priv->duplex = DUPLEX_FULL;

			anar = PHY_Cap_10_Half|PHY_Cap_10_Full|PHY_Cap_100_Half|PHY_Cap_100_Full;
			gbcr = PHY_Cap_Null;
		}else if((speed==SPEED_100)&&(duplex==DUPLEX_HALF)){
			priv->speed = SPEED_100;
			priv->duplex = DUPLEX_HALF;

			anar = PHY_Cap_10_Half|PHY_Cap_10_Full|PHY_Cap_100_Half;
			gbcr = PHY_Cap_Null;
		}else if((speed==SPEED_10)&&(duplex==DUPLEX_FULL)){
			priv->speed = SPEED_10;
			priv->duplex = DUPLEX_FULL;

			anar = PHY_Cap_10_Half|PHY_Cap_10_Full;
			gbcr = PHY_Cap_Null;
		}else if((speed==SPEED_10)&&(duplex==DUPLEX_HALF)){
			priv->speed = SPEED_10;
			priv->duplex = DUPLEX_HALF;

			anar = PHY_Cap_10_Half;
			gbcr = PHY_Cap_Null;
		}else{
			priv->speed = SPEED_100;
			priv->duplex = DUPLEX_FULL;

			anar = PHY_Cap_10_Half|PHY_Cap_10_Full|PHY_Cap_100_Half|PHY_Cap_100_Full;
			gbcr = PHY_Cap_Null;
		}
	}

	//enable flow control
	anar |=  val&0xC1F;

	ret = r1000_set_speed_duplex(ioaddr,anar,gbcr,bmcr);
	
	return	ret;
}


static int r1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd){

	if(!netif_running(netdev))
		return -EINVAL;

	switch(cmd){
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
	case SIOCETHTOOL:
		return ethtool_ioctl(ifr);
#endif
	default:
		return -EOPNOTSUPP;
	}
}





//======================================================================================================
static int __devinit r1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
	struct net_device *netdev = NULL;
	struct r1000_private *priv = NULL;
	unsigned long ioaddr = 0;
	static int board_idx = -1;
	int i,rc;
//	int val=0;
	int speed_opt = SPEED_100;
	int duplex_opt = DUPLEX_FULL;
	int autoneg_opt = AUTONEG_ENABLE;


	assert (pdev != NULL);
	assert (ent != NULL);

	board_idx++;


	i = r1000_init_board (pdev, &netdev, &ioaddr);
	if (i < 0) {
		return i;
	}

	priv = netdev->priv;

	assert (ioaddr != NULL);
	assert (netdev != NULL);
	assert (priv != NULL);

	// Get MAC address //
	for (i = 0; i < MAC_ADDR_LEN ; i++){
		netdev->dev_addr[i] = RTL_R8( MAC0 + i );
	}

	netdev->open		= r1000_open;
	netdev->hard_start_xmit	= r1000_start_xmit;
	netdev->get_stats    	= r1000_get_stats;
	netdev->stop 		= r1000_close;
	netdev->tx_timeout 	= r1000_tx_timeout;
	netdev->set_multicast_list = r1000_set_rx_mode;
	netdev->watchdog_timeo 	= TX_TIMEOUT;
	netdev->irq 		= pdev->irq;
	netdev->base_addr 	= (unsigned long) ioaddr;

#ifdef R1000_JUMBO_FRAME_SUPPORT
	netdev->change_mtu	= r1000_change_mtu;
#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT

	netdev->do_ioctl 	= r1000_ioctl;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
	netdev->ethtool_ops	= &r1000_ethtool_ops;
#endif

#ifdef	R1000_BOTTOM_HALVES
	tasklet_init(&priv->r1000_rx_tasklet,r1000_rx_interrupt,(unsigned long)netdev);
	tasklet_init(&priv->r1000_tx_tasklet,r1000_tx_interrupt,(unsigned long)netdev);
#endif	//R1000_BOTTOM_HALVES


	priv		= netdev->priv;			// private data //
	priv->pci_dev 	= pdev;
	priv->ioaddr 	= ioaddr;

//#ifdef R1000_JUMBO_FRAME_SUPPORT
	priv->curr_mtu_size = netdev->mtu;
	priv->tx_pkt_len = netdev->mtu + ETH_HDR_LEN;
	priv->rx_pkt_len = netdev->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("netdev->mtu = %d \n", netdev->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);
	spin_lock_init(&priv->tx_lock);
	spin_lock_init(&priv->rx_lock);

	rc = register_netdev(netdev);
	if(rc){
#ifndef R1000_USE_IO
		iounmap ((void *)(netdev->base_addr));
#endif
		pci_release_regions(pdev);
		pci_disable_device(pdev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
		kfree(netdev);
#else
		free_netdev(netdev);
#endif
		return rc;
	}

	pci_set_drvdata(pdev,netdev);     //      pdev->driver_data = data;


	printk (KERN_DEBUG "%s: Identified chip type is '%s'.\n",netdev->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",
				netdev->name,
				R1000_DRIVER_NAME,
				netdev->base_addr,
				netdev->dev_addr[0],netdev->dev_addr[1],
				netdev->dev_addr[2],netdev->dev_addr[3],
				netdev->dev_addr[4],netdev->dev_addr[5],
				netdev->irq);


	// Config PHY
	r1000_hw_PHY_config(netdev);

	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

		if(speed[board_idx] == -1)
			speed[board_idx] = SPEED_1000;

		if((duplex[board_idx] == -1) || ((duplex[board_idx] == DUPLEX_HALF) && (speed[board_idx] == SPEED_1000)))
			duplex[board_idx] = DUPLEX_FULL;

		if(autoneg[board_idx] == -1)
			autoneg[board_idx] = AUTONEG_ENABLE;

		speed_opt = (board_idx >= MAX_UNITS) ? -1 : speed[board_idx];
		duplex_opt = (board_idx >= MAX_UNITS) ? -1 : duplex[board_idx];
		autoneg_opt = (board_idx >= MAX_UNITS) ? -1 : autoneg[board_idx];

		r1000_set_medium(netdev,speed_opt,duplex_opt,autoneg_opt);
	}// 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",netdev->irq);

	return 0;
}

static void __devexit r1000_remove_one (struct pci_dev *pdev)
{
	struct net_device *netdev = pci_get_drvdata(pdev);

	assert (netdev != NULL);
	assert (priv != NULL);

	unregister_netdev(netdev);

#ifndef R1000_USE_IO
	iounmap ((void *)(netdev->base_addr));
#endif
	pci_release_regions (pdev);

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
	kfree(netdev);
#else
	free_netdev(netdev);
#endif

	pci_set_drvdata (pdev, NULL);
}

static int r1000_open (struct net_device *netdev)
{
	struct r1000_private *priv = netdev->priv;
	struct pci_dev *pdev = priv->pci_dev;
	int retval;
//	u8 diff;
//	u32 TxPhyAddr, RxPhyAddr;


	if( priv->drvinit_fail == 1 ){
		printk("%s: Gigabit driver open failed.\n", netdev->name );
		return -ENOMEM;
	}

	retval = request_irq (netdev->irq, r1000_interrupt, SA_SHIRQ, netdev->name, netdev);
	if (retval) {
		return retval;
	}

	//2004-05-11
	// Allocate tx/rx descriptor space
	priv->sizeof_txdesc_space = NUM_TX_DESC * sizeof(struct TxDesc)+256;
	priv->txdesc_space = pci_alloc_consistent( pdev, priv->sizeof_txdesc_space, &priv->txdesc_phy_dma_addr );
	if( priv->txdesc_space == NULL ){
		printk("%s: Gigabit driver alloc txdesc_space failed.\n", netdev->name );
		return -ENOMEM;
	}
	priv->sizeof_rxdesc_space = NUM_RX_DESC * sizeof(struct RxDesc)+256;
	priv->rxdesc_space = pci_alloc_consistent( pdev, priv->sizeof_rxdesc_space, &priv->rxdesc_phy_dma_addr );
	if( priv->rxdesc_space == NULL ){
		printk("%s: Gigabit driver alloc rxdesc_space failed.\n", netdev->name );
		return -ENOMEM;
	}

	if(priv->txdesc_phy_dma_addr & 0xff){
		printk("%s: Gigabit driver txdesc_phy_dma_addr is not 256-bytes-aligned.\n", netdev->name );
	}
	if(priv->rxdesc_phy_dma_addr & 0xff){
		printk("%s: Gigabit driver rxdesc_phy_dma_addr is not 256-bytes-aligned.\n", netdev->name );
	}
	// Set tx/rx descriptor space
	priv->TxDescArray = (struct TxDesc *)priv->txdesc_space;
	priv->RxDescArray = (struct RxDesc *)priv->rxdesc_space;

	{
		int i;
		struct sk_buff *skb = NULL;

		for(i=0;i<NUM_RX_DESC;i++){
			skb = R1000_ALLOC_RXSKB(MAX_RX_SKBDATA_SIZE);
			if( skb != NULL ) {
				skb_reserve (skb, 8);	// 16 byte align the IP fields. //
				priv->Rx_skbuff[i] = skb;
			}
			else{
				printk("%s: Gigabit driver failed to allocate skbuff.\n", netdev->name);
				priv->drvinit_fail = 1;
			}
		}
	}


	//////////////////////////////////////////////////////////////////////////////
	r1000_init_ring(netdev);
	r1000_hw_start(netdev);


	// ------------------------------------------------------
	DBG_PRINT("FIX PCS -> r1000_request_timer\n");
	priv->expire_time = R1000_TIMER_EXPIRE_TIME;
	r1000_request_timer( (&priv->r1000_timer), priv->expire_time, r1000_timer_handler, ((void *)netdev) );  //in open()


	DBG_PRINT("%s: %s() alloc_rxskb_cnt = %d\n", netdev->name, __FUNCTION__, alloc_rxskb_cnt );

	return 0;

}//end of r1000_open (struct net_device *netdev)

static void r1000_hw_PHY_reset(struct net_device *netdev)
{
	int val, phy_reset_expiretime = 50;
	struct r1000_private *priv = netdev->priv;
	unsigned long ioaddr = priv->ioaddr;

	DBG_PRINT("%s: Reset RTL8169s PHY\n", netdev->name);

	val = ( R1000_READ_GMII_REG( ioaddr, 0 ) | 0x8000 ) & 0xffff;
	R1000_WRITE_GMII_REG( ioaddr, 0, val );

	do //waiting for phy reset
	{
		if( R1000_READ_GMII_REG( ioaddr, 0 ) & 0x8000 ){
			phy_reset_expiretime --;
			udelay(100);
		}
		else{
			break;
		}
	}while( phy_reset_expiretime >= 0 );

	assert( phy_reset_expiretime > 0 );
}

static void r1000_hw_PHY_config (struct net_device *netdev)
{
	struct r1000_private *priv = netdev->priv;
	void *ioaddr = (void*)priv->ioaddr;

	DBG_PRINT("priv->mcfg=%d, priv->pcfg=%d\n",priv->mcfg,priv->pcfg);

	if( priv->mcfg == MCFG_METHOD_4 ){
#if 0
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1F, 0x0001 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1b, 0x841e );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x0e, 0x7bfb );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x09, 0x273a );
#endif

		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1F, 0x0002 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0x90D0 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1F, 0x0000 );
	}else if((priv->mcfg == MCFG_METHOD_2)||(priv->mcfg == MCFG_METHOD_3)){
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1f, 0x0001 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x06, 0x006e );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x08, 0x0708 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x15, 0x4000 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x18, 0x65c7 );

		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1f, 0x0001 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x03, 0x00a1 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x02, 0x0008 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0x0120 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x00, 0x1000 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x0800 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x0000 );

		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x03, 0xff41 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x02, 0xdf60 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0x0140 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x00, 0x0077 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x7800 );
		R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x7000 );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -