Commit 948d8589 authored by Jeff Garzik's avatar Jeff Garzik

Fix several bugs in DL2K Gigabit Ethernet driver, updating to

vendor revision 1.08.
Contributed by the vendor, D-Link.
parent d4446f7a
D-Link DL2000-based Gigabit Ethernet Adapter Installation D-Link DL2000-based Gigabit Ethernet Adapter Installation
for Linux for Linux
Nov 12, 2001 Jan 02, 2002
Contents Contents
======== ========
...@@ -182,7 +182,7 @@ driver. ...@@ -182,7 +182,7 @@ driver.
mtu=packet_size - Specifies the maximum packet size. default mtu=packet_size - Specifies the maximum packet size. default
is 1500. is 1500.
media=xxxxxxxxx - Specifies the media type the NIC operates at. media=media_type - Specifies the media type the NIC operates at.
autosense Autosensing active media. autosense Autosensing active media.
10mbps_hd 10Mbps half duplex. 10mbps_hd 10Mbps half duplex.
10mbps_fd 10Mbps full duplex. 10mbps_fd 10Mbps full duplex.
...@@ -195,28 +195,41 @@ media=xxxxxxxxx - Specifies the media type the NIC operates at. ...@@ -195,28 +195,41 @@ media=xxxxxxxxx - Specifies the media type the NIC operates at.
2 10Mbps full duplex. 2 10Mbps full duplex.
3 100Mbps half duplex. 3 100Mbps half duplex.
4 100Mbps full duplex. 4 100Mbps full duplex.
5 1000Mbps full duplex. 5 1000Mbps half duplex.
6 1000Mbps half duplex. 6 1000Mbps full duplex.
By default, the NIC operates at autosense. By default, the NIC operates at autosense.
Note that only 1000mbps_fd and 1000mbps_hd Note that only 1000mbps_fd and 1000mbps_hd
types are available for fiber adapter. types are available for fiber adapter.
vlan=x - Specifies the VLAN ID. If vlan=0, the vlan=[0|1] - Specifies the VLAN ID. If vlan=0, the
Virtual Local Area Network (VLAN) function is Virtual Local Area Network (VLAN) function is
disable. disable.
jumbo=x - Specifies the jumbo frame support. If jumbo=1, jumbo=[0|1] - Specifies the jumbo frame support. If jumbo=1,
the NIC accept jumbo frames. By default, this the NIC accept jumbo frames. By default, this
function is disabled. function is disabled.
Jumbo frame usually improve the performance Jumbo frame usually improve the performance
int gigabit. int gigabit.
int_count - Rx frame count each interrupt. rx_coalesce=n - Rx frame count each interrupt.
int_timeout - Rx DMA wait time for an interrupt. Proper rx_timeout=n - Rx DMA wait time for an interrupt. Proper
values of int_count and int_timeout bring values of rx_coalesce and rx_timeout bring
a conspicuous performance in the fast machine. a conspicuous performance in the fast machine.
Ex. int_count=5 and int_timeout=750 Ex. rx_coalesce=5 and rx_timeout=750
tx_coalesce=n - Tx transmit count each TxComp interrupt.
Setting value larger than 1 will improve
performance, but this is possible to lower
stability in slow UP machines. By default,
tx_coalesce=1. (dl2k)
tx_flow=[1|0] - Specifies the Tx flow control. If tx_flow=1,
the Tx flow control enable.
rx_flow=[1|0] - Specifies the Rx flow control. If rx_flow=1,
the Rx flow control enable.
Configuration Script Sample Configuration Script Sample
=========================== ===========================
......
...@@ -15,18 +15,24 @@ ...@@ -15,18 +15,24 @@
0.01 2001/05/03 Created DL2000-based linux driver 0.01 2001/05/03 Created DL2000-based linux driver
0.02 2001/05/21 Added VLAN and hardware checksum support. 0.02 2001/05/21 Added VLAN and hardware checksum support.
1.00 2001/06/26 Added jumbo frame support. 1.00 2001/06/26 Added jumbo frame support.
1.01 2001/08/21 Added two parameters, int_count and int_timeout. 1.01 2001/08/21 Added two parameters, rx_coalesce and rx_timeout.
1.02 2001/10/08 Supported fiber media. 1.02 2001/10/08 Supported fiber media.
Added flow control parameters. Added flow control parameters.
1.03 2001/10/12 Changed the default media to 1000mbps_fd for the 1.03 2001/10/12 Changed the default media to 1000mbps_fd for
fiber devices. the fiber devices.
1.04 2001/11/08 Fixed a bug which Tx stop when a very busy case. 1.04 2001/11/08 Fixed Tx stopped when tx very busy.
*/ 1.05 2001/11/22 Fixed Tx stopped when unidirectional tx busy.
1.06 2001/12/13 Fixed disconnect bug at 10Mbps mode.
Fixed tx_full flag incorrect.
Added tx_coalesce paramter.
1.07 2002/01/03 Fixed miscount of RX frame error.
1.08 2002/01/17 Fixed the multicast bug.
*/
#include "dl2k.h" #include "dl2k.h"
static char version[] __devinitdata = static char version[] __devinitdata =
KERN_INFO "D-Link DL2000-based linux driver v1.04 2001/11/08\n"; KERN_INFO "D-Link DL2000-based linux driver v1.08 2002/01/17\n";
#define MAX_UNITS 8 #define MAX_UNITS 8
static int mtu[MAX_UNITS]; static int mtu[MAX_UNITS];
...@@ -36,11 +42,13 @@ static char *media[MAX_UNITS]; ...@@ -36,11 +42,13 @@ static char *media[MAX_UNITS];
static int tx_flow[MAX_UNITS]; static int tx_flow[MAX_UNITS];
static int rx_flow[MAX_UNITS]; static int rx_flow[MAX_UNITS];
static int copy_thresh; static int copy_thresh;
static int int_count; /* Rx frame count each interrupt */ static int rx_coalesce = DEFAULT_RXC;
static int int_timeout; /* Rx DMA wait time in 64ns increments */ static int rx_timeout = DEFAULT_RXT;
static int tx_coalesce = DEFAULT_TXC;
MODULE_AUTHOR ("Edward Peng"); MODULE_AUTHOR ("Edward Peng");
MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter"); MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
MODULE_LICENSE("GPL");
MODULE_PARM (mtu, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM (mtu, "1-" __MODULE_STRING (MAX_UNITS) "i");
MODULE_PARM (media, "1-" __MODULE_STRING (MAX_UNITS) "s"); MODULE_PARM (media, "1-" __MODULE_STRING (MAX_UNITS) "s");
MODULE_PARM (vlan, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM (vlan, "1-" __MODULE_STRING (MAX_UNITS) "i");
...@@ -48,13 +56,16 @@ MODULE_PARM (jumbo, "1-" __MODULE_STRING (MAX_UNITS) "i"); ...@@ -48,13 +56,16 @@ MODULE_PARM (jumbo, "1-" __MODULE_STRING (MAX_UNITS) "i");
MODULE_PARM (tx_flow, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM (tx_flow, "1-" __MODULE_STRING (MAX_UNITS) "i");
MODULE_PARM (rx_flow, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM (rx_flow, "1-" __MODULE_STRING (MAX_UNITS) "i");
MODULE_PARM (copy_thresh, "i"); MODULE_PARM (copy_thresh, "i");
MODULE_PARM (int_count, "i"); MODULE_PARM (rx_coalesce, "i"); /* Rx frame count each interrupt */
MODULE_PARM (int_timeout, "i"); MODULE_PARM (rx_timeout, "i"); /* Rx DMA wait time in 64ns increments */
MODULE_PARM (tx_coalesce, "i"); /* HW xmit count each TxComplete [1-8] */
/* Enable the default interrupts */ /* Enable the default interrupts */
#define DEFAULT_INTR (RxDMAComplete | HostError | IntRequested | TxComplete| \
UpdateStats | LinkEvent)
#define EnableInt() \ #define EnableInt() \
writew(RxDMAComplete | HostError | IntRequested | TxComplete| \ writew(DEFAULT_INTR, ioaddr + IntEnable)
UpdateStats | LinkEvent, ioaddr + IntEnable)
static int max_intrloop = 50; static int max_intrloop = 50;
static int multicast_filter_limit = 0x40; static int multicast_filter_limit = 0x40;
...@@ -162,11 +173,11 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -162,11 +173,11 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
np->speed = 10; np->speed = 10;
np->full_duplex = 0; np->full_duplex = 0;
} else if (strcmp (media[card_idx], "1000mbps_fd") == 0 || } else if (strcmp (media[card_idx], "1000mbps_fd") == 0 ||
strcmp (media[card_idx], "5") == 0) { strcmp (media[card_idx], "6") == 0) {
np->speed=1000; np->speed=1000;
np->full_duplex=1; np->full_duplex=1;
} else if (strcmp (media[card_idx], "1000mbps_hd") == 0 || } else if (strcmp (media[card_idx], "1000mbps_hd") == 0 ||
strcmp (media[card_idx], "6") == 0) { strcmp (media[card_idx], "5") == 0) {
np->speed = 1000; np->speed = 1000;
np->full_duplex = 0; np->full_duplex = 0;
} else { } else {
...@@ -175,7 +186,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -175,7 +186,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
} }
if (jumbo[card_idx] != 0) { if (jumbo[card_idx] != 0) {
np->jumbo = 1; np->jumbo = 1;
dev->mtu = 9000; dev->mtu = MAX_JUMBO;
} else { } else {
np->jumbo = 0; np->jumbo = 0;
if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE) if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE)
...@@ -183,14 +194,17 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -183,14 +194,17 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
} }
np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ? np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ?
vlan[card_idx] : 0; vlan[card_idx] : 0;
if (int_count != 0 && int_timeout != 0) { if (rx_coalesce != 0 && rx_timeout != 0) {
np->int_count = int_count; np->rx_coalesce = rx_coalesce;
np->int_timeout = int_timeout; np->rx_timeout = rx_timeout;
np->coalesce = 1; np->coalesce = 1;
} }
np->tx_flow = (tx_flow[card_idx]) ? 1 : 0; np->tx_flow = (tx_flow[card_idx]) ? 1 : 0;
np->rx_flow = (rx_flow[card_idx]) ? 1 : 0; np->rx_flow = (rx_flow[card_idx]) ? 1 : 0;
if (tx_coalesce < 1)
tx_coalesce = 1;
if (tx_coalesce > 8)
tx_coalesce = 8;
} }
dev->open = &rio_open; dev->open = &rio_open;
dev->hard_start_xmit = &start_xmit; dev->hard_start_xmit = &start_xmit;
...@@ -201,8 +215,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -201,8 +215,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
dev->tx_timeout = &tx_timeout; dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
dev->change_mtu = &change_mtu; dev->change_mtu = &change_mtu;
#ifdef TX_HW_CHECKSUM #if 0
dev->features = NETIF_F_SG | NETIF_F_HW_CSUM; dev->features = NETIF_F_IP_CSUM;
#endif #endif
pci_set_drvdata (pdev, dev); pci_set_drvdata (pdev, dev);
...@@ -326,7 +340,7 @@ parse_eeprom (struct net_device *dev) ...@@ -326,7 +340,7 @@ parse_eeprom (struct net_device *dev)
} }
/* Check CRC */ /* Check CRC */
crc = ~ether_crc_le(256-4, sromdata); crc = ~ether_crc_le(256 - 4, sromdata);
if (psrom->crc != crc) { if (psrom->crc != crc) {
printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name); printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
return -1; return -1;
...@@ -388,13 +402,12 @@ rio_open (struct net_device *dev) ...@@ -388,13 +402,12 @@ rio_open (struct net_device *dev)
i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev); i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
if (i) if (i)
return i; return i;
/* DebugCtrl bit 4, 5, 9 must set */ /* DebugCtrl bit 4, 5, 9 must set */
writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl); writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
/* Jumbo frame */ /* Jumbo frame */
if (np->jumbo != 0) if (np->jumbo != 0)
writew (9014, ioaddr + MaxFrameSize); writew (MAX_JUMBO+14, ioaddr + MaxFrameSize);
alloc_list (dev); alloc_list (dev);
...@@ -404,7 +417,7 @@ rio_open (struct net_device *dev) ...@@ -404,7 +417,7 @@ rio_open (struct net_device *dev)
set_multicast (dev); set_multicast (dev);
if (np->coalesce) { if (np->coalesce) {
writel (np->int_count | np->int_timeout << 16, writel (np->rx_coalesce | np->rx_timeout << 16,
ioaddr + RxDMAIntCtrl); ioaddr + RxDMAIntCtrl);
} }
/* Set RIO to poll every N*320nsec. */ /* Set RIO to poll every N*320nsec. */
...@@ -441,13 +454,31 @@ tx_timeout (struct net_device *dev) ...@@ -441,13 +454,31 @@ tx_timeout (struct net_device *dev)
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
printk (KERN_WARNING "%s: Transmit timed out, TxStatus %4.4x.\n", printk (KERN_INFO "%s: Tx timed out (%4.4x), is buffer full?\n",
dev->name, readl (ioaddr + TxStatus)); dev->name, readl (ioaddr + TxStatus));
/* Free used tx skbuffs */
for (; np->cur_tx - np->old_tx > 0; np->old_tx++) {
int entry = np->old_tx % TX_RING_SIZE;
struct sk_buff *skb;
if (!(np->tx_ring[entry].status & TFDDone))
break;
skb = np->tx_skbuff[entry];
pci_unmap_single (np->pdev,
np->tx_ring[entry].fraginfo,
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq (skb);
np->tx_skbuff[entry] = 0;
}
dev->if_port = 0; dev->if_port = 0;
dev->trans_start = jiffies; dev->trans_start = jiffies;
np->stats.tx_errors++; np->stats.tx_errors++;
if (!np->tx_full) /* If the ring is no longer full, clear tx_full and
call netif_wake_queue() */
if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) {
np->tx_full = 0;
netif_wake_queue (dev); netif_wake_queue (dev);
}
} }
/* allocate and initialize Tx and Rx descriptors */ /* allocate and initialize Tx and Rx descriptors */
...@@ -465,16 +496,19 @@ alloc_list (struct net_device *dev) ...@@ -465,16 +496,19 @@ alloc_list (struct net_device *dev)
/* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */ /* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */
for (i = 0; i < TX_RING_SIZE; i++) { for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_skbuff[i] = 0; np->tx_skbuff[i] = 0;
np->tx_ring[i].status = 0; np->tx_ring[i].status = cpu_to_le64 (TFDDone);
np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma +
((i+1)%TX_RING_SIZE) *
sizeof (struct
netdev_desc));
} }
/* Initialize Rx descriptors */ /* Initialize Rx descriptors */
for (i = 0; i < RX_RING_SIZE; i++) { for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma + np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma +
((i + ((i + 1) % RX_RING_SIZE) *
1) % RX_RING_SIZE) * sizeof (struct
sizeof (struct netdev_desc));
netdev_desc));
np->rx_ring[i].status = 0; np->rx_ring[i].status = 0;
np->rx_ring[i].fraginfo = 0; np->rx_ring[i].fraginfo = 0;
np->rx_skbuff[i] = 0; np->rx_skbuff[i] = 0;
...@@ -522,13 +556,12 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -522,13 +556,12 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
entry = np->cur_tx % TX_RING_SIZE; entry = np->cur_tx % TX_RING_SIZE;
np->tx_skbuff[entry] = skb; np->tx_skbuff[entry] = skb;
txdesc = &np->tx_ring[entry]; txdesc = &np->tx_ring[entry];
txdesc->next_desc = 0;
/* Set TFDDone to avoid TxDMA gather this descriptor */ /* Set TFDDone to avoid TxDMA gather this descriptor */
txdesc->status = cpu_to_le64 (TFDDone); txdesc->status = cpu_to_le64 (TFDDone);
txdesc->status |= txdesc->status |=
cpu_to_le64 (entry | WordAlignDisable | (1 << FragCountShift)); cpu_to_le64 (entry | WordAlignDisable | (1 << FragCountShift));
#ifdef TX_HW_CHECKSUM #if 0
if (skb->ip_summed == CHECKSUM_HW) { if (skb->ip_summed == CHECKSUM_HW) {
txdesc->status |= txdesc->status |=
cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable | cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
...@@ -544,21 +577,13 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -544,21 +577,13 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
/* Send one packet each time at 10Mbps mode */ /* Send one packet each time at 10Mbps mode */
/* Tx coalescing loop do not exceed 8 */ /* Tx coalescing loop do not exceed 8 */
if (entry % 0x08 == 0 || np->speed == 10) if (entry % tx_coalesce == 0 || np->speed == 10)
txdesc->status |= cpu_to_le64 (TxIndicate); txdesc->status |= cpu_to_le64 (TxIndicate);
txdesc->fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data, txdesc->fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data,
skb->len, skb->len,
PCI_DMA_TODEVICE)); PCI_DMA_TODEVICE));
txdesc->fraginfo |= cpu_to_le64 (skb->len) << 48; txdesc->fraginfo |= cpu_to_le64 (skb->len) << 48;
/* Chain the last descriptor's pointer to this one */
if (np->last_tx)
np->last_tx->next_desc = cpu_to_le64 (np->tx_ring_dma +
entry *
sizeof (struct
netdev_desc));
np->last_tx = txdesc;
/* Clear TFDDone, then TxDMA start to send this descriptor */ /* Clear TFDDone, then TxDMA start to send this descriptor */
txdesc->status &= ~cpu_to_le64 (TFDDone); txdesc->status &= ~cpu_to_le64 (TFDDone);
...@@ -570,8 +595,10 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -570,8 +595,10 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
if (np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1 && np->speed != 10) { if (np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1 && np->speed != 10) {
/* do nothing */ /* do nothing */
} else { } else {
spin_lock_irqsave(&np->lock, flags);
np->tx_full = 1; np->tx_full = 1;
netif_stop_queue (dev); netif_stop_queue (dev);
spin_unlock_irqrestore (&np->lock, flags);
} }
/* The first TFDListPtr */ /* The first TFDListPtr */
...@@ -580,15 +607,15 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -580,15 +607,15 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
dev->base_addr + TFDListPtr0); dev->base_addr + TFDListPtr0);
writel (0, dev->base_addr + TFDListPtr1); writel (0, dev->base_addr + TFDListPtr1);
} }
spin_lock_irqsave (&np->lock, flags);
if (np->old_tx > TX_RING_SIZE) { if (np->old_tx > TX_RING_SIZE) {
spin_lock_irqsave (&np->lock, flags);
tx_shift = TX_RING_SIZE; tx_shift = TX_RING_SIZE;
np->old_tx -= tx_shift; np->old_tx -= tx_shift;
np->cur_tx -= tx_shift; np->cur_tx -= tx_shift;
spin_unlock_irqrestore (&np->lock, flags);
} }
spin_unlock_irqrestore (&np->lock, flags);
/* NETDEV WATCHDOG timer */ /* NETDEV WATCHDOG timer */
dev->trans_start = jiffies; dev->trans_start = jiffies;
return 0; return 0;
...@@ -605,33 +632,24 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -605,33 +632,24 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
ioaddr = dev->base_addr; ioaddr = dev->base_addr;
np = dev->priv; np = dev->priv;
spin_lock (&np->lock); spin_lock(&np->lock);
while (1) { while (1) {
int_status = readw (ioaddr + IntStatus) & int_status = readw (ioaddr + IntStatus);
(HostError | TxComplete | IntRequested | writew (int_status, ioaddr + IntStatus);
UpdateStats | LinkEvent | RxDMAComplete); int_status &= DEFAULT_INTR;
writew (int_status & (HostError | TxComplete | RxComplete |
IntRequested | UpdateStats | LinkEvent |
TxDMAComplete | RxDMAComplete | RFDListEnd
| RxDMAPriority), ioaddr + IntStatus);
if (int_status == 0) if (int_status == 0)
break; break;
/* Processing received packets */ /* Processing received packets */
if (int_status & RxDMAComplete) if (int_status & RxDMAComplete)
receive_packet (dev); receive_packet (dev);
/* TxComplete interrupt */ /* TxComplete interrupt */
if (int_status & TxComplete || np->tx_full) { if ((int_status & TxComplete) || np->tx_full) {
int tx_status = readl (ioaddr + TxStatus); int tx_status;
tx_status = readl (ioaddr + TxStatus);
if (tx_status & 0x01) if (tx_status & 0x01)
tx_error (dev, tx_status); tx_error (dev, tx_status);
/* Send one packet each time at 10Mbps mode */
if (np->speed == 10) {
np->tx_full = 0;
netif_wake_queue (dev);
}
/* Free used tx skbuffs */ /* Free used tx skbuffs */
for (; np->cur_tx - np->old_tx > 0; np->old_tx++) { for (;np->cur_tx - np->old_tx > 0; np->old_tx++) {
int entry = np->old_tx % TX_RING_SIZE; int entry = np->old_tx % TX_RING_SIZE;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -648,9 +666,12 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -648,9 +666,12 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
/* If the ring is no longer full, clear tx_full and /* If the ring is no longer full, clear tx_full and
call netif_wake_queue() */ call netif_wake_queue() */
if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) { if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) {
np->tx_full = 0; if (np->speed != 10 || int_status & TxComplete) {
netif_wake_queue (dev); np->tx_full = 0;
netif_wake_queue (dev);
}
} }
/* Handle uncommon events */ /* Handle uncommon events */
if (int_status & if (int_status &
(IntRequested | HostError | LinkEvent | UpdateStats)) (IntRequested | HostError | LinkEvent | UpdateStats))
...@@ -665,7 +686,7 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -665,7 +686,7 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
break; break;
} }
} }
spin_unlock (&np->lock); spin_unlock(&np->lock);
} }
static void static void
...@@ -741,7 +762,7 @@ tx_error (struct net_device *dev, int tx_status) ...@@ -741,7 +762,7 @@ tx_error (struct net_device *dev, int tx_status)
np->stats.collisions++; np->stats.collisions++;
#endif #endif
/* Restart the Tx. */ /* Restart the Tx */
writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl); writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
} }
...@@ -782,7 +803,7 @@ receive_packet (struct net_device *dev) ...@@ -782,7 +803,7 @@ receive_packet (struct net_device *dev)
if (frame_status & 0x00300000) if (frame_status & 0x00300000)
np->stats.rx_length_errors++; np->stats.rx_length_errors++;
if (frame_status & 0x00010000) if (frame_status & 0x00010000)
np->stats.rx_fifo_errors++; np->stats.rx_fifo_errors++;
if (frame_status & 0x00060000) if (frame_status & 0x00060000)
np->stats.rx_frame_errors++; np->stats.rx_frame_errors++;
if (frame_status & 0x00080000) if (frame_status & 0x00080000)
...@@ -807,7 +828,7 @@ receive_packet (struct net_device *dev) ...@@ -807,7 +828,7 @@ receive_packet (struct net_device *dev)
skb_put (skb, pkt_len); skb_put (skb, pkt_len);
} }
skb->protocol = eth_type_trans (skb, dev); skb->protocol = eth_type_trans (skb, dev);
#ifdef RX_HW_CHECKSUM #if 0
/* Checksum done by hw, but csum value unavailable. */ /* Checksum done by hw, but csum value unavailable. */
if (!(frame_status & (TCPError | UDPError | IPError))) { if (!(frame_status & (TCPError | UDPError | IPError))) {
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
...@@ -898,7 +919,7 @@ rio_error (struct net_device *dev, int int_status) ...@@ -898,7 +919,7 @@ rio_error (struct net_device *dev, int int_status)
/* PCI Error, a catastronphic error related to the bus interface /* PCI Error, a catastronphic error related to the bus interface
occurs, set GlobalReset and HostReset to reset. */ occurs, set GlobalReset and HostReset to reset. */
if (int_status & HostError) { if (int_status & HostError) {
printk (KERN_ERR "%s: PCI Error! IntStatus %4.4x.\n", printk (KERN_ERR "%s: HostError! IntStatus %4.4x.\n",
dev->name, int_status); dev->name, int_status);
writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2); writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2);
mdelay (500); mdelay (500);
...@@ -913,8 +934,8 @@ get_stats (struct net_device *dev) ...@@ -913,8 +934,8 @@ get_stats (struct net_device *dev)
u16 temp1; u16 temp1;
u16 temp2; u16 temp2;
int i; int i;
/* All statistics registers need to acknowledge, /* All statistics registers need to be acknowledged,
else overflow could cause some problem */ else statistic overflow could cause problems */
np->stats.rx_packets += readl (ioaddr + FramesRcvOk); np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
np->stats.tx_packets += readl (ioaddr + FramesXmtOk); np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
np->stats.rx_bytes += readl (ioaddr + OctetRcvOk); np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
...@@ -931,11 +952,11 @@ get_stats (struct net_device *dev) ...@@ -931,11 +952,11 @@ get_stats (struct net_device *dev)
readl (ioaddr + FramesWDeferredXmt) + temp2; readl (ioaddr + FramesWDeferredXmt) + temp2;
/* detailed rx_error */ /* detailed rx_error */
np->stats.rx_length_errors += readw (ioaddr + InRangeLengthErrors) + np->stats.rx_length_errors += readw (ioaddr + FrameTooLongErrors);
readw (ioaddr + FrameTooLongErrors);
np->stats.rx_crc_errors += readw (ioaddr + FrameCheckSeqError); np->stats.rx_crc_errors += readw (ioaddr + FrameCheckSeqError);
/* Clear all other statistic register. */ /* Clear all other statistic register. */
readw (ioaddr + InRangeLengthErrors);
readw (ioaddr + MacControlFramesXmtd); readw (ioaddr + MacControlFramesXmtd);
readw (ioaddr + BcstFramesXmtdOk); readw (ioaddr + BcstFramesXmtdOk);
readl (ioaddr + McstFramesXmtdOk); readl (ioaddr + McstFramesXmtdOk);
...@@ -960,7 +981,7 @@ int ...@@ -960,7 +981,7 @@ int
change_mtu (struct net_device *dev, int new_mtu) change_mtu (struct net_device *dev, int new_mtu)
{ {
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
int max = (np->jumbo) ? 9000 : 1536; int max = (np->jumbo) ? MAX_JUMBO : 1536;
if ((new_mtu < 68) || (new_mtu > max)) { if ((new_mtu < 68) || (new_mtu > max)) {
return -EINVAL; return -EINVAL;
...@@ -978,36 +999,42 @@ set_multicast (struct net_device *dev) ...@@ -978,36 +999,42 @@ set_multicast (struct net_device *dev)
u32 hash_table[2]; u32 hash_table[2];
u16 rx_mode = 0; u16 rx_mode = 0;
int i; int i;
int bit;
int index, crc;
struct dev_mc_list *mclist; struct dev_mc_list *mclist;
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
/* Default: receive broadcast and unicast */ hash_table[0] = hash_table[1] = 0;
rx_mode = ReceiveBroadcast | ReceiveUnicast; /* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
hash_table[1] |= 0x02000000;
if (dev->flags & IFF_PROMISC) { if (dev->flags & IFF_PROMISC) {
/* Receive all frames promiscuously. */ /* Receive all frames promiscuously. */
rx_mode |= ReceiveAllFrames; rx_mode = ReceiveAllFrames;
} else if (((dev->flags & IFF_MULTICAST) } else if ((dev->flags & IFF_ALLMULTI) ||
&& (dev->mc_count > multicast_filter_limit)) (dev->mc_count > multicast_filter_limit)) {
|| (dev->flags & IFF_ALLMULTI)) {
/* Receive broadcast and multicast frames */ /* Receive broadcast and multicast frames */
rx_mode |= ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast; rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
} else if ((dev->flags & IFF_MULTICAST) & (dev->mc_count > 0)) { } else if (dev->mc_count > 0) {
/* Receive broadcast frames and multicast frames filtering by Hashtable */ /* Receive broadcast frames and multicast frames filtering
rx_mode |= by Hashtable */
rx_mode =
ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast; ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist=mclist->next) {
crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
for (index=0, bit=0; bit<6; bit++, crc<<=1) {
if (crc & 0x80000000) index |= 1 << bit;
}
hash_table[index / 32] |= (1 << (index % 32));
}
} else {
rx_mode = ReceiveBroadcast | ReceiveUnicast;
} }
if (np->vlan) { if (np->vlan) {
/* ReceiveVLANMatch field in ReceiveMode */ /* ReceiveVLANMatch field in ReceiveMode */
rx_mode |= ReceiveVLANMatch; rx_mode |= ReceiveVLANMatch;
} }
hash_table[0] = 0x00000000;
hash_table[1] = 0x00000000;
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
set_bit (ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
hash_table);
}
writel (hash_table[0], ioaddr + HashTable0); writel (hash_table[0], ioaddr + HashTable0);
writel (hash_table[1], ioaddr + HashTable1); writel (hash_table[1], ioaddr + HashTable1);
writew (rx_mode, ioaddr + ReceiveMode); writew (rx_mode, ioaddr + ReceiveMode);
...@@ -1677,8 +1704,9 @@ module_exit (rio_exit); ...@@ -1677,8 +1704,9 @@ module_exit (rio_exit);
Compile command: Compile command:
gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2x.c gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2k.c
Read Documentation/networking/dl2k.txt for details. Read Documentation/networking/dl2k.txt for details.
*/ */
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/time.h> #include <linux/time.h>
#define TX_RING_SIZE 128 #define TX_RING_SIZE 128
#define TX_QUEUE_LEN 96 /* Limit ring entries actually used. */ #define TX_QUEUE_LEN 120 /* Limit ring entries actually used. */
#define RX_RING_SIZE 128 #define RX_RING_SIZE 128
#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc) #define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc)
#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc)
...@@ -183,12 +183,12 @@ enum IntStatus_bits { ...@@ -183,12 +183,12 @@ enum IntStatus_bits {
/* Bits in the ReceiveMode register. */ /* Bits in the ReceiveMode register. */
enum ReceiveMode_bits { enum ReceiveMode_bits {
ReceiveIPMulticast = 0x0020,
ReceiveMulticastHash = 0x0010,
ReceiveAllFrames = 0x0008,
ReceiveBroadcast = 0x0004,
ReceiveMulticast = 0x0002,
ReceiveUnicast = 0x0001, ReceiveUnicast = 0x0001,
ReceiveMulticast = 0x0002,
ReceiveBroadcast = 0x0004,
ReceiveAllFrames = 0x0008,
ReceiveMulticastHash = 0x0010,
ReceiveIPMulticast = 0x0020,
ReceiveVLANMatch = 0x0100, ReceiveVLANMatch = 0x0100,
ReceiveVLANHash = 0x0200, ReceiveVLANHash = 0x0200,
}; };
...@@ -650,20 +650,20 @@ struct netdev_private { ...@@ -650,20 +650,20 @@ struct netdev_private {
struct pci_dev *pdev; struct pci_dev *pdev;
spinlock_t lock; spinlock_t lock;
struct net_device_stats stats; struct net_device_stats stats;
unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int rx_buf_sz; /* Based on MTU+slack. */
unsigned int speed; /* Operating speed */ unsigned int speed; /* Operating speed */
unsigned int vlan; /* VLAN Id */ unsigned int vlan; /* VLAN Id */
unsigned int chip_id; /* PCI table chip id */ unsigned int chip_id; /* PCI table chip id */
unsigned int int_count; /* Maximum frames each RxDMAComplete intr */ unsigned int rx_coalesce; /* Maximum frames each RxDMAComplete intr */
unsigned int int_timeout; /* Wait time between RxDMAComplete intr */ unsigned int rx_timeout; /* Wait time between RxDMAComplete intr */
unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int an_enable:2; /* Auto-Negotiated Enable */ unsigned int an_enable:2; /* Auto-Negotiated Enable */
unsigned int jumbo:1; /* Jumbo frame enable */ unsigned int jumbo:1; /* Jumbo frame enable */
unsigned int coalesce:1; /* Rx coalescing enable */ unsigned int coalesce:1; /* Rx coalescing enable */
unsigned int tx_flow:1; /* Tx flow control enable */ unsigned int tx_flow:1; /* Tx flow control enable */
unsigned int rx_flow:1; /* Rx flow control enable */ unsigned int rx_flow:1; /* Rx flow control enable */
unsigned int phy_media:1; /* 1: fiber, 0: copper */ unsigned int phy_media:1; /* 1: fiber, 0: copper */
struct netdev_desc *last_tx; /* Last Tx descriptor used. */ struct netdev_desc *last_tx; /* Last Tx descriptor used. */
unsigned long cur_rx, old_rx; /* Producer/consumer ring indices */ unsigned long cur_rx, old_rx; /* Producer/consumer ring indices */
unsigned long cur_tx, old_tx; unsigned long cur_tx, old_tx;
...@@ -698,7 +698,12 @@ static struct pci_device_id rio_pci_tbl[] __devinitdata = { ...@@ -698,7 +698,12 @@ static struct pci_device_id rio_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE (pci, rio_pci_tbl); MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
#define TX_TIMEOUT (4*HZ) #define TX_TIMEOUT (4*HZ)
#define PACKET_SIZE 1536 #define PACKET_SIZE 1536
#define MAX_JUMBO 8000
#define RIO_IO_SIZE 340 #define RIO_IO_SIZE 340
#define DEFAULT_RXC 5
#define DEFAULT_RXT 750
#define DEFAULT_TXC 1
#define MAX_TXC 8
#ifdef RIO_DEBUG #ifdef RIO_DEBUG
#define DEBUG_TFD_DUMP(x) debug_tfd_dump(x) #define DEBUG_TFD_DUMP(x) debug_tfd_dump(x)
#define DEBUG_RFD_DUMP(x,flag) debug_rfd_dump(x,flag) #define DEBUG_RFD_DUMP(x,flag) debug_rfd_dump(x,flag)
......
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