]> git.neil.brown.name Git - history.git/commitdiff
acenic gige net driver fixes:
authorJes Sorensen <jes@wildopensource.com>
Thu, 14 Mar 2002 22:32:21 +0000 (17:32 -0500)
committerJeff Garzik <jgarzik@mandrakesoft.com>
Thu, 14 Mar 2002 22:32:21 +0000 (17:32 -0500)
* fix Tigon I support
* fix memory leak

drivers/net/acenic.c
drivers/net/acenic.h

index 7f0cc9675746fe90c4dc5febfa4c1c7cf7acfc69..c0cbb6ba45c82c0428410a36a019c74482a0fd90 100644 (file)
 
 #ifdef CONFIG_ACENIC_OMIT_TIGON_I
 #define ACE_IS_TIGON_I(ap)     0
+#define ACE_TX_RING_ENTRIES(ap)        MAX_TX_RING_ENTRIES
 #else
 #define ACE_IS_TIGON_I(ap)     (ap->version == 1)
+#define ACE_TX_RING_ENTRIES(ap)        ap->tx_ring_entries
 #endif
 
 #ifndef PCI_VENDOR_ID_ALTEON
@@ -554,7 +556,7 @@ static int tx_ratio[ACE_MAX_MOD_PARMS];
 static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static char version[] __initdata = 
-  "acenic.c: v0.87 03/14/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
+  "acenic.c: v0.88 03/14/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev;
@@ -960,6 +962,13 @@ static void ace_free_descriptors(struct net_device *dev)
                                    ap->evt_ring_dma);
                ap->evt_ring = NULL;
        }
+       if (ap->tx_ring != NULL && !ACE_IS_TIGON_I(ap)) {
+               size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES);
+               pci_free_consistent(ap->pdev, size, ap->tx_ring,
+                                   ap->tx_ring_dma);
+       }
+       ap->tx_ring = NULL;
+
        if (ap->evt_prd != NULL) {
                pci_free_consistent(ap->pdev, sizeof(u32),
                                    (void *)ap->evt_prd, ap->evt_prd_dma);
@@ -1006,12 +1015,19 @@ static int ace_allocate_descriptors(struct net_device *dev)
        if (ap->evt_ring == NULL)
                goto fail;
 
-       size = (sizeof(struct tx_desc) * TX_RING_ENTRIES);
+       /*
+        * Only allocate a host TX ring for the Tigon II, the Tigon I
+        * has to use PCI registers for this ;-(
+        */
+       if (!ACE_IS_TIGON_I(ap)) {
+               size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES);
 
-       ap->tx_ring = pci_alloc_consistent(ap->pdev, size, &ap->tx_ring_dma);
+               ap->tx_ring = pci_alloc_consistent(ap->pdev, size,
+                                                  &ap->tx_ring_dma);
 
-       if (ap->tx_ring == NULL)
-               goto fail;
+               if (ap->tx_ring == NULL)
+                       goto fail;
+       }
 
        ap->evt_prd = pci_alloc_consistent(ap->pdev, sizeof(u32),
                                           &ap->evt_prd_dma);
@@ -1145,6 +1161,7 @@ static int __init ace_init(struct net_device *dev)
                       tigonFwReleaseFix);
                writel(0, &regs->LocalCtrl);
                ap->version = 1;
+               ap->tx_ring_entries = TIGON_I_TX_RING_ENTRIES;
                break;
 #endif
        case 6:
@@ -1160,6 +1177,7 @@ static int __init ace_init(struct net_device *dev)
                writel(SRAM_BANK_512K, &regs->LocalCtrl);
                writel(SYNC_SRAM_TIMING, &regs->MiscCfg);
                ap->version = 2;
+               ap->tx_ring_entries = MAX_TX_RING_ENTRIES;
                break;
        default:
                printk(KERN_WARNING "  Unsupported Tigon version detected "
@@ -1390,7 +1408,7 @@ static int __init ace_init(struct net_device *dev)
 
 #ifdef INDEX_DEBUG
        spin_lock_init(&ap->debug_lock);
-       ap->last_tx = TX_RING_ENTRIES - 1;
+       ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1;
        ap->last_std_rx = 0;
        ap->last_mini_rx = 0;
 #endif
@@ -1498,12 +1516,30 @@ static int __init ace_init(struct net_device *dev)
        *(ap->rx_ret_prd) = 0;
 
        writel(TX_RING_BASE, &regs->WinBase);
-       memset(ap->tx_ring, 0, TX_RING_ENTRIES * sizeof(struct tx_desc));
 
-       set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma);
+       if (ACE_IS_TIGON_I(ap)) {
+               ap->tx_ring = (struct tx_desc *)regs->Window;
+               for (i = 0; i < (TIGON_I_TX_RING_ENTRIES * 
+                                sizeof(struct tx_desc) / 4); i++) {
+                       writel(0, (unsigned long)ap->tx_ring + i * 4);
+               }
+
+               set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
+       } else {
+               memset(ap->tx_ring, 0,
+                      MAX_TX_RING_ENTRIES * sizeof(struct tx_desc));
+
+               set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma);
+       }
+
+       info->tx_ctrl.max_len = ACE_TX_RING_ENTRIES(ap);
+       tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
 
