Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2389

kernel-2.6.18-238.el5.src.rpm

From: Andy Gospodarek <gospo@redhat.com>
Date: Fri, 26 Sep 2008 16:23:58 -0400
Subject: [net] bnx2: fix problems with multiqueue receive
Message-id: 20080926202357.GB9500@gospo.rdu.redhat.com
O-Subject: [RHEL5.3 PATCH] bnx2: fix problems with multiqueue receive
Bugzilla: 441964
RH-Acked-by: John W. Linville <linville@redhat.com>
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: Neil Horman <nhorman@redhat.com>

The driver seemed to do everything but receive frames when using MSI-X
(only some new 5709 hardware supports this), so I discovered that I was
too quick with my backport and made the needed tweaks.

I tested it and it seems to work well now.  I also got feedback from
partners/customers that it's working well too.

This will resolve RHBZ 441964.

diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 6874704..c77f2ba 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -459,13 +459,19 @@ bnx2_disable_int_sync(struct bnx2 *bp)
 static void
 bnx2_napi_disable(struct bnx2 *bp)
 {
-	netif_poll_disable(bp->dev);
+	int i;
+
+	for (i = 0; i < bp->irq_nvecs; i++)
+		netif_poll_disable(bp->bnx2_napi[i].dummy_netdev);
 }
 
 static void
 bnx2_napi_enable(struct bnx2 *bp)
 {
-	netif_poll_enable(bp->dev);
+	int i;
+
+	for (i = 0; i < bp->irq_nvecs; i++)
+		netif_poll_enable(bp->bnx2_napi[i].dummy_netdev);
 }
 
 static void
