public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Jeff Garzik <jgarzik@mandrakesoft.com>
To: dth@lin-gen.com
Cc: linux-kernel@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
Subject: Re: Drivers under 2.4
Date: Thu, 11 Jan 2001 09:32:49 -0500	[thread overview]
Message-ID: <3A5DC411.794486B0@mandrakesoft.com> (raw)
In-Reply-To: <20010110223836.A7321@gruyere.muc.suse.de> <20010111115833.A27971@lin-gen.com> <3A5D9AB1.39F6627C@uow.edu.au> <93k75v$r1u$1@voyager.cistron.net> <93ke9q$jnj$1@voyager.cistron.net>

[-- Attachment #1: Type: text/plain, Size: 2162 bytes --]

Danny ter Haar wrote:
> 
> >Jan 11 12:45:49 multimedia kernel: eth0: pcnet32_start_xmit() called, csr0 07f3.
> >Jan 11 12:46:01 multimedia last message repeated 12 times
> 
> hot from the ethernet wire: more info just arrived:
> 
> NETDEV WATCHDOG: eth0: transmit timed out
> eth0: transmit timed out, status 07f3, resetting.
>  Ring data dump: dirty_tx 0 cur_tx 16 (full) cur_rx 0.
>   03b2f012 0608 00000040 0310 03b2f812 0608 00000040 0310
>   03b2e012 0608 00000040 0310 03b2e812 0608 00000040 0310
>   03b2d012 0608 00000040 0310 03b2d812 0608 00000040 0310
>   03b2c012 0608 00000040 0310 03b2c812 0608 00000040 0310
>   03b2b012 0608 00000040 0310 03b2b812 0608 00000040 0310
>   03b2a012 0608 00000040 0310 03b2a812 0608 00000040 0310
>   03b29012 0608 00000040 0310 03b29812 0608 00000040 0310
>   03b28012 0608 00000040 0310 03b28812 0608 00000111 0310
>   03b3f012 0608 000000fc 0310 03b3f812 0608 0000006a 0310
>   03b3e012 0608 00000040 0310 03b3e812 0608 00000040 0310
>   03b3d012 0608 00000040 0310 03b3d812 0608 00000040 0310
>   03b3c012 0608 00000040 0310 03b3c812 0608 00000040 0310
>   03b3a012 0608 00000040 0310 03b3a812 0608 00000040 0310
>   03b39012 0608 00000040 0310 03b39812 0608 00000040 0340
>   03b38012 0608 00000040 0340 03b38812 0608 00000040 0340
>   03b4f012 0608 00000040 0340 03b4f812 0608 00000040 0340
>   03f9a782 0066 00000000 0300 03b4e222 002a 00000000 0300
>   03b4e2a2 002a 00000000 0300 03b4e322 002a 00000000 0300
>   03b4e3a2 002a 00000000 0300 03b4e422 002a 00000000 0300
>   03b4e4a2 002a 00000000 0300 03b4e522 002a 00000000 0300
>   03b4e5a2 002a 00000000 0300 03b4e622 002a 00000000 0300
>   03b4e6a2 002a 00000000 0300 03b4eea2 002a 00000000 0300
>   03b4ef22 002a 00000000 0300 03f9a882 007e 00000000 0300
>   03f9a982 007e 00000000 0300 03f9aa82 007e 00000000 0300
> eth0: pcnet32_start_xmit() called, csr0 05f3.
> eth0: pcnet32_start_xmit() called, csr0 07f3.
> 
> etc...

Does this patch help at all?

	Jeff


-- 
Jeff Garzik       | "You see, in this world there's two kinds of
Building 1024     |  people, my friend: Those with loaded guns
MandrakeSoft      |  and those who dig. You dig."  --Blondie

[-- Attachment #2: pcnet32.patch --]
[-- Type: text/plain, Size: 41486 bytes --]

Index: drivers/net/pcnet32.c
===================================================================
RCS file: /cvsroot/gkernel/linux_2_4/drivers/net/pcnet32.c,v
retrieving revision 1.1.1.7
retrieving revision 1.1.1.7.10.1
diff -u -r1.1.1.7 -r1.1.1.7.10.1
--- drivers/net/pcnet32.c	2000/12/12 03:23:16	1.1.1.7
+++ drivers/net/pcnet32.c	2001/01/11 13:38:07	1.1.1.7.10.1
@@ -1,19 +1,22 @@
 /* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
 /*
  *	Copyright 1996-1999 Thomas Bogendoerfer
- * 
+ *
  *	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.
- * 
+ *
  *	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
+ *
+ *	Nov 2000 (jgarzik): SMP, endian, PCI DMA, other fixes.
+ *			    Removed VLB support (use CONFIG_LANCE instead).
  */
 
-static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.25smp Nov 11, 2000 tsbogend@alpha.franken.de\n";
 
 #include <linux/module.h>
 
@@ -37,13 +40,9 @@
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 
-static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
-
 static int pcnet32_debug = 1;
 static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
 
-static struct net_device *pcnet32_dev;
-
 static const int max_interrupt_work = 80;
 static const int rx_copybreak = 200;
 
@@ -63,10 +62,10 @@
  * table to translate option values from tulip
  * to internal options
  */
-static unsigned char options_mapping[] = {
+static unsigned char options_mapping[] __initdata = {
     PORT_ASEL,			   /*  0 Auto-select	  */
     PORT_AUI,			   /*  1 BNC/AUI	  */
-    PORT_AUI,			   /*  2 AUI/BNC	  */ 
+    PORT_AUI,			   /*  2 AUI/BNC	  */
     PORT_ASEL,			   /*  3 not supported	  */
     PORT_10BT | PORT_FD,	   /*  4 10baseT-FD	  */
     PORT_ASEL,			   /*  5 not supported	  */
@@ -88,14 +87,14 @@
 
 /*
  *				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
  * to the normal lance driver is the use of the 32bit mode of PCnet32
  * and PCnetPCI chips. Because these chips are 32bit chips, there is no
  * 16MB limitation and we don't need bounce buffers.
  */
- 
+
 /*
  * History:
  * v0.01:  Initial version
@@ -149,7 +148,7 @@
  * 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 
+ *	   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
@@ -206,6 +205,10 @@
 #define PCI_DEVICE_ID_AMD_PCNETHOME   0x2001
 #endif
 
+#define DMA_ALLOC_SIZE \
+    	( (sizeof(struct pcnet32_rx_head) * RX_RING_SIZE) +	\
+          (sizeof(struct pcnet32_tx_head) * TX_RING_SIZE) +	\
+	  sizeof(struct pcnet32_init_block) )
 
 #define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
 
@@ -213,11 +216,11 @@
 struct pcnet32_rx_head {
     u32 base;
     s16 buf_length;
-    s16 status;	   
+    s16 status;
     u32 msg_length;
     u32 reserved;
 };
-	
+
 struct pcnet32_tx_head {
     u32 base;
     s16 length;
@@ -233,7 +236,7 @@
     u8	phys_addr[6];
     u16 reserved;
     u32 filter[2];
-    /* Receive and transmit ring base, along with extra bits. */    
+    /* Receive and transmit ring base, along with extra bits. */
     u32 rx_ring;
     u32 tx_ring;
 };
@@ -250,15 +253,18 @@
 };
 
 /*
- * The first three fields of pcnet32_private are read by the ethernet device 
+ * 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 pcnet32_rx_head   *rx_ring;
+    struct pcnet32_tx_head   *tx_ring;
+    struct pcnet32_init_block	*init_block;
+    dma_addr_t rx_ring_dma;
+    dma_addr_t tx_ring_dma;
+    dma_addr_t init_block_dma;
+
     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(). */
@@ -271,21 +277,16 @@
     unsigned int cur_rx, cur_tx;		/* The next free ring entry */
     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	 ltint:1,
 #ifdef DO_DXSUFLO
 	      dxsuflo:1,						    /* disable transmit stop on uflo */
 #endif
 	full_duplex:1,				/* full duplex possible */
 	mii:1;					/* mii port available */
-    struct net_device *next;
 };
 
-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_probe1(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 *);
@@ -299,26 +300,13 @@
 static int  pcnet32_mii_ioctl(struct net_device *, struct ifreq *, int);
 #endif
 
-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 pcnet32_pci_id_info {
-    const char *name;
-    u16 vendor_id, device_id, svid, sdid, flags;
-    int io_size;
-    int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *);
-};
-
-
 /*
  * PCI device identifiers for "new style" Linux PCI Device Drivers
  */