-       info->tx_ctrl.max_len = TX_RING_ENTRIES;
-       tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_TX_HOST_RING;
+       /*
+        * The Tigon I does not like having the TX ring in host memory ;-(
+        */
+       if (!ACE_IS_TIGON_I(ap))
+               tmp |= RCB_FLG_TX_HOST_RING;
 #if TX_COAL_INTS_ONLY
        tmp |= RCB_FLG_COAL_INT_ONLY;
 #endif
@@ -2264,7 +2300,7 @@ static inline void ace_tx_int(struct net_device *dev,
                        info->skb = NULL;
                }
 
-               idx = (idx + 1) % TX_RING_ENTRIES;
+               idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
        } while (idx != txcsm);
 
        if (netif_queue_stopped(dev))
@@ -2357,7 +2393,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
                 * update releases enough of space, otherwise we just
                 * wait for device to make more work.
                 */
-               if (!tx_ring_full(txcsm, ap->tx_prd))
+               if (!tx_ring_full(ap, txcsm, ap->tx_prd))
                        ace_tx_int(dev, txcsm, idx);
        }
 
@@ -2531,7 +2567,7 @@ static int ace_close(struct net_device *dev)
        save_flags(flags);
        cli();
 
-       for (i = 0; i < TX_RING_ENTRIES; i++) {
+       for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) {
                struct sk_buff *skb;
                dma_addr_t mapping;
                struct tx_ring_info *info;
@@ -2541,7 +2577,13 @@ static int ace_close(struct net_device *dev)
                mapping = pci_unmap_addr(info, mapping);
 
                if (mapping) {
-                       memset(ap->tx_ring + i, 0, sizeof(struct tx_desc));
+                       if (ACE_IS_TIGON_I(ap)) {
+                               writel(0, &ap->tx_ring[i].addr.addrhi);
+                               writel(0, &ap->tx_ring[i].addr.addrlo);
+                               writel(0, &ap->tx_ring[i].flagsize);
+                       } else
+                               memset(ap->tx_ring + i, 0,
+                                      sizeof(struct tx_desc));
                        pci_unmap_page(ap->pdev, mapping,
                                       pci_unmap_len(info, maplen),
                                       PCI_DMA_TODEVICE);
@@ -2587,15 +2629,21 @@ ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
 
 
 static inline void
-ace_load_tx_bd(struct tx_desc *desc, u64 addr, u32 flagsize)
+ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc,
+              u64 addr, u32 flagsize)
 {
 #if !USE_TX_COAL_NOW
        flagsize &= ~BD_FLG_COAL_NOW;
 #endif
-
-       desc->addr.addrhi = addr >> 32;
-       desc->addr.addrlo = addr;
-       desc->flagsize = flagsize;
+       if (!ACE_IS_TIGON_I(ap)) {
+               writel(addr >> 32, &desc->addr.addrhi);
+               writel(addr & 0xffffffff, &desc->addr.addrlo);
+               writel(flagsize, &desc->flagsize);
+       } else {
+               desc->addr.addrhi = addr >> 32;
+               desc->addr.addrlo = addr;
+               desc->flagsize = flagsize;
+       }
 }
 
 
@@ -2615,7 +2663,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 restart:
        idx = ap->tx_prd;
 
-       if (tx_ring_full(ap->tx_ret_csm, idx))
+       if (tx_ring_full(ap, ap->tx_ret_csm, idx))
                goto overflow;
 
 #if MAX_SKB_FRAGS
@@ -2629,13 +2677,13 @@ restart:
                if (skb->ip_summed == CHECKSUM_HW)
                        flagsize |= BD_FLG_TCP_UDP_SUM;
                desc = ap->tx_ring + idx;
-               idx = (idx + 1) % TX_RING_ENTRIES;
+               idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
 
                /* Look at ace_tx_int for explanations. */
-               if (tx_ring_full(ap->tx_ret_csm, idx))
+               if (tx_ring_full(ap, ap->tx_ret_csm, idx))
                        flagsize |= BD_FLG_COAL_NOW;
 
-               ace_load_tx_bd(desc, mapping, flagsize);
+               ace_load_tx_bd(ap, desc, mapping, flagsize);
        }
 #if MAX_SKB_FRAGS
        else {
@@ -2647,9 +2695,9 @@ restart:
                if (skb->ip_summed == CHECKSUM_HW)
                        flagsize |= BD_FLG_TCP_UDP_SUM;
 
-               ace_load_tx_bd(ap->tx_ring + idx, mapping, flagsize);
+               ace_load_tx_bd(ap, ap->tx_ring + idx, mapping, flagsize);
 
-               idx = (idx + 1) % TX_RING_ENTRIES;
+               idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
 
                for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2666,11 +2714,11 @@ restart:
                        flagsize = (frag->size << 16);
                        if (skb->ip_summed == CHECKSUM_HW)
                                flagsize |= BD_FLG_TCP_UDP_SUM;
-                       idx = (idx + 1) % TX_RING_ENTRIES;
+                       idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
 
                        if (i == skb_shinfo(skb)->nr_frags - 1) {
                                flagsize |= BD_FLG_END;
-                               if (tx_ring_full(ap->tx_ret_csm, idx))
+                               if (tx_ring_full(ap, ap->tx_ret_csm, idx))
                                        flagsize |= BD_FLG_COAL_NOW;
 
                                /*
@@ -2683,7 +2731,7 @@ restart:
                        }
                        pci_unmap_addr_set(info, mapping, mapping);
                        pci_unmap_len_set(info, maplen, frag->size);
-                       ace_load_tx_bd(desc, mapping, flagsize);
+                       ace_load_tx_bd(ap, desc, mapping, flagsize);
                }
        }
 #endif
@@ -2701,7 +2749,7 @@ restart:
                 * serialized, this is the only situation we have to
                 * re-test.
                 */
-               if (!tx_ring_full(ap->tx_ret_csm, idx))
+               if (!tx_ring_full(ap, ap->tx_ret_csm, idx))
                        netif_wake_queue(dev);
        }
 
@@ -2781,7 +2829,7 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
                return -EFAULT;
        switch (ecmd.cmd) {
-       case ETHTOOL_GSET: {
+       case ETHTOOL_GSET:
                ecmd.supported =
                        (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
                         SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
@@ -2829,8 +2877,8 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if(copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
                        return -EFAULT;
                return 0;
-       }
-       case ETHTOOL_SSET: {
+
+       case ETHTOOL_SSET:
                if(!capable(CAP_NET_ADMIN))
                        return -EPERM;
 
@@ -2887,7 +2935,7 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        ace_issue_cmd(regs, &cmd);
                }
                return 0;
-       }
+
        case ETHTOOL_GDRVINFO: {
                struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
                strncpy(info.driver, "acenic", sizeof(info.driver) - 1);
index 815bf8e37922787739c608340550ca1542bb7712..a268f063ce0d01da7b49c940fab1ea4939ac6908 100644 (file)
@@ -437,11 +437,12 @@ struct cmd {
 
 
 /*
- * TX ring
+ * TX ring - maximum TX ring entries for Tigon I's is 128
  */
-#define TX_RING_ENTRIES        256     
-#define TX_RING_SIZE   (TX_RING_ENTRIES * sizeof(struct tx_desc))
-#define TX_RING_BASE   0x3800
+#define MAX_TX_RING_ENTRIES    256
+#define TIGON_I_TX_RING_ENTRIES        128
+#define TX_RING_SIZE           (MAX_TX_RING_ENTRIES * sizeof(struct tx_desc))
+#define TX_RING_BASE           0x3800
 
 struct tx_desc{
         aceaddr        addr;
@@ -608,7 +609,7 @@ struct tx_ring_info {
  */
 struct ace_skb
 {
-       struct tx_ring_info     tx_skbuff[TX_RING_ENTRIES];
+       struct tx_ring_info     tx_skbuff[MAX_TX_RING_ENTRIES];
        struct ring_info        rx_std_skbuff[RX_STD_RING_ENTRIES];
        struct ring_info        rx_mini_skbuff[RX_MINI_RING_ENTRIES];
        struct ring_info        rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES];
@@ -642,6 +643,7 @@ struct ace_private
        u32                     tx_prd;
        volatile u32            tx_ret_csm;
        struct timer_list       timer;
+       int                     tx_ring_entries;
 
        /*
         * RX elements
@@ -692,17 +694,17 @@ struct ace_private
 
 #define TX_RESERVED    MAX_SKB_FRAGS
 
-static inline int tx_space (u32 csm, u32 prd)
+static inline int tx_space (struct ace_private *ap, u32 csm, u32 prd)
 {
-       return (csm - prd - 1) & (TX_RING_ENTRIES - 1);
+       return (csm - prd - 1) & (ACE_TX_RING_ENTRIES(ap) - 1);
 }
 
-#define tx_free(ap)            tx_space((ap)->tx_ret_csm, (ap)->tx_prd)
+#define tx_free(ap)            tx_space((ap)->tx_ret_csm, (ap)->tx_prd, ap)
 
 #if MAX_SKB_FRAGS
-#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED)
+#define tx_ring_full(ap, csm, prd)     (tx_space(ap, csm, prd) <= TX_RESERVED)
 #else
-#define tx_ring_full           0
+#define tx_ring_full                   0
 #endif
 
 
@@ -711,7 +713,7 @@ static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr)
        u64 baddr = (u64) addr;
        aa->addrlo = baddr & 0xffffffff;
        aa->addrhi = baddr >> 32;
-       mb();
+       wmb();
 }