📄 r6040.c
字号:
/* * 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 + -