patch-2.2.16 linux/drivers/net/eepro100.c

Next file: linux/drivers/net/hamachi.c
Previous file: linux/drivers/net/eepro.c
Back to the patch index
Back to the overall index

diff -urN v2.2.15/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
@@ -24,11 +24,22 @@
 	The driver also contains updates by different kernel developers.
 	This driver clone is maintained by Andrey V. Savochkin <saw@saw.sw.com.sg>.
 	Please use this email address and linux-kernel mailing list for bug reports.
+	
+	Modification history:
+	2000 Mar 24  Dragan Stancevic <visitor@valinux.com>
+		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
+	2000 May 27  Andrey Moruga <moruga@sw.com.sg>
+		Code duplication for 82559ER support was removed.
+		Accurate handling of all supported chips was implemented.
+		Some fixes in 2.3 clone of the driver were ported.
+	2000 May 30  Dragan Stancevic <visitor@valinux.com> and
+				 Andrey Moruga <moruga@sw.com.sg>
+		Honor PortReset timing specification.
 */
 
 static const char *version =
 "eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"
-"eepro100.c: $Revision: 1.20.2.3 $ 2000/03/02 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
+"eepro100.c: $Revision: 1.20.2.10 $ 2000/05/31 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
 
 /* A few user-configurable values that apply to all boards.
    First set is undocumented and spelled per Intel recommendations. */
@@ -42,7 +53,7 @@
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
    Lower values use more memory, but are faster. */
-#if defined(__alpha__) || defined(__sparc__)
+#ifdef __alpha__
 /* force copying of all packets to avoid unaligned accesses on Alpha */
 static int rx_copybreak = 1518;
 #else
@@ -103,17 +114,8 @@
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
-#ifdef HAS_PCI_NETIF
-#include "pci-netif.h"
-#else
-#include <linux/pci.h>
-#endif
 #include <linux/pci.h>
-#if LINUX_VERSION_CODE >= 0x20312
-#include <linux/spinlock.h>
-#else
 #include <asm/spinlock.h>
-#endif
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -124,7 +126,7 @@
 #include <linux/delay.h>
 
 #if defined(MODULE)
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
 MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
@@ -144,21 +146,24 @@
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
 
-#if LINUX_VERSION_CODE < 0x020314
 #define net_device              device
 #define pci_base_address(p, n)  (p)->base_address[n]
-#else
-#define pci_base_address(p, n)  (p)->resource[n].start
-#endif
 
 #define dev_free_skb(skb)       dev_kfree_skb(skb);
-#if ! defined(HAS_NETIF_QUEUE)
 #define netif_wake_queue(dev)   do { \
 									clear_bit(0, (void*)&dev->tbusy); \
 									mark_bh(NET_BH); \
 								} while(0)
 #define netif_start_queue(dev)  clear_bit(0, (void*)&dev->tbusy)
 #define netif_stop_queue(dev)   set_bit(0, (void*)&dev->tbusy)
+#ifndef PCI_DEVICE_ID_INTEL_82559ER
+#define PCI_DEVICE_ID_INTEL_82559ER 0x1209
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_ID1029
+#define PCI_DEVICE_ID_INTEL_ID1029 0x1029
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_ID1030
+#define PCI_DEVICE_ID_INTEL_ID1030 0x1030
 #endif
 
 /* The total I/O port extent of the board.
@@ -282,7 +287,9 @@
 */
 
 /* This table drives the PCI probe routines. */
-static struct net_device *speedo_found1(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
+static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus, 
+										int pci_devfn, long ioaddr, 
+										int chip_idx, int card_idx);
 
 #ifdef USE_IO
 #define SPEEDO_IOTYPE   PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
@@ -292,29 +299,42 @@
 #define SPEEDO_SIZE		0x1000
 #endif
 
