patch-2.3.99-pre7 linux/drivers/net/pcnet32.c

Next file: linux/drivers/net/plip.c
Previous file: linux/drivers/net/pcmcia/xircom_tulip_cb.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
@@ -1,21 +1,20 @@
 /* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
 /*
- *      Copyright 1996-1999 Thomas Bogendoerfer
+ *	Copyright 1996-1999 Thomas Bogendoerfer
  * 
- * 	Derived from the lance driver written 1993,1994,1995 by Donald Becker.
+ *	Derived from the lance driver written 1993,1994,1995 by Donald Becker.
  * 
- * 	Copyright 1993 United States Government as represented by the
- * 	Director, National Security Agency.
+ *	Copyright 1993 United States Government as represented by the
+ *	Director, National Security Agency.
  * 
- * 	This software may be used and distributed according to the terms
- * 	of the GNU Public License, incorporated herein by reference.
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
  *
- * 	This driver is for PCnet32 and PCnetPCI based ethercards
+ *	This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
 static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n";
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -56,30 +55,31 @@
 #define PORT_PORTSEL  0x03
 #define PORT_ASEL     0x04
 #define PORT_100      0x40
-#define PORT_FD       0x80
+#define PORT_FD	      0x80
 
+#define PCNET32_DMA_MASK 0xffffffff
 
 /*
  * table to translate option values from tulip
  * to internal options
  */
 static unsigned char options_mapping[] = {
-    PORT_ASEL,			   /*  0 Auto-select      */
-    PORT_AUI,			   /*  1 BNC/AUI          */
-    PORT_AUI,			   /*  2 AUI/BNC          */ 
-    PORT_ASEL,			   /*  3 not supported    */
-    PORT_10BT | PORT_FD,	   /*  4 10baseT-FD       */
-    PORT_ASEL,			   /*  5 not supported    */
-    PORT_ASEL,			   /*  6 not supported    */
-    PORT_ASEL,			   /*  7 not supported    */
-    PORT_ASEL,			   /*  8 not supported    */
-    PORT_MII,		           /*  9 MII 10baseT      */
-    PORT_MII | PORT_FD,            /* 10 MII 10baseT-FD   */
-    PORT_MII,			   /* 11 MII (autosel)    */
+    PORT_ASEL,			   /*  0 Auto-select	  */
+    PORT_AUI,			   /*  1 BNC/AUI	  */
+    PORT_AUI,			   /*  2 AUI/BNC	  */ 
+    PORT_ASEL,			   /*  3 not supported	  */
+    PORT_10BT | PORT_FD,	   /*  4 10baseT-FD	  */
+    PORT_ASEL,			   /*  5 not supported	  */
+    PORT_ASEL,			   /*  6 not supported	  */
+    PORT_ASEL,			   /*  7 not supported	  */
+    PORT_ASEL,			   /*  8 not supported	  */
+    PORT_MII,			   /*  9 MII 10baseT	  */
+    PORT_MII | PORT_FD,		   /* 10 MII 10baseT-FD	  */
+    PORT_MII,			   /* 11 MII (autosel)	  */
     PORT_10BT,			   /* 12 10BaseT	  */
-    PORT_MII | PORT_100,	   /* 13 MII 100BaseTx    */
+    PORT_MII | PORT_100,	   /* 13 MII 100BaseTx	  */
     PORT_MII | PORT_100 | PORT_FD, /* 14 MII 100BaseTx-FD */
-    PORT_ASEL			   /* 15 not supported    */
+    PORT_ASEL			   /* 15 not supported	  */
 };
 
 #define MAX_UNITS 8
