0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/tcp.h>
0034 #include <linux/if_vlan.h>
0035 #include <net/geneve.h>
0036 #include <net/dsfield.h>
0037 #include "en.h"
0038 #include "en/txrx.h"
0039 #include "ipoib/ipoib.h"
0040 #include "en_accel/en_accel.h"
0041 #include "en_accel/ipsec_rxtx.h"
0042 #include "en/ptp.h"
0043 #include <net/ipv6.h>
0044
0045 static void mlx5e_dma_unmap_wqe_err(struct mlx5e_txqsq *sq, u8 num_dma)
0046 {
0047 int i;
0048
0049 for (i = 0; i < num_dma; i++) {
0050 struct mlx5e_sq_dma *last_pushed_dma =
0051 mlx5e_dma_get(sq, --sq->dma_fifo_pc);
0052
0053 mlx5e_tx_dma_unmap(sq->pdev, last_pushed_dma);
0054 }
0055 }
0056
0057 static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb)
0058 {
0059 #define MLX5E_MIN_INLINE (ETH_HLEN + VLAN_HLEN)
0060
0061 return max(skb_network_offset(skb), MLX5E_MIN_INLINE);
0062 }
0063
0064 static inline int mlx5e_skb_l3_header_offset(struct sk_buff *skb)
0065 {
0066 if (skb_transport_header_was_set(skb))
0067 return skb_transport_offset(skb);
0068 else
0069 return mlx5e_skb_l2_header_offset(skb);
0070 }
0071
0072 static inline u16 mlx5e_calc_min_inline(enum mlx5_inline_modes mode,
0073 struct sk_buff *skb)
0074 {
0075 u16 hlen;
0076
0077 switch (mode) {
0078 case MLX5_INLINE_MODE_NONE:
0079 return 0;
0080 case MLX5_INLINE_MODE_TCP_UDP:
0081 hlen = eth_get_headlen(skb->dev, skb->data, skb_headlen(skb));
0082 if (hlen == ETH_HLEN && !skb_vlan_tag_present(skb))
0083 hlen += VLAN_HLEN;
0084 break;
0085 case MLX5_INLINE_MODE_IP:
0086 hlen = mlx5e_skb_l3_header_offset(skb);
0087 break;
0088 case MLX5_INLINE_MODE_L2:
0089 default:
0090 hlen = mlx5e_skb_l2_header_offset(skb);
0091 }
0092 return min_t(u16, hlen, skb_headlen(skb));
0093 }
0094
0095 #define MLX5_UNSAFE_MEMCPY_DISCLAIMER \
0096 "This copy has been bounds-checked earlier in " \
0097 "mlx5i_sq_calc_wqe_attr() and intentionally " \
0098 "crosses a flex array boundary. Since it is " \
0099 "performance sensitive, splitting the copy is " \
0100 "undesirable."
0101
0102 static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs)
0103 {
0104 struct vlan_ethhdr *vhdr = (struct vlan_ethhdr *)start;
0105 int cpy1_sz = 2 * ETH_ALEN;
0106 int cpy2_sz = ihs - cpy1_sz;
0107
0108 memcpy(&vhdr->addrs, skb->data, cpy1_sz);
0109 vhdr->h_vlan_proto = skb->vlan_proto;
0110 vhdr->h_vlan_TCI = cpu_to_be16(skb_vlan_tag_get(skb));
0111 unsafe_memcpy(&vhdr->h_vlan_encapsulated_proto,
0112 skb->data + cpy1_sz,
0113 cpy2_sz,
0114 MLX5_UNSAFE_MEMCPY_DISCLAIMER);
0115 }
0116
0117 static inline void
0118 mlx5e_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0119 struct mlx5e_accel_tx_state *accel,
0120 struct mlx5_wqe_eth_seg *eseg)
0121 {
0122 if (unlikely(mlx5e_ipsec_txwqe_build_eseg_csum(sq, skb, eseg)))
0123 return;
0124
0125 if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
0126 eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
0127 if (skb->encapsulation) {
0128 eseg->cs_flags |= MLX5_ETH_WQE_L3_INNER_CSUM |
0129 MLX5_ETH_WQE_L4_INNER_CSUM;
0130 sq->stats->csum_partial_inner++;
0131 } else {
0132 eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM;
0133 sq->stats->csum_partial++;
0134 }
0135 #ifdef CONFIG_MLX5_EN_TLS
0136 } else if (unlikely(accel && accel->tls.tls_tisn)) {
0137 eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
0138 sq->stats->csum_partial++;
0139 #endif
0140 } else
0141 sq->stats->csum_none++;
0142 }
0143
0144
0145
0146
0147 static inline u16
0148 mlx5e_tx_get_gso_ihs(struct mlx5e_txqsq *sq, struct sk_buff *skb, int *hopbyhop)
0149 {
0150 struct mlx5e_sq_stats *stats = sq->stats;
0151 u16 ihs;
0152
0153 *hopbyhop = 0;
0154 if (skb->encapsulation) {
0155 ihs = skb_inner_tcp_all_headers(skb);
0156 stats->tso_inner_packets++;
0157 stats->tso_inner_bytes += skb->len - ihs;
0158 } else {
0159 if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
0160 ihs = skb_transport_offset(skb) + sizeof(struct udphdr);
0161 } else {
0162 ihs = skb_tcp_all_headers(skb);
0163 if (ipv6_has_hopopt_jumbo(skb)) {
0164 *hopbyhop = sizeof(struct hop_jumbo_hdr);
0165 ihs -= sizeof(struct hop_jumbo_hdr);
0166 }
0167 }
0168 stats->tso_packets++;
0169 stats->tso_bytes += skb->len - ihs - *hopbyhop;
0170 }
0171
0172 return ihs;
0173 }
0174
0175 static inline int
0176 mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0177 unsigned char *skb_data, u16 headlen,
0178 struct mlx5_wqe_data_seg *dseg)
0179 {
0180 dma_addr_t dma_addr = 0;
0181 u8 num_dma = 0;
0182 int i;
0183
0184 if (headlen) {
0185 dma_addr = dma_map_single(sq->pdev, skb_data, headlen,
0186 DMA_TO_DEVICE);
0187 if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
0188 goto dma_unmap_wqe_err;
0189
0190 dseg->addr = cpu_to_be64(dma_addr);
0191 dseg->lkey = sq->mkey_be;
0192 dseg->byte_count = cpu_to_be32(headlen);
0193
0194 mlx5e_dma_push(sq, dma_addr, headlen, MLX5E_DMA_MAP_SINGLE);
0195 num_dma++;
0196 dseg++;
0197 }
0198
0199 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
0200 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
0201 int fsz = skb_frag_size(frag);
0202
0203 dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz,
0204 DMA_TO_DEVICE);
0205 if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
0206 goto dma_unmap_wqe_err;
0207
0208 dseg->addr = cpu_to_be64(dma_addr);
0209 dseg->lkey = sq->mkey_be;
0210 dseg->byte_count = cpu_to_be32(fsz);
0211
0212 mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE);
0213 num_dma++;
0214 dseg++;
0215 }
0216
0217 return num_dma;
0218
0219 dma_unmap_wqe_err:
0220 mlx5e_dma_unmap_wqe_err(sq, num_dma);
0221 return -ENOMEM;
0222 }
0223
0224 struct mlx5e_tx_attr {
0225 u32 num_bytes;
0226 u16 headlen;
0227 u16 ihs;
0228 __be16 mss;
0229 u16 insz;
0230 u8 opcode;
0231 u8 hopbyhop;
0232 };
0233
0234 struct mlx5e_tx_wqe_attr {
0235 u16 ds_cnt;
0236 u16 ds_cnt_inl;
0237 u16 ds_cnt_ids;
0238 u8 num_wqebbs;
0239 };
0240
0241 static u8
0242 mlx5e_tx_wqe_inline_mode(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0243 struct mlx5e_accel_tx_state *accel)
0244 {
0245 u8 mode;
0246
0247 #ifdef CONFIG_MLX5_EN_TLS
0248 if (accel && accel->tls.tls_tisn)
0249 return MLX5_INLINE_MODE_TCP_UDP;
0250 #endif
0251
0252 mode = sq->min_inline_mode;
0253
0254 if (skb_vlan_tag_present(skb) &&
0255 test_bit(MLX5E_SQ_STATE_VLAN_NEED_L2_INLINE, &sq->state))
0256 mode = max_t(u8, MLX5_INLINE_MODE_L2, mode);
0257
0258 return mode;
0259 }
0260
0261 static void mlx5e_sq_xmit_prepare(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0262 struct mlx5e_accel_tx_state *accel,
0263 struct mlx5e_tx_attr *attr)
0264 {
0265 struct mlx5e_sq_stats *stats = sq->stats;
0266
0267 if (skb_is_gso(skb)) {
0268 int hopbyhop;
0269 u16 ihs = mlx5e_tx_get_gso_ihs(sq, skb, &hopbyhop);
0270
0271 *attr = (struct mlx5e_tx_attr) {
0272 .opcode = MLX5_OPCODE_LSO,
0273 .mss = cpu_to_be16(skb_shinfo(skb)->gso_size),
0274 .ihs = ihs,
0275 .num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs,
0276 .headlen = skb_headlen(skb) - ihs - hopbyhop,
0277 .hopbyhop = hopbyhop,
0278 };
0279
0280 stats->packets += skb_shinfo(skb)->gso_segs;
0281 } else {
0282 u8 mode = mlx5e_tx_wqe_inline_mode(sq, skb, accel);
0283 u16 ihs = mlx5e_calc_min_inline(mode, skb);
0284
0285 *attr = (struct mlx5e_tx_attr) {
0286 .opcode = MLX5_OPCODE_SEND,
0287 .mss = cpu_to_be16(0),
0288 .ihs = ihs,
0289 .num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN),
0290 .headlen = skb_headlen(skb) - ihs,
0291 };
0292
0293 stats->packets++;
0294 }
0295
0296 attr->insz = mlx5e_accel_tx_ids_len(sq, accel);
0297 stats->bytes += attr->num_bytes;
0298 }
0299
0300 static void mlx5e_sq_calc_wqe_attr(struct sk_buff *skb, const struct mlx5e_tx_attr *attr,
0301 struct mlx5e_tx_wqe_attr *wqe_attr)
0302 {
0303 u16 ds_cnt = MLX5E_TX_WQE_EMPTY_DS_COUNT;
0304 u16 ds_cnt_inl = 0;
0305 u16 ds_cnt_ids = 0;
0306
0307 if (attr->insz)
0308 ds_cnt_ids = DIV_ROUND_UP(sizeof(struct mlx5_wqe_inline_seg) + attr->insz,
0309 MLX5_SEND_WQE_DS);
0310
0311 ds_cnt += !!attr->headlen + skb_shinfo(skb)->nr_frags + ds_cnt_ids;
0312 if (attr->ihs) {
0313 u16 inl = attr->ihs - INL_HDR_START_SZ;
0314
0315 if (skb_vlan_tag_present(skb))
0316 inl += VLAN_HLEN;
0317
0318 ds_cnt_inl = DIV_ROUND_UP(inl, MLX5_SEND_WQE_DS);
0319 ds_cnt += ds_cnt_inl;
0320 }
0321
0322 *wqe_attr = (struct mlx5e_tx_wqe_attr) {
0323 .ds_cnt = ds_cnt,
0324 .ds_cnt_inl = ds_cnt_inl,
0325 .ds_cnt_ids = ds_cnt_ids,
0326 .num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS),
0327 };
0328 }
0329
0330 static void mlx5e_tx_skb_update_hwts_flags(struct sk_buff *skb)
0331 {
0332 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
0333 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
0334 }
0335
0336 static void mlx5e_tx_check_stop(struct mlx5e_txqsq *sq)
0337 {
0338 if (unlikely(!mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room))) {
0339 netif_tx_stop_queue(sq->txq);
0340 sq->stats->stopped++;
0341 }
0342 }
0343
0344 static void mlx5e_tx_flush(struct mlx5e_txqsq *sq)
0345 {
0346 struct mlx5e_tx_wqe_info *wi;
0347 struct mlx5e_tx_wqe *wqe;
0348 u16 pi;
0349
0350
0351 mlx5e_tx_mpwqe_ensure_complete(sq);
0352
0353 pi = mlx5_wq_cyc_ctr2ix(&sq->wq, sq->pc);
0354 wi = &sq->db.wqe_info[pi];
0355
0356 *wi = (struct mlx5e_tx_wqe_info) {
0357 .num_wqebbs = 1,
0358 };
0359
0360 wqe = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc);
0361 mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl);
0362 }
0363
0364 static inline void
0365 mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0366 const struct mlx5e_tx_attr *attr,
0367 const struct mlx5e_tx_wqe_attr *wqe_attr, u8 num_dma,
0368 struct mlx5e_tx_wqe_info *wi, struct mlx5_wqe_ctrl_seg *cseg,
0369 bool xmit_more)
0370 {
0371 struct mlx5_wq_cyc *wq = &sq->wq;
0372 bool send_doorbell;
0373
0374 *wi = (struct mlx5e_tx_wqe_info) {
0375 .skb = skb,
0376 .num_bytes = attr->num_bytes,
0377 .num_dma = num_dma,
0378 .num_wqebbs = wqe_attr->num_wqebbs,
0379 .num_fifo_pkts = 0,
0380 };
0381
0382 cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | attr->opcode);
0383 cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | wqe_attr->ds_cnt);
0384
0385 mlx5e_tx_skb_update_hwts_flags(skb);
0386
0387 sq->pc += wi->num_wqebbs;
0388
0389 mlx5e_tx_check_stop(sq);
0390
0391 if (unlikely(sq->ptpsq)) {
0392 mlx5e_skb_cb_hwtstamp_init(skb);
0393 mlx5e_skb_fifo_push(&sq->ptpsq->skb_fifo, skb);
0394 skb_get(skb);
0395 }
0396
0397 send_doorbell = __netdev_tx_sent_queue(sq->txq, attr->num_bytes, xmit_more);
0398 if (send_doorbell)
0399 mlx5e_notify_hw(wq, sq->pc, sq->uar_map, cseg);
0400 }
0401
0402 static void
0403 mlx5e_sq_xmit_wqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0404 const struct mlx5e_tx_attr *attr, const struct mlx5e_tx_wqe_attr *wqe_attr,
0405 struct mlx5e_tx_wqe *wqe, u16 pi, bool xmit_more)
0406 {
0407 struct mlx5_wqe_ctrl_seg *cseg;
0408 struct mlx5_wqe_eth_seg *eseg;
0409 struct mlx5_wqe_data_seg *dseg;
0410 struct mlx5e_tx_wqe_info *wi;
0411 u16 ihs = attr->ihs;
0412 struct ipv6hdr *h6;
0413 struct mlx5e_sq_stats *stats = sq->stats;
0414 int num_dma;
0415
0416 stats->xmit_more += xmit_more;
0417
0418
0419 wi = &sq->db.wqe_info[pi];
0420 cseg = &wqe->ctrl;
0421 eseg = &wqe->eth;
0422 dseg = wqe->data;
0423
0424 eseg->mss = attr->mss;
0425
0426 if (ihs) {
0427 u8 *start = eseg->inline_hdr.start;
0428
0429 if (unlikely(attr->hopbyhop)) {
0430
0431
0432
0433 if (skb_vlan_tag_present(skb)) {
0434 mlx5e_insert_vlan(start, skb, ETH_HLEN + sizeof(*h6));
0435 ihs += VLAN_HLEN;
0436 h6 = (struct ipv6hdr *)(start + sizeof(struct vlan_ethhdr));
0437 } else {
0438 unsafe_memcpy(start, skb->data,
0439 ETH_HLEN + sizeof(*h6),
0440 MLX5_UNSAFE_MEMCPY_DISCLAIMER);
0441 h6 = (struct ipv6hdr *)(start + ETH_HLEN);
0442 }
0443 h6->nexthdr = IPPROTO_TCP;
0444
0445 memcpy(h6 + 1,
0446 skb->data + ETH_HLEN + sizeof(*h6) +
0447 sizeof(struct hop_jumbo_hdr),
0448 tcp_hdrlen(skb));
0449
0450 } else if (skb_vlan_tag_present(skb)) {
0451 mlx5e_insert_vlan(start, skb, ihs);
0452 ihs += VLAN_HLEN;
0453 stats->added_vlan_packets++;
0454 } else {
0455 unsafe_memcpy(eseg->inline_hdr.start, skb->data,
0456 attr->ihs,
0457 MLX5_UNSAFE_MEMCPY_DISCLAIMER);
0458 }
0459 eseg->inline_hdr.sz |= cpu_to_be16(ihs);
0460 dseg += wqe_attr->ds_cnt_inl;
0461 } else if (skb_vlan_tag_present(skb)) {
0462 eseg->insert.type = cpu_to_be16(MLX5_ETH_WQE_INSERT_VLAN);
0463 if (skb->vlan_proto == cpu_to_be16(ETH_P_8021AD))
0464 eseg->insert.type |= cpu_to_be16(MLX5_ETH_WQE_SVLAN);
0465 eseg->insert.vlan_tci = cpu_to_be16(skb_vlan_tag_get(skb));
0466 stats->added_vlan_packets++;
0467 }
0468
0469 dseg += wqe_attr->ds_cnt_ids;
0470 num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb->data + attr->ihs + attr->hopbyhop,
0471 attr->headlen, dseg);
0472 if (unlikely(num_dma < 0))
0473 goto err_drop;
0474
0475 mlx5e_txwqe_complete(sq, skb, attr, wqe_attr, num_dma, wi, cseg, xmit_more);
0476
0477 return;
0478
0479 err_drop:
0480 stats->dropped++;
0481 dev_kfree_skb_any(skb);
0482 mlx5e_tx_flush(sq);
0483 }
0484
0485 static bool mlx5e_tx_skb_supports_mpwqe(struct sk_buff *skb, struct mlx5e_tx_attr *attr)
0486 {
0487 return !skb_is_nonlinear(skb) && !skb_vlan_tag_present(skb) && !attr->ihs &&
0488 !attr->insz;
0489 }
0490
0491 static bool mlx5e_tx_mpwqe_same_eseg(struct mlx5e_txqsq *sq, struct mlx5_wqe_eth_seg *eseg)
0492 {
0493 struct mlx5e_tx_mpwqe *session = &sq->mpwqe;
0494
0495
0496 return !memcmp(&session->wqe->eth, eseg, MLX5E_ACCEL_ESEG_LEN);
0497 }
0498
0499 static void mlx5e_tx_mpwqe_session_start(struct mlx5e_txqsq *sq,
0500 struct mlx5_wqe_eth_seg *eseg)
0501 {
0502 struct mlx5e_tx_mpwqe *session = &sq->mpwqe;
0503 struct mlx5e_tx_wqe *wqe;
0504 u16 pi;
0505
0506 pi = mlx5e_txqsq_get_next_pi(sq, sq->max_sq_mpw_wqebbs);
0507 wqe = MLX5E_TX_FETCH_WQE(sq, pi);
0508 net_prefetchw(wqe->data);
0509
0510 *session = (struct mlx5e_tx_mpwqe) {
0511 .wqe = wqe,
0512 .bytes_count = 0,
0513 .ds_count = MLX5E_TX_WQE_EMPTY_DS_COUNT,
0514 .pkt_count = 0,
0515 .inline_on = 0,
0516 };
0517
0518 memcpy(&session->wqe->eth, eseg, MLX5E_ACCEL_ESEG_LEN);
0519
0520 sq->stats->mpwqe_blks++;
0521 }
0522
0523 static bool mlx5e_tx_mpwqe_session_is_active(struct mlx5e_txqsq *sq)
0524 {
0525 return sq->mpwqe.wqe;
0526 }
0527
0528 static void mlx5e_tx_mpwqe_add_dseg(struct mlx5e_txqsq *sq, struct mlx5e_xmit_data *txd)
0529 {
0530 struct mlx5e_tx_mpwqe *session = &sq->mpwqe;
0531 struct mlx5_wqe_data_seg *dseg;
0532
0533 dseg = (struct mlx5_wqe_data_seg *)session->wqe + session->ds_count;
0534
0535 session->pkt_count++;
0536 session->bytes_count += txd->len;
0537
0538 dseg->addr = cpu_to_be64(txd->dma_addr);
0539 dseg->byte_count = cpu_to_be32(txd->len);
0540 dseg->lkey = sq->mkey_be;
0541 session->ds_count++;
0542
0543 sq->stats->mpwqe_pkts++;
0544 }
0545
0546 static struct mlx5_wqe_ctrl_seg *mlx5e_tx_mpwqe_session_complete(struct mlx5e_txqsq *sq)
0547 {
0548 struct mlx5e_tx_mpwqe *session = &sq->mpwqe;
0549 u8 ds_count = session->ds_count;
0550 struct mlx5_wqe_ctrl_seg *cseg;
0551 struct mlx5e_tx_wqe_info *wi;
0552 u16 pi;
0553
0554 cseg = &session->wqe->ctrl;
0555 cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | MLX5_OPCODE_ENHANCED_MPSW);
0556 cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_count);
0557
0558 pi = mlx5_wq_cyc_ctr2ix(&sq->wq, sq->pc);
0559 wi = &sq->db.wqe_info[pi];
0560 *wi = (struct mlx5e_tx_wqe_info) {
0561 .skb = NULL,
0562 .num_bytes = session->bytes_count,
0563 .num_wqebbs = DIV_ROUND_UP(ds_count, MLX5_SEND_WQEBB_NUM_DS),
0564 .num_dma = session->pkt_count,
0565 .num_fifo_pkts = session->pkt_count,
0566 };
0567
0568 sq->pc += wi->num_wqebbs;
0569
0570 session->wqe = NULL;
0571
0572 mlx5e_tx_check_stop(sq);
0573
0574 return cseg;
0575 }
0576
0577 static void
0578 mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0579 struct mlx5_wqe_eth_seg *eseg, bool xmit_more)
0580 {
0581 struct mlx5_wqe_ctrl_seg *cseg;
0582 struct mlx5e_xmit_data txd;
0583
0584 txd.data = skb->data;
0585 txd.len = skb->len;
0586
0587 txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE);
0588 if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr)))
0589 goto err_unmap;
0590
0591 if (!mlx5e_tx_mpwqe_session_is_active(sq)) {
0592 mlx5e_tx_mpwqe_session_start(sq, eseg);
0593 } else if (!mlx5e_tx_mpwqe_same_eseg(sq, eseg)) {
0594 mlx5e_tx_mpwqe_session_complete(sq);
0595 mlx5e_tx_mpwqe_session_start(sq, eseg);
0596 }
0597
0598 sq->stats->xmit_more += xmit_more;
0599
0600 mlx5e_dma_push(sq, txd.dma_addr, txd.len, MLX5E_DMA_MAP_SINGLE);
0601 mlx5e_skb_fifo_push(&sq->db.skb_fifo, skb);
0602 mlx5e_tx_mpwqe_add_dseg(sq, &txd);
0603 mlx5e_tx_skb_update_hwts_flags(skb);
0604
0605 if (unlikely(mlx5e_tx_mpwqe_is_full(&sq->mpwqe, sq->max_sq_mpw_wqebbs))) {
0606
0607 cseg = mlx5e_tx_mpwqe_session_complete(sq);
0608
0609 if (__netdev_tx_sent_queue(sq->txq, txd.len, xmit_more))
0610 mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, cseg);
0611 } else if (__netdev_tx_sent_queue(sq->txq, txd.len, xmit_more)) {
0612
0613 cseg = mlx5e_tx_mpwqe_session_complete(sq);
0614
0615 mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, cseg);
0616 }
0617
0618 return;
0619
0620 err_unmap:
0621 mlx5e_dma_unmap_wqe_err(sq, 1);
0622 sq->stats->dropped++;
0623 dev_kfree_skb_any(skb);
0624 mlx5e_tx_flush(sq);
0625 }
0626
0627 void mlx5e_tx_mpwqe_ensure_complete(struct mlx5e_txqsq *sq)
0628 {
0629
0630 if (unlikely(mlx5e_tx_mpwqe_session_is_active(sq)))
0631 mlx5e_tx_mpwqe_session_complete(sq);
0632 }
0633
0634 static void mlx5e_cqe_ts_id_eseg(struct mlx5e_ptpsq *ptpsq, struct sk_buff *skb,
0635 struct mlx5_wqe_eth_seg *eseg)
0636 {
0637 if (ptpsq->ts_cqe_ctr_mask && unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
0638 eseg->flow_table_metadata = cpu_to_be32(ptpsq->skb_fifo_pc &
0639 ptpsq->ts_cqe_ctr_mask);
0640 }
0641
0642 static void mlx5e_txwqe_build_eseg(struct mlx5e_priv *priv, struct mlx5e_txqsq *sq,
0643 struct sk_buff *skb, struct mlx5e_accel_tx_state *accel,
0644 struct mlx5_wqe_eth_seg *eseg, u16 ihs)
0645 {
0646 mlx5e_accel_tx_eseg(priv, skb, eseg, ihs);
0647 mlx5e_txwqe_build_eseg_csum(sq, skb, accel, eseg);
0648 if (unlikely(sq->ptpsq))
0649 mlx5e_cqe_ts_id_eseg(sq->ptpsq, skb, eseg);
0650 }
0651
0652 netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev)
0653 {
0654 struct mlx5e_priv *priv = netdev_priv(dev);
0655 struct mlx5e_accel_tx_state accel = {};
0656 struct mlx5e_tx_wqe_attr wqe_attr;
0657 struct mlx5e_tx_attr attr;
0658 struct mlx5e_tx_wqe *wqe;
0659 struct mlx5e_txqsq *sq;
0660 u16 pi;
0661
0662
0663
0664
0665
0666
0667
0668
0669 sq = priv->txq2sq[skb_get_queue_mapping(skb)];
0670 if (unlikely(!sq)) {
0671
0672
0673
0674
0675
0676
0677 dev_kfree_skb_any(skb);
0678 return NETDEV_TX_OK;
0679 }
0680
0681
0682 if (unlikely(!mlx5e_accel_tx_begin(dev, sq, skb, &accel)))
0683 return NETDEV_TX_OK;
0684
0685 mlx5e_sq_xmit_prepare(sq, skb, &accel, &attr);
0686
0687 if (test_bit(MLX5E_SQ_STATE_MPWQE, &sq->state)) {
0688 if (mlx5e_tx_skb_supports_mpwqe(skb, &attr)) {
0689 struct mlx5_wqe_eth_seg eseg = {};
0690
0691 mlx5e_txwqe_build_eseg(priv, sq, skb, &accel, &eseg, attr.ihs);
0692 mlx5e_sq_xmit_mpwqe(sq, skb, &eseg, netdev_xmit_more());
0693 return NETDEV_TX_OK;
0694 }
0695
0696 mlx5e_tx_mpwqe_ensure_complete(sq);
0697 }
0698
0699 mlx5e_sq_calc_wqe_attr(skb, &attr, &wqe_attr);
0700 pi = mlx5e_txqsq_get_next_pi(sq, wqe_attr.num_wqebbs);
0701 wqe = MLX5E_TX_FETCH_WQE(sq, pi);
0702
0703
0704 mlx5e_accel_tx_finish(sq, wqe, &accel,
0705 (struct mlx5_wqe_inline_seg *)(wqe->data + wqe_attr.ds_cnt_inl));
0706 mlx5e_txwqe_build_eseg(priv, sq, skb, &accel, &wqe->eth, attr.ihs);
0707 mlx5e_sq_xmit_wqe(sq, skb, &attr, &wqe_attr, wqe, pi, netdev_xmit_more());
0708
0709 return NETDEV_TX_OK;
0710 }
0711
0712 void mlx5e_sq_xmit_simple(struct mlx5e_txqsq *sq, struct sk_buff *skb, bool xmit_more)
0713 {
0714 struct mlx5e_tx_wqe_attr wqe_attr;
0715 struct mlx5e_tx_attr attr;
0716 struct mlx5e_tx_wqe *wqe;
0717 u16 pi;
0718
0719 mlx5e_sq_xmit_prepare(sq, skb, NULL, &attr);
0720 mlx5e_sq_calc_wqe_attr(skb, &attr, &wqe_attr);
0721 pi = mlx5e_txqsq_get_next_pi(sq, wqe_attr.num_wqebbs);
0722 wqe = MLX5E_TX_FETCH_WQE(sq, pi);
0723 mlx5e_txwqe_build_eseg_csum(sq, skb, NULL, &wqe->eth);
0724 mlx5e_sq_xmit_wqe(sq, skb, &attr, &wqe_attr, wqe, pi, xmit_more);
0725 }
0726
0727 static void mlx5e_tx_wi_dma_unmap(struct mlx5e_txqsq *sq, struct mlx5e_tx_wqe_info *wi,
0728 u32 *dma_fifo_cc)
0729 {
0730 int i;
0731
0732 for (i = 0; i < wi->num_dma; i++) {
0733 struct mlx5e_sq_dma *dma = mlx5e_dma_get(sq, (*dma_fifo_cc)++);
0734
0735 mlx5e_tx_dma_unmap(sq->pdev, dma);
0736 }
0737 }
0738
0739 static void mlx5e_consume_skb(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0740 struct mlx5_cqe64 *cqe, int napi_budget)
0741 {
0742 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
0743 struct skb_shared_hwtstamps hwts = {};
0744 u64 ts = get_cqe_ts(cqe);
0745
0746 hwts.hwtstamp = mlx5e_cqe_ts_to_ns(sq->ptp_cyc2time, sq->clock, ts);
0747 if (sq->ptpsq)
0748 mlx5e_skb_cb_hwtstamp_handler(skb, MLX5E_SKB_CB_CQE_HWTSTAMP,
0749 hwts.hwtstamp, sq->ptpsq->cq_stats);
0750 else
0751 skb_tstamp_tx(skb, &hwts);
0752 }
0753
0754 napi_consume_skb(skb, napi_budget);
0755 }
0756
0757 static void mlx5e_tx_wi_consume_fifo_skbs(struct mlx5e_txqsq *sq, struct mlx5e_tx_wqe_info *wi,
0758 struct mlx5_cqe64 *cqe, int napi_budget)
0759 {
0760 int i;
0761
0762 for (i = 0; i < wi->num_fifo_pkts; i++) {
0763 struct sk_buff *skb = mlx5e_skb_fifo_pop(&sq->db.skb_fifo);
0764
0765 mlx5e_consume_skb(sq, skb, cqe, napi_budget);
0766 }
0767 }
0768
0769 bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
0770 {
0771 struct mlx5e_sq_stats *stats;
0772 struct mlx5e_txqsq *sq;
0773 struct mlx5_cqe64 *cqe;
0774 u32 dma_fifo_cc;
0775 u32 nbytes;
0776 u16 npkts;
0777 u16 sqcc;
0778 int i;
0779
0780 sq = container_of(cq, struct mlx5e_txqsq, cq);
0781
0782 if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
0783 return false;
0784
0785 cqe = mlx5_cqwq_get_cqe(&cq->wq);
0786 if (!cqe)
0787 return false;
0788
0789 stats = sq->stats;
0790
0791 npkts = 0;
0792 nbytes = 0;
0793
0794
0795
0796
0797 sqcc = sq->cc;
0798
0799
0800 dma_fifo_cc = sq->dma_fifo_cc;
0801
0802 i = 0;
0803 do {
0804 struct mlx5e_tx_wqe_info *wi;
0805 u16 wqe_counter;
0806 bool last_wqe;
0807 u16 ci;
0808
0809 mlx5_cqwq_pop(&cq->wq);
0810
0811 wqe_counter = be16_to_cpu(cqe->wqe_counter);
0812
0813 do {
0814 last_wqe = (sqcc == wqe_counter);
0815
0816 ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc);
0817 wi = &sq->db.wqe_info[ci];
0818
0819 sqcc += wi->num_wqebbs;
0820
0821 if (likely(wi->skb)) {
0822 mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
0823 mlx5e_consume_skb(sq, wi->skb, cqe, napi_budget);
0824
0825 npkts++;
0826 nbytes += wi->num_bytes;
0827 continue;
0828 }
0829
0830 if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi,
0831 &dma_fifo_cc)))
0832 continue;
0833
0834 if (wi->num_fifo_pkts) {
0835 mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
0836 mlx5e_tx_wi_consume_fifo_skbs(sq, wi, cqe, napi_budget);
0837
0838 npkts += wi->num_fifo_pkts;
0839 nbytes += wi->num_bytes;
0840 }
0841 } while (!last_wqe);
0842
0843 if (unlikely(get_cqe_opcode(cqe) == MLX5_CQE_REQ_ERR)) {
0844 if (!test_and_set_bit(MLX5E_SQ_STATE_RECOVERING,
0845 &sq->state)) {
0846 mlx5e_dump_error_cqe(&sq->cq, sq->sqn,
0847 (struct mlx5_err_cqe *)cqe);
0848 mlx5_wq_cyc_wqe_dump(&sq->wq, ci, wi->num_wqebbs);
0849 queue_work(cq->priv->wq, &sq->recover_work);
0850 }
0851 stats->cqe_err++;
0852 }
0853
0854 } while ((++i < MLX5E_TX_CQ_POLL_BUDGET) && (cqe = mlx5_cqwq_get_cqe(&cq->wq)));
0855
0856 stats->cqes += i;
0857
0858 mlx5_cqwq_update_db_record(&cq->wq);
0859
0860
0861 wmb();
0862
0863 sq->dma_fifo_cc = dma_fifo_cc;
0864 sq->cc = sqcc;
0865
0866 netdev_tx_completed_queue(sq->txq, npkts, nbytes);
0867
0868 if (netif_tx_queue_stopped(sq->txq) &&
0869 mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room) &&
0870 !test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) {
0871 netif_tx_wake_queue(sq->txq);
0872 stats->wake++;
0873 }
0874
0875 return (i == MLX5E_TX_CQ_POLL_BUDGET);
0876 }
0877
0878 static void mlx5e_tx_wi_kfree_fifo_skbs(struct mlx5e_txqsq *sq, struct mlx5e_tx_wqe_info *wi)
0879 {
0880 int i;
0881
0882 for (i = 0; i < wi->num_fifo_pkts; i++)
0883 dev_kfree_skb_any(mlx5e_skb_fifo_pop(&sq->db.skb_fifo));
0884 }
0885
0886 void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
0887 {
0888 struct mlx5e_tx_wqe_info *wi;
0889 u32 dma_fifo_cc, nbytes = 0;
0890 u16 ci, sqcc, npkts = 0;
0891
0892 sqcc = sq->cc;
0893 dma_fifo_cc = sq->dma_fifo_cc;
0894
0895 while (sqcc != sq->pc) {
0896 ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc);
0897 wi = &sq->db.wqe_info[ci];
0898
0899 sqcc += wi->num_wqebbs;
0900
0901 if (likely(wi->skb)) {
0902 mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
0903 dev_kfree_skb_any(wi->skb);
0904
0905 npkts++;
0906 nbytes += wi->num_bytes;
0907 continue;
0908 }
0909
0910 if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
0911 continue;
0912
0913 if (wi->num_fifo_pkts) {
0914 mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
0915 mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
0916
0917 npkts += wi->num_fifo_pkts;
0918 nbytes += wi->num_bytes;
0919 }
0920 }
0921
0922 sq->dma_fifo_cc = dma_fifo_cc;
0923 sq->cc = sqcc;
0924
0925 netdev_tx_completed_queue(sq->txq, npkts, nbytes);
0926 }
0927
0928 #ifdef CONFIG_MLX5_CORE_IPOIB
0929 static inline void
0930 mlx5i_txwqe_build_datagram(struct mlx5_av *av, u32 dqpn, u32 dqkey,
0931 struct mlx5_wqe_datagram_seg *dseg)
0932 {
0933 memcpy(&dseg->av, av, sizeof(struct mlx5_av));
0934 dseg->av.dqp_dct = cpu_to_be32(dqpn | MLX5_EXTENDED_UD_AV);
0935 dseg->av.key.qkey.qkey = cpu_to_be32(dqkey);
0936 }
0937
0938 static void mlx5i_sq_calc_wqe_attr(struct sk_buff *skb,
0939 const struct mlx5e_tx_attr *attr,
0940 struct mlx5e_tx_wqe_attr *wqe_attr)
0941 {
0942 u16 ds_cnt = sizeof(struct mlx5i_tx_wqe) / MLX5_SEND_WQE_DS;
0943 u16 ds_cnt_inl = 0;
0944
0945 ds_cnt += !!attr->headlen + skb_shinfo(skb)->nr_frags;
0946
0947 if (attr->ihs) {
0948 u16 inl = attr->ihs - INL_HDR_START_SZ;
0949
0950 ds_cnt_inl = DIV_ROUND_UP(inl, MLX5_SEND_WQE_DS);
0951 ds_cnt += ds_cnt_inl;
0952 }
0953
0954 *wqe_attr = (struct mlx5e_tx_wqe_attr) {
0955 .ds_cnt = ds_cnt,
0956 .ds_cnt_inl = ds_cnt_inl,
0957 .num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS),
0958 };
0959 }
0960
0961 void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
0962 struct mlx5_av *av, u32 dqpn, u32 dqkey, bool xmit_more)
0963 {
0964 struct mlx5e_tx_wqe_attr wqe_attr;
0965 struct mlx5e_tx_attr attr;
0966 struct mlx5i_tx_wqe *wqe;
0967
0968 struct mlx5_wqe_datagram_seg *datagram;
0969 struct mlx5_wqe_ctrl_seg *cseg;
0970 struct mlx5_wqe_eth_seg *eseg;
0971 struct mlx5_wqe_data_seg *dseg;
0972 struct mlx5e_tx_wqe_info *wi;
0973
0974 struct mlx5e_sq_stats *stats = sq->stats;
0975 int num_dma;
0976 u16 pi;
0977
0978 mlx5e_sq_xmit_prepare(sq, skb, NULL, &attr);
0979 mlx5i_sq_calc_wqe_attr(skb, &attr, &wqe_attr);
0980
0981 pi = mlx5e_txqsq_get_next_pi(sq, wqe_attr.num_wqebbs);
0982 wqe = MLX5I_SQ_FETCH_WQE(sq, pi);
0983
0984 stats->xmit_more += xmit_more;
0985
0986
0987 wi = &sq->db.wqe_info[pi];
0988 cseg = &wqe->ctrl;
0989 datagram = &wqe->datagram;
0990 eseg = &wqe->eth;
0991 dseg = wqe->data;
0992
0993 mlx5i_txwqe_build_datagram(av, dqpn, dqkey, datagram);
0994
0995 mlx5e_txwqe_build_eseg_csum(sq, skb, NULL, eseg);
0996
0997 eseg->mss = attr.mss;
0998
0999 if (attr.ihs) {
1000 if (unlikely(attr.hopbyhop)) {
1001 struct ipv6hdr *h6;
1002
1003
1004
1005
1006 unsafe_memcpy(eseg->inline_hdr.start, skb->data,
1007 ETH_HLEN + sizeof(*h6),
1008 MLX5_UNSAFE_MEMCPY_DISCLAIMER);
1009 h6 = (struct ipv6hdr *)((char *)eseg->inline_hdr.start + ETH_HLEN);
1010 h6->nexthdr = IPPROTO_TCP;
1011
1012 unsafe_memcpy(h6 + 1,
1013 skb->data + ETH_HLEN + sizeof(*h6) +
1014 sizeof(struct hop_jumbo_hdr),
1015 tcp_hdrlen(skb),
1016 MLX5_UNSAFE_MEMCPY_DISCLAIMER);
1017
1018 } else {
1019 unsafe_memcpy(eseg->inline_hdr.start, skb->data,
1020 attr.ihs,
1021 MLX5_UNSAFE_MEMCPY_DISCLAIMER);
1022 }
1023 eseg->inline_hdr.sz = cpu_to_be16(attr.ihs);
1024 dseg += wqe_attr.ds_cnt_inl;
1025 }
1026
1027 num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb->data + attr.ihs + attr.hopbyhop,
1028 attr.headlen, dseg);
1029 if (unlikely(num_dma < 0))
1030 goto err_drop;
1031
1032 mlx5e_txwqe_complete(sq, skb, &attr, &wqe_attr, num_dma, wi, cseg, xmit_more);
1033
1034 return;
1035
1036 err_drop:
1037 stats->dropped++;
1038 dev_kfree_skb_any(skb);
1039 mlx5e_tx_flush(sq);
1040 }
1041 #endif