bnx2x: add support for low latency rx
v2 cover bnx2x: add support for low latency rx
Hi Dave
This series adds to bnx2x driver capabilities for low latency rx. It bases on ixgbe driver code and tested with TCP_RR/UDP_RR. The results show about 50% boost in both scenarious. With second patch we have additional 5%.
Please, consider applying it to net-next.
V1->V2
* change function prototypes from int to bool (from Eric)
* do not allow poll when GRO/LRO enabled
Thanks,
Dmitry
PATCH v2 1/2 bnx2x: add support for ndo_ll_poll
Adds ndo_ll_poll method and locking for FPs between LL and the napi.
When receiving a packet we use skb_mark_ll to record the napi it came from. Add each napi to the napi_hash right after netif_napi_add().
--- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 125 +++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 67 ++++++++++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 23 ++++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 4 + 4 files changed, 208 insertions(+), 11 deletions(-)
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +125 -0
@@ -485,6 +485,21 @@ struct bnx2x_fastpath {struct bnx2x *bp;/* parent */ struct napi_struct napi; + +#ifdef CONFIG_NET_LL_RX_POLL +unsigned int state; +#define BNX2X_FP_STATE_IDLE 0 +#define BNX2X_FP_STATE_NAPI (1 << 0)/* NAPI owns this FP */ +#define BNX2X_FP_STATE_POLL (1 << 1)/* poll owns this FP */ +#define BNX2X_FP_STATE_NAPI_YIELD (1 << 2)/* NAPI yielded this FP */ +#define BNX2X_FP_STATE_POLL_YIELD (1 << 3)/* poll yielded this FP */ +#define BNX2X_FP_YIELD (BNX2X_FP_STATE_NAPI_YIELD | BNX2X_FP_STATE_POLL_YIELD) +#define BNX2X_FP_LOCKED (BNX2X_FP_STATE_NAPI | BNX2X_FP_STATE_POLL) +#define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD) +/* protect state */ +spinlock_t lock; +#endif /* CONFIG_NET_LL_RX_POLL */ +union host_hc_status_block status_blk;/* chip independent shortcuts into sb structure */ __le16 *sb_index_values;
@@ -557,6 +572,116 @@ struct bnx2x_fastpath {#define bnx2x_fp_stats (bp, fp) (&((bp)->fp_stats[(fp)->index]))#define bnx2x_fp_qstats (bp, fp) (&((bp)->fp_stats[(fp)->index].eth_q_stats)) +#ifdef CONFIG_NET_LL_RX_POLL +static inline void bnx2x_fp_init_lock (struct bnx2x_fastpath *fp) +{ +spin_lock_init (&fp->lock); + fp->state =BNX2X_FP_STATE_IDLE ; +} + +/* called from the device poll routine to get ownership of a FP */ +static inline bool bnx2x_fp_lock_napi (struct bnx2x_fastpath *fp) +{ +bool rc = true; + +spin_lock (&fp->lock); +if (fp->state &BNX2X_FP_LOCKED ) { +WARN_ON (fp->state &BNX2X_FP_STATE_NAPI ); + fp->state |=BNX2X_FP_STATE_NAPI_YIELD ; + rc = false; + }else { +/* we don't care if someone yielded */ + fp->state =BNX2X_FP_STATE_NAPI ; + } +spin_unlock (&fp->lock); +return rc; +} + +/* returns true is someone tried to get the FP while napi had it */ +static inline bool bnx2x_fp_unlock_napi (struct bnx2x_fastpath *fp) +{ +bool rc = false; + +spin_lock (&fp->lock); +WARN_ON (fp->state & + (BNX2X_FP_STATE_POLL |BNX2X_FP_STATE_NAPI_YIELD )); + +if (fp->state &BNX2X_FP_STATE_POLL_YIELD ) + rc = true; + fp->state =BNX2X_FP_STATE_IDLE ; +spin_unlock (&fp->lock); +return rc; +} + +/* called from bnx2x_low_latency_poll() */ +static inline bool bnx2x_fp_lock_poll (struct bnx2x_fastpath *fp) +{ +bool rc = true; + +spin_lock_bh (&fp->lock); +if ((fp->state &BNX2X_FP_LOCKED )) { + fp->state |=BNX2X_FP_STATE_POLL_YIELD ; + rc = false; + }else { +/* preserve yield marks */ + fp->state |=BNX2X_FP_STATE_POLL ; + } +spin_unlock_bh (&fp->lock); +return rc; +} + +/* returns true if someone tried to get the FP while it was locked */ +static inline bool bnx2x_fp_unlock_poll (struct bnx2x_fastpath *fp) +{ +bool rc = false; + +spin_lock_bh (&fp->lock); +WARN_ON (fp->state &BNX2X_FP_STATE_NAPI ); + +if (fp->state &BNX2X_FP_STATE_POLL_YIELD ) + rc = true; + fp->state =BNX2X_FP_STATE_IDLE ; +spin_unlock_bh (&fp->lock); +return rc; +} + +/* true if a socket is polling, even if it did not get the lock */ +static inline bool bnx2x_fp_ll_polling (struct bnx2x_fastpath *fp) +{ +WARN_ON (!(fp->state &BNX2X_FP_LOCKED )); +return fp->state &BNX2X_FP_USER_PEND ; +} +#else +static inline void bnx2x_fp_init_lock (struct bnx2x_fastpath *fp) +{ +} + +static inline bool bnx2x_fp_lock_napi (struct bnx2x_fastpath *fp) +{ +return true; +} + +static inline bool bnx2x_fp_unlock_napi (struct bnx2x_fastpath *fp) +{ +return false; +} + +static inline bool bnx2x_fp_lock_poll (struct bnx2x_fastpath *fp) +{ +return false; +} + +static inline bool bnx2x_fp_unlock_poll (struct bnx2x_fastpath *fp) +{ +return false; +} + +static inline bool bnx2x_fp_ll_polling (struct bnx2x_fastpath *fp) +{ +return false; +} +#endif /* CONFIG_NET_LL_RX_POLL */ +/* Use 2500 as a mini-jumbo MTU for FCoE */ #define BNX2X_FCOE_MINI_JUMBO_MTU 2500
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +60 -7
130 lines not on this page · raw message
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +19 -4
@@ -605,6 +605,13 @@ int bnx2x_enable_msi(struct bnx2x *bp);int bnx2x_poll (struct napi_struct *napi,int budget);/** +* bnx2x_low_latency_recv - LL callback +* +* @napi: napi structure +*/ +int bnx2x_low_latency_recv (struct napi_struct *napi); + +/** * bnx2x_alloc_mem_bp - allocate memories outsize main driver structure * * @bp: driver handle
@@ -846,9 +853,11 @@ static inline void bnx2x_add_all_napi_cnic(struct bnx2x *bp)int i;/* Add NAPI objects */ -for_each_rx_queue_cnic (bp, i) +for_each_rx_queue_cnic (bp, i) {netif_napi_add (bp->dev, &bnx2x_fp (bp, i, napi), bnx2x_poll,NAPI_POLL_WEIGHT ); +napi_hash_add (&bnx2x_fp (bp, i, napi)); + } }static inline void bnx2x_add_all_napi (struct bnx2x *bp)
@@ -856,25 +865,31 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp)int i;/* Add NAPI objects */ -for_each_eth_queue (bp, i) +for_each_eth_queue (bp, i) {netif_napi_add (bp->dev, &bnx2x_fp (bp, i, napi), bnx2x_poll,NAPI_POLL_WEIGHT ); +napi_hash_add (&bnx2x_fp (bp, i, napi)); + } }static inline void bnx2x_del_all_napi_cnic (struct bnx2x *bp) {int i; -for_each_rx_queue_cnic (bp, i) +for_each_rx_queue_cnic (bp, i) { +napi_hash_del (&bnx2x_fp (bp, i, napi));netif_napi_del (&bnx2x_fp (bp, i, napi)); + } }static inline void bnx2x_del_all_napi (struct bnx2x *bp) {int i; -for_each_eth_queue (bp, i) +for_each_eth_queue (bp, i) { +napi_hash_del (&bnx2x_fp (bp, i, napi));netif_napi_del (&bnx2x_fp (bp, i, napi)); + } }int bnx2x_set_int_mode (struct bnx2x *bp);
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +4 -0
@@ -12013,6 +12013,10 @@ static const struct net_device_ops bnx2x_netdev_ops = {#ifdef NETDEV_FCOE_WWNN .ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn,#endif + +#ifdef CONFIG_NET_LL_RX_POLL + .ndo_ll_poll = bnx2x_low_latency_recv, +#endif };static int bnx2x_set_coherency_mask (struct bnx2x *bp)
Signature · 1 line
1.8.1.4
Re: [PATCH v2 net-next 1/2] bnx2x: add support for ndo_ll_poll
Quoted 8 lines · Dmitry Kravkov
Adds
ndo_ll_pollmethod and locking for FPs between LL and the napi.When receiving a packet we use
skb_mark_llto record the napi it came from. Add each napi to thenapi_hashright afternetif_napi_add().Signed-off-by Dmitry Kravkov <[email protected]>Signed-off-by Eilon Greenstein <[email protected]>---
PATCH v2 2/2 bnx2x: replace mechanism to check for next available packet
In reply to Dmitry KravkovCheck next packet availability by validating that HW has finished CQE placement. This saves latency of another dma transaction performed to update SB indexes.
--- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 49 ++++++++++-------------- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 26 +++++++++---- drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 3 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 1 - 4 files changed, 42 insertions(+), 37 deletions(-)
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +21 -28
@@ -804,40 +804,32 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) {struct bnx2x *bp = fp->bp;u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons; -u16 hw_comp_cons, sw_comp_cons, sw_comp_prod; +u16 sw_comp_cons, sw_comp_prod;int rx_pkt =0 ; +union eth_rx_cqe *cqe; +struct eth_fast_path_rx_cqe *cqe_fp;#ifdef BNX2X_STOP_ON_ERROR if (unlikely (bp->panic))return 0 ;#endif -/* CQ "next element" is of the size of the regular element, -that's why it's ok here */ - hw_comp_cons =le16_to_cpu (*fp->rx_cons_sb); -if ((hw_comp_cons &MAX_RCQ_DESC_CNT ) ==MAX_RCQ_DESC_CNT ) - hw_comp_cons++; - bd_cons = fp->rx_bd_cons; bd_prod = fp->rx_bd_prod; bd_prod_fw = bd_prod; sw_comp_cons = fp->rx_comp_cons; sw_comp_prod = fp->rx_comp_prod; -/* Memory barrier necessary as speculative reads of the rx -* buffer can be ahead of the index in the status block -*/ -rmb (); + comp_ring_cons =RCQ_BD (sw_comp_cons); + cqe = &fp->rx_comp_ring[comp_ring_cons]; + cqe_fp = &cqe->fast_path_cqe;DP (NETIF_MSG_RX_STATUS , -"queue[%d]: hw_comp_cons %u sw_comp_cons %u\n" , - fp->index, hw_comp_cons, sw_comp_cons); +"queue[%d]: sw_comp_cons %u\n" , fp->index, sw_comp_cons); -while (sw_comp_cons != hw_comp_cons) { +while (BNX2X_IS_CQE_COMPLETED (cqe_fp)) {struct sw_rx_bd *rx_buf =NULL ;struct sk_buff *skb; -union eth_rx_cqe *cqe; -struct eth_fast_path_rx_cqe *cqe_fp;u8 cqe_fp_flags;enum eth_rx_cqe_type cqe_fp_type;u16 len, pad, queue;
@@ -849,12 +841,9 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)return 0 ;#endif - comp_ring_cons =RCQ_BD (sw_comp_cons); bd_prod =RX_BD (bd_prod); bd_cons =RX_BD (bd_cons); - cqe = &fp->rx_comp_ring[comp_ring_cons]; - cqe_fp = &cqe->fast_path_cqe; cqe_fp_flags = cqe_fp->type_error_flags; cqe_fp_type = cqe_fp_flags Ð_FAST_PATH_RX_CQE_TYPE ;
@@ -1018,8 +1007,15 @@ next_cqe: sw_comp_prod =NEXT_RCQ_IDX (sw_comp_prod); sw_comp_cons =NEXT_RCQ_IDX (sw_comp_cons); +/* mark CQE as free */ +BNX2X_SEED_CQE (cqe_fp); +if (rx_pkt == budget)break ; + + comp_ring_cons =RCQ_BD (sw_comp_cons); + cqe = &fp->rx_comp_ring[comp_ring_cons]; + cqe_fp = &cqe->fast_path_cqe; }/* while */ fp->rx_bd_cons = bd_cons;
@@ -1055,8 +1051,6 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)#endif /* Handle Rx and Tx according to MSI-X vector */ -prefetch (fp->rx_cons_sb); -for_each_cos_in_tx_queue (fp, cos)prefetch (fp->txdata_ptr[cos]->tx_cons_sb);
@@ -3137,10 +3131,8 @@ int bnx2x_low_latency_recv(struct napi_struct *napi)if (!bnx2x_fp_lock_poll (fp))return LL_FLUSH_BUSY ; -if (bnx2x_has_rx_work (fp)) { -bnx2x_update_fpsb_idx (fp); +if (bnx2x_has_rx_work (fp)) found =bnx2x_rx_int (fp,4 ); - }bnx2x_fp_unlock_poll (fp);
@@ -4339,10 +4331,11 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) &bnx2x_fp (bp, index, rx_desc_mapping), sizeof(struct eth_rx_bd) * NUM_RX_BD); -BNX2X_PCI_ALLOC (bnx2x_fp (bp, index, rx_comp_ring), - &bnx2x_fp (bp, index, rx_comp_mapping), -sizeof (struct eth_fast_path_rx_cqe ) * -NUM_RCQ_BD ); +/* Seed all CQEs by 1s */ +BNX2X_PCI_FALLOC (bnx2x_fp (bp, index, rx_comp_ring), + &bnx2x_fp (bp, index, rx_comp_mapping), +sizeof (struct eth_fast_path_rx_cqe ) * +NUM_RCQ_BD );/* SGE ring */ BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring),
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +19 -7
@@ -59,6 +59,16 @@ extern int int_mode; (unsigned long long)(*y), x); \ } while (0) +#define BNX2X_PCI_FALLOC (x, y, size) \ + do { \ + x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ + if (x == NULL) \ + goto alloc_mem_err; \ + memset((void *)x, 0xFFFFFFFF, size); \ + DP(NETIF_MSG_HW, "BNX2X_PCI_FALLOC: Physical %Lx Virtual %p\n",\ + (unsigned long long)(*y), x); \ + } while (0) +#define BNX2X_ALLOC (x, size) \ do { \ x = kzalloc(size, GFP_KERNEL); \
@@ -805,16 +815,18 @@ static inline bool bnx2x_has_tx_work(struct bnx2x_fastpath *fp)return false; } +#define BNX2X_IS_CQE_COMPLETED (cqe_fp) (cqe_fp->marker == 0x0) +#define BNX2X_SEED_CQE (cqe_fp) (cqe_fp->marker = 0xFFFFFFFF)static inline int bnx2x_has_rx_work (struct bnx2x_fastpath *fp) { -u16 rx_cons_sb; +u16 cons; +union eth_rx_cqe *cqe; +struct eth_fast_path_rx_cqe *cqe_fp; -/* Tell compiler that status block fields can change */ -barrier (); - rx_cons_sb =le16_to_cpu (*fp->rx_cons_sb); -if ((rx_cons_sb &MAX_RCQ_DESC_CNT ) ==MAX_RCQ_DESC_CNT ) - rx_cons_sb++; -return (fp->rx_comp_cons != rx_cons_sb); + cons =RCQ_BD (fp->rx_comp_cons); + cqe = &fp->rx_comp_ring[cons]; + cqe_fp = &cqe->fast_path_cqe; +return BNX2X_IS_CQE_COMPLETED (cqe_fp); }/**
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +2 -1
@@ -3818,7 +3818,8 @@ struct eth_fast_path_rx_cqe {__le16 len_on_bd;struct parsing_flags pars_flags;union eth_sgl_or_raw_data sgl_or_raw_data; -__le32 reserved1[8 ]; +__le32 reserved1[7 ]; +u32 marker; };
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +0 -1
@@ -1866,7 +1866,6 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) mask =0x2 << (fp->index +CNIC_SUPPORT (bp));if (status & mask) {/* Handle Rx or Tx according to SB id */ -prefetch (fp->rx_cons_sb);for_each_cos_in_tx_queue (fp, cos)prefetch (fp->txdata_ptr[cos]->tx_cons_sb);prefetch (&fp->sb_running_index[SM_RX_ID ]);
Signature · 1 line
1.8.1.4
From: "Dmitry Kravkov" <[email protected]>
Date: Wed, 19 Jun 2013 01:36:03 +0300
Quoted 6 lines
This series adds to bnx2x driver capabilities for low latency rx. It bases on ixgbe driver code and tested with TCP_RR/UDP_RR. The results show about 50% boost in both scenarious. With second patch we have additional 5%.
Please, consider applying it to net-next.
Applied, thanks.