-#if defined(HAS_PCI_NETIF)
-struct pci_id_info static pci_tbl[] = {
-	{ "Intel PCI EtherExpress Pro100",
-	  { 0x12298086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE,
-	  0, speedo_found1 },
-	{0,},						/* 0 terminated list. */
-};
-#else
 enum pci_flags_bit {
 	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
 	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
 struct pci_id_info {
 	const char *name;
-	u16	vendor_id, device_id, device_id_mask, flags;
-	int io_size;
-	struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
+	u16	vendor_id, device_id;
+	int pci_index;
 } static pci_tbl[] = {
-	{ "Intel PCI EtherExpress Pro100",
-	  0x8086, 0x1229, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 32, speedo_found1 },
-	{0,},						/* 0 terminated list. */
+	{ "Intel PCI EtherExpress Pro100 82557",
+	  PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
+	  0
+	},
+	{ "Intel PCI EtherExpress Pro100 82559ER",
+	  PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
+	  0
+	},
+	{ "Intel PCI EtherExpress Pro100 ID1029",
+	  PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029,
+	  0 
+	},
+	{ "Intel Corporation 82559 InBusiness 10/100",
+	  PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030,
+	  0 
+	},
+	{0,}						/* 0 terminated list. */
 };
-#endif
+
+static inline unsigned int io_inw(unsigned long port)
+{
+	return inw(port);
+}
+static inline void io_outw(unsigned int val, unsigned long port)
+{
+	outw(val, port);
+}
 
 #ifndef USE_IO
 #undef inb
@@ -338,6 +358,10 @@
 	int wait = 1000;
 	do   ;
 	while(inb(cmd_ioaddr) && --wait >= 0);
+#ifndef final_version
+	if (wait < 0)
+		printk(KERN_ALERT "eepro100: wait_for_cmd_done timeout!\n");
+#endif
 }
 
 /* Offsets to the various registers.
@@ -426,8 +450,7 @@
 struct speedo_mc_block {
 	struct speedo_mc_block *next;
 	unsigned int tx;
-	char fill[16 - sizeof(struct speedo_mc_block *) - sizeof(unsigned int)];
-	struct descriptor frame;
+	struct descriptor frame __attribute__ ((__aligned__(16)));
 };
 
 /* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -480,7 +503,7 @@
 	struct timer_list timer;	/* Media selection timer. */
 	struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */
 	struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */
-	long in_interrupt;					/* Word-aligned dev->interrupt */
+	int in_interrupt;					/* Word-aligned dev->interrupt */
 	char rx_mode;						/* Current PROMISC/ALLMULTI setting. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
@@ -506,7 +529,7 @@
 const char i82558_config_cmd[22] = {
 	22, 0x08, 0, 1,  0, 0, 0x22, 0x03,  1, /* 1=Use MII  0=Use AUI */
 	0, 0x2E, 0,  0x60, 0x08, 0x88,
-	0x68, 0, 0x40, 0xf2, 0xBD, 		/* 0xBD->0xFD=Force full-duplex */
+	0x68, 0, 0x40, 0xf2, 0x84,		/* Disable FC */
 	0x31, 0x05, };
 
 /* PHY media interface chips. */
@@ -551,138 +574,84 @@
 /* A list of all installed Speedo devices, for removing the driver module. */
 static struct net_device *root_speedo_dev = NULL;
 
