This patch fixes the issues with multiple irqs.

I am resending based on feedback. I decoupled the dma mask for consistent memory and fixed leak with multiple irq in error path.

Thanks to Manfred for catching the spin lock problem.

Signed-Off-By: Ayaz Abdulla <[EMAIL PROTECTED]>


-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may 
contain
confidential information.  Any unauthorized review, use, disclosure or 
distribution
is prohibited.  If you are not the intended recipient, please contact the 
sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------
--- orig-2.6/drivers/net/forcedeth.c    2006-04-04 15:26:18.000000000 -0400
+++ new-2.6/drivers/net/forcedeth.c     2006-04-04 15:26:27.000000000 -0400
@@ -108,6 +108,7 @@
  *     0.53: 20 Jan 2006: Add flow control (pause frame).
  *     0.54: 20 Jan 2006: Additional ethtool and moduleparam support.
  *     0.55: 19 Mar 2006: Fix init from low power mode and add hw reset.
+ *     0.56: 21 Mar 2006: Fix spin locks for multi irqs and cleanup.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -119,7 +120,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.55"
+#define FORCEDETH_VERSION              "0.56"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
@@ -1014,14 +1015,27 @@
                kfree(np->tx_dma_len);
 }
 
-static void nv_enable_irq(struct net_device *dev)
+static int using_multi_irqs(struct net_device *dev)
 {
        struct fe_priv *np = get_nvpriv(dev);
 
        if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
            ((np->msi_flags & NV_MSI_X_ENABLED) && 
-            ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
-               enable_irq(dev->irq);
+            ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1)))
+               return 0;
+       else
+               return 1;
+}
+
+static void nv_enable_irq(struct net_device *dev)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+
+       if (!using_multi_irqs(dev)) {
+               if (np->msi_flags & NV_MSI_X_ENABLED)
+                       enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+               else
+                       enable_irq(dev->irq);
        } else {
                enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
                enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
@@ -1033,10 +1047,11 @@
 {
        struct fe_priv *np = get_nvpriv(dev);
 
-       if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
-           ((np->msi_flags & NV_MSI_X_ENABLED) && 
-            ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
-               disable_irq(dev->irq);
+       if (!using_multi_irqs(dev)) {
+               if (np->msi_flags & NV_MSI_X_ENABLED)
+                       
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+               else
+                       disable_irq(dev->irq);
        } else {
                disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
                disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
@@ -1044,6 +1059,7 @@
        }
 }
 
+/* In MSIX mode, a write to irqmask behaves as XOR */
 static void nv_enable_hw_interrupts(struct net_device *dev, u32 mask)
 {
        u8 __iomem *base = get_hwbase(dev);
@@ -1413,24 +1429,25 @@
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
 
-
-       if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
-           ((np->msi_flags & NV_MSI_X_ENABLED) && 
-            ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
-               disable_irq(dev->irq);
+       if (!using_multi_irqs(dev)) {
+               if (np->msi_flags & NV_MSI_X_ENABLED)
+                       
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+               else
+                       disable_irq(dev->irq);
        } else {
                disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
        }
        if (nv_alloc_rx(dev)) {
-               spin_lock(&np->lock);
+               spin_lock_irq(&np->lock);
                if (!np->in_shutdown)
                        mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-               spin_unlock(&np->lock);
+               spin_unlock_irq(&np->lock);
        }
-       if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
-           ((np->msi_flags & NV_MSI_X_ENABLED) && 
-            ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
-               enable_irq(dev->irq);
+       if (!using_multi_irqs(dev)) {
+               if (np->msi_flags & NV_MSI_X_ENABLED)
+                       enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+               else
+                       enable_irq(dev->irq);
        } else {
                enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
        }
@@ -2554,16 +2571,16 @@
                if (!(events & np->irqmask))
                        break;
 
-               spin_lock(&np->lock);
+               spin_lock_irq(&np->lock);
                nv_tx_done(dev);
-               spin_unlock(&np->lock);
+               spin_unlock_irq(&np->lock);
                
                if (events & (NVREG_IRQ_TX_ERR)) {
                        dprintk(KERN_DEBUG "%s: received irq with events 0x%x. 
Probably TX fail.\n",
                                                dev->name, events);
                }
                if (i > max_interrupt_work) {
-                       spin_lock(&np->lock);
+                       spin_lock_irq(&np->lock);
                        /* disable interrupts on the nic */
                        writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
                        pci_push(base);
@@ -2573,7 +2590,7 @@
                                mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
                        }
                        printk(KERN_DEBUG "%s: too many iterations (%d) in 
nv_nic_irq_tx.\n", dev->name, i);
-                       spin_unlock(&np->lock);
+                       spin_unlock_irq(&np->lock);
                        break;
                }
 
@@ -2603,14 +2620,14 @@
                
                nv_rx_process(dev);
                if (nv_alloc_rx(dev)) {
-                       spin_lock(&np->lock);
+                       spin_lock_irq(&np->lock);
                        if (!np->in_shutdown)
                                mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-                       spin_unlock(&np->lock);
+                       spin_unlock_irq(&np->lock);
                }
                
                if (i > max_interrupt_work) {
-                       spin_lock(&np->lock);
+                       spin_lock_irq(&np->lock);
                        /* disable interrupts on the nic */
                        writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
                        pci_push(base);
@@ -2620,7 +2637,7 @@
                                mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
                        }
                        printk(KERN_DEBUG "%s: too many iterations (%d) in 
nv_nic_irq_rx.\n", dev->name, i);
-                       spin_unlock(&np->lock);
+                       spin_unlock_irq(&np->lock);
                        break;
                }
 
@@ -2649,14 +2666,14 @@
                        break;
                
                if (events & NVREG_IRQ_LINK) {
-                       spin_lock(&np->lock);
+                       spin_lock_irq(&np->lock);
                        nv_link_irq(dev);
-                       spin_unlock(&np->lock);
+                       spin_unlock_irq(&np->lock);
                }
                if (np->need_linktimer && time_after(jiffies, 
np->link_timeout)) {
-                       spin_lock(&np->lock);
+                       spin_lock_irq(&np->lock);
                        nv_linkchange(dev);
-                       spin_unlock(&np->lock);
+                       spin_unlock_irq(&np->lock);
                        np->link_timeout = jiffies + LINK_TIMEOUT;
                }
                if (events & (NVREG_IRQ_UNKNOWN)) {
@@ -2664,7 +2681,7 @@
                                                dev->name, events);
                }
                if (i > max_interrupt_work) {
-                       spin_lock(&np->lock);
+                       spin_lock_irq(&np->lock);
                        /* disable interrupts on the nic */
                        writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
                        pci_push(base);
@@ -2674,7 +2691,7 @@
                                mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
                        }
                        printk(KERN_DEBUG "%s: too many iterations (%d) in 
nv_nic_irq_other.\n", dev->name, i);
-                       spin_unlock(&np->lock);
+                       spin_unlock_irq(&np->lock);
                        break;
                }
 
@@ -2759,21 +2776,21 @@
                                        printk(KERN_INFO "forcedeth: 
request_irq failed for rx %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
-                                       return 1;
+                                       goto out_err;
                                }
                                /* Request irq for tx handling */
                                if 
(request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, 
SA_SHIRQ, dev->name, dev) != 0) {
                                        printk(KERN_INFO "forcedeth: 
request_irq failed for tx %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
-                                       return 1;
+                                       goto out_free_rx;
                                }
                                /* Request irq for link and timer handling */
                                if 
(request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, 
SA_SHIRQ, dev->name, dev) != 0) {
                                        printk(KERN_INFO "forcedeth: 
request_irq failed for link %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
-                                       return 1;
+                                       goto out_free_tx;
                                }
                                /* map interrupts to their respective vector */
                                writel(0, base + NvRegMSIXMap0);
@@ -2790,7 +2807,7 @@
                                        printk(KERN_INFO "forcedeth: 
request_irq failed %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
-                                       return 1;
+                                       goto out_err;
                                }
 
                                /* map interrupts to vector 0 */
@@ -2807,7 +2824,7 @@
                                printk(KERN_INFO "forcedeth: request_irq failed 
%d\n", ret);
                                pci_disable_msi(np->pci_dev);
                                np->msi_flags &= ~NV_MSI_ENABLED;
-                               return 1;
+                               goto out_err;
                        }
 
                        /* map interrupts to vector 0 */
@@ -2820,11 +2837,17 @@
        if (ret != 0) {
                if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, 
SA_SHIRQ, dev->name, dev) != 0) ||
                    (intr_test && request_irq(np->pci_dev->irq, 
&nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0))
-                       return 1;
+                       goto out_err;
                        
        }
 
        return 0;
+out_free_tx:
+       free_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, dev);
+out_free_rx:
+       free_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, dev);
+out_err:
+       return 1;
 }
 
 static void nv_free_irq(struct net_device *dev)
