|
@@ -577,41 +577,53 @@ static void ql_disable_interrupts(struct ql_adapter *qdev)
|
|
* incremented everytime we queue a worker and decremented everytime
|
|
* incremented everytime we queue a worker and decremented everytime
|
|
* a worker finishes. Once it hits zero we enable the interrupt.
|
|
* 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,
|
|
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)
|
|
static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
|
|
{
|
|
{
|
|
u32 var = 0;
|
|
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,
|
|
ql_write32(qdev, INTR_EN,
|
|
- qdev->intr_context[intr].intr_dis_mask);
|
|
|
|
|
|
+ ctx->intr_dis_mask);
|
|
var = ql_read32(qdev, STS);
|
|
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;
|
|
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.
|
|
* and enables only if the result is zero.
|
|
* So we precharge it here.
|
|
* 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);
|
|
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;
|
|
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
|
|
/* This handles a fatal error, MPI activity, and the default
|
|
* rx_ring in an MSI-X multiple vector environment.
|
|
* rx_ring in an MSI-X multiple vector environment.
|
|
* In MSI/Legacy environment it also process the rest of
|
|
* 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 i;
|
|
int work_done = 0;
|
|
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.
|
|
* 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;
|
|
return work_done ? IRQ_HANDLED : IRQ_NONE;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2701,8 +2706,6 @@ msi:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
irq_type = LEG_IRQ;
|
|
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");
|
|
QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n");
|
|
}
|
|
}
|
|
|
|
|