@@ -2995,9 +3001,9 @@ next_rx:
 static irqreturn_t
 bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
 {
-	struct net_device *dev = dev_instance;
-	struct bnx2 *bp = netdev_priv(dev);
-	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+	struct bnx2_napi *bnapi = dev_instance;
+	struct bnx2 *bp = bnapi->bp;
+	struct net_device *dev = bnapi->dummy_netdev;
 
 	prefetch(bnapi->status_blk.msi);
 	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
@@ -3016,9 +3022,9 @@ bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
 static irqreturn_t
 bnx2_msi_1shot(int irq, void *dev_instance, struct pt_regs *regs)
 {
-	struct net_device *dev = dev_instance;
-	struct bnx2 *bp = netdev_priv(dev);
-	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+	struct bnx2_napi *bnapi = dev_instance;
+	struct bnx2 *bp = bnapi->bp;
+	struct net_device *dev = bnapi->dummy_netdev;
 
 	prefetch(bnapi->status_blk.msi);
 
@@ -3034,9 +3040,9 @@ bnx2_msi_1shot(int irq, void *dev_instance, struct pt_regs *regs)
 static irqreturn_t
 bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
-	struct net_device *dev = dev_instance;
-	struct bnx2 *bp = netdev_priv(dev);
-	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+	struct bnx2_napi *bnapi = dev_instance;
+	struct bnx2 *bp = bnapi->bp;
+	struct net_device *dev = bnapi->dummy_netdev;
 	struct status_block *sblk = bnapi->status_blk.msi;
 
 	/* When using INTx, it is possible for the interrupt to arrive
@@ -3136,10 +3142,9 @@ static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
 	return work_done;
 }
 
-#if 0 /* not used in RHEL4...yet */
 static int bnx2_poll_msix(struct net_device *dev, int *budget)
 {
-	struct bnx2_napi *bnapi = netdev_priv(dev);
+	struct bnx2_napi *bnapi = dev->priv;
 	struct bnx2 *bp = bnapi->bp;
 	int work_done = 0;
 	struct status_block_msix *sblk = bnapi->status_blk.msix;
@@ -3147,27 +3152,27 @@ static int bnx2_poll_msix(struct net_device *dev, int *budget)
 	while (1) {
 		work_done = bnx2_poll_work(bp, bnapi, work_done, *budget);
 		if (unlikely(work_done >= *budget))
-			break;
+			return 1;
 
 		bnapi->last_status_idx = sblk->status_idx;
 		/* status idx must be read before checking for more work. */
 		rmb();
 		if (likely(!bnx2_has_fast_work(bnapi))) {
 
-			netif_rx_complete(bp->dev);
+			netif_rx_complete(dev);
 			REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
 			       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
 			       bnapi->last_status_idx);
-			break;
+			return 0;
 		}
 	}
-	return work_done;
+	return 1;
 }
-#endif 
+
 static int bnx2_poll(struct net_device *dev, int *budget)
 {
-	struct bnx2 *bp = netdev_priv(dev);
-	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+	struct bnx2_napi *bnapi = dev->priv;
+	struct bnx2 *bp = bnapi->bp;
 	int work_done = 0;
 	struct status_block *sblk = bnapi->status_blk.msi;
 
@@ -3186,7 +3191,7 @@ static int bnx2_poll(struct net_device *dev, int *budget)
 		bnapi->last_status_idx = sblk->status_idx;
 		rmb();
 		if (likely(!bnx2_has_work(bnapi))) {
-			netif_rx_complete(bp->dev);
+			netif_rx_complete(dev);
 			if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
 				REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 				       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
@@ -5744,7 +5749,6 @@ bnx2_restart_timer:
 static int
 bnx2_request_irq(struct bnx2 *bp)
 {
-	struct net_device *dev = bp->dev;
 	unsigned long flags;
 	struct bnx2_irq *irq;
 	int rc = 0, i;
@@ -5757,7 +5761,7 @@ bnx2_request_irq(struct bnx2 *bp)
 	for (i = 0; i < bp->irq_nvecs; i++) {
 		irq = &bp->irq_tbl[i];
 		rc = request_irq(irq->vector, irq->handler, flags, irq->name,
-				 dev);
+				 &bp->bnx2_napi[i]);
 		if (rc)
 			break;
 		irq->requested = 1;
@@ -5768,14 +5772,13 @@ bnx2_request_irq(struct bnx2 *bp)
 static void
 bnx2_free_irq(struct bnx2 *bp)
 {
-	struct net_device *dev = bp->dev;
 	struct bnx2_irq *irq;
 	int i;
 
 	for (i = 0; i < bp->irq_nvecs; i++) {
 		irq = &bp->irq_tbl[i];
 		if (irq->requested)
-			free_irq(irq->vector, dev);
+			free_irq(irq->vector, &bp->bnx2_napi[i]);
 		irq->requested = 0;
 	}
 	if (bp->flags & BNX2_FLAG_USING_MSI)
@@ -7703,11 +7706,29 @@ bnx2_init_napi(struct bnx2 *bp)
 	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
 		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
 		bnapi->bp = bp;
+		bnapi->dummy_netdev = alloc_netdev(0, "", ether_setup);
+		bnapi->dummy_netdev->priv = bnapi;
+		bnapi->dummy_netdev->weight = 64;
+		if (i == 0)
+			bnapi->dummy_netdev->poll = bnx2_poll;
+		else
+			bnapi->dummy_netdev->poll = bnx2_poll_msix;
+		set_bit(__LINK_STATE_START, &bnapi->dummy_netdev->state);
 	}
+}
 
-	bp->dev->poll = bnx2_poll;
-	bp->dev->weight = 64;
+static void __devexit
+bnx2_destroy_napi(struct bnx2 *bp)
+{
+	int i;
 
+	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
+		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
+		if (bnapi->dummy_netdev) {
+			free_netdev(bnapi->dummy_netdev);
+			bnapi->dummy_netdev = NULL;
+		}
+	}
 }
 
 static int __devinit
@@ -7813,6 +7834,8 @@ bnx2_remove_one(struct pci_dev *pdev)
 
 	unregister_netdev(dev);
 
+	bnx2_destroy_napi(bp);
+
 	if (bp->regview)
 		iounmap(bp->regview);