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

📄 r6040.c

📁 r6040驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* r6040.c: A RDC R6040 FastEthernet driver for linux. *//*	Re-written 2004 by Sten Wang.	Copyright 1994-2000 by Donald Becker.	Copyright 1993 United States Government as represented by the	Director, National Security Agency.	 This software may be used and	distributed according to the terms of the GNU General Public License,	incorporated herein by reference.	This driver is for RDC R6040 FastEthernet MAC series.	For kernel version after 2.4.22	Modification List	----------	------------------------------------------------	04-13-2007	Support the mac address auto download	02-14-2007	Support mii-tool to R/W phy & fix the bug which the dhcp client can not get IP	09-26-2006      Modify the Rx NAPI bug with SPD	09-14-2006	Change the previous NAPI( Tx/Rx polling) to NAPI( Rx polling )	08-24-2006	Support at linux 2.6.10 above	03-24-2006	Support NAPI	03-21-2006	By Charies,change spin_lock_irqsave(lp->lock, flags) to			spin_lock_irqsave(&lp->lock, flags) in set_multicast_list	03-15-2006      Modify the set_multicast_list ,due to when re-plug the ethernet,			it will forget the previous setting	07-12-2005      Tim, modify the set_multicast_list	03-28-2005      Tim, modify some error mac register offset in 	                function set_multicast_list	03-27-2005	Tim, Add the internal state machine reset			Sten, If multicast address more than 4, enter PROM mode			Changed rdc to r6040	12-22-2004	Sten Init MAC MBCR register=0x012A			PHY_CAP = 0x01E1	Need to Do List:	1. If multicast address more than 4, use the multicast address hash*/#define DRV_NAME	"r6040"#define DRV_VERSION	"0.17"#define DRV_RELDATE	"13Apr2007"/* PHY CHIP Address */#define PHY1_ADDR	1	/* For MAC1 */#define PHY2_ADDR	2	/* For MAC2 */#define PHY_MODE	0x3100	/* PHY CHIP Register 0 */#define PHY_CAP		0x01E1	/* PHY CHIP Register 4 *//* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT  	(600 * HZ / 1000)#define TIMER_WUT	(jiffies + HZ * 1)/* timer wakeup time : 1 second *//* RDC MAC ID */#define RDC_MAC_ID	0x6040/* RDC MAC I/O Size */#define R6040_IO_SIZE	256/* RDC Chip PCI Command */#define R6040_PCI_CMD	0x0005	/* IO, Master *//* MAX RDC MAC */#define MAX_MAC		2/* MAC setting */#define TX_DCNT		20	/* TX descriptor count */#define RX_DCNT		256	/* RX descriptor count */#define MAX_BUF_SIZE	0x600#define ALLOC_DESC_SIZE	((TX_DCNT+RX_DCNT)*sizeof(struct r6040_descriptor)+0x10)#define MBCR_DEFAULT	0x012A	/* MAC Bus Control Register *//* Debug enable or not */#define RDC_DEBUG	0#if RDC_DEBUG > 1#define RDC_DBUG(msg, value) printk("%s %x\n", msg, value);#else#define RDC_DBUG(msg, value)#endif#include <linux/module.h>#include <linux/version.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)#include <linux/moduleparam.h>#endif#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/delay.h>	/* for udelay() */#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/crc32.h>#include <linux/spinlock.h>#include <asm/processor.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>//Added by Keilven, 08/16/2006#ifdef FAST_NAT  extern software_nat_init(struct net_device *dev);  extern void shnat_external_cmd(char *cmd);#endifMODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>");MODULE_LICENSE("GPL");#ifdef CONFIG_R6040_NAPIMODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet Driver");#elseMODULE_DESCRIPTION("RDC R6040 PCI FastEthernet Driver");#endif#define RX_INT				0x0001#define TX_INT				0x0010#define RX_NO_DESC_INT			0x0002#define R6040_INT_MASK			(RX_INT | TX_INT)struct r6040_descriptor {	u16	status, len;		/* 0-3 */	u32	buf;			/* 4-7 */	u32	ndesc;			/* 8-B */	u32	rev1;			/* C-F */	char	*vbufp;			/* 10-13 */	struct r6040_descriptor *vndescp;	/* 14-17 */	struct sk_buff *skb_ptr;	/* 18-1B */	u32	rev2;			/* 1C-1F */} __attribute__(( aligned(32) ));struct r6040_private {	struct net_device_stats stats;	spinlock_t lock;  	struct timer_list timer;	struct pci_dev *pdev;	struct r6040_descriptor *rx_insert_ptr;	struct r6040_descriptor *rx_remove_ptr;	struct r6040_descriptor *tx_insert_ptr;	struct r6040_descriptor *tx_remove_ptr;	u16	tx_free_desc, rx_free_desc, phy_addr, phy_mode;	u16	mcr0, mcr1;	dma_addr_t desc_dma;	char	*desc_pool;#ifdef CONFIG_R6040_NAPI		u16 	NAPI_RX_RUNNING ;#endif	struct mii_if_info mii_if;};struct r6040_chip_info {	const char *name;	u16 pci_flags;	int io_size;	int drv_flags;};static int __devinitdata printed_version;#ifdef CONFIG_R6040_NAPIstatic char version[] __devinitdata =	KERN_INFO DRV_NAME ": RDC R6040 RX NAPI net driver, version "DRV_VERSION " (" DRV_RELDATE ")\n";	#elsestatic char version[] __devinitdata =	KERN_INFO DRV_NAME ": RDC R6040 net driver, version "DRV_VERSION " (" DRV_RELDATE ")\n";	#endifstatic struct r6040_chip_info r6040_chip_info[] __devinitdata ={	{ "RDC R6040 Knight", R6040_PCI_CMD, R6040_IO_SIZE, 0}};#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)static int NUM_MAC_TABLE = 2 ;#endifstatic int phy_table[] = {0x1, 0x2};static u8 adr_table[2][8] = {{0x00, 0x00, 0x60, 0x00, 0x00, 0x01}, {0x00, 0x00, 0x60, 0x00, 0x00, 0x02}};#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)	module_param_array(adr_table, int, &NUM_MAC_TABLE, 0644);#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) 	module_param_array(adr_table, int, NUM_MAC_TABLE, 0644);#else	MODULE_PARM(adr_table, "2-4i");#endif MODULE_PARM_DESC(adr_table, "MAC Address (assigned)");static int  mdio_read(struct net_device *dev, int phy_id, int location);static void mdio_write(struct net_device *dev, int phy_id, int location, int value);static int r6040_open(struct net_device *dev);static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev);static irqreturn_t r6040_interrupt(int irq, void *dev_id, struct pt_regs *regs);static struct net_device_stats *r6040_get_stats(struct net_device *dev);static int r6040_close(struct net_device *dev);static void set_multicast_list(struct net_device *dev);static struct ethtool_ops netdev_ethtool_ops;static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);static void r6040_down(struct net_device *dev);static void r6040_up(struct net_device *dev);static void r6040_tx_timeout (struct net_device *dev);static void r6040_timer(unsigned long);static int phy_mode_chk(struct net_device *dev);static int phy_read(int ioaddr, int phy_adr, int reg_idx);static void phy_write(int ioaddr, int phy_adr, int reg_idx, int dat);static void rx_buf_alloc(struct r6040_private *lp,struct net_device *dev);static int r6040_GetSet_MACaddress(struct net_device *dev);#ifdef CONFIG_R6040_NAPIstatic int r6040_poll(struct net_device *netdev, int *budget);#endifstatic int mdio_read(struct net_device *dev, int phy_id, int regnum){	struct r6040_private *lp = dev->priv;	long ioaddr = dev->base_addr;		return	(phy_read(ioaddr, lp->phy_addr, regnum)) ;}static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value){	struct netdev_private *np = dev->priv;	struct r6040_private *lp = dev->priv;	long ioaddr = dev->base_addr;	phy_write(ioaddr, lp->phy_addr, regnum, value);}static int __devinit r6040_init_one (struct pci_dev *pdev,					 const struct pci_device_id *ent){	struct net_device *dev;	struct r6040_private *lp;	int ioaddr, io_size, err;	static int card_idx = -1; 	int chip_id = (int)ent->driver_data;	RDC_DBUG("r6040_init_one()", 0);	if (printed_version++)		printk(version);	if ((err = pci_enable_device (pdev)))		return err;	/* this should always be supported */	if (pci_set_dma_mask(pdev, 0xffffffff)) {		printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses not supported by the card!?\n");		return  -ENODEV;	}	/* IO Size check */	io_size = r6040_chip_info[chip_id].io_size;	if (pci_resource_len  (pdev, 0) < io_size) {		return  -ENODEV;	}	ioaddr = pci_resource_start (pdev, 0);	/* IO map base address */	pci_set_master(pdev);	dev = alloc_etherdev(sizeof(struct r6040_private));	if (dev == NULL)		return -ENOMEM;	SET_MODULE_OWNER(dev);	if (pci_request_regions(pdev, DRV_NAME)) {		printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");		err = -ENODEV;		goto err_out_disable;	}	/* Init system & device */	lp = dev->priv;	dev->base_addr = ioaddr;	dev->irq = pdev->irq;	spin_lock_init(&lp->lock);	pci_set_drvdata(pdev, dev);		card_idx++;			//Check if the MAC address is 0xFFFFFFFFFFFF or 0	if(((inw(ioaddr + 0x68) ==0xFFFF) && (inw(ioaddr + 0x6A)==0xFFFF) && (inw(ioaddr + 0x6C)==0xFFFF)) ||	   ((inw(ioaddr + 0x68) == 0) && (inw(ioaddr + 0x6A)== 0) && (inw(ioaddr + 0x6C)== 0))) 	    memcpy(dev->dev_addr, (u8 *)&adr_table[card_idx][0], 6);	else	    {	  	    u16 *adrp; 	    adrp = (u16 *) dev->dev_addr;	    	    adrp[0] = inw(ioaddr + 0x68);	    adrp[1] = inw(ioaddr + 0x6A);	    adrp[2] = inw(ioaddr + 0x6C);		    }	    	/* Link new device into r6040_root_dev */	lp->pdev = pdev;	/* Init RDC private data */	lp->mcr0 = 0x1002;	lp->phy_addr = phy_table[card_idx];	/* The RDC-specific entries in the device structure. */	dev->open = &r6040_open;	dev->hard_start_xmit = &r6040_start_xmit;	dev->stop = &r6040_close;	dev->get_stats = &r6040_get_stats;	dev->set_multicast_list = &set_multicast_list;	dev->do_ioctl = &netdev_ioctl;	dev->ethtool_ops = &netdev_ethtool_ops;	dev->tx_timeout = &r6040_tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;		lp->mii_if.dev = dev;	lp->mii_if.mdio_read = mdio_read;	lp->mii_if.mdio_write = mdio_write;	lp->mii_if.phy_id = lp->phy_addr ;	lp->mii_if.phy_id_mask = 0x1f;	lp->mii_if.reg_num_mask = 0x1f;	#ifdef CONFIG_R6040_NAPI	dev->poll = &r6040_poll;	dev->weight = 64;#endif	/* Register net device. After this dev->name assign */	if ((err = register_netdev(dev))) {		printk(KERN_ERR DRV_NAME ": Failed to register net device\n");		goto err_out_res;	}	netif_carrier_on(dev);	return 0;err_out_res:	pci_release_regions(pdev);err_out_disable:	pci_disable_device(pdev);	pci_set_drvdata(pdev, NULL);	kfree(dev);	return err;}static void __devexit r6040_remove_one (struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);		unregister_netdev(dev);	pci_release_regions(pdev);	kfree(dev);	pci_disable_device(pdev);	pci_set_drvdata(pdev, NULL);}static intr6040_open(struct net_device *dev){	struct r6040_private *lp = dev->priv;	int i;	RDC_DBUG("r6040_open()", 0);		r6040_GetSet_MACaddress(dev);	/* Request IRQ and Register interrupt handler */	i = request_irq(dev->irq, &r6040_interrupt, SA_SHIRQ, dev->name, dev);	if (i) return i;	/* Allocate Descriptor memory */	lp->desc_pool = pci_alloc_consistent(lp->pdev, ALLOC_DESC_SIZE, &lp->desc_dma); 	if (!lp->desc_pool) return -ENOMEM; 	r6040_up(dev);	netif_start_queue(dev);	/* set and active a timer process */	init_timer(&lp->timer);	lp->timer.expires = TIMER_WUT;	lp->timer.data = (unsigned long)dev;	lp->timer.function = &r6040_timer;	add_timer(&lp->timer);#ifdef FAST_NAT          software_nat_init(dev);  //Added by Keilven, 08/16/2006#endif	return 0;}static voidr6040_tx_timeout (struct net_device *dev){	struct r6040_private *lp = dev->priv;	//int ioaddr = dev->base_addr;	//struct r6040_descriptor *descptr = lp->tx_remove_ptr;	RDC_DBUG("r6040_tx_timeout()", 0);	/* Transmitter timeout, serious problems. */	/* Sten: Nothing need to do so far. */	printk(KERN_ERR DRV_NAME ": Big Trobule, transmit timeout/n"); 	lp->stats.tx_errors++;	netif_stop_queue(dev);//printk("<RDC> XMT timedout: CR0 %x, CR40 %x, CR3C %x, CR2C %x, CR30 %x, CR34 %x, CR38 %x\n", inw(ioaddr), inw(ioaddr+0x40), inw(ioaddr+0x3c), inw(ioaddr+0x2c), inw(ioaddr+0x30), inw(ioaddr+0x34), inw(ioaddr+0x38));//printk("<RDC> XMT_TO: %08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);}static intr6040_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct r6040_private *lp = dev->priv;	struct r6040_descriptor *descptr;	int ioaddr = dev->base_addr;	unsigned long flags;	RDC_DBUG("r6040_start_xmit()", 0);	if (skb == NULL)	/* NULL skb directly return */ 		return 0;	if (skb->len >= MAX_BUF_SIZE) {	/* Packet too long, drop it */		dev_kfree_skb(skb);		return 0;	}	/* Critical Section */	spin_lock_irqsave(&lp->lock, flags);	/* TX resource check */	if (!lp->tx_free_desc) { 		spin_unlock_irqrestore(&lp->lock, flags);		printk(KERN_ERR DRV_NAME ": NO TX DESC "); 		return 1;	}	/* Statistic Counter */	lp->stats.tx_packets++;	lp->stats.tx_bytes += skb->len;		/* Set TX descriptor & Transmit it */	lp->tx_free_desc--;	descptr = lp->tx_insert_ptr;	if (skb->len < 0x3c) descptr->len = 0x3c;	else descptr->len = skb->len;	descptr->skb_ptr = skb;	descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));	descptr->status = 0x8000;	outw(0x01, ioaddr + 0x14);	lp->tx_insert_ptr = descptr->vndescp;#if RDC_DEBUG printk("Xmit(): %08lx:%04x %04x %08lx %08lx %08lx %08lx\n", descptr, descptr->status, descptr->len, descptr->buf, descptr->skb_ptr, descptr->ndesc, descptr->vndescp);#endif 	/* If no tx resource, stop */	if (!lp->tx_free_desc) 		netif_stop_queue(dev);	dev->trans_start = jiffies;	spin_unlock_irqrestore(&lp->lock, flags);	return 0;}/* The RDC interrupt handler. */static irqreturn_tr6040_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct r6040_private *lp;	struct r6040_descriptor *descptr;	struct sk_buff *skb_ptr;	int ioaddr, status;	unsigned long flags;#ifdef CONFIG_R6040_NAPI		int handled = 1;#else	int handled = 0;#endif		RDC_DBUG("r6040_interrupt()", 0);	if (dev == NULL) {		printk (KERN_ERR DRV_NAME ": INT() unknown device.\n");		return IRQ_RETVAL(handled);	}	lp = (struct r6040_private *)dev->priv;	spin_lock_irqsave(&lp->lock, flags);	/* Check MAC Interrupt status */	ioaddr = dev->base_addr;	outw(0x0, ioaddr + 0x40);	/* Mask Off RDC MAC interrupt */	status = inw(ioaddr + 0x3c);	/* Read INTR status and clear */	#ifdef CONFIG_R6040_NAPI			/* TX interrupt request */	if (status & 0x10) 	    {	    handled = 1;	    descptr = lp->tx_remove_ptr;	    while(lp->tx_free_desc < TX_DCNT) 	        {		if (descptr->status & 0x8000) break; /* Not complte */		skb_ptr = descptr->skb_ptr;		pci_unmap_single(lp->pdev, descptr->buf, skb_ptr->len, PCI_DMA_TODEVICE);		dev_kfree_skb_irq(skb_ptr); /* Free buffer */		descptr->skb_ptr = 0;		descptr = descptr->vndescp; /* To next descriptor */		lp->tx_free_desc++;		}	    lp->tx_remove_ptr = descptr;	    if (lp->tx_free_desc) netif_wake_queue(dev);	    } 	/* RX interrupt request */	if ((!lp->NAPI_RX_RUNNING) && (status & 0x01) )	    {	    if(netif_rx_schedule_prep(dev))		       	         		__netif_rx_schedule(dev);	        	    }	 	if(lp->NAPI_RX_RUNNING)	    outw( TX_INT , ioaddr + 0x40);		else		    outw( R6040_INT_MASK, ioaddr + 0x40);	    		spin_unlock_irqrestore(&lp->lock, flags);	return IRQ_RETVAL(handled);	#else			/* TX interrupt request */	if (status & 0x10) {		handled = 1;		descptr = lp->tx_remove_ptr;

⌨️ 快捷键说明

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