This patch fixes the issues with multiple irqs.

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-03-27 16:04:53.000000000 -0500
+++ new-2.6/drivers/net/forcedeth.c     2006-03-27 16:04:46.000000000 -0500
@@ -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.
  *
  * 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>
@@ -1012,14 +1013,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);
@@ -1031,10 +1045,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);
@@ -1408,25 +1423,27 @@
 {
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
+       unsigned long flags;
 
-
-       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_irqsave(&np->lock, flags);
                if (!np->in_shutdown)
                        mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-               spin_unlock(&np->lock);
+               spin_unlock_irqrestore(&np->lock, flags);
        }
-       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);
        }
@@ -2550,16 +2567,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);
@@ -2569,7 +2586,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;
                }
 
@@ -2599,14 +2616,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);
@@ -2616,7 +2633,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;
                }
 
@@ -2645,14 +2662,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)) {
@@ -2660,7 +2677,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);
@@ -2670,7 +2687,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;
                }
 
@@ -2856,10 +2873,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) {
@@ -2882,11 +2900,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);

Reply via email to