patch-2.2.11 linux/drivers/net/pcnet32.c

Next file: linux/drivers/net/rtl8139.c
Previous file: linux/drivers/net/olympic.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.10/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
@@ -13,7 +13,7 @@
  * 	This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
-static const char *version = "pcnet32.c:v1.21 31.3.99 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.23 6.7.1999 tsbogend@alpha.franken.de\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -149,6 +149,13 @@
  *         rewritten PCI card detection
  *         added dwio mode to get driver working on some PPC machines
  * v1.21:  added mii selection and mii ioctl
+ * v1.22:  changed pci scanning code to make PPC people happy
+ *         fixed switching to 32bit mode in pcnet32_open() (thanks
+ *         to Michael Richard <mcr@solidum.com> for noticing this one)
+ *	   added sub vendor/device id matching (thanks again to 
+ *	   Michael Richard <mcr@solidum.com>)
+ *         added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
+ * v1.23   fixed small bug, when manual selecting MII speed/duplex
  */
 
 
@@ -185,6 +192,16 @@
 
 #define PCNET32_TOTAL_SIZE 0x20
 
+/* some PCI ids */
+#ifndef PCI_DEVICE_ID_AMD_LANCE
+#define PCI_VENDOR_ID_AMD	      0x1022
+#define PCI_DEVICE_ID_AMD_LANCE	      0x2000
+#endif
+#ifndef PCI_DEVICE_ID_AMD_PCNETHOME
+#define PCI_DEVICE_ID_AMD_PCNETHOME   0x2001
+#endif
+
+
 #define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
 
 /* The PCNET32 Rx and Tx ring descriptors. */
@@ -272,14 +289,19 @@
 
 struct pcnet32_pci_id_info {
     const char *name;
-    u16 vendor_id, device_id, device_id_mask, flags;
+    u16 vendor_id, device_id, svid, sdid, flags;
     int io_size;
     int (*probe1) (struct device *, unsigned long, unsigned char, int, int);
 };
 
 static struct pcnet32_pci_id_info pcnet32_tbl[] = {
     { "AMD PCnetPCI series",
-	0x1022, 0x2000, 0xfffe, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
+	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+	pcnet32_probe1},
+    { "AMD PCnetHome series",
+	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
+	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
 	pcnet32_probe1},
     {0,}
 };
@@ -418,30 +440,27 @@
     
 #if defined(CONFIG_PCI)
     if (pci_present()) {
-	struct pci_dev *pdev;
-	unsigned char pci_bus, pci_device_fn;
-	int pci_index;
+	struct pci_dev *pdev = NULL;
 	
 	printk("pcnet32.c: PCI bios is present, checking for devices...\n");
-	for (pci_index = 0; pci_index < 0xff; pci_index++) {
-	    u16 vendor, device, pci_command;
+	while ((pdev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
+	    u16 pci_command;
 	    int chip_idx;
+	    u16 sdid,svid;
 
-	    if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
-				    pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
-		break;
-	    
-	    pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor);
-	    pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device);
-
+	    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &sdid);
+	    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &svid);
 	    for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
-		if (vendor == pcnet32_tbl[chip_idx].vendor_id &&
-		    (device & pcnet32_tbl[chip_idx].device_id_mask) == pcnet32_tbl[chip_idx].device_id)
+		if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) &&
+		    (pdev->device == pcnet32_tbl[chip_idx].device_id) &&
+		    (pcnet32_tbl[chip_idx].svid == 0 || 
+		     (svid == pcnet32_tbl[chip_idx].svid)) &&
+		    (pcnet32_tbl[chip_idx].sdid == 0 || 
+		     (sdid == pcnet32_tbl[chip_idx].sdid)))
 		    break;
 	    if (pcnet32_tbl[chip_idx].vendor_id == 0)
 		continue;
 	    
-	    pdev = pci_find_slot(pci_bus, pci_device_fn);
 	    ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 #if defined(ADDR_64BITS) && defined(__alpha__)
 	    ioaddr |= ((long)pdev->base_address[1]) << 32;
@@ -541,6 +560,10 @@
 	chipname = "PCnet/FAST+ 79C972";
 	fdx = 1; mii = 1;
 	break;
+     case 0x2625:
+	chipname = "PCnet/FAST III 79C973";
+	fdx = 1; mii = 1;
+	break;
      case 0x2626:
 	chipname = "PCnet/Home 79C978";
 	fdx = 1;
@@ -561,6 +584,9 @@
 	    printk("pcnet32: pcnet32 media reset to %#x.\n",  media);
 	a->write_bcr (ioaddr, 49, media);
 	break;
+     case 0x2627:
+	chipname = "PCnet/FAST III 79C975";
+	fdx = 1; mii = 1;
      default:
 	printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
 	return ENODEV;
@@ -693,7 +719,7 @@
     lp->a.reset (ioaddr);
 
     /* switch pcnet32 to 32bit mode */
-    lp->a.write_csr (ioaddr, 20, 2);
+    lp->a.write_bcr (ioaddr, 20, 2);
 
     if (pcnet32_debug > 1)
 	printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
@@ -725,7 +751,7 @@
 	val |= 0x10;
     lp->a.write_csr (ioaddr, 124, val);
     
-    if (lp->mii & (lp->options & PORT_ASEL)) {
+    if (lp->mii & !(lp->options & PORT_ASEL)) {
 	val = lp->a.read_bcr (ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */
 	if (lp->options & PORT_FD)
 	    val |= 0x10;
@@ -952,7 +978,7 @@
     struct device *dev = (struct device *)dev_id;
     struct pcnet32_private *lp;
     unsigned long ioaddr;
-    u16 csr0;
+    u16 csr0,rap;
     int boguscnt =  max_interrupt_work;
     int must_restart;
 
@@ -968,6 +994,7 @@
 
     dev->interrupt = 1;
 
+    rap = lp->a.read_rap(ioaddr);
     while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) {
 	/* Acknowledge all of the current interrupt sources ASAP. */
 	lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f);
@@ -1069,6 +1096,7 @@
 
     /* Clear any other interrupt, and set interrupt enable. */
     lp->a.write_csr (ioaddr, 0, 0x7940);
+    lp->a.write_rap(ioaddr,rap);
 
     if (pcnet32_debug > 4)
 	printk("%s: exiting interrupt, csr0=%#4.4x.\n",

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