]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/qlge/qlge_main.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[mv-sheeva.git] / drivers / net / qlge / qlge_main.c
index 4b2caa6b7ac5eba5a01d2cc9c3ddbe0611e3a573..b83a9c9b6a9799e73d2cd3efdf4c5177734baa80 100644 (file)
@@ -577,41 +577,53 @@ static void ql_disable_interrupts(struct ql_adapter *qdev)
  * incremented everytime we queue a worker and decremented everytime
  * a worker finishes.  Once it hits zero we enable the interrupt.
  */
-void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
+u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
 {
-       if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags)))
+       u32 var = 0;
+       unsigned long hw_flags = 0;
+       struct intr_context *ctx = qdev->intr_context + intr;
+
+       if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags) && intr)) {
+               /* Always enable if we're MSIX multi interrupts and
+                * it's not the default (zeroeth) interrupt.
+                */
                ql_write32(qdev, INTR_EN,
-                          qdev->intr_context[intr].intr_en_mask);
-       else {
-               if (qdev->legacy_check)
-                       spin_lock(&qdev->legacy_lock);
-               if (atomic_dec_and_test(&qdev->intr_context[intr].irq_cnt)) {
-                       QPRINTK(qdev, INTR, ERR, "Enabling interrupt %d.\n",
-                               intr);
-                       ql_write32(qdev, INTR_EN,
-                                  qdev->intr_context[intr].intr_en_mask);
-               } else {
-                       QPRINTK(qdev, INTR, ERR,
-                               "Skip enable, other queue(s) are active.\n");
-               }
-               if (qdev->legacy_check)
-                       spin_unlock(&qdev->legacy_lock);
+                          ctx->intr_en_mask);
+               var = ql_read32(qdev, STS);
+               return var;
        }
+
+       spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+       if (atomic_dec_and_test(&ctx->irq_cnt)) {
+               ql_write32(qdev, INTR_EN,
+                          ctx->intr_en_mask);
+               var = ql_read32(qdev, STS);
+       }
+       spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+       return var;
 }
 
 static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
 {
        u32 var = 0;
+       unsigned long hw_flags;
+       struct intr_context *ctx;
 
-       if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags)))
-               goto exit;
-       else if (!atomic_read(&qdev->intr_context[intr].irq_cnt)) {
+       /* HW disables for us if we're MSIX multi interrupts and
+        * it's not the default (zeroeth) interrupt.
+        */
+       if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags) && intr))
+               return 0;
+
+       ctx = qdev->intr_context + intr;
+       spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+       if (!atomic_read(&ctx->irq_cnt)) {
                ql_write32(qdev, INTR_EN,
-                          qdev->intr_context[intr].intr_dis_mask);
+               ctx->intr_dis_mask);
                var = ql_read32(qdev, STS);
        }
-       atomic_inc(&qdev->intr_context[intr].irq_cnt);
-exit:
+       atomic_inc(&ctx->irq_cnt);
+       spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
        return var;
 }
 
@@ -623,7 +635,9 @@ static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev)
                 * and enables only if the result is zero.
                 * So we precharge it here.
                 */
-               atomic_set(&qdev->intr_context[i].irq_cnt, 1);
+               if (unlikely(!test_bit(QL_MSIX_ENABLED, &qdev->flags) ||
+                       i == 0))
+                       atomic_set(&qdev->intr_context[i].irq_cnt, 1);
                ql_enable_completion_interrupt(qdev, i);
        }
 
@@ -1725,19 +1739,6 @@ static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* We check here to see if we're already handling a legacy
- * interrupt.  If we are, then it must belong to another
- * chip with which we're sharing the interrupt line.
- */
-int ql_legacy_check(struct ql_adapter *qdev)
-{
-       int err;
-       spin_lock(&qdev->legacy_lock);
-       err = atomic_read(&qdev->intr_context[0].irq_cnt);
-       spin_unlock(&qdev->legacy_lock);
-       return err;
-}
-
 /* This handles a fatal error, MPI activity, and the default
  * rx_ring in an MSI-X multiple vector environment.
  * In MSI/Legacy environment it also process the rest of
@@ -1752,12 +1753,15 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
        int i;
        int work_done = 0;
 
-       if (qdev->legacy_check && qdev->legacy_check(qdev)) {
-               QPRINTK(qdev, INTR, INFO, "Already busy, not our interrupt.\n");
-               return IRQ_NONE;        /* Not our interrupt */
+       spin_lock(&qdev->hw_lock);
+       if (atomic_read(&qdev->intr_context[0].irq_cnt)) {
+               QPRINTK(qdev, INTR, DEBUG, "Shared Interrupt, Not ours!\n");
+               spin_unlock(&qdev->hw_lock);
+               return IRQ_NONE;
        }
+       spin_unlock(&qdev->hw_lock);
 
-       var = ql_read32(qdev, STS);
+       var = ql_disable_completion_interrupt(qdev, intr_context->intr);
 
        /*
         * Check for fatal error.
@@ -1823,6 +1827,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
                        }
                }
        }
+       ql_enable_completion_interrupt(qdev, intr_context->intr);
        return work_done ? IRQ_HANDLED : IRQ_NONE;
 }
 
@@ -2701,8 +2706,6 @@ msi:
                }
        }
        irq_type = LEG_IRQ;
-       spin_lock_init(&qdev->legacy_lock);
-       qdev->legacy_check = ql_legacy_check;
        QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n");
 }