net/mlx5e: Xmit flow break down
Break current mlx5e xmit flow into smaller blocks (helper functions) in order to reuse them for IPoIB SKB transmission. Signed-off-by: Saeed Mahameed <saeedm@mellanox.com> Reviewed-by: Erez Shitrit <erezsh@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ec8fd927b7
commit
77bdf8950b
@ -304,6 +304,7 @@ struct mlx5e_cq {
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
struct mlx5e_tx_wqe_info {
|
||||
struct sk_buff *skb;
|
||||
u32 num_bytes;
|
||||
u8 num_wqebbs;
|
||||
u8 num_dma;
|
||||
@ -345,7 +346,6 @@ struct mlx5e_txqsq {
|
||||
|
||||
/* write@xmit, read@completion */
|
||||
struct {
|
||||
struct sk_buff **skb;
|
||||
struct mlx5e_sq_dma *dma_fifo;
|
||||
struct mlx5e_tx_wqe_info *wqe_info;
|
||||
} db;
|
||||
|
@ -1042,7 +1042,6 @@ static void mlx5e_free_txqsq_db(struct mlx5e_txqsq *sq)
|
||||
{
|
||||
kfree(sq->db.wqe_info);
|
||||
kfree(sq->db.dma_fifo);
|
||||
kfree(sq->db.skb);
|
||||
}
|
||||
|
||||
static int mlx5e_alloc_txqsq_db(struct mlx5e_txqsq *sq, int numa)
|
||||
@ -1050,13 +1049,11 @@ static int mlx5e_alloc_txqsq_db(struct mlx5e_txqsq *sq, int numa)
|
||||
int wq_sz = mlx5_wq_cyc_get_size(&sq->wq);
|
||||
int df_sz = wq_sz * MLX5_SEND_WQEBB_NUM_DS;
|
||||
|
||||
sq->db.skb = kzalloc_node(wq_sz * sizeof(*sq->db.skb),
|
||||
GFP_KERNEL, numa);
|
||||
sq->db.dma_fifo = kzalloc_node(df_sz * sizeof(*sq->db.dma_fifo),
|
||||
GFP_KERNEL, numa);
|
||||
sq->db.wqe_info = kzalloc_node(wq_sz * sizeof(*sq->db.wqe_info),
|
||||
GFP_KERNEL, numa);
|
||||
if (!sq->db.skb || !sq->db.dma_fifo || !sq->db.wqe_info) {
|
||||
if (!sq->db.dma_fifo || !sq->db.wqe_info) {
|
||||
mlx5e_free_txqsq_db(sq);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1295,7 +1292,7 @@ static void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
|
||||
if (mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, 1)) {
|
||||
struct mlx5e_tx_wqe *nop;
|
||||
|
||||
sq->db.skb[(sq->pc & sq->wq.sz_m1)] = NULL;
|
||||
sq->db.wqe_info[(sq->pc & sq->wq.sz_m1)].skb = NULL;
|
||||
nop = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc);
|
||||
mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &nop->ctrl);
|
||||
}
|
||||
|
@ -177,30 +177,9 @@ static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs,
|
||||
mlx5e_tx_skb_pull_inline(skb_data, skb_len, cpy2_sz);
|
||||
}
|
||||
|
||||
static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb)
|
||||
static inline void
|
||||
mlx5e_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg)
|
||||
{
|
||||
struct mlx5_wq_cyc *wq = &sq->wq;
|
||||
|
||||
u16 pi = sq->pc & wq->sz_m1;
|
||||
struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi);
|
||||
struct mlx5e_tx_wqe_info *wi = &sq->db.wqe_info[pi];
|
||||
|
||||
struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
|
||||
struct mlx5_wqe_eth_seg *eseg = &wqe->eth;
|
||||
struct mlx5_wqe_data_seg *dseg;
|
||||
|
||||
unsigned char *skb_data = skb->data;
|
||||
unsigned int skb_len = skb->len;
|
||||
u8 opcode = MLX5_OPCODE_SEND;
|
||||
dma_addr_t dma_addr = 0;
|
||||
unsigned int num_bytes;
|
||||
u16 headlen;
|
||||
u16 ds_cnt;
|
||||
u16 ihs;
|
||||
int i;
|
||||
|
||||
memset(wqe, 0, sizeof(*wqe));
|
||||
|
||||
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
|
||||
eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
|
||||
if (skb->encapsulation) {
|
||||
@ -212,31 +191,148 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb)
|
||||
}
|
||||
} else
|
||||
sq->stats.csum_none++;
|
||||
}
|
||||
|
||||
if (skb_is_gso(skb)) {
|
||||
eseg->mss = cpu_to_be16(skb_shinfo(skb)->gso_size);
|
||||
opcode = MLX5_OPCODE_LSO;
|
||||
static inline u16
|
||||
mlx5e_txwqe_build_eseg_gso(struct mlx5e_txqsq *sq, struct sk_buff *skb,
|
||||
struct mlx5_wqe_eth_seg *eseg, unsigned int *num_bytes)
|
||||
{
|
||||
u16 ihs;
|
||||
|
||||
if (skb->encapsulation) {
|
||||
ihs = skb_inner_transport_offset(skb) + inner_tcp_hdrlen(skb);
|
||||
sq->stats.tso_inner_packets++;
|
||||
sq->stats.tso_inner_bytes += skb->len - ihs;
|
||||
} else {
|
||||
ihs = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||
sq->stats.tso_packets++;
|
||||
sq->stats.tso_bytes += skb->len - ihs;
|
||||
}
|
||||
eseg->mss = cpu_to_be16(skb_shinfo(skb)->gso_size);
|
||||
|
||||
sq->stats.packets += skb_shinfo(skb)->gso_segs;
|
||||
num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs;
|
||||
if (skb->encapsulation) {
|
||||
ihs = skb_inner_transport_offset(skb) + inner_tcp_hdrlen(skb);
|
||||
sq->stats.tso_inner_packets++;
|
||||
sq->stats.tso_inner_bytes += skb->len - ihs;
|
||||
} else {
|
||||
ihs = mlx5e_calc_min_inline(sq->min_inline_mode, skb);
|
||||
sq->stats.packets++;
|
||||
num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
|
||||
ihs = skb_transport_offset(skb) + tcp_hdrlen(skb);
|
||||
sq->stats.tso_packets++;
|
||||
sq->stats.tso_bytes += skb->len - ihs;
|
||||
}
|
||||
|
||||
sq->stats.bytes += num_bytes;
|
||||
*num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs;
|
||||
return ihs;
|
||||
}
|
||||
|
||||
static inline int
|
||||
mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb,
|
||||
unsigned char *skb_data, u16 headlen,
|
||||
struct mlx5_wqe_data_seg *dseg)
|
||||
{
|
||||
dma_addr_t dma_addr = 0;
|
||||
u8 num_dma = 0;
|
||||
int i;
|
||||
|
||||
if (headlen) {
|
||||
dma_addr = dma_map_single(sq->pdev, skb_data, headlen,
|
||||
DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
|
||||
return -ENOMEM;
|
||||
|
||||
dseg->addr = cpu_to_be64(dma_addr);
|
||||
dseg->lkey = sq->mkey_be;
|
||||
dseg->byte_count = cpu_to_be32(headlen);
|
||||
|
||||
mlx5e_dma_push(sq, dma_addr, headlen, MLX5E_DMA_MAP_SINGLE);
|
||||
num_dma++;
|
||||
dseg++;
|
||||
}
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
||||
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
|
||||
int fsz = skb_frag_size(frag);
|
||||
|
||||
dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz,
|
||||
DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
|
||||
return -ENOMEM;
|
||||
|
||||
dseg->addr = cpu_to_be64(dma_addr);
|
||||
dseg->lkey = sq->mkey_be;
|
||||
dseg->byte_count = cpu_to_be32(fsz);
|
||||
|
||||
mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE);
|
||||
num_dma++;
|
||||
dseg++;
|
||||
}
|
||||
|
||||
return num_dma;
|
||||
}
|
||||
|
||||
static inline void
|
||||
mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
|
||||
u8 opcode, u16 ds_cnt, u32 num_bytes, u8 num_dma,
|
||||
struct mlx5e_tx_wqe_info *wi, struct mlx5_wqe_ctrl_seg *cseg)
|
||||
{
|
||||
struct mlx5_wq_cyc *wq = &sq->wq;
|
||||
u16 pi;
|
||||
|
||||
wi->num_bytes = num_bytes;
|
||||
wi->num_dma = num_dma;
|
||||
wi->num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
|
||||
wi->skb = skb;
|
||||
|
||||
cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | opcode);
|
||||
cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
|
||||
|
||||
netdev_tx_sent_queue(sq->txq, num_bytes);
|
||||
|
||||
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
|
||||
sq->pc += wi->num_wqebbs;
|
||||
if (unlikely(!mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, MLX5E_SQ_STOP_ROOM))) {
|
||||
netif_tx_stop_queue(sq->txq);
|
||||
sq->stats.stopped++;
|
||||
}
|
||||
|
||||
if (!skb->xmit_more || netif_xmit_stopped(sq->txq))
|
||||
mlx5e_notify_hw(wq, sq->pc, sq->uar_map, cseg);
|
||||
|
||||
/* fill sq edge with nops to avoid wqe wrap around */
|
||||
while ((pi = (sq->pc & wq->sz_m1)) > sq->edge) {
|
||||
sq->db.wqe_info[pi].skb = NULL;
|
||||
mlx5e_post_nop(wq, sq->sqn, &sq->pc);
|
||||
sq->stats.nop++;
|
||||
}
|
||||
}
|
||||
|
||||
static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb)
|
||||
{
|
||||
struct mlx5_wq_cyc *wq = &sq->wq;
|
||||
|
||||
u16 pi = sq->pc & wq->sz_m1;
|
||||
struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi);
|
||||
struct mlx5e_tx_wqe_info *wi = &sq->db.wqe_info[pi];
|
||||
|
||||
struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
|
||||
struct mlx5_wqe_eth_seg *eseg = &wqe->eth;
|
||||
|
||||
unsigned char *skb_data = skb->data;
|
||||
unsigned int skb_len = skb->len;
|
||||
u8 opcode = MLX5_OPCODE_SEND;
|
||||
unsigned int num_bytes;
|
||||
int num_dma;
|
||||
u16 headlen;
|
||||
u16 ds_cnt;
|
||||
u16 ihs;
|
||||
|
||||
memset(wqe, 0, sizeof(*wqe));
|
||||
|
||||
mlx5e_txwqe_build_eseg_csum(sq, skb, eseg);
|
||||
|
||||
if (skb_is_gso(skb)) {
|
||||
opcode = MLX5_OPCODE_LSO;
|
||||
ihs = mlx5e_txwqe_build_eseg_gso(sq, skb, eseg, &num_bytes);
|
||||
sq->stats.packets += skb_shinfo(skb)->gso_segs;
|
||||
} else {
|
||||
ihs = mlx5e_calc_min_inline(sq->min_inline_mode, skb);
|
||||
num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
|
||||
sq->stats.packets++;
|
||||
}
|
||||
sq->stats.bytes += num_bytes;
|
||||
sq->stats.xmit_more += skb->xmit_more;
|
||||
|
||||
ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS;
|
||||
if (ihs) {
|
||||
@ -254,77 +350,14 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb)
|
||||
eseg->insert.vlan_tci = cpu_to_be16(skb_vlan_tag_get(skb));
|
||||
}
|
||||
|
||||
dseg = (struct mlx5_wqe_data_seg *)cseg + ds_cnt;
|
||||
|
||||
wi->num_dma = 0;
|
||||
|
||||
headlen = skb_len - skb->data_len;
|
||||
if (headlen) {
|
||||
dma_addr = dma_map_single(sq->pdev, skb_data, headlen,
|
||||
DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
|
||||
goto dma_unmap_wqe_err;
|
||||
num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb_data, headlen,
|
||||
(struct mlx5_wqe_data_seg *)cseg + ds_cnt);
|
||||
if (unlikely(num_dma < 0))
|
||||
goto dma_unmap_wqe_err;
|
||||
|
||||
dseg->addr = cpu_to_be64(dma_addr);
|
||||
dseg->lkey = sq->mkey_be;
|
||||
dseg->byte_count = cpu_to_be32(headlen);
|
||||
|
||||
mlx5e_dma_push(sq, dma_addr, headlen, MLX5E_DMA_MAP_SINGLE);
|
||||
wi->num_dma++;
|
||||
|
||||
dseg++;
|
||||
}
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
||||
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
|
||||
int fsz = skb_frag_size(frag);
|
||||
|
||||
dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz,
|
||||
DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
|
||||
goto dma_unmap_wqe_err;
|
||||
|
||||
dseg->addr = cpu_to_be64(dma_addr);
|
||||
dseg->lkey = sq->mkey_be;
|
||||
dseg->byte_count = cpu_to_be32(fsz);
|
||||
|
||||
mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE);
|
||||
wi->num_dma++;
|
||||
|
||||
dseg++;
|
||||
}
|
||||
|
||||
ds_cnt += wi->num_dma;
|
||||
|
||||
cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | opcode);
|
||||
cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
|
||||
|
||||
sq->db.skb[pi] = skb;
|
||||
|
||||
wi->num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
|
||||
sq->pc += wi->num_wqebbs;
|
||||
|
||||
netdev_tx_sent_queue(sq->txq, wi->num_bytes);
|
||||
|
||||
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
|
||||
if (unlikely(!mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc,
|
||||
MLX5E_SQ_STOP_ROOM))) {
|
||||
netif_tx_stop_queue(sq->txq);
|
||||
sq->stats.stopped++;
|
||||
}
|
||||
|
||||
sq->stats.xmit_more += skb->xmit_more;
|
||||
if (!skb->xmit_more || netif_xmit_stopped(sq->txq))
|
||||
mlx5e_notify_hw(wq, sq->pc, sq->uar_map, cseg);
|
||||
|
||||
/* fill sq edge with nops to avoid wqe wrap around */
|
||||
while ((pi = (sq->pc & wq->sz_m1)) > sq->edge) {
|
||||
sq->db.skb[pi] = NULL;
|
||||
mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc);
|
||||
sq->stats.nop++;
|
||||
}
|
||||
mlx5e_txwqe_complete(sq, skb, opcode, ds_cnt + num_dma,
|
||||
num_bytes, num_dma, wi, cseg);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
@ -392,8 +425,8 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
|
||||
last_wqe = (sqcc == wqe_counter);
|
||||
|
||||
ci = sqcc & sq->wq.sz_m1;
|
||||
skb = sq->db.skb[ci];
|
||||
wi = &sq->db.wqe_info[ci];
|
||||
skb = wi->skb;
|
||||
|
||||
if (unlikely(!skb)) { /* nop */
|
||||
sqcc++;
|
||||
@ -451,8 +484,8 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
|
||||
|
||||
while (sq->cc != sq->pc) {
|
||||
ci = sq->cc & sq->wq.sz_m1;
|
||||
skb = sq->db.skb[ci];
|
||||
wi = &sq->db.wqe_info[ci];
|
||||
skb = wi->skb;
|
||||
|
||||
if (!skb) { /* nop */
|
||||
sq->cc++;
|
||||
|
Loading…
Reference in New Issue
Block a user