2.2.11 and tulip.c issues

Robert G. Brown rgb@phy.duke.edu
Wed Aug 18 16:35:39 1999


On Wed, 18 Aug 1999, Aron Griffis wrote:

> I haven't received any feedback about the tulip driver versions and my
> card.  Suggestions would be welcome.  The interface reports as
> 
>     eth0: Digital DS21142/3 Tulip at 0x8000, 00 00 f8 75 36 98, IRQ 24.
> 
> As I said earlier:
> 
> > This is is cc'd to linux-tulip; I assume Don will read it there.
> > 
> > I have an Alpha Miata on which 0.91g does not work.  The module
> > loads, but no traffic gets across the interface.  I can provide
> > whatever debugging information you'd like if you'll instruct me what
> > to do.
> > 
> > 0.89H works fine on this machine, at least until I start X, at which
> > point it stops working.  If I exit X, then "ifdown eth0; rmmod tulip;
> > ifup eth0", it starts working again.

IIRC, the tulip very rarely has interrupt/ioport conflicts with mmap
video cards.  You might try the following:

  a) Look carefully at /proc/pci to see if you can see anything obvious
that appears to be a conflict;

  b) Move the NIC to a different PCI slot.  I know, this shouldn't
matter (especially with 2.2.x and IO-APIC, although it was fairly common
with 2.0.x kernels) but I've definitely had it resolve problems with
tulip cards in the past.

  c) Finally (and most likely) there is an affliction that MANY tulip
cards of years past have had in which they basically lie when they pass
their PCI configuration back to the kernel.  The lie involved a
dysfunctional ioport.  The characteristic of this bug is that it was
repaired with exactly the same sequence of unloading and reloading the
module you describe above.  In those cards, the ioport shifted between
the first load and the second -- this was one characteristic of the bug.

I wrote a patch to solve this problem for 0.89H that I include below.
Note that according to Don this patch "should" not be necessary, but the
sad fact is that for many systems it works to solve the problem (both
for the tulip and de4x5 drivers) regardless of where the problem REALLY
lies.  It isn't entirely without documentary support -- the algorithm
employed I adopted from something given in Rubini's Linux Device Drivers
(O'Reilly bronco) book.

    rgb

Robert G. Brown	                       http://www.phy.duke.edu/~rgb/
Duke University Dept. of Physics, Box 90305
Durham, N.C. 27708-0305
Phone: 1-919-660-2567  Fax: 919-660-2525     email:rgb@phy.duke.edu

%< Snip snip snip =====================================================
--- tulip.c-0.89H	Mon Jan 11 07:59:21 1999
+++ tulip.c-0.89H.ioport	Mon Jan 11 08:28:48 1999
@@ -18,7 +18,7 @@
 */
 
 #define SMP_CHECK
-static const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
+static const char version[] = "tulip.c:v0.89H.ioport 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values. */
 
@@ -523,15 +523,53 @@
 		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
 								  &pci_ioaddr);
 #endif
+ /* 
+  * Patch to (maybe) fix ioport bug.  This fragment is from the book
+  * Linux Device Drivers, page 353, and polls each possible ioport
+  * until one is found that is writeable.  I think that this is the
+  * correct and robust approach to pci initialization.
+  */
 		{
-		u32 pci_ioaddr_check;
-		pcibios_read_config_dword(pci_bus, pci_device_fn,
-				  PCI_BASE_ADDRESS_0, &pci_ioaddr_check);
-		if (pci_ioaddr != pci_ioaddr_check)
-			printk("Buggy PCI BIOS - pcibios_read_config_dword("
-			       "%d,%d,%#x) = %#x / %#x.\n",
-			       pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
-			       pci_ioaddr, pci_ioaddr_check);
+		  int iio;
+		  u32 pci_ioaddr_check,pci_ioaddr_mask;
+		  u32 addresses[] = {
+			PCI_BASE_ADDRESS_0,
+			PCI_BASE_ADDRESS_1,
+			PCI_BASE_ADDRESS_2,
+			PCI_BASE_ADDRESS_3,
+			PCI_BASE_ADDRESS_4,
+			PCI_BASE_ADDRESS_5,
+			0
+		  };
+                  for(iio=0;addresses[iio];iio++){
+		    pcibios_read_config_dword(pci_bus, pci_device_fn,
+			addresses[iio], &pci_ioaddr_check);
+		    pcibios_write_config_dword(pci_bus, pci_device_fn,
+			addresses[iio], ~0);
+		    pcibios_read_config_dword(pci_bus, pci_device_fn,
+			addresses[iio], &pci_ioaddr_mask);
+		    pcibios_write_config_dword(pci_bus, pci_device_fn,
+			addresses[iio], pci_ioaddr_check);
+		    if (!pci_ioaddr_mask){
+		      printk("Buggy PCI BIOS - pcibios_read_config_dword("
+		         "%d,%d,%#x) = %#x / %#x.\n",
+		         pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
+		         pci_ioaddr, pci_ioaddr_check);
+		      printk("ioport %x probably unusable.  Continuing scan...\n",
+		       pci_ioaddr_check);
+		    } else {
+		      pci_ioaddr = pci_ioaddr_check;	/* Good one? */
+                      if(tulip_debug) printk(KERN_INFO "tulip_probe: ioport found at %x\n",pci_ioaddr);
+		      break;
+		    }
+		    if (pci_ioaddr != pci_ioaddr_check)
+		  }
+		  if (!pci_ioaddr){
+		    pcibios_read_config_dword(pci_bus, pci_device_fn,
+			  PCI_BASE_ADDRESS_0, &pci_ioaddr_check);
+                    printk("No valid ioport found.  Falling back on (failed) ioport %d\n",pci_ioaddr_check);
+                    pci_ioaddr = pci_ioaddr_check;
+		  }
 		}
 		/* Remove I/O space marker in bit 0. */
 		pci_ioaddr &= ~3;