lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1223745433-26440-1-git-send-email-ron.mercer@qlogic.com>
Date:	Sat, 11 Oct 2008 10:17:08 -0700
From:	Ron Mercer <ron.mercer@...gic.com>
To:	jeff@...zik.org
Cc:	netdev@...r.kernel.org, linux-driver@...gic.com,
	ron.mercer@...gic.com
Subject: [PATCH 1/6] [NET-NEXT]qlge: Clean up and fix MSI and legacy irq handling.


Signed-off-by: Ron Mercer <ron.mercer@...gic.com>
---
 drivers/net/qlge/qlge.h      |    3 +-
 drivers/net/qlge/qlge_main.c |   97 +++++++++++++++++++++---------------------
 drivers/net/qlge/qlge_mpi.c  |    1 -
 3 files changed, 50 insertions(+), 51 deletions(-)

diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index c37ea43..cc246f8 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -1375,7 +1375,6 @@ struct ql_adapter {
 	spinlock_t adapter_lock;
 	spinlock_t hw_lock;
 	spinlock_t stats_lock;
-	spinlock_t legacy_lock;	/* used for maintaining legacy intr sync */
 
 	/* PCI Bus Relative Register Addresses */
 	void __iomem *reg_base;
@@ -1502,7 +1501,7 @@ void ql_mpi_work(struct work_struct *work);
 void ql_mpi_reset_work(struct work_struct *work);
 int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit);
 void ql_queue_asic_error(struct ql_adapter *qdev);
-void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr);
+u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr);
 void ql_set_ethtool_ops(struct net_device *ndev);
 int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data);
 
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 3af822b..77a66e5 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -577,40 +577,43 @@ 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;
+	if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags) && intr)) {
 		ql_write32(qdev, INTR_EN,
 			   qdev->intr_context[intr].intr_en_mask);
-	else {
-		if (qdev->legacy_check)
-			spin_lock(&qdev->legacy_lock);
+       	var = ql_read32(qdev, STS);
+	} else {
+		unsigned long hw_flags=0;
+		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 		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");
+       		var = ql_read32(qdev, STS);
 		}
-		if (qdev->legacy_check)
-			spin_unlock(&qdev->legacy_lock);
+		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;
 
-	if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags)))
+	if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags) && intr))
 		goto exit;
-	else if (!atomic_read(&qdev->intr_context[intr].irq_cnt)) {
-		ql_write32(qdev, INTR_EN,
-			   qdev->intr_context[intr].intr_dis_mask);
-		var = ql_read32(qdev, STS);
-	}
-	atomic_inc(&qdev->intr_context[intr].irq_cnt);
+	else {
+		unsigned long hw_flags = 0;
+		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+              if (!atomic_read(&qdev->intr_context[intr].irq_cnt)) {
+		       ql_write32(qdev, INTR_EN,
+			          qdev->intr_context[intr].intr_dis_mask);
+       		var = ql_read32(qdev, STS);
+	       }
+       	atomic_inc(&qdev->intr_context[intr].irq_cnt);
+		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+       }
 exit:
 	return var;
 }
@@ -623,7 +626,8 @@ 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 +1729,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 +1743,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.
@@ -1791,22 +1785,23 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
 	 */
 	rx_ring = &qdev->rx_ring[0];
 	if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) {
-		QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n");
+		QPRINTK(qdev, INTR, DEBUG, "Waking handler for rx_ring[0].\n");
 		ql_disable_completion_interrupt(qdev, intr_context->intr);
 		queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue,
 				      &rx_ring->rx_work, 0);
 		work_done++;
 	}
 
+
+	/*
+	 * Start the DPC for each active queue.
+	 */
 	if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
-		/*
-		 * Start the DPC for each active queue.
-		 */
 		for (i = 1; i < qdev->rx_ring_count; i++) {
 			rx_ring = &qdev->rx_ring[i];
 			if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) !=
 			    rx_ring->cnsmr_idx) {
-				QPRINTK(qdev, INTR, INFO,
+				QPRINTK(qdev, INTR, DEBUG,
 					"Waking handler for rx_ring[%d].\n", i);
 				ql_disable_completion_interrupt(qdev,
 								intr_context->
@@ -1823,6 +1818,8 @@ 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 +2698,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");
 }
 
@@ -2791,8 +2786,13 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
 		/*
 		 * Single interrupt means one handler for all rings.
 		 */
-		intr_context->handler = qlge_isr;
-		sprintf(intr_context->name, "%s-single_irq", qdev->ndev->name);
+		if (likely(test_bit(QL_MSI_ENABLED, &qdev->flags))) {
+			intr_context->handler = qlge_isr;
+			sprintf(intr_context->name, "%s-msi-single_irq", qdev->ndev->name);
+		} else {
+			intr_context->handler = qlge_isr;
+			sprintf(intr_context->name, "%s-legacy-single_irq", qdev->ndev->name);
+		}
 		for (i = 0; i < qdev->rx_ring_count; i++)
 			qdev->rx_ring[i].irq = 0;
 	}
@@ -2865,7 +2865,8 @@ static int ql_request_irq(struct ql_adapter *qdev)
 				"%s: dev_id = 0x%p.\n", __func__,
 			       &qdev->rx_ring[0]);
 			status =
-			    request_irq(pdev->irq, qlge_isr,
+			    request_irq(pdev->irq,
+					intr_context->handler,
 					test_bit(QL_MSI_ENABLED,
 						 &qdev->
 						 flags) ? 0 : IRQF_SHARED,
@@ -3310,7 +3311,6 @@ static int ql_configure_rings(struct ql_adapter *qdev)
 	 * completion handler rx_rings.
 	 */
 	qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1;
-
 	if (ql_alloc_ring_cb(qdev))
 		return -ENOMEM;
 
@@ -3411,6 +3411,7 @@ static int qlge_open(struct net_device *ndev)
 error_up:
 	ql_release_adapter_resources(qdev);
 	ql_free_ring_cb(qdev);
+	QL_DUMP_ALL(qdev);
 	return err;
 }
 
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 24fe344..6bd3fad 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -132,7 +132,6 @@ void ql_mpi_work(struct work_struct *work)
 		default:
 			/* Clear the MPI firmware status. */
 			ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
-			break;
 		}
 	}
 	ql_enable_completion_interrupt(qdev, 0);
-- 
1.6.0

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