@@ -87,7 +87,7 @@
 static int full_duplex[MAX_UNITS] = {0, };
 
 /*
- * 				Theory of Operation
+ *				Theory of Operation
  * 
  * This driver uses the same software structure as the normal lance
  * driver. So look for a verbose description in lance.c. The differences
@@ -99,21 +99,21 @@
 /*
  * History:
  * v0.01:  Initial version
- *         only tested on Alpha Noname Board
+ *	   only tested on Alpha Noname Board
  * v0.02:  changed IRQ handling for new interrupt scheme (dev_id)
- *         tested on a ASUS SP3G
+ *	   tested on a ASUS SP3G
  * v0.10:  fixed an odd problem with the 79C974 in a Compaq Deskpro XL
- *         looks like the 974 doesn't like stopping and restarting in a
- *         short period of time; now we do a reinit of the lance; the
- *         bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
- *         and hangs the machine (thanks to Klaus Liedl for debugging)
+ *	   looks like the 974 doesn't like stopping and restarting in a
+ *	   short period of time; now we do a reinit of the lance; the
+ *	   bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
+ *	   and hangs the machine (thanks to Klaus Liedl for debugging)
  * v0.12:  by suggestion from Donald Becker: Renamed driver to pcnet32,
- *         made it standalone (no need for lance.c)
+ *	   made it standalone (no need for lance.c)
  * v0.13:  added additional PCI detecting for special PCI devices (Compaq)
  * v0.14:  stripped down additional PCI probe (thanks to David C Niemi
- *         and sveneric@xs4all.nl for testing this on their Compaq boxes)
+ *	   and sveneric@xs4all.nl for testing this on their Compaq boxes)
  * v0.15:  added 79C965 (VLB) probe
- *         added interrupt sharing for PCI chips
+ *	   added interrupt sharing for PCI chips
  * v0.16:  fixed set_multicast_list on Alpha machines
  * v0.17:  removed hack from dev.c; now pcnet32 uses ethif_probe in Space.c
  * v0.19:  changed setting of autoselect bit
@@ -123,42 +123,44 @@
  * v0.22:  added printing of status to ring dump
  * v0.23:  changed enet_statistics to net_devive_stats
  * v0.90:  added multicast filter
- *         added module support
- *         changed irq probe to new style
- *         added PCnetFast chip id
- *         added fix for receive stalls with Intel saturn chipsets
- *         added in-place rx skbs like in the tulip driver
- *         minor cleanups
+ *	   added module support
+ *	   changed irq probe to new style
+ *	   added PCnetFast chip id
+ *	   added fix for receive stalls with Intel saturn chipsets
+ *	   added in-place rx skbs like in the tulip driver
+ *	   minor cleanups
  * v0.91:  added PCnetFast+ chip id
- *         back port to 2.0.x
+ *	   back port to 2.0.x
  * v1.00:  added some stuff from Donald Becker's 2.0.34 version
- *         added support for byte counters in net_dev_stats
+ *	   added support for byte counters in net_dev_stats
  * v1.01:  do ring dumps, only when debugging the driver
- *         increased the transmit timeout
+ *	   increased the transmit timeout
  * v1.02:  fixed memory leak in pcnet32_init_ring()
  * v1.10:  workaround for stopped transmitter
- *         added port selection for modules
- *         detect special T1/E1 WAN card and setup port selection
+ *	   added port selection for modules
+ *	   detect special T1/E1 WAN card and setup port selection
  * v1.11:  fixed wrong checking of Tx errors
  * v1.20:  added check of return value kmalloc (cpeterso@cs.washington.edu)
- *         added save original kmalloc addr for freeing (mcr@solidum.com)
- *         added support for PCnetHome chip (joe@MIT.EDU)
- *         rewritten PCI card detection
- *         added dwio mode to get driver working on some PPC machines
+ *	   added save original kmalloc addr for freeing (mcr@solidum.com)
+ *	   added support for PCnetHome chip (joe@MIT.EDU)
+ *	   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)
+ *	   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>)
+ *	   added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
  * v1.23   fixed small bug, when manual selecting MII speed/duplex
  * v1.24   Applied Thomas' patch to use TxStartPoint and thus decrease TxFIFO
- *         underflows.  Added tx_start_pt module parameter. Increased
- *         TX_RING_SIZE from 16 to 32.  Added #ifdef'd code to use DXSUFLO
- *         for FAST[+] chipsets. <kaf@fc.hp.com>
+ *	   underflows.	Added tx_start_pt module parameter. Increased
+ *	   TX_RING_SIZE from 16 to 32.	Added #ifdef'd code to use DXSUFLO
+ *	   for FAST[+] chipsets. <kaf@fc.hp.com>
  * v1.24ac Added SMP spinlocking - Alan Cox <alan@redhat.com>
  * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
+ * v1.26   Converted to pci_alloc_consistent, Jamey Hicks / George France
+ *                                           <jamey@crl.dec.com>
  */
 
 
@@ -205,13 +207,13 @@
 #endif
 
 
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
 
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
     u32 base;
     s16 buf_length;
-    s16 status;    
+    s16 status;	   
     u32 msg_length;
     u32 reserved;
 };
@@ -228,7 +230,7 @@
 struct pcnet32_init_block {
     u16 mode;
     u16 tlen_rlen;
-    u8  phys_addr[6];
+    u8	phys_addr[6];
     u16 reserved;
     u32 filter[2];
     /* Receive and transmit ring base, along with extra bits. */    
@@ -247,35 +249,43 @@
     void (*reset)(unsigned long);
 };
 
+/*
+ * The first three fields of pcnet32_private are read by the ethernet device 
+ * so we allocate the structure should be allocated by pci_alloc_consistent().
+ */
 struct pcnet32_private {
     /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
     struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
     struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
     struct pcnet32_init_block	init_block;
+    dma_addr_t dma_addr;		/* DMA address of beginning of this object, returned by pci_alloc_consistent */
+    struct pci_dev *pci_dev;		/* Pointer to the associated pci device structure */
     const char *name;
     /* The saved address of a sent-in-place packet/buffer, for skfree(). */
     struct sk_buff *tx_skbuff[TX_RING_SIZE];
     struct sk_buff *rx_skbuff[RX_RING_SIZE];
+    dma_addr_t tx_dma_addr[TX_RING_SIZE];
+    dma_addr_t rx_dma_addr[RX_RING_SIZE];
     struct pcnet32_access a;
-    void *origmem;
-    spinlock_t lock;				/* Guard lock */
+    spinlock_t lock;					/* Guard lock */
     unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-    unsigned int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
+    unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
     struct net_device_stats stats;
     char tx_full;
-    int  options;
-    int  shared_irq:1,                      	/* shared irq possible */
-	 ltint:1,
+    int	 options;
+    int	 shared_irq:1,			/* shared irq possible */
+	ltint:1,
 #ifdef DO_DXSUFLO
-	 dxsuflo:1,			    /* disable transmit stop on uflo */
+	      dxsuflo:1,						    /* disable transmit stop on uflo */
 #endif
-         full_duplex:1,                     	/* full duplex possible */
-         mii:1;                             	/* mii port available */
+	full_duplex:1,				/* full duplex possible */
+	mii:1;					/* mii port available */
     struct net_device *next;
 };
 
