diff options
author | Michael Chan <mchan@broadcom.com> | 2007-12-20 23:01:44 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:57:39 -0500 |
commit | 57851d84533655db6948e25c54df19ecb673bf2f (patch) | |
tree | 631cf8e8cf72e5766294fb9658035d442131ceff | |
parent | c76c04758b8fd24a1c38b19742e3437e954e945b (diff) |
[BNX2]: Enable new tx ring.
Enable new tx ring and add new MSIX handler and NAPI poll function
for the new tx ring. Enable MSIX when the hardware supports it.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/bnx2.c | 87 | ||||
-rw-r--r-- | drivers/net/bnx2.h | 2 |
2 files changed, 81 insertions, 8 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4fc9d1653cda..0120df47bbc9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -598,7 +598,7 @@ bnx2_alloc_mem(struct bnx2 *bp) | |||
598 | for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) { | 598 | for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) { |
599 | struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; | 599 | struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; |
600 | 600 | ||
601 | bnapi->status_blk = (void *) | 601 | bnapi->status_blk_msix = (void *) |
602 | ((unsigned long) bp->status_blk + | 602 | ((unsigned long) bp->status_blk + |
603 | BNX2_SBLK_MSIX_ALIGN_SIZE * i); | 603 | BNX2_SBLK_MSIX_ALIGN_SIZE * i); |
604 | bnapi->int_num = i << 24; | 604 | bnapi->int_num = i << 24; |
@@ -2388,10 +2388,11 @@ bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi) | |||
2388 | return cons; | 2388 | return cons; |
2389 | } | 2389 | } |
2390 | 2390 | ||
2391 | static void | 2391 | static int |
2392 | bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi) | 2392 | bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) |
2393 | { | 2393 | { |
2394 | u16 hw_cons, sw_cons, sw_ring_cons; | 2394 | u16 hw_cons, sw_cons, sw_ring_cons; |
2395 | int tx_pkt = 0; | ||
2395 | 2396 | ||
2396 | hw_cons = bnx2_get_hw_tx_cons(bnapi); | 2397 | hw_cons = bnx2_get_hw_tx_cons(bnapi); |
2397 | sw_cons = bnapi->tx_cons; | 2398 | sw_cons = bnapi->tx_cons; |
@@ -2442,6 +2443,9 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi) | |||
2442 | sw_cons = NEXT_TX_BD(sw_cons); | 2443 | sw_cons = NEXT_TX_BD(sw_cons); |
2443 | 2444 | ||
2444 | dev_kfree_skb(skb); | 2445 | dev_kfree_skb(skb); |
2446 | tx_pkt++; | ||
2447 | if (tx_pkt == budget) | ||
2448 | break; | ||
2445 | 2449 | ||
2446 | hw_cons = bnx2_get_hw_tx_cons(bnapi); | 2450 | hw_cons = bnx2_get_hw_tx_cons(bnapi); |
2447 | } | 2451 | } |
@@ -2463,6 +2467,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi) | |||
2463 | netif_wake_queue(bp->dev); | 2467 | netif_wake_queue(bp->dev); |
2464 | netif_tx_unlock(bp->dev); | 2468 | netif_tx_unlock(bp->dev); |
2465 | } | 2469 | } |
2470 | return tx_pkt; | ||
2466 | } | 2471 | } |
2467 | 2472 | ||
2468 | static void | 2473 | static void |
@@ -2875,6 +2880,23 @@ bnx2_interrupt(int irq, void *dev_instance) | |||
2875 | return IRQ_HANDLED; | 2880 | return IRQ_HANDLED; |
2876 | } | 2881 | } |
2877 | 2882 | ||
2883 | static irqreturn_t | ||
2884 | bnx2_tx_msix(int irq, void *dev_instance) | ||
2885 | { | ||
2886 | struct net_device *dev = dev_instance; | ||
2887 | struct bnx2 *bp = netdev_priv(dev); | ||
2888 | struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC]; | ||
2889 | |||
2890 | prefetch(bnapi->status_blk_msix); | ||
2891 | |||
2892 | /* Return here if interrupt is disabled. */ | ||
2893 | if (unlikely(atomic_read(&bp->intr_sem) != 0)) | ||
2894 | return IRQ_HANDLED; | ||
2895 | |||
2896 | netif_rx_schedule(dev, &bnapi->napi); | ||
2897 | return IRQ_HANDLED; | ||
2898 | } | ||
2899 | |||
2878 | #define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \ | 2900 | #define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \ |
2879 | STATUS_ATTN_BITS_TIMER_ABORT) | 2901 | STATUS_ATTN_BITS_TIMER_ABORT) |
2880 | 2902 | ||
@@ -2895,6 +2917,29 @@ bnx2_has_work(struct bnx2_napi *bnapi) | |||
2895 | return 0; | 2917 | return 0; |
2896 | } | 2918 | } |
2897 | 2919 | ||
2920 | static int bnx2_tx_poll(struct napi_struct *napi, int budget) | ||
2921 | { | ||
2922 | struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); | ||
2923 | struct bnx2 *bp = bnapi->bp; | ||
2924 | int work_done = 0; | ||
2925 | struct status_block_msix *sblk = bnapi->status_blk_msix; | ||
2926 | |||
2927 | do { | ||
2928 | work_done += bnx2_tx_int(bp, bnapi, budget - work_done); | ||
2929 | if (unlikely(work_done >= budget)) | ||
2930 | return work_done; | ||
2931 | |||
2932 | bnapi->last_status_idx = sblk->status_idx; | ||
2933 | rmb(); | ||
2934 | } while (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons); | ||
2935 | |||
2936 | netif_rx_complete(bp->dev, napi); | ||
2937 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | | ||
2938 | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | | ||
2939 | bnapi->last_status_idx); | ||
2940 | return work_done; | ||
2941 | } | ||
2942 | |||
2898 | static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, | 2943 | static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, |
2899 | int work_done, int budget) | 2944 | int work_done, int budget) |
2900 | { | 2945 | { |
@@ -2916,7 +2961,7 @@ static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, | |||
2916 | } | 2961 | } |
2917 | 2962 | ||
2918 | if (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons) | 2963 | if (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons) |
2919 | bnx2_tx_int(bp, bnapi); | 2964 | bnx2_tx_int(bp, bnapi, 0); |
2920 | 2965 | ||
2921 | if (bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) | 2966 | if (bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) |
2922 | work_done += bnx2_rx_int(bp, bnapi, budget - work_done); | 2967 | work_done += bnx2_rx_int(bp, bnapi, budget - work_done); |
@@ -5399,10 +5444,35 @@ bnx2_free_irq(struct bnx2 *bp) | |||
5399 | static void | 5444 | static void |
5400 | bnx2_enable_msix(struct bnx2 *bp) | 5445 | bnx2_enable_msix(struct bnx2 *bp) |
5401 | { | 5446 | { |
5447 | int i, rc; | ||
5448 | struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC]; | ||
5449 | |||
5402 | bnx2_setup_msix_tbl(bp); | 5450 | bnx2_setup_msix_tbl(bp); |
5403 | REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1); | 5451 | REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1); |
5404 | REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE); | 5452 | REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE); |
5405 | REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE); | 5453 | REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE); |
5454 | |||
5455 | for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { | ||
5456 | msix_ent[i].entry = i; | ||
5457 | msix_ent[i].vector = 0; | ||
5458 | } | ||
5459 | |||
5460 | rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC); | ||
5461 | if (rc != 0) | ||
5462 | return; | ||
5463 | |||
5464 | bp->irq_tbl[BNX2_BASE_VEC].handler = bnx2_msi_1shot; | ||
5465 | bp->irq_tbl[BNX2_TX_VEC].handler = bnx2_tx_msix; | ||
5466 | |||
5467 | strcpy(bp->irq_tbl[BNX2_BASE_VEC].name, bp->dev->name); | ||
5468 | strcat(bp->irq_tbl[BNX2_BASE_VEC].name, "-base"); | ||
5469 | strcpy(bp->irq_tbl[BNX2_TX_VEC].name, bp->dev->name); | ||
5470 | strcat(bp->irq_tbl[BNX2_TX_VEC].name, "-tx"); | ||
5471 | |||
5472 | bp->irq_nvecs = BNX2_MAX_MSIX_VEC; | ||
5473 | bp->flags |= USING_MSIX_FLAG | ONE_SHOT_MSI_FLAG; | ||
5474 | for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) | ||
5475 | bp->irq_tbl[i].vector = msix_ent[i].vector; | ||
5406 | } | 5476 | } |
5407 | 5477 | ||
5408 | static void | 5478 | static void |
@@ -5504,9 +5574,10 @@ bnx2_open(struct net_device *dev) | |||
5504 | bnx2_enable_int(bp); | 5574 | bnx2_enable_int(bp); |
5505 | } | 5575 | } |
5506 | } | 5576 | } |
5507 | if (bp->flags & USING_MSI_FLAG) { | 5577 | if (bp->flags & USING_MSI_FLAG) |
5508 | printk(KERN_INFO PFX "%s: using MSI\n", dev->name); | 5578 | printk(KERN_INFO PFX "%s: using MSI\n", dev->name); |
5509 | } | 5579 | else if (bp->flags & USING_MSIX_FLAG) |
5580 | printk(KERN_INFO PFX "%s: using MSIX\n", dev->name); | ||
5510 | 5581 | ||
5511 | netif_start_queue(dev); | 5582 | netif_start_queue(dev); |
5512 | 5583 | ||
@@ -5570,7 +5641,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
5570 | u32 len, vlan_tag_flags, last_frag, mss; | 5641 | u32 len, vlan_tag_flags, last_frag, mss; |
5571 | u16 prod, ring_prod; | 5642 | u16 prod, ring_prod; |
5572 | int i; | 5643 | int i; |
5573 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | 5644 | struct bnx2_napi *bnapi = &bp->bnx2_napi[bp->tx_vec]; |
5574 | 5645 | ||
5575 | if (unlikely(bnx2_tx_avail(bp, bnapi) < | 5646 | if (unlikely(bnx2_tx_avail(bp, bnapi) < |
5576 | (skb_shinfo(skb)->nr_frags + 1))) { | 5647 | (skb_shinfo(skb)->nr_frags + 1))) { |
@@ -7253,6 +7324,8 @@ bnx2_init_napi(struct bnx2 *bp) | |||
7253 | bnapi->bp = bp; | 7324 | bnapi->bp = bp; |
7254 | } | 7325 | } |
7255 | netif_napi_add(bp->dev, &bp->bnx2_napi[0].napi, bnx2_poll, 64); | 7326 | netif_napi_add(bp->dev, &bp->bnx2_napi[0].napi, bnx2_poll, 64); |
7327 | netif_napi_add(bp->dev, &bp->bnx2_napi[BNX2_TX_VEC].napi, bnx2_tx_poll, | ||
7328 | 64); | ||
7256 | } | 7329 | } |
7257 | 7330 | ||
7258 | static int __devinit | 7331 | static int __devinit |
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 68fb5904f75c..09bd665a3b9c 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h | |||
@@ -6528,7 +6528,7 @@ struct flash_spec { | |||
6528 | }; | 6528 | }; |
6529 | 6529 | ||
6530 | #define BNX2_MAX_MSIX_HW_VEC 9 | 6530 | #define BNX2_MAX_MSIX_HW_VEC 9 |
6531 | #define BNX2_MAX_MSIX_VEC 1 | 6531 | #define BNX2_MAX_MSIX_VEC 2 |
6532 | #define BNX2_BASE_VEC 0 | 6532 | #define BNX2_BASE_VEC 0 |
6533 | #define BNX2_TX_VEC 1 | 6533 | #define BNX2_TX_VEC 1 |
6534 | #define BNX2_TX_INT_NUM (BNX2_TX_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT) | 6534 | #define BNX2_TX_INT_NUM (BNX2_TX_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT) |