-#if ! defined(HAS_PCI_NETIF)
 int eepro100_init(void)
 {
 	int cards_found = 0;
-	static int pci_index = 0;
+	int chip_idx;
+	struct pci_dev *pdev;
 
 	if (! pcibios_present())
 		return cards_found;
 
-	for (; pci_index < 8; pci_index++) {
-		unsigned char pci_bus, pci_device_fn, pci_latency;
-		unsigned long pciaddr;
-		long ioaddr;
-		int irq;
-
-		u16 pci_command, new_command;
-
-		if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
-								PCI_DEVICE_ID_INTEL_82557,
-								pci_index, &pci_bus,
-								&pci_device_fn))
-			break;
-		{
-			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+	for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) {
+		for (; pci_tbl[chip_idx].pci_index < 8; pci_tbl[chip_idx].pci_index++) {
+			unsigned char pci_bus, pci_device_fn, pci_latency;
+			unsigned long pciaddr;
+			long ioaddr;
+			int irq;
+
+			u16 pci_command, new_command;
+
+			if (pcibios_find_device(pci_tbl[chip_idx].vendor_id,
+									pci_tbl[chip_idx].device_id,
+									pci_tbl[chip_idx].pci_index, &pci_bus,
+									&pci_device_fn))
+				break;
+			{
+				pdev = pci_find_slot(pci_bus, pci_device_fn);
 #ifdef USE_IO
-			pciaddr = pci_base_address(pdev, 1);	/* Use [0] to mem-map */
+				pciaddr = pci_base_address(pdev, 1);	/* Use [0] to mem-map */
 #else
-			pciaddr = pci_base_address(pdev, 0);
+				pciaddr = pci_base_address(pdev, 0);
 #endif
-			irq = pdev->irq;
-		}
-		/* Remove I/O space marker in bit 0. */
-		if (pciaddr & 1) {
-			ioaddr = pciaddr & ~3UL;
-			if (check_region(ioaddr, 32))
+				irq = pdev->irq;
+			}
+			/* Remove I/O space marker in bit 0. */
+			if (pciaddr & 1) {
+				ioaddr = pciaddr & ~3UL;
+				if (check_region(ioaddr, 32))
+					continue;
+			} else if ((ioaddr = (long)ioremap(pciaddr & ~0xfUL, 0x1000)) == 0) {
+				printk(KERN_INFO "Failed to map PCI address %#lx.\n",
+					   pciaddr);
 				continue;
-		} else 
-#ifdef __sparc__
-		{
-			/* ioremap is hosed in 2.2.x on Sparc. */
-			ioaddr = pciaddr & ~0xfUL;
-		}
-#else
-		if ((ioaddr = (long)ioremap(pciaddr & ~0xfUL, 0x1000)) == 0) {
-			printk(KERN_INFO "Failed to map PCI address %#lx.\n",
-				   pciaddr);
-			continue;
-		}
-#endif
-		if (speedo_debug > 2)
-			printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
-				   ioaddr, irq);
+			}
+			if (speedo_debug > 2)
+				printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
+					   ioaddr, irq);
+
+			/* Get and check the bus-master and latency values. */
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_COMMAND, &pci_command);
+			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+			if (pci_command != new_command) {
+				printk(KERN_INFO "  The PCI BIOS has not enabled this"
+					   " device!  Updating PCI command %4.4x->%4.4x.\n",
+					   pci_command, new_command);
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, new_command);
+			}
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_LATENCY_TIMER, &pci_latency);
+			if (pci_latency < 32) {
+				printk("  PCI latency timer (CFLT) is unreasonably low at %d."
+					   "  Setting to 32 clocks.\n", pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, 32);
+			} else if (speedo_debug > 1)
+				printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
 
-		/* Get and check the bus-master and latency values. */
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_COMMAND, &pci_command);
-		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled this"
-				   " device!  Updating PCI command %4.4x->%4.4x.\n",
-				   pci_command, new_command);
-			pcibios_write_config_word(pci_bus, pci_device_fn,
-									  PCI_COMMAND, new_command);
-		}
-		pcibios_read_config_byte(pci_bus, pci_device_fn,
-								 PCI_LATENCY_TIMER, &pci_latency);
-		if (pci_latency < 32) {
-			printk("  PCI latency timer (CFLT) is unreasonably low at %d."
-				   "  Setting to 32 clocks.\n", pci_latency);
-			pcibios_write_config_byte(pci_bus, pci_device_fn,
-									  PCI_LATENCY_TIMER, 32);
-		} else if (speedo_debug > 1)
-			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
-
-		if (speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0, cards_found))
-			cards_found++;
-	}
-
-	for (; pci_index < 8; pci_index++) {
-		unsigned char pci_bus, pci_device_fn, pci_latency;
-		long ioaddr;
-		int irq;
-
-		u16 pci_command, new_command;
-
-		if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
-					PCI_DEVICE_ID_INTEL_82559ER,
-					pci_index, &pci_bus,
-					&pci_device_fn))
-		    break;
-		{
-		    struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-		    ioaddr = pdev->base_address[1];		/* Use [0] to mem-map */
-		    irq = pdev->irq;
+			if (speedo_found1(pdev, pci_bus, pci_device_fn, ioaddr, chip_idx, cards_found))
+				cards_found++;
 		}