-static int  pcnet32_probe(void);
-static int  pcnet32_probe1(unsigned long, unsigned char, int, int);
+static int  pcnet32_probe_vlbus(int cards_found);
+static int  pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
+static int  pcnet32_probe1(unsigned long, unsigned char, int, int, struct pci_dev *);
 static int  pcnet32_open(struct net_device *);
 static int  pcnet32_init_ring(struct net_device *);
 static int  pcnet32_start_xmit(struct sk_buff *, struct net_device *);
@@ -298,25 +308,35 @@
     const char *name;
     u16 vendor_id, device_id, svid, sdid, flags;
     int io_size;
-    int (*probe1) (unsigned long, unsigned char, int, int);
+    int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *);
 };
 
 static struct pcnet32_pci_id_info pcnet32_tbl[] = {
     { "AMD PCnetPCI series",
-	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
-	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
-	pcnet32_probe1},
+      PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
+      PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+      pcnet32_probe1},
     { "AMD PCnetPCI series (IBM)",
-	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000,
-	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
-	pcnet32_probe1},
+      PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000,
+      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},
+      PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
+      PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+      pcnet32_probe1},
     {0,}
 };
 
+/*
+ * PCI device identifiers for "new style" Linux PCI Device Drivers
+ */
+static struct pci_device_id pcnet32_pci_tbl[] __devinitdata = {
+    { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+    { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+    { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, 0, 0, 0 },
+    { 0, 0, 0, 0, 0, 0, 0 },
+};
+
 static u16 pcnet32_wio_read_csr (unsigned long addr, int index)
 {
     outw (index, addr+PCNET32_WIO_RAP);
@@ -430,96 +450,83 @@
 
 
 
-static int __init pcnet32_probe(void)
+/* only probes for non-PCI devices, the rest are handled by pci_register_driver via pcnet32_probe_pci*/
+static int __init pcnet32_probe_vlbus(int cards_found)
 {
     unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0;
     unsigned int  irq_line = 0; // FIXME dev ? dev->irq : 0;
     int *port;
-    int cards_found = 0;
-    
     
+    printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found);
 #ifndef __powerpc__
     if (ioaddr > 0x1ff) {
 	if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0)
-	    return pcnet32_probe1(ioaddr, irq_line, 0, 0);
+	    return pcnet32_probe1(ioaddr, irq_line, 0, 0, NULL);
 	else
-	    return ENODEV;
+	    return -ENODEV;
     } else
 #endif
-	if(ioaddr != 0)
-	    return ENXIO;
-    
-#if defined(CONFIG_PCI)
-    if (pci_present()) {
-	struct pci_dev *pdev = NULL;
-	
-	printk("pcnet32.c: PCI bios is present, checking for devices...\n");
-	while ((pdev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
-	    u16 pci_command;
-	    int chip_idx;
-	    u16 sdid,svid;
-
-	    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
-	    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdid);
-	    for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
-		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;
-	    
-	    ioaddr = pdev->resource[0].start;
-	    irq_line = pdev->irq;
-	    
-	    /* Avoid already found cards from previous pcnet32_probe() calls */
-	    if ((pcnet32_tbl[chip_idx].flags & PCI_USES_IO) &&
-		check_region(ioaddr, pcnet32_tbl[chip_idx].io_size))
-		continue;
-
-	    /* PCI Spec 2.1 states that it is either the driver or PCI card's
-	     * responsibility to set the PCI Master Enable Bit if needed.
-	     *	(From Mark Stockton <marks@schooner.sys.hou.compaq.com>)
-	     */
-	    pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-	    if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-		printk("PCI Master Bit has not been set. Setting...\n");
-		pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-	    }
-	    printk("Found PCnet/PCI at %#lx, irq %d.\n", ioaddr, irq_line);
-	    
-	    if (pcnet32_tbl[chip_idx].probe1(ioaddr, irq_line, 1, cards_found) == 0) {
-		cards_found++;
-	    }
-	}
-    } else 
-#endif  /* defined(CONFIG_PCI) */
+	if (ioaddr != 0)
+	    return -ENXIO;
     
     /* now look for PCnet32 VLB cards */
     for (port = pcnet32_portlist; *port; port++) {
 	unsigned long ioaddr = *port;
 	
 	if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) {
-    	    /* check if there is really a pcnet chip on that ioaddr */
-    	    if ((inb(ioaddr + 14) == 0x57) &&
+	    /* check if there is really a pcnet chip on that ioaddr */
+	    if ((inb(ioaddr + 14) == 0x57) &&
 		(inb(ioaddr + 15) == 0x57) &&
-	        (pcnet32_probe1(ioaddr, 0, 0, 0) == 0))
+		(pcnet32_probe1(ioaddr, 0, 0, 0, NULL) == 0))
 		cards_found++;
 	}
     }
-    return cards_found ? 0: ENODEV;
+    return cards_found ? 0: -ENODEV;
 }
 
 
-/* pcnet32_probe1 */
+
 static int __init
-pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx)
+pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+    static int card_idx = 0;
+    long ioaddr;
+    int err = 0;
+
+    printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device);
+
+    ioaddr = pci_resource_start (pdev, 0);
+    printk(KERN_INFO "  ioaddr=%#08lx  resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0));
+    if (!ioaddr) {
+        printk (KERN_ERR "no PCI IO resources, aborting\n");
+        return -ENODEV;
+    }
+	
+    if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {
+	printk(KERN_ERR "pcnet32.c: architecture does not support 32bit PCI busmaster DMA\n");
+	return -ENODEV;
+    }
+
+    if ((err = pci_enable_device(pdev)) < 0) {
+	printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err);
+	return err;
+    }
+    
+    pci_set_master(pdev);
+    
+    return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev);
+}
+
+
+/* pcnet32_probe1 
+ *  Called from both pcnet32_probe_vlbus and pcnet_probe_pci.  
+ *  pdev will be NULL when called from pcnet32_probe_vlbus.
+ */
+static int __init
+pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev)
 {
     struct pcnet32_private *lp;
+    dma_addr_t lp_dma_addr;
     int i,media,fdx = 0, mii = 0, fset = 0;
 #ifdef DO_DXSUFLO
     int dxsuflo = 0;
@@ -527,9 +534,8 @@
     int ltint = 0;
     int chip_version;
     char *chipname;
-    char *priv;
     struct net_device *dev;
-    struct pcnet32_access *a;
+    struct pcnet32_access *a = NULL;
 
     /* reset the chip */
     pcnet32_dwio_reset(ioaddr);
@@ -541,44 +547,44 @@
 	if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
 	    a = &pcnet32_dwio;
 	} else
-	    return ENODEV;
+	    return -ENODEV;
     }
 
     chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
     if (pcnet32_debug > 2)