-static struct pci_device_id pcnet32_pci_tbl[] __devinitdata = {
+static struct pci_device_id pcnet32_pci_tbl[] __initdata = {
     { 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 },
+/*    { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, 0, 0, 0 }, */
     { 0, }
 };
 
@@ -435,52 +423,15 @@
 
 };
 
-\f
-
-/* 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;
-    
-    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, NULL);
-	else
-	    return -ENODEV;
-    } else
-#endif
-	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) &&
-		(inb(ioaddr + 15) == 0x57) &&
-		(pcnet32_probe1(ioaddr, 0, 0, 0, NULL) == 0))
-		cards_found++;
-	}
-    }
-    return cards_found ? 0: -ENODEV;
-}
-
 
-
 static int __init
 pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
     static int card_idx;
-    long ioaddr;
-    int err = 0;
+    int err;
+    unsigned long ioaddr;
 
-    printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device);
+    printk(KERN_DEBUG "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));
@@ -493,37 +444,58 @@
 	printk(KERN_ERR "pcnet32.c: architecture does not support 32bit PCI busmaster DMA\n");
 	return -ENODEV;
     }
+    pdev->dma_mask = PCNET32_DMA_MASK;
 
-    if ((err = pci_enable_device(pdev)) < 0) {
+    err = pci_enable_device(pdev);
+    if (err) {
 	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);
+
+    err = pcnet32_probe1(card_idx, pdev);
+
+    if (err == 0)
+    	card_idx++;
+
+    return err;
 }
 
 
-/* pcnet32_probe1 
- *  Called from both pcnet32_probe_vlbus and pcnet_probe_pci.  
- *  pdev will be NULL when called from pcnet32_probe_vlbus.
+/* pcnet32_probe1
+ *  Called from both pcnet32_probe_vlbus and pcnet_probe_pci.
  */
 static int __init
-pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev)
+pcnet32_probe1(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;
 #endif
     int ltint = 0;
-    int chip_version;
+    int chip_version, ret = -ENODEV;
     char *chipname;
     struct net_device *dev;
     struct pcnet32_access *a = NULL;
+    unsigned long ioaddr = pci_resource_start(pdev, 0);
 
+    if (!ioaddr) {
+        printk (KERN_ERR "no PCI IO resources, aborting\n");
+        return -ENODEV;
+    }
+
+    dev = init_etherdev(NULL, sizeof(*lp));
+    if (dev == NULL)
+	return -ENOMEM;
+    SET_MODULE_OWNER(dev);
+
+    if (!request_region(ioaddr, PCNET32_TOTAL_SIZE, dev->name)) {
+	ret = -EBUSY;
+	goto err_out;
+    }
+
     /* reset the chip */
     pcnet32_dwio_reset(ioaddr);
     pcnet32_wio_reset(ioaddr);
@@ -534,24 +506,21 @@
 	if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
 	    a = &pcnet32_dwio;
 	} else
-	    return -ENODEV;
+	    goto err_out_res;
     }
 
     chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
     if (pcnet32_debug > 2)
 	printk(KERN_INFO "  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003)
-	return -ENODEV;
+	goto err_out_res;
     chip_version = (chip_version >> 12) & 0xffff;
     switch (chip_version) {
     case 0x2420:
 	chipname = "PCnet/PCI 79C970"; /* PCI */
 	break;
     case 0x2430:
-	if (shared)
-	    chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */
-	else
-	    chipname = "PCnet/32 79C965"; /* 486/VL bus */
+	chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */
 	break;
     case 0x2621:
 	chipname = "PCnet/PCI II 79C970A"; /* PCI */
@@ -573,7 +542,7 @@
     case 0x2626:
 	chipname = "PCnet/Home 79C978"; /* PCI */
 	fdx = 1;
-	/* 
+	/*
 	 * This is based on specs published at www.amd.com.  This section
 	 * assumes that a card with a 79C978 wants to go into 1Mb HomePNA
 	 * mode.  The 79C978 can also go into standard ethernet, and there
@@ -598,16 +567,16 @@
 	break;
     default:
 	printk(KERN_INFO "pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
-	return -ENODEV;
+	goto err_out_res;
     }
 
     /*
      *	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 
+     *	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));
@@ -617,10 +586,6 @@
 #endif
 	ltint = 1;
     }
-    
-    dev = init_etherdev(NULL, 0);
-    if(dev==NULL)
-	return -ENOMEM;
 
     printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr);
 
@@ -653,22 +618,29 @@
     }
 
     dev->base_addr = ioaddr;
-    request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
-    
-    /* 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;
 
-    memset(lp, 0, sizeof(*lp));
-    lp->dma_addr = lp_dma_addr;
-    lp->pci_dev = pdev;
-    printk("\n" KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x", lp, lp_dma_addr);
+    lp = dev->priv;
 
+    lp->rx_ring = pci_alloc_consistent(pdev, DMA_ALLOC_SIZE, &lp->rx_ring_dma);
+    if (!lp->rx_ring) {
+	ret = -ENOMEM;
+	goto err_out_res;
+    }
+
+    printk(KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x\n", lp, lp->rx_ring_dma);
+
+    lp->tx_ring = ((void*)lp->rx_ring) +
+    		  sizeof(struct pcnet32_rx_head) * RX_RING_SIZE;
+    lp->init_block = ((void*)lp->tx_ring) +
+		     sizeof(struct pcnet32_rx_head) * TX_RING_SIZE;
+    lp->tx_ring_dma = lp->rx_ring_dma +
+    		      sizeof(struct pcnet32_rx_head) * RX_RING_SIZE;
+    lp->init_block_dma = lp->tx_ring_dma +
+			 sizeof(struct pcnet32_rx_head) * TX_RING_SIZE;
+
     spin_lock_init(&lp->lock);
-    
-    dev->priv = lp;
+    lp->pci_dev = pdev;
     lp->name = chipname;
-    lp->shared_irq = shared;
     lp->full_duplex = fdx;
 #ifdef DO_DXSUFLO
     lp->dxsuflo = dxsuflo;
@@ -679,44 +651,43 @@
 	lp->options = PORT_ASEL;
     else
 	lp->options = options_mapping[options[card_idx]];
-    
+
     if (fdx && !(lp->options & PORT_ASEL) && full_duplex[card_idx])
 	lp->options |= PORT_FD;
-    
+
     if (a == NULL) {
       printk(KERN_ERR "pcnet32: No access methods\n");
-      return -ENODEV;
+      goto err_out_dma_mem;
     }
     lp->a = *a;
-    
+
     /* 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.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); 
+    lp->init_block->mode = cpu_to_le16(0x0003);	/* Disable Rx and Tx. */
+    lp->init_block->tlen_rlen = cpu_to_le16(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.filter[0] = 0x00000000;
-    lp->init_block.filter[1] = 0x00000000;
-    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));
-    
+	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 = cpu_to_le32(lp->rx_ring_dma);
+    lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma);
+
     /* switch pcnet32 to 32bit mode */
     a->write_bcr (ioaddr, 20, 2);
 