-		/* Remove I/O space marker in bit 0. */
-		ioaddr &= ~3;
-		if (speedo_debug > 2)
-		    printk("Found Intel i82559ER PCI Speedo at I/O %#lx, IRQ %d.\n",
-			   ioaddr, irq);
-		
-		/* Get and check the bus-master and latency values. */
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-					 PCI_COMMAND, &pci_command);
-		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-		if (pci_command != new_command) {
-		    printk(KERN_INFO "  The PCI BIOS has not enabled this"
-			   " device!  Updating PCI command %4.4x->%4.4x.\n",
-			   pci_command, new_command);
-		    pcibios_write_config_word(pci_bus, pci_device_fn,
-					      PCI_COMMAND, new_command);
-		}
-		pcibios_read_config_byte(pci_bus, pci_device_fn,
-					 PCI_LATENCY_TIMER, &pci_latency);
-		if (pci_latency < 32) {
-		    printk("  PCI latency timer (CFLT) is unreasonably low at %d."
-			   "  Setting to 32 clocks.\n", pci_latency);
-		    pcibios_write_config_byte(pci_bus, pci_device_fn,
-					      PCI_LATENCY_TIMER, 32);
-		} else if (speedo_debug > 1)
-			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
-		
-		if(speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0, cards_found))
-			cards_found++;
 	}
 
 	return cards_found;
 }
-#endif
 