-	printk("  PCnet chip version is %#x.\n", chip_version);
+	printk(KERN_INFO "  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003)
-	return ENODEV;
+	return -ENODEV;
     chip_version = (chip_version >> 12) & 0xffff;
     switch (chip_version) {
-     case 0x2420:
-	chipname = "PCnet/PCI 79C970";
+    case 0x2420:
+	chipname = "PCnet/PCI 79C970"; /* PCI */
 	break;
-     case 0x2430:
+    case 0x2430:
 	if (shared)
 	    chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */
 	else
-	    chipname = "PCnet/32 79C965";
+	    chipname = "PCnet/32 79C965"; /* 486/VL bus */
 	break;
-     case 0x2621:
-	chipname = "PCnet/PCI II 79C970A";
+    case 0x2621:
+	chipname = "PCnet/PCI II 79C970A"; /* PCI */
 	fdx = 1;
 	break;
-     case 0x2623:
-	chipname = "PCnet/FAST 79C971";
+    case 0x2623:
+	chipname = "PCnet/FAST 79C971"; /* PCI */
 	fdx = 1; mii = 1; fset = 1;
 	ltint = 1;
 	break;
-     case 0x2624:
-	chipname = "PCnet/FAST+ 79C972";
+    case 0x2624:
+	chipname = "PCnet/FAST+ 79C972"; /* PCI */
 	fdx = 1; mii = 1; fset = 1;
 	break;
-     case 0x2625:
-	chipname = "PCnet/FAST III 79C973";
+    case 0x2625:
+	chipname = "PCnet/FAST III 79C973"; /* PCI */
 	fdx = 1; mii = 1;
 	break;
-     case 0x2626:
-	chipname = "PCnet/Home 79C978";
+    case 0x2626:
+	chipname = "PCnet/Home 79C978"; /* PCI */
 	fdx = 1;
 	/* 
 	 * This is based on specs published at www.amd.com.  This section
@@ -589,33 +595,35 @@
 	 */
 	/* switch to home wiring mode */
 	media = a->read_bcr (ioaddr, 49);
+#if 0
 	if (pcnet32_debug > 2)
-	    printk("pcnet32: pcnet32 media value %#x.\n",  media);
+	    printk(KERN_DEBUG "pcnet32: pcnet32 media value %#x.\n",  media);
 	media &= ~3;
 	media |= 1;
+#endif
 	if (pcnet32_debug > 2)
-	    printk("pcnet32: pcnet32 media reset to %#x.\n",  media);
+	    printk(KERN_DEBUG "pcnet32: pcnet32 media reset to %#x.\n",  media);
 	a->write_bcr (ioaddr, 49, media);
 	break;
-     case 0x2627:
-	chipname = "PCnet/FAST III 79C975";
+    case 0x2627:
+	chipname = "PCnet/FAST III 79C975"; /* PCI */
 	fdx = 1; mii = 1;
 	break;
-     default:
-	printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
-	return ENODEV;
+    default:
+	printk(KERN_INFO "pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
+	return -ENODEV;
     }
 
     /*
      *	On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
-     *  starting until the packet is loaded. Strike one for reliability, lose
-     *  one for latency - although on PCI this isnt a big loss. Older chips 
-     *  have FIFO's smaller than a packet, so you can't do this.
+     *	starting until the packet is loaded. Strike one for reliability, lose
+     *	one for latency - although on PCI this isnt a big loss. Older chips 
+     *	have FIFO's smaller than a packet, so you can't do this.
      */
-         
+	 
     if(fset)
     {
-    	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
 	a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);
 #ifdef DO_DXSUFLO
 	dxsuflo = 1;
@@ -625,52 +633,50 @@
     
     dev = init_etherdev(NULL, 0);
     if(dev==NULL)
-    	return ENOMEM;
+	return -ENOMEM;
 
     printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr);
 
     /* There is a 16 byte station address PROM at the base address.
-     The first six bytes are the station address. */
+       The first six bytes are the station address. */
     for (i = 0; i < 6; i++)
-      printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+	printk( KERN_INFO " %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
     if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
-        i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
-	printk("\n    tx_start_pt(0x%04x):",i);
+	i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
+	printk(KERN_INFO"\n    tx_start_pt(0x%04x):",i);
 	switch(i>>10) {
-	    case 0: printk("  20 bytes,"); break;
-	    case 1: printk("  64 bytes,"); break;
-	    case 2: printk(" 128 bytes,"); break;
-	    case 3: printk("~220 bytes,"); break;
+	    case 0: printk(KERN_INFO "  20 bytes,"); break;
+	    case 1: printk(KERN_INFO "  64 bytes,"); break;
+	    case 2: printk(KERN_INFO " 128 bytes,"); break;
+	    case 3: printk(KERN_INFO "~220 bytes,"); break;
 	}
-        i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
-        printk(" BCR18(%x):",i&0xffff);
-	if (i & (1<<5)) printk("BurstWrEn ");
-	if (i & (1<<6)) printk("BurstRdEn ");
-	if (i & (1<<7)) printk("DWordIO ");
-	if (i & (1<<11)) printk("NoUFlow ");
-        i = a->read_bcr(ioaddr, 25);
-        printk("\n    SRAMSIZE=0x%04x,",i<<8);
-        i = a->read_bcr(ioaddr, 26);
-        printk(" SRAM_BND=0x%04x,",i<<8);
-        i = a->read_bcr(ioaddr, 27);
-	if (i & (1<<14)) printk("LowLatRx,");
+	i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
+	printk(KERN_INFO" BCR18(%x):",i&0xffff);
+	if (i & (1<<5)) printk(KERN_INFO "BurstWrEn ");
+	if (i & (1<<6)) printk(KERN_INFO "BurstRdEn ");
+	if (i & (1<<7)) printk(KERN_INFO "DWordIO ");
+	if (i & (1<<11)) printk(KERN_INFO"NoUFlow ");
+	i = a->read_bcr(ioaddr, 25);
+	printk(KERN_INFO "\n    SRAMSIZE=0x%04x,",i<<8);
+	i = a->read_bcr(ioaddr, 26);
+	printk(KERN_INFO " SRAM_BND=0x%04x,",i<<8);
+	i = a->read_bcr(ioaddr, 27);
+	if (i & (1<<14)) printk(KERN_INFO "LowLatRx,");
     }
 
     dev->base_addr = ioaddr;
     request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
     
-    if ((priv = kmalloc(sizeof(*lp)+15,GFP_KERNEL)) == NULL)
-	return ENOMEM;
+    /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
+    if ((lp = (struct pcnet32_private *)pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL)
+	return -ENOMEM;
 
-    /*
-     * Make certain the data structures used by
-     * the PCnet32 are 16byte aligned
-      */
-    lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15);
-      
     memset(lp, 0, sizeof(*lp));
-    
+    lp->dma_addr = lp_dma_addr;
+    lp->pci_dev = pdev;
+    printk(KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x\n", lp, lp_dma_addr);
+
     spin_lock_init(&lp->lock);
     
     dev->priv = lp;
@@ -690,34 +696,37 @@
     if (fdx && !(lp->options & PORT_ASEL) && full_duplex[card_idx])
 	lp->options |= PORT_FD;
     
-    lp->origmem = priv;
     lp->a = *a;
+    if (a == NULL) {
+      printk(KERN_ERR "pcnet32: No access methods\n");
+      return -ENODEV;
+    }
     
     /* detect special T1/E1 WAN card by checking for MAC address */
     if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75)
 	lp->options = PORT_FD | PORT_GPSI;
 
-    lp->init_block.mode = le16_to_cpu(0x0003); 	/* Disable Rx and Tx. */
+    lp->init_block.mode = le16_to_cpu(0x0003);	/* Disable Rx and Tx. */
     lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); 
     for (i = 0; i < 6; i++)
-      lp->init_block.phys_addr[i] = dev->dev_addr[i];
+	lp->init_block.phys_addr[i] = dev->dev_addr[i];
     lp->init_block.filter[0] = 0x00000000;
     lp->init_block.filter[1] = 0x00000000;
-    lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
-    lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+    lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, tx_ring));
     
     /* switch pcnet32 to 32bit mode */
     a->write_bcr (ioaddr, 20, 2);
 
-    a->write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) & 0xffff);
-    a->write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16);
+    a->write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) & 0xffff);
+    a->write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16);
     
     if (irq_line) {
 	dev->irq = irq_line;
     }
     
     if (dev->irq >= 2)
-	printk(" assigned IRQ %d.\n", dev->irq);
+	printk(KERN_INFO " assigned IRQ %d.\n", dev->irq);
     else {
 	unsigned long irq_mask = probe_irq_on();
 	
@@ -732,15 +741,15 @@
 	
 	dev->irq = probe_irq_off (irq_mask);
 	if (dev->irq)
-	  printk(", probed IRQ %d.\n", dev->irq);
+	    printk(KERN_INFO ", probed IRQ %d.\n", dev->irq);
 	else {
-	    printk(", failed to detect IRQ line.\n");
-	    return ENODEV;
+	    printk(KERN_ERR ", failed to detect IRQ line.\n");
+	    return -ENODEV;
 	}
     }
 
     if (pcnet32_debug > 0)
