[PATCH] : Add msi support

Linux Kernel Mailing List <[email protected]> Tue, 24 May 2005 12:44:16 +0000
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1546, 2005/05/24 09:44:16-03:00, [email protected]

	[PATCH] : Add msi support
	
	[TG3]: Add msi support
	
	Add MSI support for 5751 C0 and 5752.
	
	Signed-off-by: Michael Chan <[email protected]>
	Signed-off-by: David S. Miller <[email protected]>



 tg3.c |   93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 tg3.h |    1 
 2 files changed, 88 insertions(+), 6 deletions(-)


diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	2005-05-24 14:06:15 -07:00
+++ b/drivers/net/tg3.c	2005-05-24 14:06:15 -07:00
@@ -56,6 +56,12 @@
 #define TG3_TSO_SUPPORT	0
 #endif
 
+#ifdef CONFIG_PCI_MSI
+#define TG3_MSI_SUPPORT 1
+#else
+#define TG3_MSI_SUPPORT 0
+#endif
+
 #include "tg3.h"
 
 #define DRV_MODULE_NAME		"tg3"
@@ -2889,6 +2895,45 @@
 	return work_exists;
 }
 
+#if TG3_MSI_SUPPORT != 0
+/* MSI ISR - No need to check for interrupt sharing and no need to
+ * flush status block and interrupt mailbox. PCI ordering rules
+ * guarantee that MSI will arrive after the status block.
+ */
+static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct tg3 *tp = netdev_priv(dev);
+	struct tg3_hw_status *sblk = tp->hw_status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+
+	/*
+	 * writing any value to intr-mbox-0 clears PCI INTA# and
+	 * chip-internal interrupt pending events.
+	 * writing non-zero to intr-mbox-0 additional tells the
+	 * NIC to stop sending us irqs, engaging "in-intr-handler"
+	 * event coalescing.
+	 */
+	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+	sblk->status &= ~SD_STATUS_UPDATED;
+
+	if (likely(tg3_has_work(dev, tp)))
+		netif_rx_schedule(dev);		/* schedule NAPI poll */
+	else {
+		/* no work, re-enable interrupts
+		 */
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     0x00000000);
+	}
+
+	spin_unlock_irqrestore(&tp->lock, flags);
+
+	return IRQ_RETVAL(1);
+}
+#endif
+
 static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
@@ -2947,7 +2992,9 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void tg3_poll_controller(struct net_device *dev)
 {
-	tg3_interrupt(dev->irq, dev, NULL);
+	struct tg3 *tp = netdev_priv(dev);
+
+	tg3_interrupt(tp->pdev->irq, dev, NULL);
 }
 #endif
 
@@ -5749,10 +5796,33 @@
 	if (err)
 		return err;
 
-	err = request_irq(dev->irq, tg3_interrupt,
-			  SA_SHIRQ, dev->name, dev);
+#if TG3_MSI_SUPPORT != 0
+	if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
+	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) &&
+	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX)) {
+		if (pci_enable_msi(tp->pdev) == 0) {
+			u32 msi_mode;
+
+			msi_mode = tr32(MSGINT_MODE);
+			tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
+			tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
+		}
+	}
+	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
+		err = request_irq(tp->pdev->irq, tg3_msi,
+				  0, dev->name, dev);
+	else
+#endif
+		err = request_irq(tp->pdev->irq, tg3_interrupt,
+				  SA_SHIRQ, dev->name, dev);
 
 	if (err) {
+#if TG3_MSI_SUPPORT != 0
+		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+			pci_disable_msi(tp->pdev);
+			tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+		}
+#endif
 		tg3_free_consistent(tp);
 		return err;
 	}
@@ -5782,7 +5852,13 @@
 	spin_unlock_irq(&tp->lock);
 
 	if (err) {
-		free_irq(dev->irq, dev);
+		free_irq(tp->pdev->irq, dev);
+#if TG3_MSI_SUPPORT != 0
+		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+			pci_disable_msi(tp->pdev);
+			tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+		}
+#endif
 		tg3_free_consistent(tp);
 		return err;
 	}
@@ -6057,8 +6133,13 @@
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
-	free_irq(dev->irq, dev);
-
+	free_irq(tp->pdev->irq, dev);
+#if TG3_MSI_SUPPORT != 0
+	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+		pci_disable_msi(tp->pdev);
+		tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+	}
+#endif
 	memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev),
 	       sizeof(tp->net_stats_prev));
 	memcpy(&tp->estats_prev, tg3_get_estats(tp),
diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h
--- a/drivers/net/tg3.h	2005-05-24 14:06:15 -07:00
+++ b/drivers/net/tg3.h	2005-05-24 14:06:15 -07:00
@@ -2137,6 +2137,7 @@
 #define TG3_FLG2_5705_PLUS		0x00040000
 #define TG3_FLG2_5750_PLUS		0x00080000
 #define TG3_FLG2_PROTECTED_NVRAM	0x00100000
+#define TG3_FLG2_USING_MSI		0x00200000
 
 	u32				split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ		3