@@ -2860,10 +2883,11 @@
         * nv_nic_irq because that may decide to do otherwise
         */
 
-       if (!(np->msi_flags & NV_MSI_X_ENABLED) ||
-           ((np->msi_flags & NV_MSI_X_ENABLED) && 
-            ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
-               disable_irq(dev->irq);
+       if (!using_multi_irqs(dev)) {
+               if (np->msi_flags & NV_MSI_X_ENABLED)
+                       
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+               else
+                       disable_irq(dev->irq);
                mask = np->irqmask;
        } else {
                if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
@@ -2886,11 +2910,12 @@
        writel(mask, base + NvRegIrqMask);
        pci_push(base);
 
-       if (!(np->msi_flags & NV_MSI_X_ENABLED) || 
-           ((np->msi_flags & NV_MSI_X_ENABLED) && 
-            ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) {
+       if (!using_multi_irqs(dev)) {
                nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);
-               enable_irq(dev->irq);
+               if (np->msi_flags & NV_MSI_X_ENABLED)
+                       enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+               else
+                       enable_irq(dev->irq);
        } else {
                if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
                        nv_nic_irq_rx((int) 0, (void *) data, (struct pt_regs 
*) NULL);
@@ -4269,22 +4294,20 @@
        if (id->driver_data & DEV_HAS_HIGH_DMA) {
                /* packet format 3: supports 40-bit addressing */
                np->desc_ver = DESC_VER_3;
+               np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
                if (dma_64bit) {
                        if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
                                printk(KERN_INFO "forcedeth: 64-bit DMA failed, 
using 32-bit addressing for device %s.\n",
                                       pci_name(pci_dev));
                        } else {
-                               if (pci_set_consistent_dma_mask(pci_dev, 
0x0000007fffffffffULL)) {
-                                       printk(KERN_INFO "forcedeth: 64-bit DMA 
(consistent) failed for device %s.\n",
-                                              pci_name(pci_dev));
-                                       goto out_relreg;
-                               } else {
-                                       dev->features |= NETIF_F_HIGHDMA;
-                                       printk(KERN_INFO "forcedeth: using 
HIGHDMA\n");
-                               }
+                               dev->features |= NETIF_F_HIGHDMA;
+                               printk(KERN_INFO "forcedeth: using HIGHDMA\n");
+                       }
+                       if (pci_set_consistent_dma_mask(pci_dev, 
0x0000007fffffffffULL)) {
+                               printk(KERN_INFO "forcedeth: 64-bit DMA 
(consistent) failed, using 32-bit ring buffers for device %s.\n",
+                                      pci_name(pci_dev));
                        }
                }
-               np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
        } else if (id->driver_data & DEV_HAS_LARGEDESC) {
                /* packet format 2: supports jumbo frames */
                np->desc_ver = DESC_VER_2;

Reply via email to