-	printk(version);
+	printk(KERN_INFO, version);
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -784,11 +793,11 @@
     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",
+	printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
 	       dev->name, dev->irq,
-	       (u32) virt_to_bus(lp->tx_ring),
-	       (u32) virt_to_bus(lp->rx_ring),
-	       (u32) virt_to_bus(&lp->init_block));
+	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)),
+	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, rx_ring)),
+	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)));
     
     /* set/reset autoselect bit */
     val = lp->a.read_bcr (ioaddr, 2) & ~2;
@@ -824,15 +833,15 @@
 
 #ifdef DO_DXSUFLO 
     if (lp->dxsuflo) { /* Disable transmit stop on underflow */
-        val = lp->a.read_csr (ioaddr, 3);
+	val = lp->a.read_csr (ioaddr, 3);
 	val |= 0x40;
-        lp->a.write_csr (ioaddr, 3, val);
+	lp->a.write_csr (ioaddr, 3, val);
     }
 #endif
     if (lp->ltint) { /* Enable TxDone-intr inhibitor */
-        val = lp->a.read_csr (ioaddr, 5);
+	val = lp->a.read_csr (ioaddr, 5);
 	val |= (1<<14);
-        lp->a.write_csr (ioaddr, 5, val);
+	lp->a.write_csr (ioaddr, 5, val);
     }
    
     lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
@@ -842,8 +851,8 @@
 	return -ENOMEM;
     
     /* Re-initialize the PCNET32, and start it when done. */
-    lp->a.write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) &0xffff);
-    lp->a.write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16);
+    lp->a.write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) &0xffff);
+    lp->a.write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16);
 
     lp->a.write_csr (ioaddr, 4, 0x0915);
     lp->a.write_csr (ioaddr, 0, 0x0001);
@@ -861,10 +870,11 @@
     lp->a.write_csr (ioaddr, 0, 0x0042);
 
     if (pcnet32_debug > 2)
-	printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
-	       dev->name, i, (u32) virt_to_bus(&lp->init_block),
+	printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
+	       dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)),
 	       lp->a.read_csr (ioaddr, 0));
 
+
     MOD_INC_USE_COUNT;
     
     return 0;	/* Always succeed */
@@ -891,8 +901,10 @@
 
     for (i = 0; i < TX_RING_SIZE; i++) {
 	if (lp->tx_skbuff[i]) {
-	    dev_kfree_skb(lp->tx_skbuff[i]);
+            pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
+	    dev_kfree_skb(lp->tx_skbuff[i]); 
 	    lp->tx_skbuff[i] = NULL;
+            lp->tx_dma_addr[i] = 0;
 	}
     }
 }
@@ -910,30 +922,33 @@
     lp->dirty_rx = lp->dirty_tx = 0;
 
     for (i = 0; i < RX_RING_SIZE; i++) {
-	if (lp->rx_skbuff[i] == NULL) {
-	    if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
+        struct sk_buff *rx_skbuff = lp->rx_skbuff[i];
+	if (rx_skbuff == NULL) {
+	    if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
 		/* there is not much, we can do at this point */
-		printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
+		printk(KERN_ERR "%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
 		return -1;
 	    }
-	    skb_reserve (lp->rx_skbuff[i], 2);
+	    skb_reserve (rx_skbuff, 2);
 	}
-	lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail));
+        lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE);
+	lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
 	lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
 	lp->rx_ring[i].status = le16_to_cpu(0x8000);
     }
     /* The Tx buffer address is filled in as needed, but we do need to clear
-     the upper ownership bit. */
+       the upper ownership bit. */
     for (i = 0; i < TX_RING_SIZE; i++) {
 	lp->tx_ring[i].base = 0;
 	lp->tx_ring[i].status = 0;
+        lp->tx_dma_addr[i] = 0;
     }
 
     lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
     for (i = 0; i < 6; i++)
 	lp->init_block.phys_addr[i] = dev->dev_addr[i];
-    lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
-    lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+    lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, tx_ring));
     return 0;
 }
 
@@ -966,24 +981,24 @@
     unsigned int ioaddr = dev->base_addr;
 
     /* Transmitter timeout, serious problems. */
-	printk("%s: transmit timed out, status %4.4x, resetting.\n",
+	printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
 	lp->a.write_csr (ioaddr, 0, 0x0004);
 	lp->stats.tx_errors++;
 	if (pcnet32_debug > 2) {
 	    int i;
-	    printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
-		   lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
-		   lp->cur_rx);
+	    printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+	       lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+	       lp->cur_rx);
 	    for (i = 0 ; i < RX_RING_SIZE; i++)