-static struct net_device *speedo_found1(int pci_bus, int pci_devfn, 
-			  long ioaddr, int irq, int chip_idx, int card_idx)
+static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus, 
+										int pci_devfn, long ioaddr, 
+										int chip_idx, int card_idx)
 {
 	struct net_device *dev;
 	struct speedo_private *sp;
@@ -705,21 +674,21 @@
 	else
 		option = 0;
 
-#if defined(HAS_PCI_NETIF)
-	acpi_idle_state = acpi_set_pwr_state(pci_bus, pci_devfn, ACPI_D0);
-#endif
-
 	/* Read the station address EEPROM before doing the reset.
 	   Nominally his should even be done before accepting the device, but
 	   then we wouldn't have a device name with which to report the error.
 	   The size test is for 6 bit vs. 8 bit address serial EEPROMs.
 	*/
 	{
-		u16 sum = 0;
-		int j;
+		unsigned long iobase;
 		int read_cmd, ee_size;
+		u16 sum;
+		int j;
 
-		if ((do_eeprom_cmd(ioaddr, EE_READ_CMD << 24, 27) & 0xffe0000)
+		/* Use IO only to avoid postponed writes and satisfy EEPROM timing
+		   requirements. */
+		iobase = pci_base_address(pdev, 1) & ~3UL;
+		if ((do_eeprom_cmd(iobase, EE_READ_CMD << 24, 27) & 0xffe0000)
 			== 0xffe0000) {
 			ee_size = 0x100;
 			read_cmd = EE_READ_CMD << 24;
@@ -728,8 +697,8 @@
 			read_cmd = EE_READ_CMD << 22;
 		}
 
-		for (j = 0, i = 0; i < ee_size; i++) {
-			u16 value = do_eeprom_cmd(ioaddr, read_cmd | (i << 16), 27);
+		for (j = 0, i = 0, sum = 0; i < ee_size; i++) {
+			u16 value = do_eeprom_cmd(iobase, read_cmd | (i << 16), 27);
 			eeprom[i] = value;
 			sum += value;
 			if (i < 3) {
@@ -742,24 +711,31 @@
 				   "check settings before activating this device!\n",
 				   dev->name, sum);
 		/* Don't  unregister_netdev(dev);  as the EEPro may actually be
-		   usable, especially if the MAC address is set later. */
+		   usable, especially if the MAC address is set later.
+		   On the other hand, it may be unusable if MDI data is corrupted. */
 	}
 
 	/* Reset the chip: stop Tx and Rx processes and clear counters.
 	   This takes less than 10usec and will easily finish before the next
 	   action. */
 	outl(PortReset, ioaddr + SCBPort);
+	/* Honor PortReset timing. */
+	udelay(10);
 
 	if (eeprom[3] & 0x0100)
 		product = "OEM i82557/i82558 10/100 Ethernet";
 	else
 		product = pci_tbl[chip_idx].name;
 
-	printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
+	printk(KERN_INFO "%s: %s, ", dev->name, product);
 
 	for (i = 0; i < 5; i++)
 		printk("%2.2X:", dev->dev_addr[i]);
-	printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);
+	printk("%2.2X, ", dev->dev_addr[i]);
+#ifdef USE_IO
+	printk("I/O at %#3lx, ", ioaddr);
+#endif
+	printk("IRQ %d.\n", pdev->irq);
 
 #if 1 || defined(kernel_bloat)
 	/* OK, this is pure kernel bloat.  I don't like it when other drivers
@@ -831,16 +807,14 @@
 #endif  /* kernel_bloat */
 
 	outl(PortReset, ioaddr + SCBPort);
-#if defined(HAS_PCI_NETIF)
-	/* Return the chip to its original power state. */
-	acpi_set_pwr_state(pci_bus, pci_devfn, acpi_idle_state);
-#endif
+	/* Honor PortReset timing. */
+	udelay(10);
 
 	/* We do a request_region() only to register /proc/ioports info. */
 	request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
 
 	dev->base_addr = ioaddr;
-	dev->irq = irq;
+	dev->irq = pdev->irq;
 
 	sp = dev->priv;
 	if (dev->priv == NULL) {
@@ -898,30 +872,32 @@
 #define EE_WRITE_1		0x4806
 #define EE_OFFSET		SCBeeprom
 
-/* Delay between EEPROM clock transitions.
-   The code works with no delay on 33Mhz PCI.  */
-#define eeprom_delay()	inw(ee_addr)
-
+/* The fixes for the code were kindly provided by Dragan Stancevic
+   <visitor@valinux.com> to strictly follow Intel specifications of EEPROM
+   access timing.
+   The publicly available sheet 64486302 (sec. 3.1) specifies 1us access
+   interval for serial EEPROM.  However, it looks like that there is an
+   additional requirement dictating larger udelay's in the code below.
+   2000/05/24  SAW */
 static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len)
 {
 	unsigned retval = 0;
 	long ee_addr = ioaddr + SCBeeprom;
 
-	outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
+	io_outw(EE_ENB, ee_addr); udelay(2);
+	io_outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2);
 
 	/* Shift the command bits out. */
 	do {
 		short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
-		outw(dataval, ee_addr);
-		eeprom_delay();
-		outw(dataval | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay();
-		retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		io_outw(dataval, ee_addr); udelay(2);
+		io_outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2);
+		retval = (retval << 1) | ((io_inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
 	} while (--cmd_len >= 0);
-	outw(EE_ENB, ee_addr);
+	io_outw(EE_ENB, ee_addr); udelay(2);
 
 	/* Terminate the EEPROM access. */
-	outw(EE_ENB & ~EE_CS, ee_addr);
+	io_outw(EE_ENB & ~EE_CS, ee_addr);
 	return retval;
 }
 
@@ -961,13 +937,11 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-#if defined(HAS_PCI_NETIF)
-	acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
-#endif
-
 	if (speedo_debug > 1)
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
+	MOD_INC_USE_COUNT;
+
 	/* Set up the Tx queue early.. */
 	sp->cur_tx = 0;
 	sp->dirty_tx = 0;
@@ -978,9 +952,9 @@
 
 	/* .. we can safely take handler calls during init. */
 	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
+		MOD_DEC_USE_COUNT;
 		return -EAGAIN;
 	}
-	MOD_INC_USE_COUNT;
 
 	dev->if_port = sp->default_port;
 
@@ -1098,7 +1072,9 @@
 	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
 		 ioaddr + SCBPointer);
-	outw(CUStart, ioaddr + SCBCmd);
+	/* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
+	   remain masked --Dragan */
+	outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
 }
 
 /* Media monitoring and control. */
@@ -1114,8 +1090,11 @@
 		int partner = mdio_read(ioaddr, phy_num, 5);
 		if (partner != sp->partner) {
 			int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0;
-			if (speedo_debug > 2)
+			if (speedo_debug > 2) {
 				printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
+				printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n",
+					   dev->name, sp->partner, partner, sp->advertising);
+			}
 			sp->partner = partner;
 			if (flow_ctrl != sp->flow_ctrl) {
 				sp->flow_ctrl = flow_ctrl;
@@ -1179,12 +1158,14 @@
 			   i, (sp->rx_ringp[i] != NULL) ?
 					   (unsigned)sp->rx_ringp[i]->status : 0);
 
+#if 0
 	for (i = 0; i < 16; i++) {
 		/* FIXME: what does it mean?  --SAW */
 		if (i == 6) i = 21;
 		printk(KERN_DEBUG "%s:  PHY index %d register %d is %4.4x.\n",
 			   dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
 	}
+#endif
 
 }
 
@@ -1213,12 +1194,8 @@
 		last_rxf = rxf;
 		rxf->status = cpu_to_le32(0x00000001);	/* '1' is flag value only. */
 		rxf->link = 0;						/* None yet. */
-		/* This field unused by i82557, we use it as a consistency check. */
-#ifdef final_version
+		/* This field unused by i82557. */
 		rxf->rx_buf_addr = 0xffffffff;
-#else
-		rxf->rx_buf_addr = virt_to_bus(skb->tail);
-#endif
 		rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
 	}
 	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1254,6 +1231,29 @@
 	netif_wake_queue(dev);
 }
 