-    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;
-    }
-    
+    /* XXX endian problems here? */
+    a->write_csr (ioaddr, 1, lp->init_block_dma & 0xffff);
+    a->write_csr (ioaddr, 2, lp->init_block_dma >> 16);
+
+    dev->irq = pdev->irq;
+
     if (dev->irq >= 2)
 	printk(" assigned IRQ %d.\n", dev->irq);
     else {
 	unsigned long irq_mask = probe_irq_on();
-	
+
 	/*
 	 * To auto-IRQ we enable the initialization-done and DMA error
 	 * interrupts. For ISA boards we get a DMA error, but VLB and PCI
@@ -725,7 +696,7 @@
 	/* Trigger an initialization just for the interrupt. */
 	a->write_csr (ioaddr, 0, 0x41);
 	mdelay (1);
-	
+
 	dev->irq = probe_irq_off (irq_mask);
 	if (dev->irq)
 	    printk(", probed IRQ %d.\n", dev->irq);
@@ -737,7 +708,7 @@
 
     if (pcnet32_debug > 0)
 	printk(KERN_INFO "%s", version);
-    
+
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
     dev->hard_start_xmit = &pcnet32_start_xmit;
@@ -748,30 +719,32 @@
     dev->do_ioctl = &pcnet32_mii_ioctl;
 #endif
     dev->tx_timeout = pcnet32_tx_timeout;
-    dev->watchdog_timeo = (HZ >> 1);
-
-    lp->next = pcnet32_dev;
-    pcnet32_dev = dev;
+    dev->watchdog_timeo = (1 * HZ);
 
-    /* Fill in the generic fields of the device structure. */
-    ether_setup(dev);
+    pci_set_drvdata(pdev, dev);
     return 0;
+
+err_out_dma_mem:
+    pci_free_consistent(pdev, DMA_ALLOC_SIZE, lp->rx_ring, lp->rx_ring_dma);
+err_out_res:
+    release_region(ioaddr, PCNET32_TOTAL_SIZE);
+err_out:
+    unregister_netdev(dev);
+    kfree(dev);
+    return ret;
 }
+
 
-\f
 static int
 pcnet32_open(struct net_device *dev)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    struct pcnet32_private *lp = dev->priv;
     unsigned long ioaddr = dev->base_addr;
     u16 val;
-    int i;
+    int i, ret;
 
-    if (dev->irq == 0 ||
-	request_irq(dev->irq, &pcnet32_interrupt,
-		    lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) {
-	return -EAGAIN;
-    }
+    ret = request_irq(dev->irq, &pcnet32_interrupt, SA_SHIRQ, lp->name, dev);
+    if (ret) return ret;
 
     /* Reset the PCNET32 */
     lp->a.reset (ioaddr);
@@ -781,17 +754,15 @@
 
     if (pcnet32_debug > 1)
 	printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
-	       dev->name, dev->irq,
-	       (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)));
-    
+	       dev->name, dev->irq, (u32) lp->tx_ring_dma,
+	       (u32) lp->rx_ring_dma, (u32) lp->init_block_dma);
+
     /* set/reset autoselect bit */
     val = lp->a.read_bcr (ioaddr, 2) & ~2;
     if (lp->options & PORT_ASEL)
 	val |= 2;
     lp->a.write_bcr (ioaddr, 2, val);
-    
+
     /* handle full duplex setting */
     if (lp->full_duplex) {
 	val = lp->a.read_bcr (ioaddr, 9) & ~3;
@@ -802,13 +773,13 @@
 	}
 	lp->a.write_bcr (ioaddr, 9, val);
     }
-    
+
     /* set/reset GPSI bit in test register */
     val = lp->a.read_csr (ioaddr, 124) & ~0x10;
     if ((lp->options & PORT_PORTSEL) == PORT_GPSI)
 	val |= 0x10;
     lp->a.write_csr (ioaddr, 124, val);
-    
+
     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)
@@ -818,7 +789,7 @@
 	lp->a.write_bcr (ioaddr, 32, val);
     }
 
-#ifdef DO_DXSUFLO 
+#ifdef DO_DXSUFLO
     if (lp->dxsuflo) { /* Disable transmit stop on underflow */
 	val = lp->a.read_csr (ioaddr, 3);
 	val |= 0x40;
@@ -830,16 +801,25 @@
 	val |= (1<<14);
 	lp->a.write_csr (ioaddr, 5, val);
     }
-   
-    lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
-    lp->init_block.filter[0] = 0x00000000;
-    lp->init_block.filter[1] = 0x00000000;
-    if (pcnet32_init_ring(dev))
-	return -ENOMEM;
-    
+
+    lp->init_block->mode = cpu_to_le16((lp->options & PORT_PORTSEL) << 7);
+    lp->init_block->filter[0] = 0x00000000;
+    lp->init_block->filter[1] = 0x00000000;
+    ret = pcnet32_init_ring(dev);
+    if (ret) {
+    	free_irq(dev->irq, dev);
+	for (i = 0; i < RX_RING_SIZE; i++)
+	    if (lp->rx_skbuff[i]) {
+	    	dev_kfree_skb(lp->rx_skbuff[i]);
+		lp->rx_skbuff[i] = NULL;
+	    }
+	return ret;
+    }
+
     /* Re-initialize the PCNET32, and start it when done. */