-		printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-		       lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
-		       lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
+	    printk(KERN_DEBUG "%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+		   lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+		   lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
 	    for (i = 0 ; i < TX_RING_SIZE; i++)
-		printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-		       lp->tx_ring[i].base, -lp->tx_ring[i].length,
-		       lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
-	    printk("\n");
+	    printk(KERN_DEBUG "%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+		   lp->tx_ring[i].base, -lp->tx_ring[i].length,
+		   lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
+	    printk(KERN_DEBUG "\n");
 	}
 	pcnet32_restart(dev, 0x0042);
 
@@ -1002,7 +1017,7 @@
     unsigned long flags;
 
     if (pcnet32_debug > 3) {
-	printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
+	printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
     }
 
@@ -1037,7 +1052,8 @@
     lp->tx_ring[entry].misc = 0x00000000;
 
     lp->tx_skbuff[entry] = skb;
-    lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
+    lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+    lp->tx_ring[entry].base = (u32)le32_to_cpu(lp->tx_dma_addr[entry]);
     lp->tx_ring[entry].status = le16_to_cpu(status);
 
     lp->cur_tx++;
@@ -1070,7 +1086,7 @@
     int must_restart;
 
     if (dev == NULL) {
-	printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
+	printk (KERN_DEBUG "pcnet32_interrupt(): irq %d for unknown device.\n", irq);
 	return;
     }
 
@@ -1087,7 +1103,7 @@
 	must_restart = 0;
 
 	if (pcnet32_debug > 5)
-	    printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+	    printk(KERN_DEBUG "%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
 		   dev->name, csr0, lp->a.read_csr (ioaddr, 0));
 
 	if (csr0 & 0x0400)		/* Rx interrupt */
@@ -1113,13 +1129,13 @@
 		    if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
 		    if (err_status & 0x10000000) lp->stats.tx_window_errors++;
 #ifndef DO_DXSUFLO
- 		    if (err_status & 0x40000000) {
- 			lp->stats.tx_fifo_errors++;
+		    if (err_status & 0x40000000) {
+			lp->stats.tx_fifo_errors++;
 			/* Ackk!  On FIFO errors the Tx unit is turned off! */
- 			/* Remove this verbosity later! */
-			printk("%s: Tx FIFO error! CSR0=%4.4x\n",
-					    dev->name, csr0);
- 			must_restart = 1;
+			/* Remove this verbosity later! */
+			printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
+			       dev->name, csr0);
+			must_restart = 1;
 		    }
 #else
 		    if (err_status & 0x40000000) {
@@ -1127,8 +1143,8 @@
 			if (! lp->dxsuflo) {  /* If controller doesn't recover ... */
 			    /* Ackk!  On FIFO errors the Tx unit is turned off! */
 			    /* Remove this verbosity later! */
-			    printk("%s: Tx FIFO error! CSR0=%4.4x\n",
-					   	dev->name, csr0);
+			    printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
+				   dev->name, csr0);
 			    must_restart = 1;
 			}
 		    }
@@ -1141,22 +1157,24 @@
 
 		/* We must free the original skb */
 		if (lp->tx_skbuff[entry]) {
+                    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
 		    dev_kfree_skb_irq(lp->tx_skbuff[entry]);
 		    lp->tx_skbuff[entry] = 0;
+                    lp->tx_dma_addr[entry] = 0;
 		}
 		dirty_tx++;
 	    }
 
 #ifndef final_version
 	    if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-		printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
 		       dirty_tx, lp->cur_tx, lp->tx_full);
 		dirty_tx += TX_RING_SIZE;
 	    }
 #endif
 	    if (lp->tx_full &&
-	        netif_queue_stopped(dev) &&
-			dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+		netif_queue_stopped(dev) &&
+		dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
 		/* The ring is no longer full, clear tbusy. */
 		lp->tx_full = 0;
 		netif_wake_queue (dev);
@@ -1180,7 +1198,7 @@
 	    lp->stats.rx_errors++; /* Missed a Rx frame. */
 	}
 	if (csr0 & 0x0800) {
-	    printk("%s: Bus master arbitration failure, status %4.4x.\n",
+	    printk(KERN_ERR "%s: Bus master arbitration failure, status %4.4x.\n",
 		   dev->name, csr0);
 	    /* unlike for the lance, there is no restart needed */
 	}
@@ -1197,7 +1215,7 @@
     lp->a.write_rap(ioaddr,rap);
     
     if (pcnet32_debug > 4)
-	printk("%s: exiting interrupt, csr0=%#4.4x.\n",
+	printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
 
     spin_unlock(&lp->lock);
@@ -1208,7 +1226,6 @@
 {
     struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
     int entry = lp->cur_rx & RX_RING_MOD_MASK;
-    int i;
 
     /* If we own the next entry, it's a new packet. Send it up. */
     while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
@@ -1234,10 +1251,11 @@
 	    struct sk_buff *skb;
 			
 	    if(pkt_len < 60) {
-		printk("%s: Runt packet!\n",dev->name);
+		printk(KERN_ERR "%s: Runt packet!\n",dev->name);
 		lp->stats.rx_errors++;
 	    } else {
 		int rx_in_place = 0;
+                dma_addr_t rx_dma_addr = lp->rx_dma_addr[entry];
 			    
 		if (pkt_len > rx_copybreak) {
 		    struct sk_buff *newskb;
@@ -1248,16 +1266,19 @@
 			skb_put (skb, pkt_len);
 			lp->rx_skbuff[entry] = newskb;
 			newskb->dev = dev;
-			lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail));
+                        lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE);
+			lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
 			rx_in_place = 1;
 		    } else
 			skb = NULL;
-		} else
+		} else {
 		    skb = dev_alloc_skb(pkt_len+2);
+                }
 			    
 		if (skb == NULL) {
-		    printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-		    for (i=0; i < RX_RING_SIZE; i++)
+                    int i;
+		    printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
+		    for (i = 0; i < RX_RING_SIZE; i++)
 			if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
 			    break;
 
@@ -1270,10 +1291,10 @@
 		}
 		skb->dev = dev;
 		if (!rx_in_place) {
-		    skb_reserve(skb,2);	/* 16 byte align */
+		    skb_reserve(skb,2); /* 16 byte align */
 		    skb_put(skb,pkt_len);	/* Make room */
 		    eth_copy_and_sum(skb,
-				     (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
+				     (unsigned char *)(lp->rx_skbuff[entry]->tail),
 				     pkt_len,0);
 		}
 		lp->stats.rx_bytes += skb->len;
@@ -1306,7 +1327,7 @@
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
 
     if (pcnet32_debug > 1)
-	printk("%s: Shutting down ethercard, status was %2.2x.\n",
+	printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
 
     /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
@@ -1322,16 +1343,22 @@
     
     /* free all allocated skbuffs */
     for (i = 0; i < RX_RING_SIZE; i++) {
-	lp->rx_ring[i].status = 0;	    	    	    
-	if (lp->rx_skbuff[i])
+	lp->rx_ring[i].status = 0;			    
+	if (lp->rx_skbuff[i]) {
+            pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], lp->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE);
 	    dev_kfree_skb(lp->rx_skbuff[i]);
+        }
 	lp->rx_skbuff[i] = NULL;
+        lp->rx_dma_addr[i] = 0;
     }
     
     for (i = 0; i < TX_RING_SIZE; i++) {
-	if (lp->tx_skbuff[i])
+	if (lp->tx_skbuff[i]) {
+            pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
 	    dev_kfree_skb(lp->tx_skbuff[i]);
-	lp->rx_skbuff[i] = NULL;
+        }
+	lp->tx_skbuff[i] = NULL;
+        lp->tx_dma_addr[i] = 0;
     }
     
     MOD_DEC_USE_COUNT;
@@ -1412,11 +1439,11 @@
 static void pcnet32_set_multicast_list(struct net_device *dev)
 {
     unsigned long ioaddr = dev->base_addr;
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;	 
 
     if (dev->flags&IFF_PROMISC) {
 	/* Log any net taps. */
-	printk("%s: Promiscuous mode enabled.\n", dev->name);
+	printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
 	lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7);
     } else {
 	lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
@@ -1432,35 +1459,42 @@
 static int pcnet32_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
     unsigned long ioaddr = dev->base_addr;
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;	 
     u16 *data = (u16 *)&rq->ifr_data;
     int phyaddr = lp->a.read_bcr (ioaddr, 33);
 
     if (lp->mii) {
 	switch(cmd) {
-	 case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 	    data[0] = (phyaddr >> 5) & 0x1f;
 	    /* Fall Through */
-	 case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 	    lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));
 	    data[3] = lp->a.read_bcr (ioaddr, 34);
 	    lp->a.write_bcr (ioaddr, 33, phyaddr);
 	    return 0;
-	 case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 	    if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 	    lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));
 	    lp->a.write_bcr (ioaddr, 34, data[2]);
 	    lp->a.write_bcr (ioaddr, 33, phyaddr);
 	    return 0;
-	 default:
+	default:
 	    return -EOPNOTSUPP;
 	}
     }
     return -EOPNOTSUPP;
 }
-#endif  /* HAVE_PRIVATE_IOCTL */
+#endif	/* HAVE_PRIVATE_IOCTL */
 					    
+static struct pci_driver pcnet32_driver = {
+    name:  "pcnet32",
+    probe: pcnet32_probe_pci,
+    remove: NULL,
+    id_table: pcnet32_pci_tbl,
+};
+
 MODULE_PARM(debug, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
@@ -1476,13 +1510,36 @@
 
 static int __init pcnet32_init_module(void)
 {
+    int cards_found = 0;
+    int err;
+
     if (debug > 0)
 	pcnet32_debug = debug;
     if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
 	tx_start = tx_start_pt;
     
     pcnet32_dev = NULL;
-    return pcnet32_probe();
+    /* find the PCI devices */
+#define USE_PCI_REGISTER_DRIVER
+#ifdef USE_PCI_REGISTER_DRIVER
+    if (err = pci_module_init(&pcnet32_driver) < 0 )
+       return err;
+#else
+    {
+        struct pci_device_id *devid = pcnet32_pci_tbl;
+        for (devid = pcnet32_pci_tbl; devid != NULL && devid->vendor != 0; devid++) {
+            struct pci_dev *pdev = pci_find_subsys(devid->vendor, devid->device, devid->subvendor, devid->subdevice, NULL);
+            if (pdev != NULL) {
+                if (pcnet32_probe_pci(pdev, devid) >= 0) {
+                    cards_found++;
+                }
+            }
+        }
+    }
+#endif
+    return 0;
+    /* find any remaining VLbus devices */
+    return pcnet32_probe_vlbus(cards_found);
 }
 
 static void __exit pcnet32_cleanup_module(void)
@@ -1491,10 +1548,11 @@
 
     /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
     while (pcnet32_dev) {
-	next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next;
+        struct pcnet32_private *lp = (struct pcnet32_private *) pcnet32_dev->priv;
+	next_dev = lp->next;
 	unregister_netdev(pcnet32_dev);
 	release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-	kfree(((struct pcnet32_private *)pcnet32_dev->priv)->origmem);
+        pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
 	kfree(pcnet32_dev);
 	pcnet32_dev = next_dev;
     }
@@ -1507,6 +1565,6 @@
  * Local variables:
  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c"
  *  c-indent-level: 4
- *  tab-width: 4
+ *  tab-width: 8
  * End:
  */

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