Commit e9e8a986 authored by Edward Peng's avatar Edward Peng Committed by Jeff Garzik

[netdrvr sundance] bug fixes, VLAN support

    - Fix tx bugs in big-endian machines
    - Remove unused max_interrupt_work module parameter, the new 
      NAPI-like rx scheme doesn't need it.
    - Remove redundancy get_stats() in intr_handler(), those 
      I/O access could affect performance in ARM-based system
    - Add Linux software VLAN support
    - Fix bug of custom mac address 
    (StationAddr register only accept word write) 
parent 46514619
...@@ -71,19 +71,29 @@ ...@@ -71,19 +71,29 @@
Versin LK1.06b (D-Link): Versin LK1.06b (D-Link):
- New tx scheme, adaptive tx_coalesce - New tx scheme, adaptive tx_coalesce
Version LK1.07 (D-Link):
- Fix tx bugs in big-endian machines
- Remove unused max_interrupt_work module parameter, the new
NAPI-like rx scheme doesn't need it.
- Remove redundancy get_stats() in intr_handler(), those
I/O access could affect performance in ARM-based system
- Add Linux software VLAN support
Version LK1.08 (D-Link):
- Fix bug of custom mac address
(StationAddr register only accept word write)
*/ */
#define DRV_NAME "sundance" #define DRV_NAME "sundance"
#define DRV_VERSION "1.01+LK1.06b" #define DRV_VERSION "1.01+LK1.08a"
#define DRV_RELDATE "6-Nov-2002" #define DRV_RELDATE "23-Apr-2003"
/* The user-configurable values. /* The user-configurable values.
These may be modified when a driver module is loaded.*/ These may be modified when a driver module is loaded.*/
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 0;
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
Typical is a 64 element hash table based on the Ethernet CRC. */ Typical is a 64 element hash table based on the Ethernet CRC. */
static int multicast_filter_limit = 32; static int multicast_filter_limit = 32;
...@@ -129,8 +139,7 @@ static char *media[MAX_UNITS]; ...@@ -129,8 +139,7 @@ static char *media[MAX_UNITS];
/* Operational parameters that usually are not changed. */ /* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */ /* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*HZ) #define TX_TIMEOUT (4*HZ)
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
#ifndef __KERNEL__ #ifndef __KERNEL__
#define __KERNEL__ #define __KERNEL__
...@@ -181,12 +190,10 @@ MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); ...@@ -181,12 +190,10 @@ MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("Sundance Alta Ethernet driver"); MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(debug, "i"); MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
MODULE_PARM(flowctrl, "i"); MODULE_PARM(flowctrl, "i");
MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt");
MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)"); MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]"); MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
...@@ -502,6 +509,7 @@ static void refill_rx (struct net_device *dev); ...@@ -502,6 +509,7 @@ static void refill_rx (struct net_device *dev);
static void netdev_error(struct net_device *dev, int intr_status); static void netdev_error(struct net_device *dev, int intr_status);
static void netdev_error(struct net_device *dev, int intr_status); static void netdev_error(struct net_device *dev, int intr_status);
static void set_rx_mode(struct net_device *dev); static void set_rx_mode(struct net_device *dev);
static int __set_mac_addr(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev); static struct net_device_stats *get_stats(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);
static int netdev_close(struct net_device *dev); static int netdev_close(struct net_device *dev);
...@@ -847,17 +855,18 @@ static int netdev_open(struct net_device *dev) ...@@ -847,17 +855,18 @@ static int netdev_open(struct net_device *dev)
if (netif_msg_ifup(np)) if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
dev->name, dev->irq); dev->name, dev->irq);
init_ring(dev); init_ring(dev);
writel(np->rx_ring_dma, ioaddr + RxListPtr); writel(np->rx_ring_dma, ioaddr + RxListPtr);
/* The Tx list pointer is written as packets are queued. */ /* The Tx list pointer is written as packets are queued. */
for (i = 0; i < 6; i++)
writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
/* Initialize other registers. */ /* Initialize other registers. */
__set_mac_addr(dev);
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
writew(dev->mtu + 18, ioaddr + MaxFrameSize);
#else
writew(dev->mtu + 14, ioaddr + MaxFrameSize); writew(dev->mtu + 14, ioaddr + MaxFrameSize);
#endif
if (dev->mtu > 2047) if (dev->mtu > 2047)
writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl); writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
...@@ -879,7 +888,7 @@ static int netdev_open(struct net_device *dev) ...@@ -879,7 +888,7 @@ static int netdev_open(struct net_device *dev)
writeb(0x01, ioaddr + DebugCtrl1); writeb(0x01, ioaddr + DebugCtrl1);
netif_start_queue(dev); netif_start_queue(dev);
writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); writew (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
if (netif_msg_ifup(np)) if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
...@@ -966,11 +975,11 @@ static void tx_timeout(struct net_device *dev) ...@@ -966,11 +975,11 @@ static void tx_timeout(struct net_device *dev)
for (i=0; i<TX_RING_SIZE; i++) { for (i=0; i<TX_RING_SIZE; i++) {
printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i, printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i,
np->tx_ring_dma + i*sizeof(*np->tx_ring), np->tx_ring_dma + i*sizeof(*np->tx_ring),
np->tx_ring[i].next_desc, le32_to_cpu(np->tx_ring[i].next_desc),
np->tx_ring[i].status, le32_to_cpu(np->tx_ring[i].status),
(np->tx_ring[i].status >> 2) & 0xff, (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff,
np->tx_ring[i].frag[0].addr, le32_to_cpu(np->tx_ring[i].frag[0].addr),
np->tx_ring[i].frag[0].length); le32_to_cpu(np->tx_ring[i].frag[0].length));
} }
printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
readl(dev->base_addr + TxListPtr), readl(dev->base_addr + TxListPtr),
...@@ -1157,7 +1166,6 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs ...@@ -1157,7 +1166,6 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
struct net_device *dev = (struct net_device *)dev_instance; struct net_device *dev = (struct net_device *)dev_instance;
struct netdev_private *np; struct netdev_private *np;
long ioaddr; long ioaddr;
int boguscnt = max_interrupt_work;
int hw_frame_id; int hw_frame_id;
int tx_cnt; int tx_cnt;
int tx_status; int tx_status;
...@@ -1229,11 +1237,14 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs ...@@ -1229,11 +1237,14 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
int entry = np->dirty_tx % TX_RING_SIZE; int entry = np->dirty_tx % TX_RING_SIZE;
struct sk_buff *skb; struct sk_buff *skb;
int sw_frame_id; int sw_frame_id;
sw_frame_id = (np->tx_ring[entry].status >> 2) & 0xff; sw_frame_id = (le32_to_cpu(
if (sw_frame_id == hw_frame_id && np->tx_ring[entry].status) >> 2) & 0xff;
!(np->tx_ring[entry].status & 0x00010000)) if (sw_frame_id == hw_frame_id &&
!(le32_to_cpu(np->tx_ring[entry].status)
& 0x00010000))
break; break;
if (sw_frame_id == (hw_frame_id + 1) % TX_RING_SIZE) if (sw_frame_id == (hw_frame_id + 1) %
TX_RING_SIZE)
break; break;
skb = np->tx_skbuff[entry]; skb = np->tx_skbuff[entry];
/* Free the original skb. */ /* Free the original skb. */
...@@ -1251,7 +1262,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs ...@@ -1251,7 +1262,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
int entry = np->dirty_tx % TX_RING_SIZE; int entry = np->dirty_tx % TX_RING_SIZE;
struct sk_buff *skb; struct sk_buff *skb;
if (!(np->tx_ring[entry].status & 0x00010000)) if (!(le32_to_cpu(np->tx_ring[entry].status)
& 0x00010000))
break; break;
skb = np->tx_skbuff[entry]; skb = np->tx_skbuff[entry];
/* Free the original skb. */ /* Free the original skb. */
...@@ -1274,15 +1286,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs ...@@ -1274,15 +1286,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
/* Abnormal error summary/uncommon events handlers. */ /* Abnormal error summary/uncommon events handlers. */
if (intr_status & (IntrPCIErr | LinkChange | StatsMax)) if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
netdev_error(dev, intr_status); netdev_error(dev, intr_status);
if (--boguscnt < 0) { } while (0);
get_stats(dev);
if (netif_msg_hw(np))
printk(KERN_WARNING "%s: Too much work at interrupt, "
"status=0x%4.4x / 0x%4.4x.\n",
dev->name, intr_status, readw(ioaddr + IntrClear));
break;
}
} while (1);
if (netif_msg_intr(np)) if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, readw(ioaddr + IntrStatus)); dev->name, readw(ioaddr + IntrStatus));
...@@ -1466,8 +1470,8 @@ static void netdev_error(struct net_device *dev, int intr_status) ...@@ -1466,8 +1470,8 @@ static void netdev_error(struct net_device *dev, int intr_status)
static struct net_device_stats *get_stats(struct net_device *dev) static struct net_device_stats *get_stats(struct net_device *dev)
{ {
long ioaddr = dev->base_addr;
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
int i; int i;
/* We should lock this segment of code for SMP eventually, although /* We should lock this segment of code for SMP eventually, although
...@@ -1480,7 +1484,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) ...@@ -1480,7 +1484,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
np->stats.collisions += readb(ioaddr + StatsLateColl); np->stats.collisions += readb(ioaddr + StatsLateColl);
np->stats.collisions += readb(ioaddr + StatsMultiColl); np->stats.collisions += readb(ioaddr + StatsMultiColl);
np->stats.collisions += readb(ioaddr + StatsOneColl); np->stats.collisions += readb(ioaddr + StatsOneColl);
readb(ioaddr + StatsCarrierError); np->stats.tx_carrier_errors += readb(ioaddr + StatsCarrierError);
readb(ioaddr + StatsTxDefer); readb(ioaddr + StatsTxDefer);
for (i = StatsTxDefer; i <= StatsMcastRx; i++) for (i = StatsTxDefer; i <= StatsMcastRx; i++)
readb(ioaddr + i); readb(ioaddr + i);
...@@ -1532,6 +1536,20 @@ static void set_rx_mode(struct net_device *dev) ...@@ -1532,6 +1536,20 @@ static void set_rx_mode(struct net_device *dev)
writeb(rx_mode, ioaddr + RxMode); writeb(rx_mode, ioaddr + RxMode);
} }
static int __set_mac_addr(struct net_device *dev)
{
u16 addr16;
addr16 = (dev->dev_addr[0] | (dev->dev_addr[1] << 8));
writew(addr16, dev->base_addr + StationAddr);
addr16 = (dev->dev_addr[2] | (dev->dev_addr[3] << 8));
writew(addr16, dev->base_addr + StationAddr+2);
addr16 = (dev->dev_addr[4] | (dev->dev_addr[5] << 8));
writew(addr16, dev->base_addr + StationAddr+4);
return 0;
}
static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
{ {
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
...@@ -1618,6 +1636,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1618,6 +1636,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
int rc; int rc;
int i; int i;
long ioaddr = dev->base_addr;
if (!netif_running(dev)) if (!netif_running(dev))
return -EINVAL; return -EINVAL;
...@@ -1635,11 +1654,12 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1635,11 +1654,12 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
for (i=0; i<TX_RING_SIZE; i++) { for (i=0; i<TX_RING_SIZE; i++) {
printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i, printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i,
np->tx_ring_dma + i*sizeof(*np->tx_ring), np->tx_ring_dma + i*sizeof(*np->tx_ring),
np->tx_ring[i].next_desc, le32_to_cpu(np->tx_ring[i].next_desc),
np->tx_ring[i].status, le32_to_cpu(np->tx_ring[i].status),
(np->tx_ring[i].status >> 2) & 0xff, (le32_to_cpu(np->tx_ring[i].status) >> 2)
np->tx_ring[i].frag[0].addr, & 0xff,
np->tx_ring[i].frag[0].length); le32_to_cpu(np->tx_ring[i].frag[0].addr),
le32_to_cpu(np->tx_ring[i].frag[0].length));
} }
printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
readl(dev->base_addr + TxListPtr), readl(dev->base_addr + TxListPtr),
...@@ -1649,6 +1669,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1649,6 +1669,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
np->dirty_tx, np->dirty_tx % TX_RING_SIZE); np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx); printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
printk(KERN_DEBUG "cur_task=%d\n", np->cur_task); printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
printk(KERN_DEBUG "TxStatus=%04x\n", readw(ioaddr + TxStatus));
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment