net/mlx5: re-factorize functions
[dpdk.git] / drivers / net / mlx5 / mlx5_rxtx.c
index be63d84..c7e538f 100644 (file)
@@ -152,6 +152,9 @@ check_cqe64(volatile struct mlx5_cqe64 *cqe,
        return 0;
 }
 
+static inline void
+txq_complete(struct txq *txq) __attribute__((always_inline));
+
 /**
  * Manage TX completions.
  *
@@ -160,7 +163,7 @@ check_cqe64(volatile struct mlx5_cqe64 *cqe,
  * @param txq
  *   Pointer to TX queue structure.
  */
-static void
+static inline void
 txq_complete(struct txq *txq)
 {
        const unsigned int elts_n = txq->elts_n;
@@ -290,8 +293,8 @@ txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
  *   Pointer to TX queue structure.
  * @param wqe
  *   Pointer to the WQE to fill.
- * @param addr
- *   Buffer data address.
+ * @param buf
+ *   Buffer.
  * @param length
  *   Packet length.
  * @param lkey
@@ -299,8 +302,24 @@ txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
  */
 static inline void
 mlx5_wqe_write(struct txq *txq, volatile union mlx5_wqe *wqe,
-              uintptr_t addr, uint32_t length, uint32_t lkey)
+              struct rte_mbuf *buf, uint32_t length, uint32_t lkey)
 {
+       uintptr_t addr = rte_pktmbuf_mtod(buf, uintptr_t);
+
+       rte_mov16((uint8_t *)&wqe->wqe.eseg.inline_hdr_start,
+                 (uint8_t *)addr);
+       addr += 16;
+       length -= 16;
+       /* Need to insert VLAN ? */
+       if (buf->ol_flags & PKT_TX_VLAN_PKT) {
+               uint32_t vlan = htonl(0x81000000 | buf->vlan_tci);
+
+               memcpy((uint8_t *)&wqe->wqe.eseg.inline_hdr_start + 12,
+                      &vlan, sizeof(vlan));
+               addr -= sizeof(vlan);
+               length += sizeof(vlan);
+       }
+       /* Write the WQE. */
        wqe->wqe.ctrl.data[0] = htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND);
        wqe->wqe.ctrl.data[1] = htonl((txq->qp_num_8s) | 4);
        wqe->wqe.ctrl.data[2] = 0;
@@ -309,66 +328,7 @@ mlx5_wqe_write(struct txq *txq, volatile union mlx5_wqe *wqe,
        wqe->inl.eseg.rsvd1 = 0;
        wqe->inl.eseg.mss = 0;
        wqe->inl.eseg.rsvd2 = 0;
-       wqe->wqe.eseg.inline_hdr_sz = htons(MLX5_ETH_INLINE_HEADER_SIZE);
-       /* Copy the first 16 bytes into inline header. */
-       rte_memcpy((uint8_t *)(uintptr_t)wqe->wqe.eseg.inline_hdr_start,
-                  (uint8_t *)(uintptr_t)addr,
-                  MLX5_ETH_INLINE_HEADER_SIZE);
-       addr += MLX5_ETH_INLINE_HEADER_SIZE;
-       length -= MLX5_ETH_INLINE_HEADER_SIZE;
-       /* Store remaining data in data segment. */
-       wqe->wqe.dseg.byte_count = htonl(length);
-       wqe->wqe.dseg.lkey = lkey;
-       wqe->wqe.dseg.addr = htonll(addr);
-       /* Increment consumer index. */
-       ++txq->wqe_ci;
-}
-
-/**
- * Write a regular WQE with VLAN.
- *
- * @param txq
- *   Pointer to TX queue structure.
- * @param wqe
- *   Pointer to the WQE to fill.
- * @param addr
- *   Buffer data address.
- * @param length
- *   Packet length.
- * @param lkey
- *   Memory region lkey.
- * @param vlan_tci
- *   VLAN field to insert in packet.
- */
-static inline void
-mlx5_wqe_write_vlan(struct txq *txq, volatile union mlx5_wqe *wqe,
-                   uintptr_t addr, uint32_t length, uint32_t lkey,
-                   uint16_t vlan_tci)
-{
-       uint32_t vlan = htonl(0x81000000 | vlan_tci);
-
-       wqe->wqe.ctrl.data[0] = htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND);
-       wqe->wqe.ctrl.data[1] = htonl((txq->qp_num_8s) | 4);
-       wqe->wqe.ctrl.data[2] = 0;
-       wqe->wqe.ctrl.data[3] = 0;
-       wqe->inl.eseg.rsvd0 = 0;
-       wqe->inl.eseg.rsvd1 = 0;
-       wqe->inl.eseg.mss = 0;
-       wqe->inl.eseg.rsvd2 = 0;
-       wqe->wqe.eseg.inline_hdr_sz = htons(MLX5_ETH_VLAN_INLINE_HEADER_SIZE);
-       /*
-        * Copy 12 bytes of source & destination MAC address.
-        * Copy 4 bytes of VLAN.
-        * Copy 2 bytes of Ether type.
-        */
-       rte_memcpy((uint8_t *)(uintptr_t)wqe->wqe.eseg.inline_hdr_start,
-                  (uint8_t *)(uintptr_t)addr, 12);
-       rte_memcpy((uint8_t *)((uintptr_t)wqe->wqe.eseg.inline_hdr_start + 12),
-                  &vlan, sizeof(vlan));
-       rte_memcpy((uint8_t *)((uintptr_t)wqe->wqe.eseg.inline_hdr_start + 16),
-                  (uint8_t *)((uintptr_t)addr + 12), 2);
-       addr += MLX5_ETH_VLAN_INLINE_HEADER_SIZE - sizeof(vlan);
-       length -= MLX5_ETH_VLAN_INLINE_HEADER_SIZE - sizeof(vlan);
+       wqe->wqe.eseg.inline_hdr_sz = htons(16);
        /* Store remaining data in data segment. */
        wqe->wqe.dseg.byte_count = htonl(length);
        wqe->wqe.dseg.lkey = lkey;
