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);