patch-2.4.22 linux-2.4.22/drivers/net/sundance.c
Next file: linux-2.4.22/drivers/net/sungem.c
Previous file: linux-2.4.22/drivers/net/sonic.c
Back to the patch index
Back to the overall index
- Lines: 350
- Date:
2003-08-25 04:44:42.000000000 -0700
- Orig file:
linux-2.4.21/drivers/net/sundance.c
- Orig date:
2002-11-28 15:53:14.000000000 -0800
diff -urN linux-2.4.21/drivers/net/sundance.c linux-2.4.22/drivers/net/sundance.c
@@ -71,19 +71,36 @@
Versin LK1.06b (D-Link):
- 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)
+
+ Version LK1.09 (D-Link):
+ - Fix the flowctrl bug.
+ - Set Pause bit in MII ANAR if flow control enabled.
+
+ Version LK1.09a (ICPlus):
+ - Add the delay time in reading the contents of EEPROM
*/
#define DRV_NAME "sundance"
-#define DRV_VERSION "1.01+LK1.06b"
-#define DRV_RELDATE "6-Nov-2002"
+#define DRV_VERSION "1.01+LK1.09a"
+#define DRV_RELDATE "10-Jul-2003"
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
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).
Typical is a 64 element hash table based on the Ethernet CRC. */
static int multicast_filter_limit = 32;
@@ -129,8 +146,7 @@
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
#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__
#define __KERNEL__
@@ -181,12 +197,10 @@
MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
MODULE_LICENSE("GPL");
-MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
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(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
@@ -502,6 +516,7 @@
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 int __set_mac_addr(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_close(struct net_device *dev);
@@ -662,8 +677,8 @@
np->an_enable = 1;
}
}
- if (flowctrl == 0)
- np->flowctrl = 0;
+ if (flowctrl == 1)
+ np->flowctrl = 1;
}
/* Fibre PHY? */
@@ -678,6 +693,9 @@
/* Reset PHY */
mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET);
mdelay (300);
+ /* If flow control enabled, we need to advertise it.*/
+ if (np->flowctrl)
+ mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400);
mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
/* Force media type */
if (!np->an_enable) {
@@ -729,12 +747,14 @@
return 0;
}
+#define eeprom_delay(ee_addr) readl(ee_addr)
/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
static int __devinit eeprom_read(long ioaddr, int location)
{
- int boguscnt = 1000; /* Typical 190 ticks. */
+ int boguscnt = 10000; /* Typical 1900 ticks. */
writew(0x0200 | (location & 0xff), ioaddr + EECtrl);
do {
+ eeprom_delay(ioaddr + EECtrl);
if (! (readw(ioaddr + EECtrl) & 0x8000)) {
return readw(ioaddr + EEData);
}
@@ -847,17 +867,18 @@
if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
dev->name, dev->irq);
-
init_ring(dev);
writel(np->rx_ring_dma, ioaddr + RxListPtr);
/* 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. */
+ __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);
+#endif
if (dev->mtu > 2047)
writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
@@ -879,7 +900,7 @@
writeb(0x01, ioaddr + DebugCtrl1);
netif_start_queue(dev);
- writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
+ writew (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
@@ -925,7 +946,7 @@
printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
"negotiated capability %4.4x.\n", dev->name,
duplex ? "full" : "half", np->phys[0], negotiated);
- writew(duplex ? 0x20 : 0, ioaddr + MACCtrl0);
+ writew(readw(ioaddr + MACCtrl0) | duplex ? 0x20 : 0, ioaddr + MACCtrl0);
}
}
@@ -951,7 +972,7 @@
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
- long flag;
+ unsigned long flag;
netif_stop_queue(dev);
tasklet_disable(&np->tx_tasklet);
@@ -966,11 +987,11 @@
for (i=0; i<TX_RING_SIZE; 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[i].next_desc,
- np->tx_ring[i].status,
- (np->tx_ring[i].status >> 2) & 0xff,
- np->tx_ring[i].frag[0].addr,
- np->tx_ring[i].frag[0].length);
+ le32_to_cpu(np->tx_ring[i].next_desc),
+ le32_to_cpu(np->tx_ring[i].status),
+ (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff,
+ 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",
readl(dev->base_addr + TxListPtr),
@@ -1157,7 +1178,6 @@
struct net_device *dev = (struct net_device *)dev_instance;
struct netdev_private *np;
long ioaddr;
- int boguscnt = max_interrupt_work;
int hw_frame_id;
int tx_cnt;
int tx_status;
@@ -1226,11 +1246,14 @@
int entry = np->dirty_tx % TX_RING_SIZE;
struct sk_buff *skb;
int sw_frame_id;
- sw_frame_id = (np->tx_ring[entry].status >> 2) & 0xff;
- if (sw_frame_id == hw_frame_id &&
- !(np->tx_ring[entry].status & 0x00010000))
+ sw_frame_id = (le32_to_cpu(
+ np->tx_ring[entry].status) >> 2) & 0xff;
+ if (sw_frame_id == hw_frame_id &&
+ !(le32_to_cpu(np->tx_ring[entry].status)
+ & 0x00010000))
break;
- if (sw_frame_id == (hw_frame_id + 1) % TX_RING_SIZE)
+ if (sw_frame_id == (hw_frame_id + 1) %
+ TX_RING_SIZE)
break;
skb = np->tx_skbuff[entry];
/* Free the original skb. */
@@ -1248,7 +1271,8 @@
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
int entry = np->dirty_tx % TX_RING_SIZE;
struct sk_buff *skb;
- if (!(np->tx_ring[entry].status & 0x00010000))
+ if (!(le32_to_cpu(np->tx_ring[entry].status)
+ & 0x00010000))
break;
skb = np->tx_skbuff[entry];
/* Free the original skb. */
@@ -1271,15 +1295,7 @@
/* Abnormal error summary/uncommon events handlers. */
if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
netdev_error(dev, intr_status);
- if (--boguscnt < 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);
+ } while (0);
if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, readw(ioaddr + IntrStatus));
@@ -1447,9 +1463,12 @@
"full" : "half");
}
check_duplex (dev);
- if (np->flowctrl == 0)
- writew(readw(ioaddr + MACCtrl0) & ~EnbFlowCtrl,
+ if (np->flowctrl && np->mii_if.full_duplex) {
+ writew(readw(ioaddr + MulticastFilter1+2) | 0x0200,
+ ioaddr + MulticastFilter1+2);
+ writew(readw(ioaddr + MACCtrl0) | EnbFlowCtrl,
ioaddr + MACCtrl0);
+ }
}
if (intr_status & StatsMax) {
get_stats(dev);
@@ -1463,8 +1482,8 @@
static struct net_device_stats *get_stats(struct net_device *dev)
{
- long ioaddr = dev->base_addr;
struct netdev_private *np = dev->priv;
+ long ioaddr = dev->base_addr;
int i;
/* We should lock this segment of code for SMP eventually, although
@@ -1477,7 +1496,7 @@
np->stats.collisions += readb(ioaddr + StatsLateColl);
np->stats.collisions += readb(ioaddr + StatsMultiColl);
np->stats.collisions += readb(ioaddr + StatsOneColl);
- readb(ioaddr + StatsCarrierError);
+ np->stats.tx_carrier_errors += readb(ioaddr + StatsCarrierError);
readb(ioaddr + StatsTxDefer);
for (i = StatsTxDefer; i <= StatsMcastRx; i++)
readb(ioaddr + i);
@@ -1492,6 +1511,7 @@
static void set_rx_mode(struct net_device *dev)
{
long ioaddr = dev->base_addr;
+ struct netdev_private *np = dev->priv;
u16 mc_filter[4]; /* Multicast hash filter */
u32 rx_mode;
int i;
@@ -1524,11 +1544,28 @@
writeb(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode);
return;
}
+ if (np->mii_if.full_duplex && np->flowctrl)
+ mc_filter[3] |= 0x0200;
+
for (i = 0; i < 4; i++)
writew(mc_filter[i], ioaddr + MulticastFilter0 + i*2);
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)
{
struct netdev_private *np = dev->priv;
@@ -1615,6 +1652,7 @@
struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
int rc;
int i;
+ long ioaddr = dev->base_addr;
if (!netif_running(dev))
return -EINVAL;
@@ -1632,11 +1670,12 @@
for (i=0; i<TX_RING_SIZE; 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[i].next_desc,
- np->tx_ring[i].status,
- (np->tx_ring[i].status >> 2) & 0xff,
- np->tx_ring[i].frag[0].addr,
- np->tx_ring[i].frag[0].length);
+ le32_to_cpu(np->tx_ring[i].next_desc),
+ le32_to_cpu(np->tx_ring[i].status),
+ (le32_to_cpu(np->tx_ring[i].status) >> 2)
+ & 0xff,
+ 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",
readl(dev->base_addr + TxListPtr),
@@ -1646,6 +1685,7 @@
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_task=%d\n", np->cur_task);
+ printk(KERN_DEBUG "TxStatus=%04x\n", readw(ioaddr + TxStatus));
return 0;
}
@@ -1753,10 +1793,10 @@
}
static struct pci_driver sundance_driver = {
- name: DRV_NAME,
- id_table: sundance_pci_tbl,
- probe: sundance_probe1,
- remove: __devexit_p(sundance_remove1),
+ .name = DRV_NAME,
+ .id_table = sundance_pci_tbl,
+ .probe = sundance_probe1,
+ .remove = __devexit_p(sundance_remove1),
};
static int __init sundance_init(void)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)