@@ -472,8 +432,8 @@ mlx5_wqe_write_inline_vlan(struct txq *txq, volatile union mlx5_wqe *wqe,
                   (uint8_t *)addr, 12);
        rte_memcpy((uint8_t *)(uintptr_t)wqe->inl.eseg.inline_hdr_start + 12,
                   &vlan, sizeof(vlan));
-       rte_memcpy((uint8_t *)(uintptr_t)wqe->inl.eseg.inline_hdr_start + 16,
-                  ((uint8_t *)addr + 12), 2);
+       rte_memcpy((uint8_t *)((uintptr_t)wqe->inl.eseg.inline_hdr_start + 16),
+                  (uint8_t *)(addr + 12), 2);
        addr += MLX5_ETH_VLAN_INLINE_HEADER_SIZE - sizeof(vlan);
        length -= MLX5_ETH_VLAN_INLINE_HEADER_SIZE - sizeof(vlan);
        size = (sizeof(wqe->inl.ctrl.ctrl) +
@@ -609,7 +569,6 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
        do {
                struct rte_mbuf *buf = *(pkts++);
                unsigned int elts_head_next;
-               uintptr_t addr;
                uint32_t length;
                uint32_t lkey;
                unsigned int segs_n = buf->nb_segs;
@@ -631,8 +590,6 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
                rte_prefetch0(wqe);
                if (pkts_n)
                        rte_prefetch0(*pkts);
-               /* Retrieve buffer information. */
-               addr = rte_pktmbuf_mtod(buf, uintptr_t);
                length = DATA_LEN(buf);
                /* Update element. */
                (*txq->elts)[elts_head] = buf;
@@ -642,11 +599,7 @@ mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
                                                       volatile void *));
                /* Retrieve Memory Region key for this memory pool. */
                lkey = txq_mp2mr(txq, txq_mb2mp(buf));
