Hello, Alan. Attached are some patches against 2.4.0-test1-ac2.
drivers/net/3c59x.c
- Use del_timer_sync to avoid race on device close
- Fix the rx-stops-after-2^32 packets prob (from 2.2.16-pre4)
- Suppress EEPROM checksum error reporting for 3c905C (from
2.2.16-pre4)
- Fix "the infamous 8K 3c590 stall bug"
(Yay and it only took 3 years and 3 days to find ;))
- Print a warning on dev_alloc_skb() failure (rate limited to one
per 10 seconds)
- Remove bitfield-to-ioport mapping in favour of open-coded
shift/AND/OR.
The latter is for sparc64 support. I'm still sitting on the 2.2.16
version of this, awaiting definitive testing results. It looks like
we hold off on 2.2 sparc64 support until 2.2.17-pre.
Things are very quiet on the 3c59x front now. Still three
unexplained failures; two of these probably due to APICs losing their
interrupt routing. Very little feedback from PCMCIA (3c575) users
though.
drivers/net/smc9194.c
- Fed forward Heiko Pruessing's memory allocation bugfix (you've
applied this to 2.2.16. He was pretty convincing).
drivers/net/3c515.c
- Fed forward the rx-stops-after-2^32 packets fix.
Documentation/networking/cs89x0.txt
- Some stuff which got lost on the me->davem->Linus path back in
March.
Thanks.
--- linux-2.4.0test1-ac2/drivers/net/3c59x.c Wed May 24 23:00:19 2000
+++ linux-akpm/drivers/net/3c59x.c Mon May 29 00:12:40 2000
@@ -53,7 +53,7 @@
- Increased the loop counter in wait_for_completion from 2,000 to 4,000.
LK1.1.5 28 April 2000, andrewm
- - Added powerpc defines
+ - Added powerpc defines (John Daniel <[EMAIL PROTECTED]> said these work...)
- Some extra diagnostics
- In vortex_error(), reset the Tx on maxCollisions. Otherwise most
chips usually get a Tx timeout.
@@ -63,6 +63,19 @@
- In vortex_up(), don't make Wn3_config initialisation dependent upon has_nway
(this came across from 3c575_cb).
+ LK1.1.6 13 May 2000, andrewm
+ - Backed out the PPC defines.
+ - Use del_timer_sync(), mod_timer().
+ - Fix wrapped ulong comparison in boomerang_rx()
+ - Add IS_TORNADO, use it to suppress 3c905C checksum error msg
+ (Don Becker, I Lee Hetherington <[EMAIL PROTECTED]>)
+ - Replace union wn3_config with BFINS/BFEXT manipulation for
+ sparc64 (Pete Zaitcev, Peter Jones)
+ - In vortex_error, do_tx_reset and vortex_tx_timeout(Vortex):
+ do a netif_wake_queue() to better recover from errors. (Anders Pedersen,
+ Donald Becker)
+ - Print a warning on out-of-memory (rate limited to 1 per 10 secs)
+
- See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
*/
@@ -92,6 +105,7 @@
* AKPM 26 April 2000: enabling this still gets vestigial Tx timeouts
* in a heavily loaded (collision-prone) 10BaseT LAN. Should be OK with
* switched Ethernet.
+ * AKPM 24May00: vestigial timeouts have been removed by later fixes.
*/
#define tx_interrupt_mitigation 1
@@ -141,12 +155,6 @@
#include <asm/bitops.h>
#include <asm/io.h>
-/* John Daniel <[EMAIL PROTECTED]> said these work... */
-#ifdef __powerpc__
-#define outsl outsl_ns
-#define insl insl_ns
-#endif
-
/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
This is only in the support-all-kernels source code. */
@@ -155,7 +163,7 @@
#include <linux/delay.h>
static char version[] __devinitdata =
-"3c59x.c:v0.99L+LK1.1.5 30 Apr 2000 Donald Becker and others
http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html " "$Revision: 1.78 $\n";
+"3c59x.c:v0.99L+LK1.1.6 28 May 2000 Donald Becker and others.
+http://www.scyld.com/network/vortex.html " "$Revision: 1.86 $\n";
MODULE_AUTHOR("Donald Becker <[EMAIL PROTECTED]>");
MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
@@ -271,8 +279,8 @@
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
- EEPROM_230=8, /* AKPM: Uses 0x230 as the base bitmpas for EEPROM reads */
+enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
+ EEPROM_230=8, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
@@ -364,7 +372,7 @@
{"3c905B-FX Cyclone 100baseFx",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
{"3c905C Tornado",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, },
{"3c980 Cyclone",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
@@ -383,8 +391,8 @@
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128,
},
{"3CCFEM656 Cyclone CardBus",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128,
},
- {"3c450 Cyclone/unknown", /*
AKPM: from Don's 0.99N */
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+ {"3c450 HomePNA Tornado", /*
+AKPM: from Don's 0.99Q */
+ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, },
{0,}, /* 0 terminated list. */
};
@@ -501,15 +509,21 @@
enum Window3 { /* Window 3: MAC/config bits. */
Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
};
-union wn3_config {
- int i;
- struct w3_config_fields {
- unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
- int pad8:8;
- unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1;
- int pad24:7;
- } u;
-};
+
+#define BFEXT(value, offset, bitcount) \
+ ((((unsigned long)(value)) >> (offset)) & ((1 << (bitcount)) - 1))
+
+#define BFINS(lhs, rhs, offset, bitcount) \
+ (((lhs) & ~((((1 << (bitcount)) - 1)) << (offset))) | \
+ (((rhs) & ((1 << (bitcount)) - 1)) << (offset)))
+
+#define RAM_SIZE(v) BFEXT(v, 0, 3)
+#define RAM_WIDTH(v) BFEXT(v, 3, 1)
+#define RAM_SPEED(v) BFEXT(v, 4, 2)
+#define ROM_SIZE(v) BFEXT(v, 6, 2)
+#define RAM_SPLIT(v) BFEXT(v, 16, 2)
+#define XCVR(v) BFEXT(v, 20, 4)
+#define AUTOSELECT(v) BFEXT(v, 24, 1)
enum Window4 { /* Window 4: Xcvr/media bits. */
Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
@@ -785,6 +799,7 @@
struct net_device *dev;
static int printed_version = 0;
int retval;
+ struct vortex_chip_info * const vci = &vortex_info_tbl[chip_idx];
if (!printed_version) {
printk (KERN_INFO "%s", version);
@@ -801,7 +816,7 @@
printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
dev->name,
pdev ? "PCI" : "EISA",
- vortex_info_tbl[chip_idx].name,
+ vci->name,
ioaddr);
/* private struct aligned and zeroed by init_etherdev */
@@ -809,8 +824,8 @@
dev->base_addr = ioaddr;
dev->irq = irq;
dev->mtu = mtu;
- vp->has_nway = (vortex_info_tbl[chip_idx].drv_flags & HAS_NWAY) ? 1 : 0;
- vp->io_size = vortex_info_tbl[chip_idx].io_size;
+ vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;
+ vp->io_size = vci->io_size;
/* module list only for EISA devices */
if (pdev == NULL) {
@@ -821,10 +836,9 @@
/* PCI-only startup logic */
if (pdev) {
/* EISA resources already marked, so only PCI needs to do this here */
- if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size,
- dev->name)) {
+ if (!request_region (ioaddr, vci->io_size, dev->name)) {
printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @
0x%lx, aborting\n",
- dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr);
+ dev->name, vci->io_size, ioaddr);
retval = -EBUSY;
goto free_dev;
}
@@ -836,7 +850,7 @@
}
/* enable bus-mastering if necessary */
- if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER)
+ if (vci->flags & PCI_USES_MASTER)
pci_set_master (pdev);
}
@@ -891,7 +905,7 @@
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
{
- int base = (vortex_info_tbl[chip_idx].drv_flags & EEPROM_230) ? 0x230
: EEPROM_Read;
+ int base = (vci->drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read;
for (i = 0; i < 0x40; i++) {
int timer;
outw(base + i, ioaddr + Wn0EepromCmd);
@@ -912,7 +926,7 @@
checksum ^= eeprom[i++];
checksum = (checksum ^ (checksum >> 8)) & 0xff;
}
- if (checksum != 0x00)
+ if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
for (i = 0; i < 3; i++)
((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
@@ -932,7 +946,7 @@
dev->irq);
#endif
- if (pdev && vortex_info_tbl[chip_idx].drv_flags & HAS_CB_FNS) {
+ if (pdev && vci->drv_flags & HAS_CB_FNS) {
u32 fn_st_addr; /* Cardbus function status space */
fn_st_addr = pci_resource_start (pdev, 2);
if (fn_st_addr)
@@ -960,24 +974,24 @@
{
static const char * ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
- union wn3_config config;
+ unsigned int config;
EL3WINDOW(3);
vp->available_media = inw(ioaddr + Wn3_Options);
if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */
vp->available_media = 0x40;
- config.i = inl(ioaddr + Wn3_Config);
+ config = inl(ioaddr + Wn3_Config);
if (vortex_debug > 1)
printk(KERN_DEBUG " Internal config register is %4.4x, "
- "transceivers %#x.\n", config.i, inw(ioaddr +
Wn3_Options));
+ "transceivers %#x.\n", config, inw(ioaddr +
+Wn3_Options));
printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
- 8 << config.u.ram_size,
- config.u.ram_width ? "word" : "byte",
- ram_split[config.u.ram_split],
- config.u.autoselect ? "autoselect/" : "",
- config.u.xcvr > XCVR_ExtMII ? "<invalid transceiver>" :
- media_tbl[config.u.xcvr].name);
- vp->default_media = config.u.xcvr;
- vp->autoselect = config.u.autoselect;
+ 8 << RAM_SIZE(config),
+ RAM_WIDTH(config) ? "word" : "byte",
+ ram_split[RAM_SPLIT(config)],
+ AUTOSELECT(config) ? "autoselect/" : "",
+ XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" :
+ media_tbl[XCVR(config)].name);
+ vp->default_media = XCVR(config);
+ vp->autoselect = AUTOSELECT(config);
}
if (vp->media_override != 7) {
@@ -1042,7 +1056,7 @@
return 0;
free_region:
- release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
+ release_region (ioaddr, vci->io_size);
free_dev:
unregister_netdev(dev);
kfree (dev);
@@ -1070,7 +1084,7 @@
{
long ioaddr = dev->base_addr;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- union wn3_config config;
+ unsigned int config;
int i, device_id;
if (vp->pdev)
@@ -1080,7 +1094,7 @@
/* Before initializing select the active media port. */
EL3WINDOW(3);
- config.i = inl(ioaddr + Wn3_Config);
+ config = inl(ioaddr + Wn3_Config);
if (vp->media_override != 7) {
if (vortex_debug > 1)
@@ -1118,13 +1132,13 @@
dev->name, media_tbl[dev->if_port].name);
vp->full_duplex = vp->force_fd;
- config.u.xcvr = dev->if_port;
+ config = BFINS(config, dev->if_port, 20, 4);
//AKPM if (!vp->has_nway)
{
if (vortex_debug > 6)
printk(KERN_DEBUG "vortex_up(): writing 0x%x to
InternalConfig\n",
- config.i);
- outl(config.i, ioaddr + Wn3_Config);
+ config);
+ outl(config, ioaddr + Wn3_Config);
}
if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
@@ -1151,7 +1165,7 @@
if (vortex_debug > 1) {
printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n",
- dev->name, config.i);
+ dev->name, config);
}
wait_for_completion(dev, TxReset);
@@ -1383,7 +1397,7 @@
ok = 1;
}
if ( ! ok) {
- union wn3_config config;
+ unsigned int config;
do {
dev->if_port = media_tbl[dev->if_port].next;
@@ -1405,14 +1419,14 @@
media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
EL3WINDOW(3);
- config.i = inl(ioaddr + Wn3_Config);
- config.u.xcvr = dev->if_port;
- outl(config.i, ioaddr + Wn3_Config);
+ config = inl(ioaddr + Wn3_Config);
+ config = BFINS(config, dev->if_port, 20, 4);
+ outl(config, ioaddr + Wn3_Config);
outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
ioaddr + EL3_CMD);
if (vortex_debug > 1)
- printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config.i);
+ printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config);
/* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */
}
EL3WINDOW(old_window);
@@ -1422,10 +1436,10 @@
printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
dev->name, media_tbl[dev->if_port].name);
- vp->timer.expires = RUN_AT(next_tick);
- add_timer(&vp->timer);
+ mod_timer(&vp->timer, RUN_AT(next_tick));
if (vp->deferred)
outw(FakeIntr, ioaddr + EL3_CMD);
+ timer_exit(&vp->timer);
return;
}
@@ -1481,8 +1495,10 @@
netif_stop_queue (dev);
outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
outw(DownUnstall, ioaddr + EL3_CMD);
- } else
+ } else {
vp->stats.tx_dropped++;
+ netif_wake_queue(dev);
+ }
/* Issue Tx Enable */
outw(TxEnable, ioaddr + EL3_CMD);
@@ -1607,6 +1623,7 @@
} else {
wait_for_completion(dev, TxReset);
outw(TxEnable, ioaddr + EL3_CMD);
+ netif_wake_queue(dev);
}
}
}
@@ -1899,8 +1916,6 @@
netif_wake_queue (dev);
}
}
- if (vp->tx_full)
- netif_stop_queue (dev);
/* Check for all uncommon interrupts at once. */
if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq))
@@ -1925,7 +1940,7 @@
if (vp->cb_fn_base) /* The PCMCIA people are
idiots. */
writel(0x8000, vp->cb_fn_base + 4);
- } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
+ } while ((status = inw(ioaddr + EL3_STATUS)) & IntLatch);
if (vortex_debug > 4)
printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
@@ -2041,8 +2056,7 @@
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */
- if (pkt_len < rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
+ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len +
+2)) != 0) {
skb->dev = dev;
skb_reserve(skb, 2); /* Align IP on 16 byte
boundaries */
pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
@@ -2076,13 +2090,19 @@
entry = (++vp->cur_rx) % RX_RING_SIZE;
}
/* Refill the Rx ring buffers. */
- for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
+ for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) {
struct sk_buff *skb;
entry = vp->dirty_rx % RX_RING_SIZE;
if (vp->rx_skbuff[entry] == NULL) {
skb = dev_alloc_skb(PKT_BUF_SZ);
- if (skb == NULL)
+ if (skb == NULL) {
+ static unsigned long last_jif;
+ if ((jiffies - last_jif) > 10 * HZ) {
+ printk(KERN_WARNING "%s: memory shortage\n",
+dev->name);
+ last_jif = jiffies;
+ }
break; /* Bad news! */
+ }
skb->dev = dev; /* Mark as being used by this
device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev,
skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
@@ -2102,7 +2122,7 @@
netif_stop_queue (dev);
- del_timer(&vp->timer);
+ del_timer_sync(&vp->timer);
/* Turn off statistics ASAP. We update vp->stats below. */
outw(StatsDisable, ioaddr + EL3_CMD);
--- linux-2.4.0test1-ac2/drivers/net/smc9194.c Sun Feb 13 10:45:05 2000
+++ linux-akpm/drivers/net/smc9194.c Sun May 28 22:52:50 2000
@@ -45,10 +45,12 @@
. Fixed bug reported by Gardner Buchanan in
. smc_enable, with outw instead of outb
. 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert
+ . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory
+ . allocation
----------------------------------------------------------------------------*/
static const char *version =
- "smc9194.c:v0.12 03/06/96 by Erik Stahlman ([EMAIL PROTECTED])\n";
+ "smc9194.c:v0.13 04/14/00 by Erik Stahlman ([EMAIL PROTECTED])\n";
#include <linux/module.h>
#include <linux/version.h>
@@ -517,11 +519,15 @@
length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+
/*
- . the MMU wants the number of pages to be the number of 256 bytes
- . 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+ ** The MMU wants the number of pages to be the number of 256 bytes
+ ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+ **
+ ** Pkt size for allocating is data length +6 (for additional status words,
+ ** length and ctl!) If odd size last byte is included in this header.
*/
- numPages = length / 256;
+ numPages = ((length & 0xfffe) + 6) / 256;
if (numPages > 7 ) {
printk(CARDNAME": Far too big packet error. \n");
--- linux-2.4.0test1-ac2/drivers/net/3c515.c Mon May 15 21:24:14 2000
+++ linux-akpm/drivers/net/3c515.c Sun May 28 22:45:15 2000
@@ -448,7 +448,7 @@
goto no_pnp;
for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) {
struct pci_dev *idev = NULL;
- int irq, j;
+ int irq;
while((idev = isapnp_find_dev(NULL,
corkscrew_isapnp_adapters[i].vendor,
corkscrew_isapnp_adapters[i].function,
@@ -1427,7 +1427,7 @@
entry = (++vp->cur_rx) % RX_RING_SIZE;
}
/* Refill the Rx ring buffers. */
- for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
+ for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) {
struct sk_buff *skb;
entry = vp->dirty_rx % RX_RING_SIZE;
if (vp->rx_skbuff[entry] == NULL) {
--- linux-2.4.0test1-ac2/Documentation/networking/cs89x0.txt Wed Apr 26 22:52:16
2000
+++ linux-akpm/Documentation/networking/cs89x0.txt Fri Mar 24 01:13:38 2000
@@ -308,6 +308,30 @@
l) If during DMA operation you find erratic behavior or network data
corruption you should use your PC's BIOS to slow the EISA bus clock.
+m) If the cs89x0 driver is compiled directly into the kernel
+ (non-modular) then its I/O address is automatically determined by
+ ISA bus probing. The IRQ number, media options, etc are determined
+ from the card's EEPROM.
+
+n) If the cs89x0 driver is compiled directly into the kernel, DMA
+ mode may be selected by providing the kernel with a boot option
+ 'cs89x0_dma=N' where 'N' is the desired DMA channel number (5, 6 or
+ 7).
+
+ Kernel boot options may be provided on the LILO command line:
+
+ LILO boot: linux cs89x0_dma=5
+
+ or they may be placed in /etc/lilo.conf:
+
+ image=/boot/bzImage-2.3.48
+ append="cs89x0_dma=5"
+ label=linux
+ root=/dev/hda5
+ read-only
+
+ The DMA Rx buffer size is hardwared to 16 kbytes in this mode.
+ (64k mode is not available).
4.0 COMPILING THE DRIVER
===============================================================================