Use an updated r6040 ethernet driver which implements NAPI polling

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@6805 3c298f89-4303-0410-b956-a3cf2f4a3e73
master
Florian Fainelli 2007-04-01 18:40:56 +00:00
parent bcb7491164
commit 2315b7b527
1 changed files with 275 additions and 269 deletions

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.
@ -8,21 +8,33 @@
distributed according to the terms of the GNU General Public License,
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
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
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 BOOSTRDC /* Accelerate Ethernet performance */
#define DRV_NAME "rdc"
#define DRV_VERSION "0.6"
#define DRV_RELDATE "9July2004"
#define DRV_NAME "r6040"
#define DRV_VERSION "0.13"
#define DRV_RELDATE "24Aug2006"
/* PHY CHIP Address */
#define PHY1_ADDR 1 /* For MAC1 */
@ -31,7 +43,7 @@
#define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */
/* 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 */
/* RDC MAC ID */
@ -47,16 +59,11 @@
#define MAX_MAC 2
/* MAC setting */
#ifdef BOOSTRDC
#define TX_DCNT 32 /* TX 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 TX_DCNT 0x80 /* TX descriptor count */
#define RX_DCNT 0x80 /* RX descriptor count */
#define MAX_BUF_SIZE 0x600
#define ALLOC_DESC_SIZE ((TX_DCNT+RX_DCNT)*sizeof(struct rdc_descriptor)+0x10)
#define MBCR_DEFAULT 0x012A /* MAC Control Register */
#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
@ -69,6 +76,10 @@
#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>
@ -94,110 +105,114 @@
#include <asm/uaccess.h>
MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>");
MODULE_DESCRIPTION("RDC R6040 PCI FastEthernet Driver");
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");
MODULE_PARM_DESC(adr_table, "MAC Address (assigned)");
#define R6040_INT_MASK 0x0011
struct rdc_descriptor {
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 rdc_descriptor *vndescp; /* 14-17 */
struct r6040_descriptor *vndescp; /* 14-17 */
struct sk_buff *skb_ptr; /* 18-1B */
u32 rev2; /* 1C-1F */
} __attribute__(( aligned(32) ));
struct rdc_private {
struct r6040_private {
struct net_device_stats stats;
spinlock_t lock;
struct timer_list timer;
struct pci_dev *pdev;
struct rdc_descriptor *rx_insert_ptr;
struct rdc_descriptor *rx_remove_ptr;
struct rdc_descriptor *tx_insert_ptr;
struct rdc_descriptor *tx_remove_ptr;
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;
};
struct rdc_chip_info {
struct r6040_chip_info {
const char *name;
u16 pci_flags;
int io_size;
int drv_flags;
};
static int __devinitdata printed_version;
static char version[] __devinitdata =
KERN_INFO DRV_NAME ": RDC R6040 net driver, version "
DRV_VERSION " (" DRV_RELDATE ")\n";
#ifdef CONFIG_R6040_NAPI
static int NAPI_status;
#endif
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}
};
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
static int NUM_MAC_TABLE = 2 ;
#endif
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 int rdc_open(struct net_device *dev);
static int rdc_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t rdc_interrupt(int irq, void *dev_id);
static struct net_device_stats *rdc_get_stats(struct net_device *dev);
static int rdc_close(struct net_device *dev);
#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 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 rdc_down(struct net_device *dev);
static void rdc_up(struct net_device *dev);
static void rdc_tx_timeout (struct net_device *dev);
static void rdc_timer(unsigned long);
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);
#ifdef BOOSTRDC
#define rx_buf_alloc(lp) \
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);
static void rx_buf_alloc(struct r6040_private *lp,struct net_device *dev);
#ifdef CONFIG_R6040_NAPI
static int r6040_poll(struct net_device *netdev, int *budget);
#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)
{
struct net_device *dev;
struct rdc_private *lp;
struct r6040_private *lp;
int ioaddr, io_size, err;
static int card_idx = -1;
int chip_id = (int)ent->driver_data;
RDC_DBUG("rdc_init_one()", 0);
RDC_DBUG("r6040_init_one()", 0);
if (printed_version++)
printk(version);
@ -212,7 +227,7 @@ static int __devinit rdc_init_one (struct pci_dev *pdev,
}
/* 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) {
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 */
pci_set_master(pdev);
dev = alloc_etherdev(sizeof(struct rdc_private));
dev = alloc_etherdev(sizeof(struct r6040_private));
if (dev == NULL)
return -ENOMEM;
SET_MODULE_OWNER(dev);
@ -243,7 +258,7 @@ static int __devinit rdc_init_one (struct pci_dev *pdev,
card_idx++;
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;
/* 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];
/* The RDC-specific entries in the device structure. */
dev->open = &rdc_open;
dev->hard_start_xmit = &rdc_start_xmit;
dev->stop = &rdc_close;
dev->get_stats = &rdc_get_stats;
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 = &rdc_tx_timeout;
dev->tx_timeout = &r6040_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 */
if ((err = register_netdev(dev))) {
@ -280,7 +299,7 @@ err_out_disable:
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);
@ -292,45 +311,43 @@ static void __devexit rdc_remove_one (struct pci_dev *pdev)
}
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;
RDC_DBUG("rdc_open()", 0);
RDC_DBUG("r6040_open()", 0);
/* 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;
/* Allocate Descriptor memory */
lp->desc_pool = pci_alloc_consistent(lp->pdev, ALLOC_DESC_SIZE, &lp->desc_dma);
if (!lp->desc_pool) return -ENOMEM;
rdc_up(dev);
r6040_up(dev);
netif_start_queue(dev);
#ifndef FORICPLUS
/* set and active a timer process */
init_timer(&lp->timer);
lp->timer.expires = TIMER_WUT;
lp->timer.data = (unsigned long)dev;
lp->timer.function = &rdc_timer;
lp->timer.function = &r6040_timer;
add_timer(&lp->timer);
#endif
return 0;
}
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;
//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. */
/* Sten: Nothing need to do so far. */
@ -345,14 +362,14 @@ rdc_tx_timeout (struct net_device *dev)
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 rdc_descriptor *descptr;
struct r6040_private *lp = dev->priv;
struct r6040_descriptor *descptr;
int ioaddr = dev->base_addr;
unsigned long flags;
RDC_DBUG("rdc_start_xmit()", 0);
RDC_DBUG("r6040_start_xmit()", 0);
if (skb == NULL) /* NULL skb directly return */
return 0;
@ -401,30 +418,46 @@ rdc_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The RDC interrupt handler. */
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 rdc_private *lp;
struct rdc_descriptor *descptr;
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("rdc_interrupt()", 0);
RDC_DBUG("r6040_interrupt()", 0);
if (dev == NULL) {
printk (KERN_ERR DRV_NAME ": INT() unknown device.\n");
return IRQ_RETVAL(handled);
}
lp = (struct rdc_private *)dev->priv;
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
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 */
if (status & 0x10) {
handled = 1;
@ -464,21 +497,21 @@ rdc_interrupt(int irq, void *dev_id)
}
/* 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);
#endif
return IRQ_RETVAL(handled);
}
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;
}
@ -488,7 +521,7 @@ rdc_get_stats(struct net_device *dev)
static void
set_multicast_list(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
struct r6040_private *lp = dev->priv;
struct dev_mc_list *mcptr;
int ioaddr = dev->base_addr;
u16 *adrp, i;
@ -496,24 +529,28 @@ set_multicast_list(struct net_device *dev)
RDC_DBUG("set_multicast_list()", 0);
/* MAC Address */
ioaddr += 0x68;
/* MAC Address */
adrp = (u16 *) dev->dev_addr;
outw(adrp[0], ioaddr); ioaddr += 2;
outw(adrp[1], ioaddr); ioaddr += 2;
outw(adrp[2], ioaddr); ioaddr += 2;
outw(adrp[0], ioaddr + 0x68);
outw(adrp[1], ioaddr + 0x6A);
outw(adrp[2], ioaddr + 0x6C);
#if RDC_DEBUG
printk("MAC ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);
#endif
/* Promiscous Mode */
spin_lock_irqsave(lp->lock, flags);
spin_lock_irqsave(&lp->lock, flags);
i = inw(ioaddr) & ~0x0120; /* Clear AMCP & PROM */
if (dev->flags & IFF_PROMISC) i |= 0x0020;
if (dev->mc_count > 4) i |= 0x0100; /* Too many multicast address */
if (dev->flags & IFF_PROMISC)
{
i |= 0x0020;
lp->mcr0 |= 0x0020 ;
}
if (dev->mc_count > 4) i |= 0x0020; /* Too many multicast address */
outw(i, ioaddr);
spin_unlock_irqrestore(lp->lock, flags);
spin_unlock_irqrestore(&lp->lock, flags);
/* Multicast Address */
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 */
for (i = 0, mcptr = dev->mc_list; (i<dev->mc_count) && (i<4); i++) {
adrp = (u16 *)mcptr->dmi_addr;
outw(adrp[0], ioaddr); ioaddr += 2;
outw(adrp[1], ioaddr); ioaddr += 2;
outw(adrp[2], ioaddr); ioaddr += 2;
outw(adrp[0], ioaddr + 0x70 + 8*i);
outw(adrp[1], ioaddr + 0x72 + 8*i);
outw(adrp[2], ioaddr + 0x74 + 8*i);
mcptr = mcptr->next;
#if RDC_DEBUG
printk("M_ADDR: %04x %04x %04x\n", adrp[0], adrp[1], adrp[2]);
#endif
}
for (i = dev->mc_count; i < 4; i++) {
outw(0xffff, ioaddr); ioaddr += 2;
outw(0xffff, ioaddr); ioaddr += 2;
outw(0xffff, ioaddr); ioaddr += 2;
outw(0xffff, ioaddr + 0x68 + 8*i);
outw(0xffff, ioaddr + 0x6A + 8*i);
outw(0xffff, ioaddr + 0x6C + 8*i);
}
}
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->version, DRV_VERSION);
@ -551,11 +588,11 @@ static struct ethtool_ops netdev_ethtool_ops = {
};
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 */
del_timer_sync(&lp->timer);
@ -564,7 +601,7 @@ rdc_close(struct net_device *dev)
netif_stop_queue(dev);
rdc_down(dev);
r6040_down(dev);
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)
{
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;
}
/**
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 ioaddr = dev->base_addr;
RDC_DBUG("rdc_down()", 0);
RDC_DBUG("r6040_down()", 0);
/* Stop MAC */
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);
}
/* 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 rdc_descriptor *descptr;
struct r6040_private *lp;
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 ioaddr = dev->base_addr;
u32 tmp_addr;
dma_addr_t desc_dma, start_dma;
RDC_DBUG("rdc_up()", 0);
RDC_DBUG("r6040_up()", 0);
/* Initilize */
lp->tx_free_desc = TX_DCNT;
@ -663,9 +747,9 @@ static void rdc_up(struct net_device *dev)
/* Init descriptor */
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->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;
/* Init TX descriptor */
@ -673,10 +757,10 @@ static void rdc_up(struct net_device *dev)
desc_dma = lp->desc_dma;
start_dma = desc_dma;
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 = (descptr + 1);
desc_dma += sizeof(struct rdc_descriptor);
desc_dma += sizeof(struct r6040_descriptor);
}
(descptr - 1)->ndesc = cpu_to_le32(start_dma);
(descptr - 1)->vndescp = lp->tx_insert_ptr;
@ -685,16 +769,16 @@ static void rdc_up(struct net_device *dev)
start_dma = desc_dma;
descptr = lp->rx_insert_ptr;
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 = (descptr + 1);
desc_dma += sizeof(struct rdc_descriptor);
desc_dma += sizeof(struct r6040_descriptor);
}
(descptr - 1)->ndesc = cpu_to_le32(start_dma);
(descptr - 1)->vndescp = lp->rx_insert_ptr;
/* Allocate buffer for RX descriptor */
rx_buf_alloc(lp);
rx_buf_alloc(lp,dev);
#if RDC_DEBUG
descptr = lp->tx_insert_ptr;
@ -710,19 +794,17 @@ for (i = 0; i < RX_DCNT; i++) {
#endif
/* MAC operation register */
outw(0x01, ioaddr); /* Reset MAC */
outw(2 , ioaddr+0xAC);
outw(0x01, ioaddr+0x04); /* Reset MAC */
outw(2 , ioaddr+0xAC); /* Reset internal state machine */
outw(0 , ioaddr+0xAC);
udelay(5000);
/* TX and RX descriptor start Register */
tmp_addr = cpu_to_le32(lp->tx_insert_ptr);
//timc
tmp_addr = virt_to_bus((volatile void *)tmp_addr);
outw((u16) tmp_addr, ioaddr+0x2c);
outw(tmp_addr >> 16, ioaddr+0x30);
tmp_addr = cpu_to_le32(lp->rx_insert_ptr);
//timc
tmp_addr = virt_to_bus((volatile void *)tmp_addr);
outw((u16) tmp_addr, ioaddr+0x34);
outw(tmp_addr >> 16, ioaddr+0x38);
@ -730,15 +812,6 @@ for (i = 0; i < RX_DCNT; i++) {
/* Buffer Size Register */
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_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
@ -746,51 +819,29 @@ for (i = 0; i < RX_DCNT; i++) {
if (PHY_MODE == 0x3100)
lp->phy_mode = phy_mode_chk(dev);
else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
#endif
/* MAC Bus Control Register */
outw(MBCR_DEFAULT, ioaddr+0x8);
/* MAC TX/RX Enable */
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);
#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 */
outw(0x0011, ioaddr + 0x40);
outw(R6040_INT_MASK, ioaddr + 0x40);
}
/*
A periodic timer routine
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 rdc_private *lp = dev->priv;
struct r6040_private *lp = dev->priv;
u16 ioaddr = dev->base_addr, phy_mode;
RDC_DBUG("rdc_timer()", 0);
RDC_DBUG("r6040_timer()", 0);
/* Polling PHY Chip Status */
if (PHY_MODE == 0x3100)
@ -812,11 +863,11 @@ static void rdc_timer(unsigned long data)
add_timer(&lp->timer);
}
#ifndef BOOSTRDC
/* 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);
descptr = lp->rx_insert_ptr;
@ -827,20 +878,19 @@ static void rx_buf_alloc(struct rdc_private *lp)
descptr->status = 0x8000;
descptr = descptr->vndescp;
lp->rx_free_desc++;
outw(lp->mcr0 | 0x0002, ioaddr); //Trigger Rx DMA
}
lp->rx_insert_ptr = descptr;
}
#endif
/* Status of PHY CHIP */
static int phy_mode_chk(struct net_device *dev)
{
struct rdc_private *lp = dev->priv;
struct r6040_private *lp = dev->priv;
int ioaddr = dev->base_addr, phy_dat;
RDC_DBUG("phy_mode_chk()", 0);
/* PHY Link Status Check */
phy_dat = phy_read(ioaddr, lp->phy_addr, 1);
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;
};
/* Read a word data from PHY Chip */
@ -891,90 +940,47 @@ enum {
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},
//{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RDC_6040},
{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",
.id_table = rdc_pci_tbl,
.probe = rdc_init_one,
.remove = __devexit_p(rdc_remove_one),
.id_table = r6040_pci_tbl,
.probe = r6040_init_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);
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);
pci_unregister_driver (&rdc_driver);
RDC_DBUG("r6040_cleanup()", 0);
pci_unregister_driver (&r6040_driver);
}
module_init(rdc_init);
module_exit(rdc_cleanup);
module_init(r6040_init);
module_exit(r6040_cleanup);
/*
* 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-basic-offset: 4
* tab-width: 4
* 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 */