-    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);
+    /* XXX endian problems here? */
+    lp->a.write_csr (ioaddr, 1, lp->init_block_dma & 0xffff);
+    lp->a.write_csr (ioaddr, 2, lp->init_block_dma >> 16);
 
     lp->a.write_csr (ioaddr, 4, 0x0915);
     lp->a.write_csr (ioaddr, 0, 0x0001);
@@ -850,7 +830,7 @@
     while (i++ < 100)
 	if (lp->a.read_csr (ioaddr, 0) & 0x0100)
 	    break;
-    /* 
+    /*
      * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
      * reports that doing so triggers a bug in the '974.
      */
@@ -858,13 +838,10 @@
 
     if (pcnet32_debug > 2)
 	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)),
+	       dev->name, i, (u32) lp->init_block_dma,
 	       lp->a.read_csr (ioaddr, 0));
-
 
-    MOD_INC_USE_COUNT;
-    
-    return 0;	/* Always succeed */
+    return 0;
 }
 
 /*
@@ -880,16 +857,16 @@
  * restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
  */
 
-static void 
+static void
 pcnet32_purge_tx_ring(struct net_device *dev)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    struct pcnet32_private *lp = dev->priv;
     int i;
 
     for (i = 0; i < TX_RING_SIZE; 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]); 
+	    dev_kfree_skb_any(lp->tx_skbuff[i]);
 	    lp->tx_skbuff[i] = NULL;
             lp->tx_dma_addr[i] = 0;
 	}
@@ -901,10 +878,9 @@
 static int
 pcnet32_init_ring(struct net_device *dev)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    struct pcnet32_private *lp = dev->priv;
     int i;
 
-    lp->tx_full = 0;
     lp->cur_rx = lp->cur_tx = 0;
     lp->dirty_rx = lp->dirty_tx = 0;
 
@@ -914,14 +890,14 @@
 	    if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
 		/* there is not much, we can do at this point */
 		printk(KERN_ERR "%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
-		return -1;
+		return -ENOMEM;
 	    }
 	    skb_reserve (rx_skbuff, 2);
 	}
         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);
+	lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]);
+	lp->rx_ring[i].buf_length = cpu_to_le16(-PKT_BUF_SZ);
+	lp->rx_ring[i].status = cpu_to_le16(0x8000);
     }
     /* The Tx buffer address is filled in as needed, but we do need to clear
        the upper ownership bit. */
@@ -931,25 +907,25 @@
         lp->tx_dma_addr[i] = 0;
     }
 
-    lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
+    lp->init_block->tlen_rlen = cpu_to_le16(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(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));
+	lp->init_block->phys_addr[i] = dev->dev_addr[i];
+    lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma);
+    lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma);
     return 0;
 }
 
 static void
 pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    struct pcnet32_private *lp = dev->priv;
     unsigned long ioaddr = dev->base_addr;
     int i;
-    
+
     pcnet32_purge_tx_ring(dev);
     if (pcnet32_init_ring(dev))
 	return;
-    
+
     /* ReInit Ring */
     lp->a.write_csr (ioaddr, 0, 1);
     i = 0;
@@ -964,30 +940,41 @@
 static void
 pcnet32_tx_timeout (struct net_device *dev)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-    unsigned int ioaddr = dev->base_addr;
+	struct pcnet32_private *lp = dev->priv;
+	unsigned int ioaddr = dev->base_addr;
 
-    /* Transmitter timeout, serious problems. */
+	/* Transmitter timeout, serious problems. */
 	printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
+
+	spin_lock_irq(&lp->lock);
 	lp->a.write_csr (ioaddr, 0, 0x0004);
+	spin_unlock_irq(&lp->lock);
+
 	lp->stats.tx_errors++;
 	if (pcnet32_debug > 2) {
 	    int i;
 	    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->dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? " (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);
+		   le32_to_cpu(lp->rx_ring[i].base),
+		   -le16_to_cpu(lp->rx_ring[i].buf_length),
+		   le32_to_cpu(lp->rx_ring[i].msg_length),
+		   (unsigned)le16_to_cpu(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");
+		   le32_to_cpu(lp->tx_ring[i].base),
+		   -le16_to_cpu(lp->tx_ring[i].length),
+		   le32_to_cpu(lp->tx_ring[i].misc),
+		   (unsigned)le16_to_cpu(lp->tx_ring[i].status));
+	    printk(KERN_DEBUG "\n");
 	}
+
+	spin_lock_irq(&lp->lock);
 	pcnet32_restart(dev, 0x0042);
+	spin_unlock_irq(&lp->lock);
 
 	dev->trans_start = jiffies;
 	netif_start_queue(dev);
@@ -997,19 +984,18 @@
 static int
 pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    struct pcnet32_private *lp = dev->priv;
     unsigned int ioaddr = dev->base_addr;
     u16 status;
     int entry;
-    unsigned long flags;
 
     if (pcnet32_debug > 3) {
+	spin_lock_irq(&lp->lock);
 	printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
+	spin_unlock_irq(&lp->lock);
     }
 
-    spin_lock_irqsave(&lp->lock, flags);
-
     /* Default status -- will not enable Successful-TxDone
      * interrupt when that option is available to us.
      */
@@ -1025,39 +1011,39 @@
 	 */
 	status = 0x9300;
     }
-  
+
     /* Fill in a Tx ring entry */
-  
+
     /* Mask to ring buffer boundary. */
     entry = lp->cur_tx & TX_RING_MOD_MASK;