+static void reset_mii(struct net_device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
+	if ((sp->phy[0] & 0x8000) == 0) {
+		int phy_addr = sp->phy[0] & 0x1f;
+		int advertising = mdio_read(ioaddr, phy_addr, 4);
+		int mii_bmcr = mdio_read(ioaddr, phy_addr, 0);
+		mdio_write(ioaddr, phy_addr, 0, 0x0400);
+		mdio_write(ioaddr, phy_addr, 1, 0x0000);
+		mdio_write(ioaddr, phy_addr, 4, 0x0000);
+		mdio_write(ioaddr, phy_addr, 0, 0x8000);
+#ifdef honor_default_port
+		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+#else
+		mdio_read(ioaddr, phy_addr, 0);
+		mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
+		mdio_write(ioaddr, phy_addr, 4, advertising);
+#endif
+	}
+}
+
 static void speedo_tx_timeout(struct net_device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
@@ -1280,6 +1280,7 @@
 		outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
 			 ioaddr + SCBPointer);
 		outw(CUStart, ioaddr + SCBCmd);
+		reset_mii(dev);
 	} else {
 #else
 	{
@@ -1309,26 +1310,12 @@
 		dev->trans_start = jiffies;
 		spin_unlock_irqrestore(&sp->lock, flags);
 		set_rx_mode(dev); /* it takes the spinlock itself --SAW */
+		/* Reset MII transceiver.  Do it before starting the timer to serialize
+		   mdio_xxx operations.  Yes, it's a paranoya :-)  2000/05/09 SAW */
+		reset_mii(dev);
 		sp->timer.expires = RUN_AT(2*HZ);
 		add_timer(&sp->timer);
 	}
-	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
-	if ((sp->phy[0] & 0x8000) == 0) {
-		int phy_addr = sp->phy[0] & 0x1f;
-		int advertising = mdio_read(ioaddr, phy_addr, 4);
-		int mii_bmcr = mdio_read(ioaddr, phy_addr, 0);
-		mdio_write(ioaddr, phy_addr, 0, 0x0400);
-		mdio_write(ioaddr, phy_addr, 1, 0x0000);
-		mdio_write(ioaddr, phy_addr, 4, 0x0000);
-		mdio_write(ioaddr, phy_addr, 0, 0x8000);
-#ifdef honor_default_port
-		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
-#else
-		mdio_read(ioaddr, phy_addr, 0);
-		mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
-		mdio_write(ioaddr, phy_addr, 4, advertising);
-#endif
-	}
 	return;
 }
 
@@ -1346,7 +1333,13 @@
 			return 1;
 		if (tickssofar < TX_TIMEOUT) {
 			/* Reap sent packets from the full Tx queue. */
+			unsigned long flags;
+			/* Take a spinlock to make wait_for_cmd_done and sending the
+			command atomic.  --SAW */
+			spin_lock_irqsave(&sp->lock, flags);
+			wait_for_cmd_done(ioaddr + SCBCmd);
 			outw(SCBTriggerIntr, ioaddr + SCBCmd);
+			spin_unlock_irqrestore(&sp->lock, flags);
 			return 1;
 		}
 		speedo_tx_timeout(dev);
@@ -1495,6 +1488,8 @@
 	do {
 		status = inw(ioaddr + SCBStatus);
 		/* Acknowledge all of the current interrupt sources ASAP. */
+		/* Will change from 0xfc00 to 0xff00 when we start handling
+		   FCP and ER interrupts --Dragan */
 		outw(status & 0xfc00, ioaddr + SCBStatus);
 
 		if (speedo_debug > 4)
@@ -1594,6 +1589,8 @@
 			printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
 				   dev->name, status);
 			/* Clear all interrupt sources. */
+			/* Will change from 0xfc00 to 0xff00 when we start handling
+			   FCP and ER interrupts --Dragan */
 			outl(0xfc00, ioaddr + SCBStatus);
 			break;
 		}
