nv_msi_workaround(np);
 
+#ifdef CONFIG_FORCEDETH_NAPI
                spin_lock(&np->lock);
-               nv_tx_done(dev, np->tx_ring_size);
-               spin_unlock(&np->lock);
+               napi_schedule(&np->napi);
 
-#ifdef CONFIG_FORCEDETH_NAPI
-               if (np->events & NVREG_IRQ_RX_ALL) {
-                       spin_lock(&np->lock);
-                       napi_schedule(&np->napi);
+               /* Disable furthur irq's
+                  (msix not enabled with napi) */
+               writel(0, base + NvRegIrqMask);
 
-                       /* Disable furthur receive irq's */
-                       np->irqmask &= ~NVREG_IRQ_RX_ALL;
+               spin_unlock(&np->lock);
 
-                       if (np->msi_flags & NV_MSI_X_ENABLED)
-                               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       spin_unlock(&np->lock);
-               }
+               return IRQ_HANDLED;
 #else
+               spin_lock(&np->lock);
+               nv_tx_done(dev, np->tx_ring_size);
+               spin_unlock(&np->lock);
+
                if (nv_rx_process(dev, RX_WORK_PER_LOOP)) {
                        if (unlikely(nv_alloc_rx(dev))) {
                                spin_lock(&np->lock);
                                spin_unlock(&np->lock);
                        }
                }
-#endif
+
                if (unlikely(np->events & NVREG_IRQ_LINK)) {
                        spin_lock(&np->lock);
                        nv_link_irq(dev);
                        printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
                        break;
                }
-
+#endif
        }
        dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
 
 
                nv_msi_workaround(np);
 
+#ifdef CONFIG_FORCEDETH_NAPI
                spin_lock(&np->lock);
-               nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
-               spin_unlock(&np->lock);
+               napi_schedule(&np->napi);
 
-#ifdef CONFIG_FORCEDETH_NAPI
-               if (np->events & NVREG_IRQ_RX_ALL) {
-                       spin_lock(&np->lock);
-                       napi_schedule(&np->napi);
+               /* Disable furthur irq's
+                  (msix not enabled with napi) */
+               writel(0, base + NvRegIrqMask);
 
-                       /* Disable furthur receive irq's */
-                       np->irqmask &= ~NVREG_IRQ_RX_ALL;
+               spin_unlock(&np->lock);
 
-                       if (np->msi_flags & NV_MSI_X_ENABLED)
-                               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       spin_unlock(&np->lock);
-               }
+               return IRQ_HANDLED;
 #else
+               spin_lock(&np->lock);
+               nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+               spin_unlock(&np->lock);
+
                if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
                        if (unlikely(nv_alloc_rx_optimized(dev))) {
                                spin_lock(&np->lock);
                                spin_unlock(&np->lock);
                        }
                }
-#endif
+
                if (unlikely(np->events & NVREG_IRQ_LINK)) {
                        spin_lock(&np->lock);
                        nv_link_irq(dev);
                        printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
                        break;
                }
-
+#endif
        }
        dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
 
        int pkts, retcode;
 
        if (!nv_optimized(np)) {
+               spin_lock_irqsave(&np->lock, flags);
+               nv_tx_done(dev, np->tx_ring_size);
+               spin_unlock_irqrestore(&np->lock, flags);
+
                pkts = nv_rx_process(dev, budget);
                retcode = nv_alloc_rx(dev);
        } else {
+               spin_lock_irqsave(&np->lock, flags);
+               nv_tx_done_optimized(dev, np->tx_ring_size);
+               spin_unlock_irqrestore(&np->lock, flags);
+
                pkts = nv_rx_process_optimized(dev, budget);
                retcode = nv_alloc_rx_optimized(dev);
        }
                spin_unlock_irqrestore(&np->lock, flags);
        }
 
+       if (unlikely(np->events & NVREG_IRQ_LINK)) {
+               spin_lock_irqsave(&np->lock, flags);
+               nv_link_irq(dev);
+               spin_unlock_irqrestore(&np->lock, flags);
+       }
+       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+               spin_lock_irqsave(&np->lock, flags);
+               nv_linkchange(dev);
+               spin_unlock_irqrestore(&np->lock, flags);
+               np->link_timeout = jiffies + LINK_TIMEOUT;
+       }
+       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
+               spin_lock_irqsave(&np->lock, flags);
+               if (!np->in_shutdown) {
+                       np->nic_poll_irq = np->irqmask;
+                       np->recover_error = 1;
+                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+               }
+               spin_unlock_irqrestore(&np->lock, flags);
+               __napi_complete(napi);
+               return pkts;
+       }
+
        if (pkts < budget) {
-               /* re-enable receive interrupts */
+               /* re-enable interrupts
+                  (msix not enabled in napi) */
                spin_lock_irqsave(&np->lock, flags);
 
                __napi_complete(napi);
 
-               np->irqmask |= NVREG_IRQ_RX_ALL;
-               if (np->msi_flags & NV_MSI_X_ENABLED)
-                       writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-               else
-                       writel(np->irqmask, base + NvRegIrqMask);
+               writel(np->irqmask, base + NvRegIrqMask);
 
                spin_unlock_irqrestore(&np->lock, flags);
        }