-  
+
     /* Caution: the write order is important here, set the base address
        with the "ownership" bits last. */
 
-    lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
+    lp->tx_ring[entry].length = cpu_to_le16(-skb->len);
 
     lp->tx_ring[entry].misc = 0x00000000;
 
     lp->tx_skbuff[entry] = skb;
     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->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]);
+    lp->tx_ring[entry].status = cpu_to_le16(status);
 
     lp->cur_tx++;
     lp->stats.tx_bytes += skb->len;
 
     /* Trigger an immediate send poll. */
+    spin_lock_irq(&lp->lock);
     lp->a.write_csr (ioaddr, 0, 0x0048);
+    spin_unlock_irq(&lp->lock);
 
     dev->trans_start = jiffies;
 
-    if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
-	netif_start_queue(dev);
-    else {
-	lp->tx_full = 1;
+    if ((lp->cur_tx - lp->dirty_tx) > TX_RING_SIZE)
+	BUG();
+    if ((lp->cur_tx - lp->dirty_tx) == TX_RING_SIZE)
 	netif_stop_queue(dev);
-    }
-    spin_unlock_irqrestore(&lp->lock, flags);
+
     return 0;
 }
 
@@ -1065,7 +1051,7 @@
 static void
 pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-    struct net_device *dev = (struct net_device *)dev_id;
+    struct net_device *dev = dev_id;
     struct pcnet32_private *lp;
     unsigned long ioaddr;
     u16 csr0,rap;
@@ -1078,10 +1064,10 @@
     }
 
     ioaddr = dev->base_addr;
-    lp = (struct pcnet32_private *)dev->priv;
-    
+    lp = dev->priv;
+
     spin_lock(&lp->lock);
-    
+
     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. */
@@ -1102,7 +1088,7 @@
 	    while (dirty_tx < lp->cur_tx) {
 		int entry = dirty_tx & TX_RING_MOD_MASK;
 		int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
-			
+
 		if (status < 0)
 		    break;		/* It still hasn't been Txed */
 
@@ -1155,17 +1141,15 @@
 #ifndef final_version
 	    if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
 		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-		       dirty_tx, lp->cur_tx, lp->tx_full);
+		       dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? 1 : 0);
 		dirty_tx += TX_RING_SIZE;
 	    }
 #endif
-	    if (lp->tx_full &&
-		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;
+	    /* If the ring is no longer full, accept more packets. */
+	    if (netif_queue_stopped(dev) &&
+		(dirty_tx > lp->cur_tx - TX_RING_SIZE + 2))
 		netif_wake_queue (dev);
-	    }
+
 	    lp->dirty_tx = dirty_tx;
 	}
 
@@ -1200,7 +1184,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(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
 	       dev->name, lp->a.read_csr (ioaddr, 0));
@@ -1211,7 +1195,7 @@
 static int
 pcnet32_rx(struct net_device *dev)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    struct pcnet32_private *lp = dev->priv;
     int entry = lp->cur_rx & RX_RING_MOD_MASK;
 
     /* If we own the next entry, it's a new packet. Send it up. */
@@ -1219,7 +1203,7 @@
 	int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
 
 	if (status != 0x03) {			/* There was an error. */
-	    /* 
+	    /*
 	     * There is a tricky error noted by John Murphy,
 	     * <murf@perftech.com> to Russ Nelson: Even with full-sized
 	     * buffers it's possible for a jabber packet to use two
@@ -1231,12 +1215,13 @@
 	    if (status & 0x10) lp->stats.rx_over_errors++;
 	    if (status & 0x08) lp->stats.rx_crc_errors++;
 	    if (status & 0x04) lp->stats.rx_fifo_errors++;
-	    lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
+	    lp->rx_ring[entry].status =
+		cpu_to_le16(le16_to_cpu(lp->rx_ring[entry].status) & 0x03ff);
 	} else {
 	    /* Malloc up new buffer, compatible with net-2e. */
 	    short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
 	    struct sk_buff *skb;
-			
+
 	    if(pkt_len < 60) {
 		printk(KERN_ERR "%s: Runt packet!\n",dev->name);
 		lp->stats.rx_errors++;
@@ -1245,7 +1230,7 @@
 
 		if (pkt_len > rx_copybreak) {
 		    struct sk_buff *newskb;
-				
+
 		    if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
 			skb_reserve (newskb, 2);
 			skb = lp->rx_skbuff[entry];
@@ -1253,14 +1238,14 @@
 			lp->rx_skbuff[entry] = newskb;
 			newskb->dev = dev;
                         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]);
+			lp->rx_ring[entry].base = cpu_to_le32(lp->rx_dma_addr[entry]);
 			rx_in_place = 1;
 		    } else
 			skb = NULL;
 		} else {
 		    skb = dev_alloc_skb(pkt_len+2);
                 }
