patch-2.4.0-test8 linux/drivers/net/natsemi.c
Next file: linux/drivers/net/ncr885e.c
Previous file: linux/drivers/net/epic100.c
Back to the patch index
Back to the overall index
- Lines: 293
- Date:
Tue Sep 5 12:57:51 2000
- Orig file:
v2.4.0-test7/linux/drivers/net/natsemi.c
- Orig date:
Wed Aug 23 18:36:38 2000
diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c
@@ -17,6 +17,14 @@
Support information and updates available at
http://www.scyld.com/network/netsemi.html
+
+
+ Linux kernel modifications:
+
+ Version 1.0.1:
+ - Spinlock fixes
+ - Bug fixes and better intr performance (Tjeerd)
+
*/
/* These identify the driver base version and may not be removed. */
@@ -25,7 +33,7 @@
static const char version2[] =
" http://www.scyld.com/network/natsemi.html\n";
static const char version3[] =
-" (unofficial 2.4.x kernel port, version 1.0.0, August 10, 2000)\n";
+" (unofficial 2.4.x kernel port, version 1.0.1, September 5, 2000 Jeff Garzik, Tjeerd Mulder)\n";
/* Updated to recommendations in pci-skeleton v2.03. */
/* Automatically extracted configuration info:
@@ -193,7 +201,8 @@
http://www.scyld.com/expert/100mbps.html
http://www.scyld.com/expert/NWay.html
-No NatSemi datasheet was publically available at the initial release date.
+Datasheet is available from:
+http://www.national.com/pf/DP/DP83815.html
IVc. Errata
@@ -237,7 +246,7 @@
ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C,
IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18,
TxRingPtr=0x20, TxConfig=0x24,
- RxRingPtr=0x30, RxConfig=0x34,
+ RxRingPtr=0x30, RxConfig=0x34, ClkRun=0x3C,
WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C,
BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60,
RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64,
@@ -259,15 +268,19 @@
WOLPkt=0x2000,
RxResetDone=0x1000000, TxResetDone=0x2000000,
IntrPCIErr=0x00f00000,
- IntrNormalSummary=0x0251, IntrAbnormalSummary=0xCD20,
+ IntrAbnormalSummary=0xCD20,
};
/* Bits in the RxMode register. */
enum rx_mode_bits {
- AcceptErr=0x20, AcceptRunt=0x10,
- AcceptBroadcast=0xC0000000,
- AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000,
- AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000,
+ EnableFilter = 0x80000000,
+ AcceptBroadcast = 0x40000000,
+ AcceptAllMulticast = 0x20000000,
+ AcceptAllPhys = 0x10000000,
+ AcceptMyPhys = 0x08000000,
+ AcceptMulticast = 0x00200000,
+ AcceptErr=0x20, /* these 2 are in another register */
+ AcceptRunt=0x10,/* and are not used in this driver */
};
/* The Rx and Tx buffer descriptors. */
@@ -315,6 +328,8 @@
u32 rx_filter[16];
/* FIFO and PCI burst thresholds. */
int tx_config, rx_config;
+ /* original contents of ClkRun register */
+ int SavedClkRun;
/* MII transceiver section. */
u16 advertising; /* NWay media advertisement */
@@ -349,7 +364,7 @@
int i, option, irq = pdev->irq, chip_idx = ent->driver_data;
static int find_cnt = -1;
static int printed_version;
- unsigned long ioaddr;
+ unsigned long ioaddr, iosize;
const int pcibar = 1; /* PCI base address register */
if ((debug <= 1) && !printed_version++)
@@ -359,6 +374,7 @@
find_cnt++;
option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
ioaddr = pci_resource_start(pdev, pcibar);
+ iosize = pci_resource_len(pdev, pcibar);
if (pci_enable_device(pdev))
return -EIO;
@@ -371,15 +387,14 @@
{
void *mmio;
- if (request_mem_region(ioaddr, pci_resource_len (pdev, pcibar),
- dev->name) == NULL) {
+ if (request_mem_region(ioaddr, iosize, dev->name) == NULL) {
unregister_netdev(dev);
kfree(dev);
return -EBUSY;
}
- mmio = ioremap (ioaddr, pci_resource_len (pdev, pcibar));
+ mmio = ioremap (ioaddr, iosize);
if (!mmio) {
- release_mem_region(ioaddr, pci_resource_len (pdev, pcibar));
+ release_mem_region(ioaddr, iosize);
unregister_netdev(dev);
kfree(dev);
return -ENOMEM;
@@ -390,9 +405,9 @@
printk(KERN_INFO "%s: %s at 0x%lx, ",
dev->name, natsemi_pci_info[chip_idx].name, ioaddr);
- for (i = 0; i < 3; i++)
+ for (i = 0; i < ETH_ALEN/2; i++)
((u16 *)dev->dev_addr)[i] = be16_to_cpu(eeprom_read(ioaddr, i + 7));
- for (i = 0; i < 5; i++)
+ for (i = 0; i < ETH_ALEN-1; i++)
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
@@ -413,7 +428,8 @@
np->pci_dev = pdev;
pdev->driver_data = dev;
- np->iosize = pci_resource_len(pdev, pcibar);
+ np->iosize = iosize;
+ spin_lock_init(&np->lock);
if (dev->mem_start)
option = dev->mem_start;
@@ -551,7 +567,7 @@
writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
- for (i = 0; i < 6; i += 2) {
+ for (i = 0; i < ETH_ALEN; i += 2) {
writel(i, ioaddr + RxFilterAddr);
writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8),
ioaddr + RxFilterData);
@@ -560,21 +576,32 @@
/* Initialize other registers. */
/* Configure the PCI bus bursts and FIFO thresholds. */
/* Configure for standard, in-spec Ethernet. */
- np->tx_config = 0x10800802;
+ np->tx_config = (1<<28) + /* Automatic transmit padding */
+ (1<<23) + /* Excessive collision retry */
+ (0x0<<20) + /* Max DMA burst = 512 byte */
+ (8<<8) + /* fill threshold = 256 byte */
+ 2; /* drain threshold = 64 byte */
writel(np->tx_config, ioaddr + TxConfig);
- np->rx_config = 0x0020;
+ np->rx_config = (0x0<<20) /* Max DMA burst = 512 byte */ +
+ (0x8<<1); /* Drain Threshold = 64 byte */
writel(np->rx_config, ioaddr + RxConfig);
if (dev->if_port == 0)
dev->if_port = np->default_port;
+ /* Disable PME */
+ np->SavedClkRun = readl(ioaddr + ClkRun);
+ writel(np->SavedClkRun & ~0x100, ioaddr + ClkRun);
+
netif_start_queue(dev);
check_duplex(dev);
set_rx_mode(dev);
- /* Enable interrupts by setting the interrupt mask. */
- writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask);
+ /* Enable interrupts by setting the interrupt mask.
+ * We don't listen for TxDone interrupts and rely on TxIdle. */
+ writel(IntrAbnormalSummary | IntrTxIdle | IntrRxIdle | IntrRxDone,
+ ioaddr + IntrMask);
writel(1, ioaddr + IntrEnable);
writel(RxOn | TxOn, ioaddr + ChipCmd);
@@ -616,8 +643,8 @@
np->rx_config &= ~0x10000000;
np->tx_config &= ~0xC0000000;
}
- writew(np->tx_config, ioaddr + TxConfig);
- writew(np->rx_config, ioaddr + RxConfig);
+ writel(np->tx_config, ioaddr + TxConfig);
+ writel(np->rx_config, ioaddr + RxConfig);
}
}
@@ -700,7 +727,7 @@
skb->dev = dev; /* Mark as being used by this device. */
np->rx_ring[i].addr = virt_to_le32desc(skb->tail);
np->rx_ring[i].cmd_status =
- cpu_to_le32(DescIntr | np->rx_buf_sz);
+ cpu_to_le32(np->rx_buf_sz);
}
np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -727,7 +754,7 @@
np->tx_skbuff[entry] = skb;
np->tx_ring[entry].addr = virt_to_le32desc(skb->data);
- np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len);
+ np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);
np->cur_tx++;
/* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */
@@ -768,8 +795,7 @@
ioaddr = dev->base_addr;
np = (struct netdev_private *)dev->priv;
- if (!spin_trylock(&np->lock))
- return;
+ spin_lock(&np->lock);
do {
u32 intr_status = readl(ioaddr + IntrStatus);
@@ -784,7 +810,7 @@
if (intr_status == 0)
break;
- if (intr_status & (IntrRxDone | IntrRxIntr))
+ if (intr_status & (IntrRxDone | IntrRxErr | IntrRxIdle | IntrRxOverrun))
netdev_rx(dev);
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
@@ -805,7 +831,7 @@
np->stats.tx_errors++;
}
/* Free the original skb. */
- dev_kfree_skb(np->tx_skbuff[entry]);
+ dev_kfree_skb_irq(np->tx_skbuff[entry]);
np->tx_skbuff[entry] = 0;
}
if (np->tx_full
@@ -862,6 +888,7 @@
entry, desc_status);
if (--boguscnt < 0)
break;
+
if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) {
if (desc_status & DescMore) {
printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned "
@@ -947,7 +974,7 @@
np->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
}
np->rx_ring[entry].cmd_status =
- cpu_to_le32(DescIntr | np->rx_buf_sz);
+ cpu_to_le32(np->rx_buf_sz);
}
/* Restart Rx engine if stopped. */
@@ -1045,13 +1072,13 @@
set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
mc_filter);
}
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
for (i = 0; i < 32; i++) {
writew(0x200 + (i<<1), ioaddr + RxFilterAddr);
writew(cpu_to_be16(mc_filter[i]), ioaddr + RxFilterData);
}
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
}
- writel(rx_mode, ioaddr + RxFilterAddr);
+ writel(rx_mode | EnableFilter, ioaddr + RxFilterAddr);
np->cur_rx_mode = rx_mode;
}
@@ -1138,7 +1165,8 @@
dev_kfree_skb(np->tx_skbuff[i]);
np->tx_skbuff[i] = 0;
}
-
+ /* Restore PME enable bit */
+ writel(np->SavedClkRun, ioaddr + ClkRun);
#if 0
writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */
#endif
@@ -1153,9 +1181,10 @@
{
struct net_device *dev = pdev->driver_data;
struct netdev_private *np = (struct netdev_private *)dev->priv;
+ const int pcibar = 1; /* PCI base address register */
unregister_netdev (dev);
- release_mem_region(dev->base_addr, np->iosize);
+ release_mem_region(pci_resource_start(pdev, pcibar), np->iosize);
iounmap ((char *) dev->base_addr);
kfree (dev);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)