]> err.no Git - linux-2.6/blobdiff - drivers/net/pcnet32.c
Pull esi-support into release branch
[linux-2.6] / drivers / net / pcnet32.c
index fe0558242835c908eeeda19059f4185889aa5c43..d50bcb89dd2898564b6c86a8e516113f59c263ef 100644 (file)
@@ -202,6 +202,8 @@ static int homepna[MAX_UNITS];
 #define CSR15          15
 #define PCNET32_MC_FILTER      8
 
+#define PCNET32_79C970A        0x2621
+
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
        u32     base;
@@ -289,6 +291,7 @@ struct pcnet32_private {
 
        /* each bit indicates an available PHY */
        u32                     phymask;
+       unsigned short          chip_version;   /* which variant this is */
 };
 
 static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
@@ -645,6 +648,25 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
        return;
 }
 
+static void pcnet32_purge_rx_ring(struct net_device *dev)
+{
+       struct pcnet32_private *lp = dev->priv;
+       int i;
+
+       /* free all allocated skbuffs */
+       for (i = 0; i < lp->rx_ring_size; i++) {
+               lp->rx_ring[i].status = 0;      /* CPU owns buffer */
+               wmb();          /* Make sure adapter sees owner change */
+               if (lp->rx_skbuff[i]) {
+                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
+                                        PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb_any(lp->rx_skbuff[i]);
+               }
+               lp->rx_skbuff[i] = NULL;
+               lp->rx_dma_addr[i] = 0;
+       }
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void pcnet32_poll_controller(struct net_device *dev)
 {
@@ -705,9 +727,11 @@ static u32 pcnet32_get_link(struct net_device *dev)
        spin_lock_irqsave(&lp->lock, flags);
        if (lp->mii) {
                r = mii_link_ok(&lp->mii_if);
-       } else {
+       } else if (lp->chip_version >= PCNET32_79C970A) {
                ulong ioaddr = dev->base_addr;  /* card base I/O address */
                r = (lp->a.read_bcr(ioaddr, 4) != 0xc0);
+       } else {        /* can not detect link on really old chips */
+               r = 1;
        }
        spin_unlock_irqrestore(&lp->lock, flags);
 
@@ -856,29 +880,27 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
        unsigned long flags;
        unsigned long ticks;
 
-       *data1 = 1;             /* status of test, default to fail */
        rc = 1;                 /* default to fail */
 
        if (netif_running(dev))
                pcnet32_close(dev);
 
        spin_lock_irqsave(&lp->lock, flags);
+       lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);       /* stop the chip */
+
+       numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
 
        /* Reset the PCNET32 */
        lp->a.reset(ioaddr);
+       lp->a.write_csr(ioaddr, CSR4, 0x0915);
 
        /* switch pcnet32 to 32bit mode */
        lp->a.write_bcr(ioaddr, 20, 2);
 
-       lp->init_block.mode =
-           le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
-       lp->init_block.filter[0] = 0;
-       lp->init_block.filter[1] = 0;
-
        /* purge & init rings but don't actually restart */
        pcnet32_restart(dev, 0x0000);
 
-       lp->a.write_csr(ioaddr, 0, 0x0004);     /* Set STOP bit */
+       lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);       /* Set STOP bit */
 
        /* Initialize Transmit buffers. */
        size = data_len + 15;
@@ -920,14 +942,15 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                }
        }
 
-       x = a->read_bcr(ioaddr, 32);    /* set internal loopback in BSR32 */
-       x = x | 0x0002;
-       a->write_bcr(ioaddr, 32, x);
+       x = a->read_bcr(ioaddr, 32);    /* set internal loopback in BCR32 */
+       a->write_bcr(ioaddr, 32, x | 0x0002);
 
-       lp->a.write_csr(ioaddr, 15, 0x0044);    /* set int loopback in CSR15 */
+       /* set int loopback in CSR15 */
+       x = a->read_csr(ioaddr, CSR15) & 0xfffc;
+       lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
 
        teststatus = le16_to_cpu(0x8000);
-       lp->a.write_csr(ioaddr, 0, 0x0002);     /* Set STRT bit */
+       lp->a.write_csr(ioaddr, CSR0, CSR0_START);      /* Set STRT bit */
 
        /* Check status of descriptors */
        for (x = 0; x < numbuffs; x++) {
@@ -935,7 +958,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                rmb();
                while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
                        spin_unlock_irqrestore(&lp->lock, flags);
-                       mdelay(1);
+                       msleep(1);
                        spin_lock_irqsave(&lp->lock, flags);
                        rmb();
                        ticks++;
@@ -948,7 +971,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                }
        }
 
-       lp->a.write_csr(ioaddr, 0, 0x0004);     /* Set STOP bit */
+       lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);       /* Set STOP bit */
        wmb();
        if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
                printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
@@ -981,25 +1004,24 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                }
                x++;
        }
-       if (!rc) {
-               *data1 = 0;
-       }
 
       clean_up:
