Use an updated r6040 ethernet driver which implements NAPI polling

SVN-Revision: 6805
This commit is contained in:
Florian Fainelli 2007-04-01 18:40:56 +00:00
parent 2266aad2ec
commit 478fdc180a

View File

@ -1,4 +1,4 @@
/* rdc.c: A RDC FastEthernet driver for linux. */ /* r6040.c: A RDC R6040 FastEthernet driver for linux. */
/* /*
Re-written 2004 by Sten Wang. Re-written 2004 by Sten Wang.
@ -8,21 +8,33 @@
distributed according to the terms of the GNU General Public License, distributed according to the terms of the GNU General Public License,
incorporated herein by reference. incorporated herein by reference.
This driver is for RDC FastEthernet MAC series. This driver is for RDC R6040 FastEthernet MAC series.
For kernel version after 2.4.22 For kernel version after 2.4.22
Modification List Modification List
---------- ------------------------------------------------ ---------- ------------------------------------------------
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 12-22-2004 Sten Init MAC MBCR register=0x012A
PHY_CAP = 0x01E1 PHY_CAP = 0x01E1
Need to Do LIst:
1. If multicast address more than 4, use the multicast address hash
*/ */
#define FORICPLUS /* Supports ICPlus IP175C switch chip */ #define DRV_NAME "r6040"
#define BOOSTRDC /* Accelerate Ethernet performance */ #define DRV_VERSION "0.13"
#define DRV_RELDATE "24Aug2006"
#define DRV_NAME "rdc"
#define DRV_VERSION "0.6"
#define DRV_RELDATE "9July2004"
/* PHY CHIP Address */ /* PHY CHIP Address */
#define PHY1_ADDR 1 /* For MAC1 */ #define PHY1_ADDR 1 /* For MAC1 */
@ -31,7 +43,7 @@
#define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */ #define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */
/* Time in jiffies before concluding the transmitter is hung. */ /* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (400 * HZ / 1000) #define TX_TIMEOUT (6000 * HZ / 1000)
#define TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */ #define TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */
/* RDC MAC ID */ /* RDC MAC ID */
@ -47,16 +59,11 @@
#define MAX_MAC 2 #define MAX_MAC 2
/* MAC setting */ /* MAC setting */
#ifdef BOOSTRDC #define TX_DCNT 0x80 /* TX descriptor count */
#define TX_DCNT 32 /* TX descriptor count */ #define RX_DCNT 0x80 /* RX descriptor count */
#define RX_DCNT 32 /* RX descriptor count */
#else
#define TX_DCNT 0x8 /* TX descriptor count */
#define RX_DCNT 0x8 /* RX descriptor count */
#endif
#define MAX_BUF_SIZE 0x600 #define MAX_BUF_SIZE 0x600
#define ALLOC_DESC_SIZE ((TX_DCNT+RX_DCNT)*sizeof(struct rdc_descriptor)+0x10) #define ALLOC_DESC_SIZE ((TX_DCNT+RX_DCNT)*sizeof(struct r6040_descriptor)+0x10)
#define MBCR_DEFAULT 0x012A /* MAC Control Register */ #define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */
/* Debug enable or not */ /* Debug enable or not */
#define RDC_DEBUG 0 #define RDC_DEBUG 0
@ -69,6 +76,10 @@
#include <linux/module.h> #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/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/timer.h> #include <linux/timer.h>
@ -94,110 +105,114 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>"); MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>");
MODULE_DESCRIPTION("RDC R6040 PCI FastEthernet Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifdef CONFIG_R6040_NAPI
MODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet Driver");
#else
MODULE_DESCRIPTION("RDC R6040 PCI FastEthernet Driver");
#endif
//MODULE_PARM(adr_table, "2-4i"); #define R6040_INT_MASK 0x0011
MODULE_PARM_DESC(adr_table, "MAC Address (assigned)");
struct rdc_descriptor { struct r6040_descriptor {
u16 status, len; /* 0-3 */ u16 status, len; /* 0-3 */
u32 buf; /* 4-7 */ u32 buf; /* 4-7 */
u32 ndesc; /* 8-B */ u32 ndesc; /* 8-B */
u32 rev1; /* C-F */ u32 rev1; /* C-F */
char *vbufp; /* 10-13 */ char *vbufp; /* 10-13 */
struct rdc_descriptor *vndescp; /* 14-17 */ struct r6040_descriptor *vndescp; /* 14-17 */
struct sk_buff *skb_ptr; /* 18-1B */ struct sk_buff *skb_ptr; /* 18-1B */
u32 rev2; /* 1C-1F */ u32 rev2; /* 1C-1F */
} __attribute__(( aligned(32) )); } __attribute__(( aligned(32) ));
struct rdc_private { struct r6040_private {
struct net_device_stats stats; struct net_device_stats stats;
spinlock_t lock; spinlock_t lock;
struct timer_list timer; struct timer_list timer;
struct pci_dev *pdev; struct pci_dev *pdev;
struct rdc_descriptor *rx_insert_ptr; struct r6040_descriptor *rx_insert_ptr;
struct rdc_descriptor *rx_remove_ptr; struct r6040_descriptor *rx_remove_ptr;
struct rdc_descriptor *tx_insert_ptr; struct r6040_descriptor *tx_insert_ptr;
struct rdc_descriptor *tx_remove_ptr; struct r6040_descriptor *tx_remove_ptr;
u16 tx_free_desc, rx_free_desc, phy_addr, phy_mode; u16 tx_free_desc, rx_free_desc, phy_addr, phy_mode;
u16 mcr0, mcr1; u16 mcr0, mcr1;
dma_addr_t desc_dma; dma_addr_t desc_dma;
char *desc_pool; char *desc_pool;
}; };
struct rdc_chip_info { struct r6040_chip_info {
const char *name; const char *name;
u16 pci_flags; u16 pci_flags;
int io_size; int io_size;
int drv_flags; int drv_flags;
}; };
static int __devinitdata printed_version; #ifdef CONFIG_R6040_NAPI
static char version[] __devinitdata = static int NAPI_status;
KERN_INFO DRV_NAME ": RDC R6040 net driver, version " #endif
DRV_VERSION " (" DRV_RELDATE ")\n";
static struct rdc_chip_info rdc_chip_info[] __devinitdata = static int __devinitdata printed_version;
#ifdef CONFIG_R6040_NAPI
static char version[] __devinitdata =
KERN_INFO DRV_NAME ": RDC R6040 NAPI net driver, version "DRV_VERSION " (" DRV_RELDATE ")\n";
#else
static char version[] __devinitdata =
KERN_INFO DRV_NAME ": RDC R6040 net driver, version "DRV_VERSION " (" DRV_RELDATE ")\n";
#endif
static struct r6040_chip_info r6040_chip_info[] __devinitdata =
{ {
{ "RDC R6040 Knight", R6040_PCI_CMD, R6040_IO_SIZE, 0} { "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 ;
#endif
static int phy_table[] = { 0x1, 0x2}; static int phy_table[] = { 0x1, 0x2};
static u8 adr_table[2][8] = {{0x00, 0x00, 0x60, 0x00, 0x00, 0x01}, {0x00, 0x00, 0x60, 0x00, 0x00, 0x02}}; static u8 adr_table[2][8] = {{0x00, 0x00, 0x60, 0x00, 0x00, 0x01}, {0x00, 0x00, 0x60, 0x00, 0x00, 0x02}};
static int rdc_open(struct net_device *dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
static int rdc_start_xmit(struct sk_buff *skb, struct net_device *dev); module_param_array(adr_table, int, &NUM_MAC_TABLE, 0644);
static irqreturn_t rdc_interrupt(int irq, void *dev_id); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
static struct net_device_stats *rdc_get_stats(struct net_device *dev); module_param_array(adr_table, int, NUM_MAC_TABLE, 0644);
static int rdc_close(struct net_device *dev); #else
MODULE_PARM(adr_table, "2-4i");
#endif
MODULE_PARM_DESC(adr_table, "MAC Address (assigned)");
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 void set_multicast_list(struct net_device *dev);
static struct ethtool_ops netdev_ethtool_ops; static struct ethtool_ops netdev_ethtool_ops;
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static void rdc_down(struct net_device *dev); static void r6040_down(struct net_device *dev);
static void rdc_up(struct net_device *dev); static void r6040_up(struct net_device *dev);
static void rdc_tx_timeout (struct net_device *dev); static void r6040_tx_timeout (struct net_device *dev);
static void rdc_timer(unsigned long); static void r6040_timer(unsigned long);
static int phy_mode_chk(struct net_device *dev); static int phy_mode_chk(struct net_device *dev);
static int phy_read(int ioaddr, int phy_adr, int reg_idx); 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 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);
#ifdef BOOSTRDC #ifdef CONFIG_R6040_NAPI
#define rx_buf_alloc(lp) \ static int r6040_poll(struct net_device *netdev, int *budget);
do { \
struct rdc_descriptor *descptr; \
descptr = lp->rx_insert_ptr; \
while(lp->rx_free_desc < RX_DCNT){ \
descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE); \
if (!descptr->skb_ptr) break; \
descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, descptr->skb_ptr->tail, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE)); \
descptr->status = 0x8000; \
descptr = descptr->vndescp; \
lp->rx_free_desc++; \
} \
lp->rx_insert_ptr = descptr; \
} while(0)
#else
static void rx_buf_alloc(struct rdc_private *lp);
#endif #endif
#ifdef FORICPLUS
static void process_ioctl(struct net_device*, unsigned long* );
#endif
static int __devinit rdc_init_one (struct pci_dev *pdev, static int __devinit r6040_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
struct net_device *dev; struct net_device *dev;
struct rdc_private *lp; struct r6040_private *lp;
int ioaddr, io_size, err; int ioaddr, io_size, err;
static int card_idx = -1; static int card_idx = -1;
int chip_id = (int)ent->driver_data; int chip_id = (int)ent->driver_data;
RDC_DBUG("rdc_init_one()", 0); RDC_DBUG("r6040_init_one()", 0);
if (printed_version++) if (printed_version++)
printk(version); printk(version);
@ -212,7 +227,7 @@ static int __devinit rdc_init_one (struct pci_dev *pdev,
} }
/* IO Size check */ /* IO Size check */
io_size = rdc_chip_info[chip_id].io_size; io_size = r6040_chip_info[chip_id].io_size;
if (pci_resource_len (pdev, 0) < io_size) { if (pci_resource_len (pdev, 0) < io_size) {
return -ENODEV; return -ENODEV;
} }
@ -220,7 +235,7 @@ static int __devinit rdc_init_one (struct pci_dev *pdev,
ioaddr = pci_resource_start (pdev, 0); /* IO map base address */ ioaddr = pci_resource_start (pdev, 0); /* IO map base address */
pci_set_master(pdev); pci_set_master(pdev);
dev = alloc_etherdev(sizeof(struct rdc_private)); dev = alloc_etherdev(sizeof(struct r6040_private));
if (dev == NULL) if (dev == NULL)
return -ENOMEM; return -ENOMEM;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
@ -243,7 +258,7 @@ static int __devinit rdc_init_one (struct pci_dev *pdev,
card_idx++; card_idx++;
memcpy(dev->dev_addr, (u8 *)&adr_table[card_idx][0], 6); memcpy(dev->dev_addr, (u8 *)&adr_table[card_idx][0], 6);
/* Link new device into rdc_root_dev */ /* Link new device into r6040_root_dev */
lp->pdev = pdev; lp->pdev = pdev;
/* Init RDC private data */ /* Init RDC private data */
@ -251,15 +266,19 @@ static int __devinit rdc_init_one (struct pci_dev *pdev,
lp->phy_addr = phy_table[card_idx]; lp->phy_addr = phy_table[card_idx];
/* The RDC-specific entries in the device structure. */ /* The RDC-specific entries in the device structure. */
dev->open = &rdc_open; dev->open = &r6040_open;
dev->hard_start_xmit = &rdc_start_xmit; dev->hard_start_xmit = &r6040_start_xmit;
dev->stop = &rdc_close; dev->stop = &r6040_close;
dev->get_stats = &rdc_get_stats; dev->get_stats = &r6040_get_stats;
dev->set_multicast_list = &set_multicast_list; dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &netdev_ioctl; dev->do_ioctl = &netdev_ioctl;
dev->ethtool_ops = &netdev_ethtool_ops; dev->ethtool_ops = &netdev_ethtool_ops;
dev->tx_timeout = &rdc_tx_timeout; dev->tx_timeout = &r6040_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_R6040_NAPI
dev->poll = &r6040_poll;
dev->weight = 64;
#endif
/* Register net device. After this dev->name assign */ /* Register net device. After this dev->name assign */
if ((err = register_netdev(dev))) { if ((err = register_netdev(dev))) {
@ -280,7 +299,7 @@ err_out_disable:
return err; return err;
} }
static void __devexit rdc_remove_one (struct pci_dev *pdev) static void __devexit r6040_remove_one (struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
@ -292,45 +311,43 @@ static void __devexit rdc_remove_one (struct pci_dev *pdev)
} }
static int static int
rdc_open(struct net_device *dev) r6040_open(struct net_device *dev)
{ {
struct rdc_private *lp = dev->priv; struct r6040_private *lp = dev->priv;
int i; int i;
RDC_DBUG("rdc_open()", 0); RDC_DBUG("r6040_open()", 0);
/* Request IRQ and Register interrupt handler */ /* Request IRQ and Register interrupt handler */
i = request_irq(dev->irq, &rdc_interrupt, SA_SHIRQ, dev->name, dev); i = request_irq(dev->irq, &r6040_interrupt, SA_SHIRQ, dev->name, dev);
if (i) return i; if (i) return i;
/* Allocate Descriptor memory */ /* Allocate Descriptor memory */
lp->desc_pool = pci_alloc_consistent(lp->pdev, ALLOC_DESC_SIZE, &lp->desc_dma); lp->desc_pool = pci_alloc_consistent(lp->pdev, ALLOC_DESC_SIZE, &lp->desc_dma);
if (!lp->desc_pool) return -ENOMEM; if (!lp->desc_pool) return -ENOMEM;
rdc_up(dev); r6040_up(dev);
netif_start_queue(dev); netif_start_queue(dev);
#ifndef FORICPLUS
/* set and active a timer process */ /* set and active a timer process */
init_timer(&lp->timer); init_timer(&lp->timer);
lp->timer.expires = TIMER_WUT; lp->timer.expires = TIMER_WUT;
lp->timer.data = (unsigned long)dev; lp->timer.data = (unsigned long)dev;
lp->timer.function = &rdc_timer; lp->timer.function = &r6040_timer;
add_timer(&lp->timer); add_timer(&lp->timer);
#endif
return 0; return 0;
} }
static void static void
rdc_tx_timeout (struct net_device *dev) r6040_tx_timeout (struct net_device *dev)
{ {
struct rdc_private *lp = dev->priv; struct r6040_private *lp = dev->priv;
//int ioaddr = dev->base_addr; //int ioaddr = dev->base_addr;
//struct rdc_descriptor *descptr = lp->tx_remove_ptr; //struct r6040_descriptor *descptr = lp->tx_remove_ptr;
RDC_DBUG("rdc_tx_timeout()", 0); RDC_DBUG("r6040_tx_timeout()", 0);
/* Transmitter timeout, serious problems. */ /* Transmitter timeout, serious problems. */
/* Sten: Nothing need to do so far. */ /* Sten: Nothing need to do so far. */
@ -345,14 +362,14 @@ rdc_tx_timeout (struct net_device *dev)
static int static int
rdc_start_xmit(struct sk_buff *skb, struct net_device *dev) r6040_start_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct rdc_private *lp = dev->priv; struct r6040_private *lp = dev->priv;
struct rdc_descriptor *descptr; struct r6040_descriptor *descptr;
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
unsigned long flags; unsigned long flags;
RDC_DBUG("rdc_start_xmit()", 0); RDC_DBUG("r6040_start_xmit()", 0);
if (skb == NULL) /* NULL skb directly return */ if (skb == NULL) /* NULL skb directly return */
return 0; return 0;
@ -401,30 +418,46 @@ rdc_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The RDC interrupt handler. */ /* The RDC interrupt handler. */
static irqreturn_t static irqreturn_t
rdc_interrupt(int irq, void *dev_id) r6040_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct net_device *dev = dev_id; struct net_device *dev = dev_id;
struct rdc_private *lp; struct r6040_private *lp;
struct rdc_descriptor *descptr; struct r6040_descriptor *descptr;
struct sk_buff *skb_ptr; struct sk_buff *skb_ptr;
int ioaddr, status; int ioaddr, status;
unsigned long flags; unsigned long flags;
#ifdef CONFIG_R6040_NAPI
int handled = 1;
#else
int handled = 0; int handled = 0;
#endif
RDC_DBUG("rdc_interrupt()", 0); RDC_DBUG("r6040_interrupt()", 0);
if (dev == NULL) { if (dev == NULL) {
printk (KERN_ERR DRV_NAME ": INT() unknown device.\n"); printk (KERN_ERR DRV_NAME ": INT() unknown device.\n");
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
lp = (struct rdc_private *)dev->priv; lp = (struct r6040_private *)dev->priv;
spin_lock_irqsave(&lp->lock, flags); spin_lock_irqsave(&lp->lock, flags);
/* Check MAC Interrupt status */ /* Check MAC Interrupt status */
ioaddr = dev->base_addr; ioaddr = dev->base_addr;
outw(0x0, ioaddr + 0x40); /* Mask Off RDC MAC interrupt */ outw(0x0, ioaddr + 0x40); /* Mask Off RDC MAC interrupt */
status = inw(ioaddr + 0x3c); /* Read INTR status and clear */ status = inw(ioaddr + 0x3c); /* Read INTR status and clear */
#ifdef CONFIG_R6040_NAPI
if(netif_rx_schedule_prep(dev))
{
NAPI_status = status ;
__netif_rx_schedule(dev);
}
spin_unlock_irqrestore(&lp->lock, flags);
return IRQ_RETVAL(handled);
#else
/* TX interrupt request */ /* TX interrupt request */
if (status & 0x10) { if (status & 0x10) {
handled = 1; handled = 1;
@ -464,21 +497,21 @@ rdc_interrupt(int irq, void *dev_id)
} }
/* Allocate new RX buffer */ /* Allocate new RX buffer */
if (lp->rx_free_desc < RX_DCNT) rx_buf_alloc(lp); if (lp->rx_free_desc < RX_DCNT) rx_buf_alloc(lp,dev);
outw(0x0011, ioaddr + 0x40); /* TX/RX interrupt enable */ outw(R6040_INT_MASK, ioaddr + 0x40); /* TX/RX interrupt enable */
spin_unlock_irqrestore(&lp->lock, flags); spin_unlock_irqrestore(&lp->lock, flags);
#endif
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
static struct net_device_stats * static struct net_device_stats *
rdc_get_stats(struct net_device *dev) r6040_get_stats(struct net_device *dev)
{ {
struct rdc_private *lp = dev->priv; struct r6040_private *lp = dev->priv;
RDC_DBUG("rdc_get_stats()", 0); RDC_DBUG("r6040_get_stats()", 0);
return &lp->stats; return &lp->stats;
} }
@ -488,7 +521,7 @@ rdc_get_stats(struct net_device *dev)
static void static void
set_multicast_list(struct net_device *dev) set_multicast_list(struct net_device *dev)
{ {
struct rdc_private *lp = dev->priv; struct r6040_private *lp = dev->priv;
struct dev_mc_list *mcptr; struct dev_mc_list *mcptr;
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
u16 *adrp, i; u16 *adrp, i;
@ -496,24 +529,28 @@ set_multicast_list(struct net_device *dev)
RDC_DBUG("set_multicast_list()", 0); RDC_DBUG("set_multicast_list()", 0);
/* MAC Address */ /* MAC Address */
ioaddr += 0x68;
adrp = (u16 *) dev->dev_addr; adrp = (u16 *) dev->dev_addr;
outw(adrp[0], ioaddr); ioaddr += 2; outw(adrp[0], ioaddr + 0x68);
outw(adrp[1], ioaddr); ioaddr += 2; outw(adrp[1], ioaddr + 0x6A);
outw(adrp[2], ioaddr); ioaddr += 2; outw(adrp[2], ioaddr + 0x6C);
#if RDC_DEBUG #if RDC_DEBUG
printk("MAC ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]); printk("MAC ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);
#endif #endif
/* Promiscous Mode */ /* Promiscous Mode */
spin_lock_irqsave(lp->lock, flags); spin_lock_irqsave(&lp->lock, flags);
i = inw(ioaddr) & ~0x0120; /* Clear AMCP & PROM */ i = inw(ioaddr) & ~0x0120; /* Clear AMCP & PROM */
if (dev->flags & IFF_PROMISC) i |= 0x0020; if (dev->flags & IFF_PROMISC)
if (dev->mc_count > 4) i |= 0x0100; /* Too many multicast address */ {
i |= 0x0020;
lp->mcr0 |= 0x0020 ;
}
if (dev->mc_count > 4) i |= 0x0020; /* Too many multicast address */
outw(i, ioaddr); outw(i, ioaddr);
spin_unlock_irqrestore(lp->lock, flags); spin_unlock_irqrestore(&lp->lock, flags);
/* Multicast Address */ /* Multicast Address */
if (dev->mc_count > 4) /* Wait to do: Hash Table for multicast */ if (dev->mc_count > 4) /* Wait to do: Hash Table for multicast */
@ -522,24 +559,24 @@ set_multicast_list(struct net_device *dev)
/* Multicast Address 1~4 case */ /* Multicast Address 1~4 case */
for (i = 0, mcptr = dev->mc_list; (i<dev->mc_count) && (i<4); i++) { for (i = 0, mcptr = dev->mc_list; (i<dev->mc_count) && (i<4); i++) {
adrp = (u16 *)mcptr->dmi_addr; adrp = (u16 *)mcptr->dmi_addr;
outw(adrp[0], ioaddr); ioaddr += 2; outw(adrp[0], ioaddr + 0x70 + 8*i);
outw(adrp[1], ioaddr); ioaddr += 2; outw(adrp[1], ioaddr + 0x72 + 8*i);
outw(adrp[2], ioaddr); ioaddr += 2; outw(adrp[2], ioaddr + 0x74 + 8*i);
mcptr = mcptr->next; mcptr = mcptr->next;
#if RDC_DEBUG #if RDC_DEBUG
printk("M_ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]); printk("M_ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);
#endif #endif
} }
for (i = dev->mc_count; i < 4; i++) { for (i = dev->mc_count; i < 4; i++) {
outw(0xffff, ioaddr); ioaddr += 2; outw(0xffff, ioaddr + 0x68 + 8*i);
outw(0xffff, ioaddr); ioaddr += 2; outw(0xffff, ioaddr + 0x6A + 8*i);
outw(0xffff, ioaddr); ioaddr += 2; outw(0xffff, ioaddr + 0x6C + 8*i);
} }
} }
static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
{ {
struct rdc_private *rp = dev->priv; struct r6040_private *rp = dev->priv;
strcpy (info->driver, DRV_NAME); strcpy (info->driver, DRV_NAME);
strcpy (info->version, DRV_VERSION); strcpy (info->version, DRV_VERSION);
@ -551,11 +588,11 @@ static struct ethtool_ops netdev_ethtool_ops = {
}; };
static int static int
rdc_close(struct net_device *dev) r6040_close(struct net_device *dev)
{ {
struct rdc_private *lp = dev->priv; struct r6040_private *lp = dev->priv;
RDC_DBUG("rdc_close()", 0); RDC_DBUG("r6040_close()", 0);
/* deleted timer */ /* deleted timer */
del_timer_sync(&lp->timer); del_timer_sync(&lp->timer);
@ -564,7 +601,7 @@ rdc_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
rdc_down(dev); r6040_down(dev);
spin_unlock_irq(&lp->lock); spin_unlock_irq(&lp->lock);
@ -576,42 +613,19 @@ rdc_close(struct net_device *dev)
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{ {
RDC_DBUG("netdev_ioctl()", 0); RDC_DBUG("netdev_ioctl()", 0);
#ifdef FORICPLUS
switch(cmd)
{
case SIOCDEVPRIVATE:
//printk(KERN_INFO"Ethernet IOCTL: cmd SIOCDEVPRIVATE\n");
{
unsigned long *data;
unsigned long args[4];
data = (unsigned long *)rq->ifr_data;
if (copy_from_user(args, data, 4*sizeof(unsigned long)))
return -EFAULT;
process_ioctl(dev, args);
}
break;
default:
break;
}
#endif
return 0; return 0;
} }
/** /**
Stop RDC MAC and Free the allocated resource Stop RDC MAC and Free the allocated resource
*/ */
static void rdc_down(struct net_device *dev) static void r6040_down(struct net_device *dev)
{ {
struct rdc_private *lp = dev->priv; struct r6040_private *lp = dev->priv;
int i; int i;
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
RDC_DBUG("rdc_down()", 0); RDC_DBUG("r6040_down()", 0);
/* Stop MAC */ /* Stop MAC */
outw(0x0000, ioaddr + 0x40); /* Mask Off Interrupt */ outw(0x0000, ioaddr + 0x40); /* Mask Off Interrupt */
@ -645,17 +659,87 @@ static void rdc_down(struct net_device *dev)
pci_free_consistent(lp->pdev, ALLOC_DESC_SIZE, lp->desc_pool, lp->desc_dma); pci_free_consistent(lp->pdev, ALLOC_DESC_SIZE, lp->desc_pool, lp->desc_dma);
} }
/* Init RDC MAC */
static void rdc_up(struct net_device *dev)
#ifdef CONFIG_R6040_NAPI
static int r6040_poll(struct net_device *dev, int *budget)
{ {
struct rdc_private *lp = dev->priv; struct r6040_private *lp;
struct rdc_descriptor *descptr; struct r6040_descriptor *descptr;
struct sk_buff *skb_ptr;
int ioaddr, status;
unsigned long flags;
ioaddr = dev->base_addr;
lp = (struct r6040_private *)dev->priv;
unsigned long rx_work = dev->quota ;
unsigned long rx ;
#if 1
/* TX interrupt request */
if (NAPI_status & 0x10) {
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);
}
#endif
#if 1
/* RX interrupt request */
if (NAPI_status & 0x01) {
descptr = lp->rx_remove_ptr;
while(lp->rx_free_desc) {
if (descptr->status & 0x8000) break; /* No Rx packet */
skb_ptr = descptr->skb_ptr;
descptr->skb_ptr = 0;
skb_ptr->dev = dev;
skb_put(skb_ptr, descptr->len - 4);
pci_unmap_single(lp->pdev, descptr->buf, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
skb_ptr->protocol = eth_type_trans(skb_ptr, dev);
netif_receive_skb(skb_ptr); /* Send to upper layer */
lp->stats.rx_packets++;
lp->stats.rx_bytes += descptr->len;
descptr = descptr->vndescp; /* To next descriptor */
lp->rx_free_desc--;
}
lp->rx_remove_ptr = descptr;
}
/* Allocate new RX buffer */
if (lp->rx_free_desc < RX_DCNT) rx_buf_alloc(lp,dev);
local_irq_disable();
netif_rx_complete(dev);
outw(R6040_INT_MASK,ioaddr + 0x40);
local_irq_enable();
return 0;
#endif
}
#endif
/* Init RDC MAC */
static void r6040_up(struct net_device *dev)
{
struct r6040_private *lp = dev->priv;
struct r6040_descriptor *descptr;
int i; int i;
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
u32 tmp_addr; u32 tmp_addr;
dma_addr_t desc_dma, start_dma; dma_addr_t desc_dma, start_dma;
RDC_DBUG("rdc_up()", 0); RDC_DBUG("r6040_up()", 0);
/* Initilize */ /* Initilize */
lp->tx_free_desc = TX_DCNT; lp->tx_free_desc = TX_DCNT;
@ -663,9 +747,9 @@ static void rdc_up(struct net_device *dev)
/* Init descriptor */ /* Init descriptor */
memset(lp->desc_pool, 0, ALLOC_DESC_SIZE); /* Let all descriptor = 0 */ memset(lp->desc_pool, 0, ALLOC_DESC_SIZE); /* Let all descriptor = 0 */
lp->tx_insert_ptr = (struct rdc_descriptor *)lp->desc_pool; lp->tx_insert_ptr = (struct r6040_descriptor *)lp->desc_pool;
lp->tx_remove_ptr = lp->tx_insert_ptr; lp->tx_remove_ptr = lp->tx_insert_ptr;
lp->rx_insert_ptr = (struct rdc_descriptor *)lp->tx_insert_ptr+TX_DCNT; lp->rx_insert_ptr = (struct r6040_descriptor *)lp->tx_insert_ptr+TX_DCNT;
lp->rx_remove_ptr = lp->rx_insert_ptr; lp->rx_remove_ptr = lp->rx_insert_ptr;
/* Init TX descriptor */ /* Init TX descriptor */
@ -673,10 +757,10 @@ static void rdc_up(struct net_device *dev)
desc_dma = lp->desc_dma; desc_dma = lp->desc_dma;
start_dma = desc_dma; start_dma = desc_dma;
for (i = 0; i < TX_DCNT; i++) { for (i = 0; i < TX_DCNT; i++) {
descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct rdc_descriptor)); descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct r6040_descriptor));
descptr->vndescp = (descptr + 1); descptr->vndescp = (descptr + 1);
descptr = (descptr + 1); descptr = (descptr + 1);
desc_dma += sizeof(struct rdc_descriptor); desc_dma += sizeof(struct r6040_descriptor);
} }
(descptr - 1)->ndesc = cpu_to_le32(start_dma); (descptr - 1)->ndesc = cpu_to_le32(start_dma);
(descptr - 1)->vndescp = lp->tx_insert_ptr; (descptr - 1)->vndescp = lp->tx_insert_ptr;
@ -685,16 +769,16 @@ static void rdc_up(struct net_device *dev)
start_dma = desc_dma; start_dma = desc_dma;
descptr = lp->rx_insert_ptr; descptr = lp->rx_insert_ptr;
for (i = 0; i < RX_DCNT; i++) { for (i = 0; i < RX_DCNT; i++) {
descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct rdc_descriptor)); descptr->ndesc = cpu_to_le32(desc_dma + sizeof(struct r6040_descriptor));
descptr->vndescp = (descptr + 1); descptr->vndescp = (descptr + 1);
descptr = (descptr + 1); descptr = (descptr + 1);
desc_dma += sizeof(struct rdc_descriptor); desc_dma += sizeof(struct r6040_descriptor);
} }
(descptr - 1)->ndesc = cpu_to_le32(start_dma); (descptr - 1)->ndesc = cpu_to_le32(start_dma);
(descptr - 1)->vndescp = lp->rx_insert_ptr; (descptr - 1)->vndescp = lp->rx_insert_ptr;
/* Allocate buffer for RX descriptor */ /* Allocate buffer for RX descriptor */
rx_buf_alloc(lp); rx_buf_alloc(lp,dev);
#if RDC_DEBUG #if RDC_DEBUG
descptr = lp->tx_insert_ptr; descptr = lp->tx_insert_ptr;
@ -710,19 +794,17 @@ for (i = 0; i < RX_DCNT; i++) {
#endif #endif
/* MAC operation register */ /* MAC operation register */
outw(0x01, ioaddr); /* Reset MAC */ outw(0x01, ioaddr+0x04); /* Reset MAC */
outw(2 , ioaddr+0xAC); outw(2 , ioaddr+0xAC); /* Reset internal state machine */
outw(0 , ioaddr+0xAC); outw(0 , ioaddr+0xAC);
udelay(5000); udelay(5000);
/* TX and RX descriptor start Register */ /* TX and RX descriptor start Register */
tmp_addr = cpu_to_le32(lp->tx_insert_ptr); tmp_addr = cpu_to_le32(lp->tx_insert_ptr);
//timc
tmp_addr = virt_to_bus((volatile void *)tmp_addr); tmp_addr = virt_to_bus((volatile void *)tmp_addr);
outw((u16) tmp_addr, ioaddr+0x2c); outw((u16) tmp_addr, ioaddr+0x2c);
outw(tmp_addr >> 16, ioaddr+0x30); outw(tmp_addr >> 16, ioaddr+0x30);
tmp_addr = cpu_to_le32(lp->rx_insert_ptr); tmp_addr = cpu_to_le32(lp->rx_insert_ptr);
//timc
tmp_addr = virt_to_bus((volatile void *)tmp_addr); tmp_addr = virt_to_bus((volatile void *)tmp_addr);
outw((u16) tmp_addr, ioaddr+0x34); outw((u16) tmp_addr, ioaddr+0x34);
outw(tmp_addr >> 16, ioaddr+0x38); outw(tmp_addr >> 16, ioaddr+0x38);
@ -730,15 +812,6 @@ for (i = 0; i < RX_DCNT; i++) {
/* Buffer Size Register */ /* Buffer Size Register */
outw(MAX_BUF_SIZE, ioaddr+0x18); outw(MAX_BUF_SIZE, ioaddr+0x18);
#ifdef FORICPLUS
if(phy_read(ioaddr, 0, 2) == 0x0243) // ICPlus IP175C Signature
{
phy_write(ioaddr, 29,31, 0x175C); //Enable registers
}
lp->phy_mode = 0x8000;
#else
/* PHY Mode Check */ /* PHY Mode Check */
phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP); phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE); phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
@ -746,51 +819,29 @@ for (i = 0; i < RX_DCNT; i++) {
if (PHY_MODE == 0x3100) if (PHY_MODE == 0x3100)
lp->phy_mode = phy_mode_chk(dev); lp->phy_mode = phy_mode_chk(dev);
else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0; else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
#endif
/* MAC Bus Control Register */ /* MAC Bus Control Register */
outw(MBCR_DEFAULT, ioaddr+0x8); outw(MBCR_DEFAULT, ioaddr+0x8);
/* MAC TX/RX Enable */ /* MAC TX/RX Enable */
lp->mcr0 |= lp->phy_mode; lp->mcr0 |= lp->phy_mode;
// Dante
// BIT15 | BIT12 | BIT5 | BIT1
lp->mcr0 |= 0x0020;
//Xavier, only set promiscuous mode with eth1 (LAN i/f)
//This is a very bad hard code...
//if(ioaddr == 0xe900)lp->mcr0 |= 0x0020;
outw(lp->mcr0, ioaddr); outw(lp->mcr0, ioaddr);
#ifdef BOOSTRDC
/* set interrupt waiting time and packet numbers */
outw(0x0802, ioaddr + 0x0C);
outw(0x0802, ioaddr + 0x10);
#ifdef FORICPLUS
/* upgrade performance (by RDC guys) */
phy_write(ioaddr,30,17,(phy_read(ioaddr,30,17)|0x4000)); //bit 14=1
phy_write(ioaddr,30,17,~((~phy_read(ioaddr,30,17))|0x2000)); //bit 13=0
phy_write(ioaddr,0,19,0x0000);
phy_write(ioaddr,0,30,0x01F0);
#endif
#endif
/* Interrupt Mask Register */ /* Interrupt Mask Register */
outw(0x0011, ioaddr + 0x40); outw(R6040_INT_MASK, ioaddr + 0x40);
} }
/* /*
A periodic timer routine A periodic timer routine
Polling PHY Chip Link Status Polling PHY Chip Link Status
*/ */
static void rdc_timer(unsigned long data) static void r6040_timer(unsigned long data)
{ {
struct net_device *dev=(struct net_device *)data; struct net_device *dev=(struct net_device *)data;
struct rdc_private *lp = dev->priv; struct r6040_private *lp = dev->priv;
u16 ioaddr = dev->base_addr, phy_mode; u16 ioaddr = dev->base_addr, phy_mode;
RDC_DBUG("rdc_timer()", 0); RDC_DBUG("r6040_timer()", 0);
/* Polling PHY Chip Status */ /* Polling PHY Chip Status */
if (PHY_MODE == 0x3100) if (PHY_MODE == 0x3100)
@ -812,11 +863,11 @@ static void rdc_timer(unsigned long data)
add_timer(&lp->timer); add_timer(&lp->timer);
} }
#ifndef BOOSTRDC
/* Allocate skb buffer for rx descriptor */ /* Allocate skb buffer for rx descriptor */
static void rx_buf_alloc(struct rdc_private *lp) static void rx_buf_alloc(struct r6040_private *lp,struct net_device *dev)
{ {
struct rdc_descriptor *descptr; struct r6040_descriptor *descptr;
int ioaddr = dev->base_addr ;
RDC_DBUG("rx_buf_alloc()", 0); RDC_DBUG("rx_buf_alloc()", 0);
descptr = lp->rx_insert_ptr; descptr = lp->rx_insert_ptr;
@ -827,20 +878,19 @@ static void rx_buf_alloc(struct rdc_private *lp)
descptr->status = 0x8000; descptr->status = 0x8000;
descptr = descptr->vndescp; descptr = descptr->vndescp;
lp->rx_free_desc++; lp->rx_free_desc++;
outw(lp->mcr0 | 0x0002, ioaddr); //Trigger Rx DMA
} }
lp->rx_insert_ptr = descptr; lp->rx_insert_ptr = descptr;
} }
#endif
/* Status of PHY CHIP */ /* Status of PHY CHIP */
static int phy_mode_chk(struct net_device *dev) static int phy_mode_chk(struct net_device *dev)
{ {
struct r6040_private *lp = dev->priv;
struct rdc_private *lp = dev->priv;
int ioaddr = dev->base_addr, phy_dat; int ioaddr = dev->base_addr, phy_dat;
RDC_DBUG("phy_mode_chk()", 0); RDC_DBUG("phy_mode_chk()", 0);
/* PHY Link Status Check */ /* PHY Link Status Check */
phy_dat = phy_read(ioaddr, lp->phy_addr, 1); phy_dat = phy_read(ioaddr, lp->phy_addr, 1);
if (!(phy_dat & 0x4)) return 0x8000; /* Link Failed, full duplex */ if (!(phy_dat & 0x4)) return 0x8000; /* Link Failed, full duplex */
@ -861,7 +911,6 @@ static int phy_mode_chk(struct net_device *dev)
} }
return phy_dat; return phy_dat;
}; };
/* Read a word data from PHY Chip */ /* Read a word data from PHY Chip */
@ -891,90 +940,47 @@ enum {
RDC_6040 = 0 RDC_6040 = 0
}; };
static struct pci_device_id rdc_pci_tbl[] = { static struct pci_device_id r6040_pci_tbl[] = {
{0x17F3, 0x6040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040}, {0x17F3, 0x6040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},
//{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040}, //{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},
{0,} /* terminate list */ {0,} /* terminate list */
}; };
MODULE_DEVICE_TABLE(pci, rdc_pci_tbl); MODULE_DEVICE_TABLE(pci, r6040_pci_tbl);
static struct pci_driver rdc_driver = { static struct pci_driver r6040_driver = {
.name = "r6040", .name = "r6040",
.id_table = rdc_pci_tbl, .id_table = r6040_pci_tbl,
.probe = rdc_init_one, .probe = r6040_init_one,
.remove = __devexit_p(rdc_remove_one), .remove = __devexit_p(r6040_remove_one),
}; };
static int __init rdc_init (void) static int __init r6040_init (void)
{ {
RDC_DBUG("rdc_init()", 0); RDC_DBUG("r6040_init()", 0);
printk(version); printk(version);
printed_version = 1; printed_version = 1;
return pci_module_init (&rdc_driver); return pci_module_init (&r6040_driver);
} }
static void __exit rdc_cleanup (void) static void __exit r6040_cleanup (void)
{ {
RDC_DBUG("rdc_cleanup()", 0); RDC_DBUG("r6040_cleanup()", 0);
pci_unregister_driver (&rdc_driver); pci_unregister_driver (&r6040_driver);
} }
module_init(rdc_init); module_init(r6040_init);
module_exit(rdc_cleanup); module_exit(r6040_cleanup);
/* /*
* Local variables: * Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c rdc.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c r6040.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4 * c-indent-level: 4
* c-basic-offset: 4 * c-basic-offset: 4
* tab-width: 4 * tab-width: 4
* End: * End:
*/ */
#ifdef FORICPLUS
#define DMZ_GPIO 1
#define RDC3210_CFGREG_ADDR 0x0CF8
#define RDC3210_CFGREG_DATA 0x0CFC
static void process_ioctl(struct net_device *dev, unsigned long* args)
{
int ioaddr = dev->base_addr;
/* port priority */
if(args[0]&(1<<31))phy_write(ioaddr,29,19,(phy_read(ioaddr,29,19)|0x2000)); /* port 0 */
if(args[0]&(1<<29))phy_write(ioaddr,29,19,(phy_read(ioaddr,29,19)|0x0020)); /* port 1 */
if(args[0]&(1<<27))phy_write(ioaddr,29,20,(phy_read(ioaddr,29,20)|0x2000)); /* port 2 */
if(args[0]&(1<<25))phy_write(ioaddr,29,20,(phy_read(ioaddr,29,20)|0x0020)); /* port 3 */
/* DMZ LED */
{
unsigned int val;
val = 0x80000000 | (7 << 11) | ((0x48));
outl(val, RDC3210_CFGREG_ADDR);
udelay(10);
val = inl(RDC3210_CFGREG_DATA);
val |= (0x1 << DMZ_GPIO);
outl(val, RDC3210_CFGREG_DATA);
udelay(10);
val = 0x80000000 | (7 << 11) | ((0x4C));
outl(val, RDC3210_CFGREG_ADDR);
udelay(10);
val = inl(RDC3210_CFGREG_DATA);
if(args[0]&(1<<23)) /* DMZ enabled */
val &= ~(0x1 << DMZ_GPIO); /* low activated */
else val |= (0x1 << DMZ_GPIO);
outl(val, RDC3210_CFGREG_DATA);
udelay(10);
}
}
#endif /* FORICPLUS */