-               if (buf->ol_flags & PKT_TX_VLAN_PKT)
-                       mlx5_wqe_write_vlan(txq, wqe, addr, length, lkey,
-                                           buf->vlan_tci);
-               else
-                       mlx5_wqe_write(txq, wqe, addr, length, lkey);
+               mlx5_wqe_write(txq, wqe, buf, length, lkey);
                /* Should we enable HW CKSUM offload */
                if (buf->ol_flags &
                    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
@@ -810,11 +763,7 @@ mlx5_tx_burst_inline(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
                } else {
                        /* Retrieve Memory Region key for this memory pool. */
                        lkey = txq_mp2mr(txq, txq_mb2mp(buf));
-                       if (buf->ol_flags & PKT_TX_VLAN_PKT)
-                               mlx5_wqe_write_vlan(txq, wqe, addr, length,
-                                                   lkey, buf->vlan_tci);
-                       else
-                               mlx5_wqe_write(txq, wqe, addr, length, lkey);
+                       mlx5_wqe_write(txq, wqe, buf, length, lkey);
                }
                while (--segs_n) {
                        /*
@@ -1548,99 +1497,134 @@ uint16_t
 mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
 {
        struct rxq *rxq = dpdk_rxq;
-       unsigned int pkts_ret = 0;
-       unsigned int i;
-       unsigned int rq_ci = rxq->rq_ci;
-       const unsigned int elts_n = rxq->elts_n;
-       const unsigned int wqe_cnt = elts_n - 1;
+       const unsigned int wqe_cnt = rxq->elts_n - 1;
        const unsigned int cqe_cnt = rxq->cqe_n - 1;
+       const unsigned int sges_n = rxq->sges_n;
+       struct rte_mbuf *pkt = NULL;
+       struct rte_mbuf *seg = NULL;
+       volatile struct mlx5_cqe64 *cqe =
+               &(*rxq->cqes)[rxq->cq_ci & cqe_cnt].cqe64;
+       unsigned int i = 0;
+       unsigned int rq_ci = rxq->rq_ci << sges_n;
+       int len;
 
-       for (i = 0; (i != pkts_n); ++i) {
+       while (pkts_n) {
                unsigned int idx = rq_ci & wqe_cnt;
-               int len;
-               struct rte_mbuf *rep;
-               struct rte_mbuf *pkt;
                volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
-               volatile struct mlx5_cqe64 *cqe =
-                       &(*rxq->cqes)[rxq->cq_ci & cqe_cnt].cqe64;
+               struct rte_mbuf *rep = (*rxq->elts)[idx];
 
-               pkt = (*rxq->elts)[idx];
+               if (pkt)
+                       NEXT(seg) = rep;
+               seg = rep;
+               rte_prefetch0(seg);
                rte_prefetch0(cqe);
+               rte_prefetch0(wqe);
                rep = rte_mbuf_raw_alloc(rxq->mp);
                if (unlikely(rep == NULL)) {
                        ++rxq->stats.rx_nombuf;
+                       if (!pkt) {
+                               /*
+                                * no buffers before we even started,
+                                * bail out silently.
+                                */
+                               break;
+                       }
+                       while (pkt != seg) {
+                               assert(pkt != (*rxq->elts)[idx]);
+                               seg = NEXT(pkt);
+                               rte_mbuf_refcnt_set(pkt, 0);
+                               __rte_mbuf_raw_free(pkt);
+                               pkt = seg;
+                       }
                        break;
                }
-               SET_DATA_OFF(rep, RTE_PKTMBUF_HEADROOM);
-               NB_SEGS(rep) = 1;
-               PORT(rep) = rxq->port_id;
-               NEXT(rep) = NULL;
-               len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt);
-               if (unlikely(len == 0)) {
-                       rte_mbuf_refcnt_set(rep, 0);
-                       __rte_mbuf_raw_free(rep);
-                       break;
-               }
-               if (unlikely(len == -1)) {
-                       /* RX error, packet is likely too large. */
-                       rte_mbuf_refcnt_set(rep, 0);
-                       __rte_mbuf_raw_free(rep);
-                       ++rxq->stats.idropped;
-                       --i;
-                       goto skip;
+               if (!pkt) {
+                       cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt].cqe64;
+                       len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt);
+                       if (len == 0) {
+                               rte_mbuf_refcnt_set(rep, 0);
+                               __rte_mbuf_raw_free(rep);
+                               break;
+                       }
+                       if (unlikely(len == -1)) {
+                               /* RX error, packet is likely too large. */
+                               rte_mbuf_refcnt_set(rep, 0);
+                               __rte_mbuf_raw_free(rep);
+                               ++rxq->stats.idropped;
+                               goto skip;
+                       }
+                       pkt = seg;
+                       assert(len >= (rxq->crc_present << 2));
+                       /* Update packet information. */
+                       pkt->packet_type = 0;
+                       pkt->ol_flags = 0;
+                       if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip |
+                           rxq->crc_present) {
+                               if (rxq->csum) {
+                                       pkt->packet_type =
+                                               rxq_cq_to_pkt_type(cqe);
+                                       pkt->ol_flags =
+                                               rxq_cq_to_ol_flags(rxq, cqe);
+                               }
+                               if (cqe->l4_hdr_type_etc &
+                                   MLX5_CQE_VLAN_STRIPPED) {
+                                       pkt->ol_flags |= PKT_RX_VLAN_PKT |
+                                               PKT_RX_VLAN_STRIPPED;
+                                       pkt->vlan_tci = ntohs(cqe->vlan_info);
+                               }
+                               if (rxq->crc_present)
+                                       len -= ETHER_CRC_LEN;
+                       }
+                       PKT_LEN(pkt) = len;
                }