+       *data1 = rc;
        pcnet32_purge_tx_ring(dev);
-       x = a->read_csr(ioaddr, 15) & 0xFFFF;
-       a->write_csr(ioaddr, 15, (x & ~0x0044));        /* reset bits 6 and 2 */
 
-       x = a->read_bcr(ioaddr, 32);    /* reset internal loopback */
-       x = x & ~0x0002;
-       a->write_bcr(ioaddr, 32, x);
+       x = a->read_csr(ioaddr, CSR15);
+       a->write_csr(ioaddr, CSR15, (x & ~0x0044));     /* reset bits 6 and 2 */
 
-       spin_unlock_irqrestore(&lp->lock, flags);
+       x = a->read_bcr(ioaddr, 32);    /* reset internal loopback */
+       a->write_bcr(ioaddr, 32, (x & ~0x0002));
 
        if (netif_running(dev)) {
+               spin_unlock_irqrestore(&lp->lock, flags);
                pcnet32_open(dev);
        } else {
+               pcnet32_purge_rx_ring(dev);
                lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+               spin_unlock_irqrestore(&lp->lock, flags);
        }
 
        return (rc);
@@ -1074,6 +1096,10 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
        ulong ioaddr = dev->base_addr;
        int ticks;
 
+       /* really old chips have to be stopped. */
+       if (lp->chip_version < PCNET32_79C970A)
+               return 0;
+
        /* set SUSPEND (SPND) - CSR5 bit 0 */
        csr5 = a->read_csr(ioaddr, CSR5);
        a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
@@ -1512,6 +1538,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
        lp->mii_if.reg_num_mask = 0x1f;
        lp->dxsuflo = dxsuflo;
        lp->mii = mii;
+       lp->chip_version = chip_version;
        lp->msg_enable = pcnet32_debug;
        if ((cards_found >= MAX_UNITS)
            || (options[cards_found] > sizeof(options_mapping)))
@@ -1822,10 +1849,7 @@ static int pcnet32_open(struct net_device *dev)
                                val |= 2;
                } else if (lp->options & PCNET32_PORT_ASEL) {
                        /* workaround of xSeries250, turn on for 79C975 only */
-                       i = ((lp->a.read_csr(ioaddr, 88) |
-                             (lp->a.
-                              read_csr(ioaddr, 89) << 16)) >> 12) & 0xffff;
-                       if (i == 0x2627)
+                       if (lp->chip_version == 0x2627)
                                val |= 3;
                }
                lp->a.write_bcr(ioaddr, 9, val);
@@ -1969,9 +1993,11 @@ static int pcnet32_open(struct net_device *dev)
 
        netif_start_queue(dev);
 
-       /* Print the link status and start the watchdog */
-       pcnet32_check_media(dev, 1);
-       mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+       if (lp->chip_version >= PCNET32_79C970A) {
+               /* Print the link status and start the watchdog */
+               pcnet32_check_media(dev, 1);
+               mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+       }
 
        i = 0;
        while (i++ < 100)
@@ -1997,16 +2023,7 @@ static int pcnet32_open(struct net_device *dev)
 
       err_free_ring:
        /* free any allocated skbuffs */
-       for (i = 0; i < lp->rx_ring_size; i++) {
-               lp->rx_ring[i].status = 0;
-               if (lp->rx_skbuff[i]) {
-                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
-                                        PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb(lp->rx_skbuff[i]);
-               }
-               lp->rx_skbuff[i] = NULL;
-               lp->rx_dma_addr[i] = 0;
-       }
+       pcnet32_purge_rx_ring(dev);
 
        /*
         * Switch back to 16bit mode to avoid problems with dumb
@@ -2588,7 +2605,6 @@ static int pcnet32_close(struct net_device *dev)
 {
        unsigned long ioaddr = dev->base_addr;
        struct pcnet32_private *lp = dev->priv;
-       int i;
        unsigned long flags;
 
        del_timer_sync(&lp->watchdog_timer);
@@ -2619,31 +2635,8 @@ static int pcnet32_close(struct net_device *dev)
 
        spin_lock_irqsave(&lp->lock, flags);
 
-       /* free all allocated skbuffs */
-       for (i = 0; i < lp->rx_ring_size; i++) {
-               lp->rx_ring[i].status = 0;
-               wmb();          /* Make sure adapter sees owner change */
-               if (lp->rx_skbuff[i]) {
-                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
-                                        PKT_BUF_SZ - 2, 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 < lp->tx_ring_size; i++) {
-               lp->tx_ring[i].status = 0;      /* CPU owns buffer */
-               wmb();          /* Make sure adapter sees owner change */
-               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->tx_skbuff[i] = NULL;
-               lp->tx_dma_addr[i] = 0;
-       }
+       pcnet32_purge_rx_ring(dev);
+       pcnet32_purge_tx_ring(dev);
 
        spin_unlock_irqrestore(&lp->lock, flags);