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

📄 r6040.c

📁 Linux Home Server 是专门为家庭和SOHO/SMB 设计的高性价比的ISCSI 存储服务器, 具有如下的特色: 强大的iscsi 存储服务器软件; 混合iscsi 和NAS 服务;
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * RDC R6040 Fast Ethernet MAC support * * Copyright (C) 2004 Sten Wang <sten.wang@rdc.com.tw> * Copyright (C) 2007 *	Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> *	Florian Fainelli <florian@openwrt.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA  02110-1301, USA.*/#include <linux/kernel.h>#include <linux/module.h>#include <linux/version.h>#include <linux/moduleparam.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>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/crc32.h>#include <linux/spinlock.h>#include <linux/bitops.h>#include <linux/io.h>#include <linux/irq.h>#include <linux/uaccess.h>#include <asm/processor.h>#define DRV_NAME	"r6040"#define DRV_VERSION	"0.19"#define DRV_RELDATE	"16Jun2008"/* define bits of a debug mask */#define DBG_PHY           0x00000001 /*!< show PHY read/write */#define DBG_FREE_BUFS     0x00000002 /*!< show calls to r6040_free_*bufs */#define DBG_RING          0x00000004 /*!< debug init./freeing of descr rings */#define DBG_RX_BUF        0x00000008 /*!< show alloc. of new rx buf (in IRQ context !) */#define DBG_TX_BUF        0x00000010 /*!< show arrival of new tx buf */#define DBG_TX_DONE       0x00000020 /*!< debug TX done */#define DBG_RX_DESCR      0x00000040 /*!< debug rx descr to be processed */#define DBG_RX_DATA       0x00000080 /*!< show some user data of incoming packet */#define DBG_EXIT          0x00000100 /*!< show exit code calls */#define DBG_INIT          0x00000200 /*!< show init. code calls */#define DBG_TX_RING_DUMP  0x00000400 /*!< dump the tx ring after creation */#define DBG_RX_RING_DUMP  0x00000800 /*!< dump the rx ring after creation */#define DBG_TX_DESCR      0x00001000 /*!< dump the setting of a descr for tx */#define DBG_TX_DATA       0x00002000 /*!< dump some tx data */#define DBG_IRQ           0x00004000 /*!< print inside the irq handler */#define DBG_POLL          0x00008000 /*!< dump info on poll procedure */#define DBG_MAC_ADDR      0x00010000 /*!< debug mac address setting */#define DBG_OPEN          0x00020000 /*!< debug open proc. */static int debug = 0;module_param(debug, int, 0);MODULE_PARM_DESC(debug, "debug mask (-1 for all)");/* define which debugs are left in the code during compilation */#define DEBUG (-1) /* all debugs */#define dbg(l, f, ...)				\  do { \    if ((DEBUG & l) && (debug & l)) { \      printk(KERN_INFO DRV_NAME " %s: " f, __FUNCTION__, ## __VA_ARGS__); \    } \  } while (0)#define err(f, ...) printk(KERN_WARNING DRV_NAME " %s: " f, __FUNCTION__, ## __VA_ARGS__)/* 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	(6000 * HZ / 1000)/* RDC MAC I/O Size */#define R6040_IO_SIZE	256/* MAX RDC MAC */#define MAX_MAC		2/* MAC registers */#define MCR0		0x00	/* Control register 0 */#define MCR1		0x04	/* Control register 1 */#define  MAC_RST	0x0001	/* Reset the MAC */#define MBCR		0x08	/* Bus control */#define MT_ICR		0x0C	/* TX interrupt control */#define MR_ICR		0x10	/* RX interrupt control */#define MTPR		0x14	/* TX poll command register */#define MR_BSR		0x18	/* RX buffer size */#define MR_DCR		0x1A	/* RX descriptor control */#define MLSR		0x1C	/* Last status */#define MMDIO		0x20	/* MDIO control register */#define  MDIO_WRITE	0x4000	/* MDIO write */#define  MDIO_READ	0x2000	/* MDIO read */#define MMRD		0x24	/* MDIO read data register */#define MMWD		0x28	/* MDIO write data register */#define MTD_SA0		0x2C	/* TX descriptor start address 0 */#define MTD_SA1		0x30	/* TX descriptor start address 1 */#define MRD_SA0		0x34	/* RX descriptor start address 0 */#define MRD_SA1		0x38	/* RX descriptor start address 1 */#define MISR		0x3C	/* Status register */#define MIER		0x40	/* INT enable register */#define  MSK_INT	0x0000	/* Mask off interrupts */#define  RX_FINISH      0x0001  /* rx finished irq */#define  RX_NO_DESC     0x0002  /* rx no descr. avail. irq */#define  RX_FIFO_FULL   0x0004  /* rx fifo full irq */#define  RX_EARLY       0x0008  /* rx early irq */#define  TX_FINISH      0x0010  /* tx finished irq */#define  TX_EARLY       0x0080  /* tx early irq */#define  EVENT_OVRFL    0x0100  /* event counter overflow irq */#define  LINK_CHANGED   0x0200  /* PHY link changed irq */#define ME_CISR		0x44	/* Event counter INT status */#define ME_CIER		0x48	/* Event counter INT enable  */#define MR_CNT		0x50	/* Successfully received packet counter */#define ME_CNT0		0x52	/* Event counter 0 */#define ME_CNT1		0x54	/* Event counter 1 */#define ME_CNT2		0x56	/* Event counter 2 */#define ME_CNT3		0x58	/* Event counter 3 */#define MT_CNT		0x5A	/* Successfully transmit packet counter */#define ME_CNT4		0x5C	/* Event counter 4 */#define MP_CNT		0x5E	/* Pause frame counter register */#define MAR0		0x60	/* Hash table 0 */#define MAR1		0x62	/* Hash table 1 */#define MAR2		0x64	/* Hash table 2 */#define MAR3		0x66	/* Hash table 3 */#define MID_0L		0x68	/* Multicast address MID0 Low */#define MID_0M		0x6A	/* Multicast address MID0 Medium */#define MID_0H		0x6C	/* Multicast address MID0 High */#define MID_1L		0x70	/* MID1 Low */#define MID_1M		0x72	/* MID1 Medium */#define MID_1H		0x74	/* MID1 High */#define MID_2L		0x78	/* MID2 Low */#define MID_2M		0x7A	/* MID2 Medium */#define MID_2H		0x7C	/* MID2 High */#define MID_3L		0x80	/* MID3 Low */#define MID_3M		0x82	/* MID3 Medium */#define MID_3H		0x84	/* MID3 High */#define PHY_CC		0x88	/* PHY status change configuration register */#define PHY_ST		0x8A	/* PHY status register */#define MAC_SM		0xAC	/* MAC status machine */#define MAC_ID		0xBE	/* Identifier register */#define TX_DCNT		0x80	/* TX descriptor count */#define RX_DCNT		0x80	/* RX descriptor count */#define MAX_BUF_SIZE	0x600#define RX_DESC_SIZE	(RX_DCNT * sizeof(struct r6040_descriptor))#define TX_DESC_SIZE	(TX_DCNT * sizeof(struct r6040_descriptor))#define MBCR_DEFAULT	0x012A	/* MAC Bus Control Register: 				   - wait 1 host clock until SDRAM bus request				     becomes high priority				   - RX FIFO: 32 byte				   - TX FIFO: 64 byte				   - FIFO transfer length: 16 byte */#define MCAST_MAX	4	/* Max number multicast addresses to filter *//* PHY settings */#define ICPLUS_PHY_ID	0x0243MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>,"	"Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>,"	"Florian Fainelli <florian@openwrt.org>");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver");/*! which rx interrupts do we allow */#define RX_INTS                        (RX_FIFO_FULL|RX_NO_DESC|RX_FINISH)/*! which tx interrupts do we allow */#define TX_INTS                        (TX_FINISH)#define INT_MASK                 (RX_INTS | TX_INTS)struct r6040_descriptor {	u16	status, len;		/* 0-3 */	__le32	buf;			/* 4-7 */	__le32	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)));/*! defines for the status field in the r6040_descriptor */#define DESC_STATUS_OWNER_MAC       (1<<15) /*!< if set the MAC is the owner of this descriptor */#define DESC_STATUS_RX_OK           (1<<14) /*!< rx was successful */#define DESC_STATUS_RX_ERR          (1<<11) /*!< rx PHY error */#define DESC_STATUS_RX_ERR_DRIBBLE  (1<<10) /*!< rx dribble packet */#define DESC_STATUS_RX_ERR_BUFLEN   (1<< 9) /*!< rx length exceeded buffer size */#define DESC_STATUS_RX_ERR_LONG     (1<< 8) /*!< rx length > maximum packet length */#define DESC_STATUS_RX_ERR_RUNT     (1<< 7) /*!< rx: packet length < 64 byte */#define DESC_STATUS_RX_ERR_CRC      (1<< 6) /*!< rx: crc error */#define DESC_STATUS_RX_BROADCAST    (1<< 5) /*!< rx: broadcast (no error) */#define DESC_STATUS_RX_MULTICAST    (1<< 4) /*!< rx: multicast (no error) */#define DESC_STATUS_RX_MCH_HIT      (1<< 3) /*!< rx: multicast hit in hash table (no error) */#define DESC_STATUS_RX_MIDH_HIT     (1<< 2) /*!< rx: MID table hit (no error) */#define DESC_STATUS_RX_IDX_MID_MASK 3       /*!< rx: mask for the index of matched MIDx */struct r6040_private {	spinlock_t lock;		/* driver 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;	struct r6040_descriptor *rx_ring;	struct r6040_descriptor *tx_ring;	dma_addr_t rx_ring_dma;	dma_addr_t tx_ring_dma;	u16	tx_free_desc, phy_addr, phy_mode;	u16	mcr0, mcr1;	u16	switch_sig;	struct net_device *dev;	struct mii_if_info mii_if;	struct napi_struct napi;	void __iomem *base;};struct net_device *parent_dev;static char *parent;module_param(parent, charp, 0444);MODULE_PARM_DESC(parent, "Parent network device name to get the MAC address from");static char version[] __devinitdata = KERN_INFO DRV_NAME	": RDC R6040 NAPI net driver,"	"version "DRV_VERSION " (" DRV_RELDATE ")\n";static int phy_table[] = { PHY1_ADDR, PHY2_ADDR };/* forward declarations */void r6040_multicast_list(struct net_device *dev);/* jal2: comment out to get more symbols for debugging *///#define STATIC static#define STATIC#if DEBUG/*! hexdump an memory area into a string. delim is taken as the delimiter between two bytes.    It is omitted if delim == '\0' */STATIC char *hex2str(void *addr, char *buf, int nr_bytes, int delim){	unsigned char *src = addr;	char *outb = buf;#define BIN2HEXDIGIT(x) ((x) < 10 ? '0'+(x) : 'A'-10+(x))	while (nr_bytes > 0) {		*outb++ = BIN2HEXDIGIT(*src>>4);		*outb++ = BIN2HEXDIGIT(*src&0xf);		if (delim)			*outb++ = delim;		nr_bytes--;		src++;	}	if (delim)		outb--;	*outb = '\0';	return buf;}#endif /* #if DEBUG *//* Read a word data from PHY Chip */STATIC int phy_read(void __iomem *ioaddr, int phy_addr, int reg){	int limit = 2048;	u16 cmd;	int rc;	iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO);	/* Wait for the read bit to be cleared */	while (limit--) {		cmd = ioread16(ioaddr + MMDIO);		if (cmd & MDIO_READ)			break;	}	if (limit <= 0)		err("phy addr x%x reg x%x timed out\n",		    phy_addr, reg);	rc=ioread16(ioaddr + MMRD);	dbg(DBG_PHY, "phy addr x%x reg x%x val x%x\n", phy_addr, reg, rc);	return rc;}/* Write a word data from PHY Chip */STATIC void phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val){	int limit = 2048;	u16 cmd;	dbg(DBG_PHY, "phy addr x%x reg x%x val x%x\n", phy_addr, reg, val);	iowrite16(val, ioaddr + MMWD);	/* Write the command to the MDIO bus */	iowrite16(MDIO_WRITE + reg + (phy_addr << 8), ioaddr + MMDIO);	/* Wait for the write bit to be cleared */	while (limit--) {		cmd = ioread16(ioaddr + MMDIO);		if (cmd & MDIO_WRITE)			break;	}	if (limit <= 0)		err("phy addr x%x reg x%x val x%x timed out\n",		    phy_addr, reg, val);}STATIC int mdio_read(struct net_device *dev, int mii_id, int reg){	struct r6040_private *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	return (phy_read(ioaddr, lp->phy_addr, reg));}STATIC void mdio_write(struct net_device *dev, int mii_id, int reg, int val){	struct r6040_private *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	phy_write(ioaddr, lp->phy_addr, reg, val);}void r6040_free_txbufs(struct net_device *dev){	struct r6040_private *lp = netdev_priv(dev);	int i;	dbg(DBG_FREE_BUFS, "ENTER\n");	for (i = 0; i < TX_DCNT; i++) {		if (lp->tx_insert_ptr->skb_ptr) {			pci_unmap_single(lp->pdev,				le32_to_cpu(lp->tx_insert_ptr->buf),				MAX_BUF_SIZE, PCI_DMA_TODEVICE);			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);			lp->rx_insert_ptr->skb_ptr = NULL;		}		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;	}	dbg(DBG_FREE_BUFS, "EXIT\n");}/*! unmap and free all rx skb */void r6040_free_rxbufs(struct net_device *dev){	struct r6040_private *lp = netdev_priv(dev);	int i;	dbg(DBG_FREE_BUFS, "ENTER\n");	for (i = 0; i < RX_DCNT; i++) {		if (lp->rx_insert_ptr->skb_ptr) {			pci_unmap_single(lp->pdev,				le32_to_cpu(lp->rx_insert_ptr->buf),				MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);			dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);			lp->rx_insert_ptr->skb_ptr = NULL;		}		lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;	}	dbg(DBG_FREE_BUFS, "EXIT\n");}void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,				 dma_addr_t desc_dma, int size){	struct r6040_descriptor *desc = desc_ring;	dma_addr_t mapping = desc_dma;	dbg(DBG_RING, "desc_ring %p desc_dma %08x size x%x\n",	    desc_ring, desc_dma, size);		while (size-- > 0) {		mapping += sizeof(*desc);		memset(desc, 0, sizeof(*desc));		desc->ndesc = cpu_to_le32(mapping);		desc->vndescp = desc + 1;		desc++;	}	/* last descriptor points to first one to close the descriptor ring */	desc--;	desc->ndesc = cpu_to_le32(desc_dma);	desc->vndescp = desc_ring;}#if (DEBUG & DBG_TX_RING_DUMP)/*! dump the tx ring to syslog */STATIC voiddump_tx_ring(struct r6040_private *lp){	int i;	struct r6040_descriptor *ptr;	printk(KERN_INFO "%s: nr_desc x%x tx_ring %p tx_ring_dma %08x "	       "tx_insert %p tx_remove %p\n",	       DRV_NAME, TX_DCNT, lp->tx_ring, lp->tx_ring_dma,	       lp->tx_insert_ptr, lp->tx_remove_ptr);	if (lp->tx_ring) {		for(i=0, ptr=lp->tx_ring; i < TX_DCNT; i++, ptr++) {			printk(KERN_INFO "%s: %d. descr: status x%x len x%x "			       "ndesc %08x vbufp %p vndescp %p skb_ptr %p\n", 			       DRV_NAME, i, ptr->status, ptr->len,			       ptr->ndesc, ptr->vbufp, ptr->vndescp, ptr->skb_ptr);		}	}}#endif /* #if (DEBUG & DBG_TX_RING_DUMP) */void r6040_init_txbufs(struct net_device *dev){	struct r6040_private *lp = netdev_priv(dev);	lp->tx_free_desc = TX_DCNT;	lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring;	r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT);#if (DEBUG & DBG_TX_RING_DUMP)	if (debug & DBG_TX_RING_DUMP) {		dump_tx_ring(lp);	}#endif}#if (DEBUG & DBG_RX_RING_DUMP)/*! dump the rx ring to syslog */STATIC voiddump_rx_ring(struct r6040_private *lp){	int i;	struct r6040_descriptor *ptr;	printk(KERN_INFO "%s: nr_desc x%x rx_ring %p rx_ring_dma %08x "	       "rx_insert %p rx_remove %p\n",	       DRV_NAME, RX_DCNT, lp->rx_ring, lp->rx_ring_dma,	       lp->rx_insert_ptr, lp->rx_remove_ptr);

⌨️ 快捷键说明

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