+               DATA_LEN(rep) = DATA_LEN(seg);
+               PKT_LEN(rep) = PKT_LEN(seg);
+               SET_DATA_OFF(rep, DATA_OFF(seg));
+               NB_SEGS(rep) = NB_SEGS(seg);
+               PORT(rep) = PORT(seg);
+               NEXT(rep) = NULL;
+               (*rxq->elts)[idx] = rep;
                /*
                 * Fill NIC descriptor with the new buffer.  The lkey and size
                 * of the buffers are already known, only the buffer address
                 * changes.
                 */
-               wqe->addr = htonll((uintptr_t)rep->buf_addr +
-                                  RTE_PKTMBUF_HEADROOM);
-               (*rxq->elts)[idx] = rep;
-               /* Update pkt information. */
-               if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip |
-                   rxq->crc_present) {
-                       if (rxq->csum) {
-                               pkt->packet_type = rxq_cq_to_pkt_type(cqe);
-                               pkt->ol_flags = rxq_cq_to_ol_flags(rxq, cqe);
-                       }
-                       if (cqe->l4_hdr_type_etc & MLX5_CQE_VLAN_STRIPPED) {
-                               pkt->ol_flags |= PKT_RX_VLAN_PKT |
-                                       PKT_RX_VLAN_STRIPPED;
-                               pkt->vlan_tci = ntohs(cqe->vlan_info);
-                       }
-                       if (rxq->crc_present)
-                               len -= ETHER_CRC_LEN;
+               wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t));
+               if (len > DATA_LEN(seg)) {
+                       len -= DATA_LEN(seg);
+                       ++NB_SEGS(pkt);
+                       ++rq_ci;
+                       continue;
                }
-               PKT_LEN(pkt) = len;
-               DATA_LEN(pkt) = len;
+               DATA_LEN(seg) = len;
 #ifdef MLX5_PMD_SOFT_COUNTERS
                /* Increment bytes counter. */
-               rxq->stats.ibytes += len;
+               rxq->stats.ibytes += PKT_LEN(pkt);
 #endif
                /* Return packet. */
                *(pkts++) = pkt;
-               ++pkts_ret;
+               pkt = NULL;
+               --pkts_n;
+               ++i;
 skip:
+               /* Align consumer index to the next stride. */
+               rq_ci >>= sges_n;
                ++rq_ci;
+               rq_ci <<= sges_n;
        }
-       if (unlikely((i == 0) && (rq_ci == rxq->rq_ci)))
+       if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
                return 0;
-       /* Repost WRs. */
-#ifdef DEBUG_RECV
-       DEBUG("%p: reposting %u WRs", (void *)rxq, i);
-#endif
        /* Update the consumer index. */
-       rxq->rq_ci = rq_ci;
+       rxq->rq_ci = rq_ci >> sges_n;
        rte_wmb();
        *rxq->cq_db = htonl(rxq->cq_ci);
        rte_wmb();
        *rxq->rq_db = htonl(rxq->rq_ci);
 #ifdef MLX5_PMD_SOFT_COUNTERS
        /* Increment packets counter. */
-       rxq->stats.ipackets += pkts_ret;
+       rxq->stats.ipackets += i;
 #endif
-       return pkts_ret;
+       return i;
 }
 
 /**