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

📄 r1000_n.c

📁 REALTEC RTL8618 8111 Driver for linux 版权归周立发
💻 C
📖 第 1 页 / 共 4 页
字号:
//=========================================================================
//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 + -