diff options
author | Michael Chan <mchan@broadcom.com> | 2008-06-19 19:41:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-06-19 19:41:08 -0400 |
commit | 43e80b89b65cbc62b5e0fde09b47c9fc572a8b11 (patch) | |
tree | 894984eda36c720a44e00a6bd1c1c2567b45102b /drivers/net/bnx2.c | |
parent | bb4f98abf590cf9899017f14f1a54984f02a0009 (diff) |
bnx2: Optimize fast-path tx and rx work.
Add hw_tx_cons_ptr and hw_rx_cons_ptr to speed up the retreival of
the tx and rx consumer index, since the MSI-X and default status
blocks have different structures.
Combine status_blk and status_blk_msix into a union. We'll only use
one type of status block for each vector.
Separate the code to detect more rx and tx work from the code to
detect link related work.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r-- | drivers/net/bnx2.c | 107 |
1 files changed, 66 insertions, 41 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4360528ded39..3872e51b3c85 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -624,6 +624,7 @@ static void | |||
624 | bnx2_free_mem(struct bnx2 *bp) | 624 | bnx2_free_mem(struct bnx2 *bp) |
625 | { | 625 | { |
626 | int i; | 626 | int i; |
627 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | ||
627 | 628 | ||
628 | bnx2_free_tx_mem(bp); | 629 | bnx2_free_tx_mem(bp); |
629 | bnx2_free_rx_mem(bp); | 630 | bnx2_free_rx_mem(bp); |
@@ -636,10 +637,11 @@ bnx2_free_mem(struct bnx2 *bp) | |||
636 | bp->ctx_blk[i] = NULL; | 637 | bp->ctx_blk[i] = NULL; |
637 | } | 638 | } |
638 | } | 639 | } |
639 | if (bp->status_blk) { | 640 | if (bnapi->status_blk.msi) { |
640 | pci_free_consistent(bp->pdev, bp->status_stats_size, | 641 | pci_free_consistent(bp->pdev, bp->status_stats_size, |
641 | bp->status_blk, bp->status_blk_mapping); | 642 | bnapi->status_blk.msi, |
642 | bp->status_blk = NULL; | 643 | bp->status_blk_mapping); |
644 | bnapi->status_blk.msi = NULL; | ||
643 | bp->stats_blk = NULL; | 645 | bp->stats_blk = NULL; |
644 | } | 646 | } |
645 | } | 647 | } |
@@ -648,6 +650,8 @@ static int | |||
648 | bnx2_alloc_mem(struct bnx2 *bp) | 650 | bnx2_alloc_mem(struct bnx2 *bp) |
649 | { | 651 | { |
650 | int i, status_blk_size, err; | 652 | int i, status_blk_size, err; |
653 | struct bnx2_napi *bnapi; | ||
654 | void *status_blk; | ||
651 | 655 | ||
652 | /* Combine status and statistics blocks into one allocation. */ | 656 | /* Combine status and statistics blocks into one allocation. */ |
653 | status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block)); | 657 | status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block)); |
@@ -657,27 +661,37 @@ bnx2_alloc_mem(struct bnx2 *bp) | |||
657 | bp->status_stats_size = status_blk_size + | 661 | bp->status_stats_size = status_blk_size + |
658 | sizeof(struct statistics_block); | 662 | sizeof(struct statistics_block); |
659 | 663 | ||
660 | bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size, | 664 | status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size, |
661 | &bp->status_blk_mapping); | 665 | &bp->status_blk_mapping); |
662 | if (bp->status_blk == NULL) | 666 | if (status_blk == NULL) |
663 | goto alloc_mem_err; | 667 | goto alloc_mem_err; |
664 | 668 | ||
665 | memset(bp->status_blk, 0, bp->status_stats_size); | 669 | memset(status_blk, 0, bp->status_stats_size); |
666 | 670 | ||
667 | bp->bnx2_napi[0].status_blk = bp->status_blk; | 671 | bnapi = &bp->bnx2_napi[0]; |
672 | bnapi->status_blk.msi = status_blk; | ||
673 | bnapi->hw_tx_cons_ptr = | ||
674 | &bnapi->status_blk.msi->status_tx_quick_consumer_index0; | ||
675 | bnapi->hw_rx_cons_ptr = | ||
676 | &bnapi->status_blk.msi->status_rx_quick_consumer_index0; | ||
668 | if (bp->flags & BNX2_FLAG_MSIX_CAP) { | 677 | if (bp->flags & BNX2_FLAG_MSIX_CAP) { |
669 | for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) { | 678 | for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) { |
670 | struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; | 679 | struct status_block_msix *sblk; |
680 | |||
681 | bnapi = &bp->bnx2_napi[i]; | ||
671 | 682 | ||
672 | bnapi->status_blk_msix = (void *) | 683 | sblk = (void *) (status_blk + |
673 | ((unsigned long) bp->status_blk + | 684 | BNX2_SBLK_MSIX_ALIGN_SIZE * i); |
674 | BNX2_SBLK_MSIX_ALIGN_SIZE * i); | 685 | bnapi->status_blk.msix = sblk; |
686 | bnapi->hw_tx_cons_ptr = | ||
687 | &sblk->status_tx_quick_consumer_index; | ||
688 | bnapi->hw_rx_cons_ptr = | ||
689 | &sblk->status_rx_quick_consumer_index; | ||
675 | bnapi->int_num = i << 24; | 690 | bnapi->int_num = i << 24; |
676 | } | 691 | } |
677 | } | 692 | } |
678 | 693 | ||
679 | bp->stats_blk = (void *) ((unsigned long) bp->status_blk + | 694 | bp->stats_blk = status_blk + status_blk_size; |
680 | status_blk_size); | ||
681 | 695 | ||
682 | bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size; | 696 | bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size; |
683 | 697 | ||
@@ -2515,7 +2529,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) | |||
2515 | static int | 2529 | static int |
2516 | bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event) | 2530 | bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event) |
2517 | { | 2531 | { |
2518 | struct status_block *sblk = bnapi->status_blk; | 2532 | struct status_block *sblk = bnapi->status_blk.msi; |
2519 | u32 new_link_state, old_link_state; | 2533 | u32 new_link_state, old_link_state; |
2520 | int is_set = 1; | 2534 | int is_set = 1; |
2521 | 2535 | ||
@@ -2551,11 +2565,9 @@ bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi) | |||
2551 | { | 2565 | { |
2552 | u16 cons; | 2566 | u16 cons; |
2553 | 2567 | ||
2554 | if (bnapi->int_num == 0) | 2568 | /* Tell compiler that status block fields can change. */ |
2555 | cons = bnapi->status_blk->status_tx_quick_consumer_index0; | 2569 | barrier(); |
2556 | else | 2570 | cons = *bnapi->hw_tx_cons_ptr; |
2557 | cons = bnapi->status_blk_msix->status_tx_quick_consumer_index; | ||
2558 | |||
2559 | if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT)) | 2571 | if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT)) |
2560 | cons++; | 2572 | cons++; |
2561 | return cons; | 2573 | return cons; |
@@ -2822,11 +2834,9 @@ bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi) | |||
2822 | { | 2834 | { |
2823 | u16 cons; | 2835 | u16 cons; |
2824 | 2836 | ||
2825 | if (bnapi->int_num == 0) | 2837 | /* Tell compiler that status block fields can change. */ |
2826 | cons = bnapi->status_blk->status_rx_quick_consumer_index0; | 2838 | barrier(); |
2827 | else | 2839 | cons = *bnapi->hw_rx_cons_ptr; |
2828 | cons = bnapi->status_blk_msix->status_rx_quick_consumer_index; | ||
2829 | |||
2830 | if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)) | 2840 | if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)) |
2831 | cons++; | 2841 | cons++; |
2832 | return cons; | 2842 | return cons; |
@@ -2990,7 +3000,7 @@ bnx2_msi(int irq, void *dev_instance) | |||
2990 | struct bnx2 *bp = netdev_priv(dev); | 3000 | struct bnx2 *bp = netdev_priv(dev); |
2991 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | 3001 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; |
2992 | 3002 | ||
2993 | prefetch(bnapi->status_blk); | 3003 | prefetch(bnapi->status_blk.msi); |
2994 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, | 3004 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, |
2995 | BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | | 3005 | BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | |
2996 | BNX2_PCICFG_INT_ACK_CMD_MASK_INT); | 3006 | BNX2_PCICFG_INT_ACK_CMD_MASK_INT); |
@@ -3011,7 +3021,7 @@ bnx2_msi_1shot(int irq, void *dev_instance) | |||
3011 | struct bnx2 *bp = netdev_priv(dev); | 3021 | struct bnx2 *bp = netdev_priv(dev); |
3012 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | 3022 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; |
3013 | 3023 | ||
3014 | prefetch(bnapi->status_blk); | 3024 | prefetch(bnapi->status_blk.msi); |
3015 | 3025 | ||
3016 | /* Return here if interrupt is disabled. */ | 3026 | /* Return here if interrupt is disabled. */ |
3017 | if (unlikely(atomic_read(&bp->intr_sem) != 0)) | 3027 | if (unlikely(atomic_read(&bp->intr_sem) != 0)) |
@@ -3028,7 +3038,7 @@ bnx2_interrupt(int irq, void *dev_instance) | |||
3028 | struct net_device *dev = dev_instance; | 3038 | struct net_device *dev = dev_instance; |
3029 | struct bnx2 *bp = netdev_priv(dev); | 3039 | struct bnx2 *bp = netdev_priv(dev); |
3030 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | 3040 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; |
3031 | struct status_block *sblk = bnapi->status_blk; | 3041 | struct status_block *sblk = bnapi->status_blk.msi; |
3032 | 3042 | ||
3033 | /* When using INTx, it is possible for the interrupt to arrive | 3043 | /* When using INTx, it is possible for the interrupt to arrive |
3034 | * at the CPU before the status block posted prior to the | 3044 | * at the CPU before the status block posted prior to the |
@@ -3069,7 +3079,7 @@ bnx2_tx_msix(int irq, void *dev_instance) | |||
3069 | struct bnx2 *bp = netdev_priv(dev); | 3079 | struct bnx2 *bp = netdev_priv(dev); |
3070 | struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC]; | 3080 | struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC]; |
3071 | 3081 | ||
3072 | prefetch(bnapi->status_blk_msix); | 3082 | prefetch(bnapi->status_blk.msix); |
3073 | 3083 | ||
3074 | /* Return here if interrupt is disabled. */ | 3084 | /* Return here if interrupt is disabled. */ |
3075 | if (unlikely(atomic_read(&bp->intr_sem) != 0)) | 3085 | if (unlikely(atomic_read(&bp->intr_sem) != 0)) |
@@ -3079,19 +3089,28 @@ bnx2_tx_msix(int irq, void *dev_instance) | |||
3079 | return IRQ_HANDLED; | 3089 | return IRQ_HANDLED; |
3080 | } | 3090 | } |
3081 | 3091 | ||
3082 | #define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \ | ||
3083 | STATUS_ATTN_BITS_TIMER_ABORT) | ||
3084 | |||
3085 | static inline int | 3092 | static inline int |
3086 | bnx2_has_work(struct bnx2_napi *bnapi) | 3093 | bnx2_has_fast_work(struct bnx2_napi *bnapi) |
3087 | { | 3094 | { |
3088 | struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; | 3095 | struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; |
3089 | struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; | 3096 | struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; |
3090 | struct status_block *sblk = bnapi->status_blk; | ||
3091 | 3097 | ||
3092 | if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) || | 3098 | if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) || |
3093 | (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)) | 3099 | (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)) |
3094 | return 1; | 3100 | return 1; |
3101 | return 0; | ||
3102 | } | ||
3103 | |||
3104 | #define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \ | ||
3105 | STATUS_ATTN_BITS_TIMER_ABORT) | ||
3106 | |||
3107 | static inline int | ||
3108 | bnx2_has_work(struct bnx2_napi *bnapi) | ||
3109 | { | ||
3110 | struct status_block *sblk = bnapi->status_blk.msi; | ||
3111 | |||
3112 | if (bnx2_has_fast_work(bnapi)) | ||
3113 | return 1; | ||
3095 | 3114 | ||
3096 | if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != | 3115 | if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != |
3097 | (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) | 3116 | (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) |
@@ -3106,7 +3125,7 @@ static int bnx2_tx_poll(struct napi_struct *napi, int budget) | |||
3106 | struct bnx2 *bp = bnapi->bp; | 3125 | struct bnx2 *bp = bnapi->bp; |
3107 | struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; | 3126 | struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; |
3108 | int work_done = 0; | 3127 | int work_done = 0; |
3109 | struct status_block_msix *sblk = bnapi->status_blk_msix; | 3128 | struct status_block_msix *sblk = bnapi->status_blk.msix; |
3110 | 3129 | ||
3111 | do { | 3130 | do { |
3112 | work_done += bnx2_tx_int(bp, bnapi, budget - work_done); | 3131 | work_done += bnx2_tx_int(bp, bnapi, budget - work_done); |
@@ -3124,12 +3143,9 @@ static int bnx2_tx_poll(struct napi_struct *napi, int budget) | |||
3124 | return work_done; | 3143 | return work_done; |
3125 | } | 3144 | } |
3126 | 3145 | ||
3127 | static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, | 3146 | static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi) |
3128 | int work_done, int budget) | ||
3129 | { | 3147 | { |
3130 | struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; | 3148 | struct status_block *sblk = bnapi->status_blk.msi; |
3131 | struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; | ||
3132 | struct status_block *sblk = bnapi->status_blk; | ||
3133 | u32 status_attn_bits = sblk->status_attn_bits; | 3149 | u32 status_attn_bits = sblk->status_attn_bits; |
3134 | u32 status_attn_bits_ack = sblk->status_attn_bits_ack; | 3150 | u32 status_attn_bits_ack = sblk->status_attn_bits_ack; |
3135 | 3151 | ||
@@ -3145,6 +3161,13 @@ static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, | |||
3145 | bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); | 3161 | bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); |
3146 | REG_RD(bp, BNX2_HC_COMMAND); | 3162 | REG_RD(bp, BNX2_HC_COMMAND); |
3147 | } | 3163 | } |
3164 | } | ||
3165 | |||
3166 | static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, | ||
3167 | int work_done, int budget) | ||
3168 | { | ||
3169 | struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; | ||
3170 | struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; | ||
3148 | 3171 | ||
3149 | if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons) | 3172 | if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons) |
3150 | bnx2_tx_int(bp, bnapi, 0); | 3173 | bnx2_tx_int(bp, bnapi, 0); |
@@ -3160,9 +3183,11 @@ static int bnx2_poll(struct napi_struct *napi, int budget) | |||
3160 | struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); | 3183 | struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); |
3161 | struct bnx2 *bp = bnapi->bp; | 3184 | struct bnx2 *bp = bnapi->bp; |
3162 | int work_done = 0; | 3185 | int work_done = 0; |
3163 | struct status_block *sblk = bnapi->status_blk; | 3186 | struct status_block *sblk = bnapi->status_blk.msi; |
3164 | 3187 | ||
3165 | while (1) { | 3188 | while (1) { |
3189 | bnx2_poll_link(bp, bnapi); | ||
3190 | |||
3166 | work_done = bnx2_poll_work(bp, bnapi, work_done, budget); | 3191 | work_done = bnx2_poll_work(bp, bnapi, work_done, budget); |
3167 | 3192 | ||
3168 | if (unlikely(work_done >= budget)) | 3193 | if (unlikely(work_done >= budget)) |