-			    
+
 		if (skb == NULL) {
                     int i;
 		    printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
@@ -1270,7 +1255,8 @@
 
 		    if (i > RX_RING_SIZE -2) {
 			lp->stats.rx_dropped++;
-			lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+			lp->rx_ring[entry].status =
+			    cpu_to_le16(le16_to_cpu(lp->rx_ring[entry].status) | 0x8000);
 			lp->cur_rx++;
 		    }
 		    break;
@@ -1293,8 +1279,9 @@
 	 * The docs say that the buffer length isn't touched, but Andrew Boyd
 	 * of QNX reports that some revs of the 79C965 clear it.
 	 */
-	lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);
-	lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+	lp->rx_ring[entry].buf_length = cpu_to_le16(-PKT_BUF_SZ);
+	lp->rx_ring[entry].status =
+	    cpu_to_le16(le16_to_cpu(lp->rx_ring[entry].status) | 0x8000);
 	entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
     }
 
@@ -1305,11 +1292,13 @@
 pcnet32_close(struct net_device *dev)
 {
     unsigned long ioaddr = dev->base_addr;
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    struct pcnet32_private *lp = dev->priv;
     int i;
 
     netif_stop_queue(dev);
 
+    spin_lock_irq(&lp->lock);
+
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
 
     if (pcnet32_debug > 1)
@@ -1320,16 +1309,19 @@
     lp->a.write_csr (ioaddr, 0, 0x0004);
 
     /*
-     * Switch back to 16bit mode to avoid problems with dumb 
+     * Switch back to 16bit mode to avoid problems with dumb
      * DOS packet driver after a warm reboot
      */
     lp->a.write_bcr (ioaddr, 20, 4);
 
+    spin_unlock_irq(&lp->lock);
+    synchronize_irq();
+
     free_irq(dev->irq, dev);
-    
+
     /* free all allocated skbuffs */
     for (i = 0; i < RX_RING_SIZE; i++) {
-	lp->rx_ring[i].status = 0;			    
+	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]);
@@ -1337,7 +1329,7 @@
 	lp->rx_skbuff[i] = NULL;
         lp->rx_dma_addr[i] = 0;
     }
-    
+
     for (i = 0; i < TX_RING_SIZE; 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);
@@ -1346,8 +1338,6 @@
 	lp->tx_skbuff[i] = NULL;
         lp->tx_dma_addr[i] = 0;
     }
-    
-    MOD_DEC_USE_COUNT;
 
     return 0;
 }
@@ -1355,16 +1345,15 @@
 static struct net_device_stats *
 pcnet32_get_stats(struct net_device *dev)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    struct pcnet32_private *lp = dev->priv;
     unsigned long ioaddr = dev->base_addr;
     u16 saved_addr;
-    unsigned long flags;
 
-    spin_lock_irqsave(&lp->lock, flags);
+    spin_lock_irq(&lp->lock);
     saved_addr = lp->a.read_rap(ioaddr);
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
     lp->a.write_rap(ioaddr, saved_addr);
-    spin_unlock_irqrestore(&lp->lock, flags);
+    spin_unlock_irq(&lp->lock);
 
     return &lp->stats;
 }
@@ -1372,16 +1361,16 @@
 /* taken from the sunlance driver, which it took from the depca driver */
 static void pcnet32_load_multicast (struct net_device *dev)
 {
-    struct pcnet32_private *lp = (struct pcnet32_private *) dev->priv;
-    volatile struct pcnet32_init_block *ib = &lp->init_block;
+    struct pcnet32_private *lp = dev->priv;
+    volatile struct pcnet32_init_block *ib = lp->init_block;
     volatile u16 *mcast_table = (u16 *)&ib->filter;
     struct dev_mc_list *dmi=dev->mc_list;
     char *addrs;
     int i, j, bit, byte;
     u32 crc, poly = CRC_POLYNOMIAL_LE;
-	
+
     /* set all multicast bits */
-    if (dev->flags & IFF_ALLMULTI){ 
+    if (dev->flags & IFF_ALLMULTI){
 	ib->filter [0] = 0xffffffff;
 	ib->filter [1] = 0xffffffff;
 	return;
@@ -1394,24 +1383,24 @@
     for (i = 0; i < dev->mc_count; i++){
 	addrs = dmi->dmi_addr;
 	dmi   = dmi->next;
-	
+
 	/* multicast address? */
 	if (!(*addrs & 1))
 	    continue;
-	
+
 	crc = 0xffffffff;
 	for (byte = 0; byte < 6; byte++)
 	    for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
 		int test;
-		
+
 		test = ((bit ^ crc) & 0x01);
 		crc >>= 1;
-		
+
 		if (test) {
 		    crc = crc ^ poly;
 		}
 	    }
-	
+
 	crc = crc >> 26;
 	mcast_table [crc >> 4] |= 1 << (crc & 0xf);
     }
@@ -1425,30 +1414,38 @@
 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 = dev->priv;
+
+    spin_lock_irq(&lp->lock);
 
     if (dev->flags&IFF_PROMISC) {
 	/* Log any net taps. */
 	printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
-	lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7);
+	lp->init_block->mode = cpu_to_le16(0x8000 | (lp->options & PORT_PORTSEL) << 7);
     } else {
-	lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
+	lp->init_block->mode = cpu_to_le16((lp->options & PORT_PORTSEL) << 7);
 	pcnet32_load_multicast (dev);
     }
-    
+
     lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
 
     pcnet32_restart(dev, 0x0042); /*  Resume normal operation */
+
+    spin_unlock_irq(&lp->lock);
 }
 
 #ifdef HAVE_PRIVATE_IOCTL
 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 = dev->priv;
     u16 *data = (u16 *)&rq->ifr_data;