@@ -1754,7 +1751,6 @@
 					   pkt_len);
 #endif
 			} else {
-				void *temp;
 				/* Pass up the already-filled skbuff. */
 				skb = sp->rx_skbuff[entry];
 				if (skb == NULL) {
@@ -1763,13 +1759,7 @@
 					break;
 				}
 				sp->rx_skbuff[entry] = NULL;
-				temp = skb_put(skb, pkt_len);
-				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-					printk(KERN_ERR "%s: Rx consistency error -- the skbuff "
-						   "addresses do not match in speedo_rx: %p vs. %p "
-						   "/ %p.\n", dev->name,
-						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-						   skb->head, temp);
+				skb_put(skb, pkt_len);
 				sp->rx_ringp[entry] = NULL;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
@@ -1808,7 +1798,9 @@
 			   dev->name, inw(ioaddr + SCBStatus));
 
 	/* Shut off the media monitoring timer. */
+	start_bh_atomic();
 	del_timer(&sp->timer);
+	end_bh_atomic();
 
 	/* Shutting down the chip nicely fails to disable flow control. So.. */
 	outl(PortPartialReset, ioaddr + SCBPort);
@@ -1847,10 +1839,6 @@
 	if (speedo_debug > 0)
 		printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i);
 
-#if defined(HAS_PCI_NETIF)
-	/* Alt: acpi_set_pwr_state(pci_bus, pci_devfn, sp->acpi_pwr); */
-	acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D2);
-#endif
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -1891,7 +1879,7 @@
 		if (dev->start) {
 			unsigned long flags;
 			/* Take a spinlock to make wait_for_cmd_done and sending the
-			 * command atomic.  --SAW */
+			   command atomic.  --SAW */
 			spin_lock_irqsave(&sp->lock, flags);
 			wait_for_cmd_done(ioaddr + SCBCmd);
 			outb(CUDumpStats, ioaddr + SCBCmd);
@@ -1907,32 +1895,25 @@
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = sp->phy[0] & 0x1f;
-#if defined(HAS_PCI_NETIF)
-	int saved_acpi;
-#endif
 
     switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = phy;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-#if defined(HAS_PCI_NETIF)
-		saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
-		data[3] = mdio_read(ioaddr, data[0], data[1]);
-		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
-#else
+		/* FIXME: these operations need to be serialized with MDIO
+		   access from the timeout handler.
+		   They are currently serialized only with MDIO access from the
+		   timer routine.  2000/05/09 SAW */
+		start_bh_atomic();
 		data[3] = mdio_read(ioaddr, data[0], data[1]);
-#endif
+		end_bh_atomic();
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-#if defined(HAS_PCI_NETIF)
-		saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
-		mdio_write(ioaddr, data[0], data[1], data[2]);
-		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
-#else
+		start_bh_atomic();
 		mdio_write(ioaddr, data[0], data[1], data[2]);
-#endif
+		end_bh_atomic();
 		return 0;
 	default:
 		return -EOPNOTSUPP;
@@ -1995,7 +1976,10 @@
 		config_cmd_data[4] = rxdmacount;
 		config_cmd_data[5] = txdmacount + 0x80;
 		config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
-		config_cmd_data[19] = sp->flow_ctrl ? 0xBD : 0x80;
+		/* 0x80 doesn't disable FC 0x84 does.
+		   Disable Flow control since we are not ACK-ing any FC interrupts
+		   for now. --Dragan */
+		config_cmd_data[19] = 0x84;
 		config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
 		config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
 		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
@@ -2142,18 +2126,11 @@
 	if (speedo_debug)
 		printk(KERN_INFO "%s", version);
 
-#if defined(HAS_PCI_NETIF)
-	cards_found = netif_pci_probe(pci_tbl);
-	if (cards_found < 0)
-		printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
-	return cards_found;
-#else
 	cards_found = eepro100_init();
 	if (cards_found <= 0) {
 		printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
 		return -ENODEV;
 	}
-#endif
 	return 0;
 }
 
@@ -2169,9 +2146,6 @@
 		release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
 #ifndef USE_IO
 		iounmap((char *)root_speedo_dev->base_addr);
-#endif
-#if defined(HAS_PCI_NETIF)
-		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, sp->acpi_pwr);
 #endif
 		next_dev = sp->next_module;
 		if (sp->priv_addr)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)