-    int phyaddr = lp->a.read_bcr (ioaddr, 33);
+    int ret = -EOPNOTSUPP, phyaddr;
+
+    spin_lock_irq(&lp->lock);
 
+    phyaddr = lp->a.read_bcr (ioaddr, 33);
+
     if (lp->mii) {
 	switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
@@ -1458,27 +1455,45 @@
 	    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;
+	    ret = 0;
+	    break;
 	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:
-	    return -EOPNOTSUPP;
+	    ret = 0;
+	    break;
+	default: /* do nothing */
+	    break;
 	}
     }
-    return -EOPNOTSUPP;
+
+    spin_unlock_irq(&lp->lock);
+    return ret;
 }
 #endif	/* HAVE_PRIVATE_IOCTL */
-					    
+
+static void __exit pcnet32_remove_one (struct pci_dev *pdev)
+{
+    struct net_device *dev = pci_get_drvdata(pdev);
+    struct pcnet32_private *lp = dev->priv;
+
+    if (!dev)
+	BUG();
+    unregister_netdev(dev);
+    release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
+    pci_free_consistent(pdev, DMA_ALLOC_SIZE, lp->rx_ring, lp->rx_ring_dma);
+    kfree(dev);
+    pci_set_drvdata(pdev, NULL);
+}
+
 static struct pci_driver pcnet32_driver = {
-    name:  "pcnet32",
-    probe: pcnet32_probe_pci,
-    remove: NULL,
-    id_table: pcnet32_pci_tbl,
+    name:	"pcnet32",
+    probe:	pcnet32_probe_pci,
+    remove:	pcnet32_remove_one,
+    id_table:	pcnet32_pci_tbl,
 };
 
 MODULE_PARM(debug, "i");
@@ -1496,52 +1511,29 @@
 
 static int __init pcnet32_init_module(void)
 {
-    int cards_found = 0;
-    int err;
+    int cards_found;
 
     if (debug > 0)
 	pcnet32_debug = debug;
+
     if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
 	tx_start = tx_start_pt;
-    
-    pcnet32_dev = NULL;
+
     /* 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++;
-                }
-            }
-        }
+    cards_found = pci_register_driver(&pcnet32_driver);
+    if (cards_found < 0)
+	return cards_found;
+    if (cards_found == 0) {
+	pci_unregister_driver(&pcnet32_driver);
+	return -ENODEV;
     }
-#endif
+
     return 0;
-    /* find any remaining VLbus devices */
-    return pcnet32_probe_vlbus(cards_found);
 }
 
 static void __exit pcnet32_cleanup_module(void)
 {
-    struct net_device *next_dev;
-
-    /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-    while (pcnet32_dev) {
-        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);
-        pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
-	kfree(pcnet32_dev);
-	pcnet32_dev = next_dev;
-    }
+    pci_unregister_driver(&pcnet32_driver);
 }
 
 module_init(pcnet32_init_module);

  reply	other threads:[~2001-01-11 14:33 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-01-09  9:12 Failure building 2.4 while running 2.4. Success in building 2.4 while running 2.2 Silviu Marin-Caea
2001-01-09 10:17 ` Alessandro Suardi
2001-01-09 10:33   ` Failure building 2.4 while running 2.4. Success in building 2.4 Alan Cox
2001-01-09 18:20     ` Failure building 2.4 while running 2.4. There is no such thing Silviu Marin-Caea
2001-01-09 18:43       ` Alan Cox
2001-01-09 19:57       ` Drivers under 2.4 Dennis
2001-01-09 20:13         ` suser checks in 2.2.x Bosko Radivojevic
2001-01-09 18:39           ` Arnaldo Carvalho de Melo
2001-01-10 18:22       ` Drivers under 2.4 Dennis
2001-01-10 20:01         ` Hans Grobler
2001-01-10 21:37         ` Dennis
2001-01-10 21:38           ` Andi Kleen
2001-01-10 22:08             ` Hans Grobler
2001-01-11 10:24               ` Danny ter Haar
2001-01-11 10:31                 ` Andi Kleen
2001-01-11 10:58                   ` Danny ter Haar
2001-01-11 11:36                     ` Andrew Morton
2001-01-11 11:58                       ` Danny ter Haar
2001-01-11 14:00                         ` Danny ter Haar
2001-01-11 14:32                           ` Jeff Garzik [this message]
2001-01-11 16:33                             ` Danny ter Haar
2001-01-11 16:44                               ` Hans Grobler
2001-01-12 11:50                                 ` PRoblem with pcnet32 under 2.4.0 , was :Drivers " Danny ter Haar
2001-01-12 12:01                                   ` Hans Grobler
2001-01-12 12:16                                     ` Danny ter Haar
2001-01-12 22:33                                   ` Thomas Bogendoerfer
2001-01-15 16:29                                     ` Danny ter Haar
2001-01-11 12:56                 ` Drivers " Alan Cox
2001-01-09 10:28 ` Failure building 2.4 while running 2.4. Success in building 2.4 while running 2.2 Alan Cox
2001-01-09 16:10 ` [rlug] " Eugen
2001-01-09 19:01 ` J Sloan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3A5DC411.794486B0@mandrakesoft.com \
    --to=jgarzik@mandrakesoft.com \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=dth@lin-gen.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox