New upstream version 17.08
[deb_dpdk.git] / drivers / net / mlx5 / mlx5_rxtx.h
index 8db8eb1..7de1d10 100644 (file)
@@ -115,10 +115,13 @@ struct rxq {
        unsigned int port_id:8;
        unsigned int rss_hash:1; /* RSS hash result is enabled. */
        unsigned int mark:1; /* Marked flow available on the queue. */
-       unsigned int :8; /* Remaining bits. */
+       unsigned int pending_err:1; /* CQE error needs to be handled. */
+       unsigned int trim_elts:1; /* Whether elts needs clean-up. */
+       unsigned int :6; /* Remaining bits. */
        volatile uint32_t *rq_db;
        volatile uint32_t *cq_db;
        uint16_t rq_ci;
+       uint16_t rq_pi;
        uint16_t cq_ci;
        volatile struct mlx5_wqe_data_seg(*wqes)[];
        volatile struct mlx5_cqe(*cqes)[];
@@ -126,6 +129,8 @@ struct rxq {
        struct rte_mbuf *(*elts)[];
        struct rte_mempool *mp;
        struct mlx5_rxq_stats stats;
+       uint64_t mbuf_initializer; /* Default rearm_data for vectorized Rx. */
+       struct rte_mbuf fake_mbuf; /* elts padding for vectorized Rx. */
 } __rte_cache_aligned;
 
 /* RX queue control descriptor. */
@@ -240,10 +245,10 @@ struct hash_rxq {
 };
 
 /* TX queue descriptor. */
-RTE_STD_C11
+__extension__
 struct txq {
-       uint16_t elts_head; /* Current index in (*elts)[]. */
-       uint16_t elts_tail; /* First element awaiting completion. */
+       uint16_t elts_head; /* Current counter in (*elts)[]. */
+       uint16_t elts_tail; /* Counter of first element awaiting completion. */
        uint16_t elts_comp; /* Counter since last completion request. */
        uint16_t mpw_comp; /* WQ index since last completion request. */
        uint16_t cq_ci; /* Consumer index for completion queue. */
@@ -261,16 +266,19 @@ struct txq {
        uint16_t max_inline; /* Multiple of RTE_CACHE_LINE_SIZE to inline. */
        uint16_t inline_max_packet_sz; /* Max packet size for inlining. */
        uint32_t qp_num_8s; /* QP number shifted by 8. */
+       uint32_t flags; /* Flags for Tx Queue. */
        volatile struct mlx5_cqe (*cqes)[]; /* Completion queue. */
        volatile void *wqes; /* Work queue (use volatile to write into). */
        volatile uint32_t *qp_db; /* Work queue doorbell. */
        volatile uint32_t *cq_db; /* Completion queue doorbell. */
        volatile void *bf_reg; /* Blueflame register. */
        struct {
-               const struct rte_mempool *mp; /* Cached Memory Pool. */
+               uintptr_t start; /* Start address of MR */
+               uintptr_t end; /* End address of MR */
                struct ibv_mr *mr; /* Memory Region (for mp). */
                uint32_t lkey; /* htonl(mr->lkey) */
        } mp2mr[MLX5_PMD_TX_MP_CACHE]; /* MP to MR translation table. */
+       uint16_t mr_cache_idx; /* Index of last hit entry. */
        struct rte_mbuf *(*elts)[]; /* TX elements. */
        struct mlx5_txq_stats stats; /* TX queue counters. */
 } __rte_cache_aligned;
@@ -298,19 +306,17 @@ int priv_create_hash_rxqs(struct priv *);
 void priv_destroy_hash_rxqs(struct priv *);
 int priv_allow_flow_type(struct priv *, enum hash_rxq_flow_type);
 int priv_rehash_flows(struct priv *);
-int priv_intr_efd_enable(struct priv *priv);
-void priv_intr_efd_disable(struct priv *priv);
-int priv_create_intr_vec(struct priv *priv);
-void priv_destroy_intr_vec(struct priv *priv);
 void rxq_cleanup(struct rxq_ctrl *);
-int rxq_rehash(struct rte_eth_dev *, struct rxq_ctrl *);
-int rxq_ctrl_setup(struct rte_eth_dev *, struct rxq_ctrl *, uint16_t,
-                  unsigned int, const struct rte_eth_rxconf *,
-                  struct rte_mempool *);
 int mlx5_rx_queue_setup(struct rte_eth_dev *, uint16_t, uint16_t, unsigned int,
                        const struct rte_eth_rxconf *, struct rte_mempool *);
 void mlx5_rx_queue_release(void *);
 uint16_t mlx5_rx_burst_secondary_setup(void *, struct rte_mbuf **, uint16_t);
+int priv_rx_intr_vec_enable(struct priv *priv);
+void priv_rx_intr_vec_disable(struct priv *priv);
+#ifdef HAVE_UPDATE_CQ_CI
+int mlx5_rx_intr_enable(struct rte_eth_dev *dev, uint16_t rx_queue_id);
+int mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id);
+#endif /* HAVE_UPDATE_CQ_CI */
 
 /* mlx5_txq.c */
 
@@ -324,6 +330,9 @@ uint16_t mlx5_tx_burst_secondary_setup(void *, struct rte_mbuf **, uint16_t);
 
 /* mlx5_rxtx.c */
 
+extern uint32_t mlx5_ptype_table[];
+
+void mlx5_set_ptype_table(void);
 uint16_t mlx5_tx_burst(void *, struct rte_mbuf **, uint16_t);
 uint16_t mlx5_tx_burst_mpw(void *, struct rte_mbuf **, uint16_t);
 uint16_t mlx5_tx_burst_mpw_inline(void *, struct rte_mbuf **, uint16_t);
@@ -333,8 +342,16 @@ uint16_t removed_tx_burst(void *, struct rte_mbuf **, uint16_t);
 uint16_t removed_rx_burst(void *, struct rte_mbuf **, uint16_t);
 int mlx5_rx_descriptor_status(void *, uint16_t);
 int mlx5_tx_descriptor_status(void *, uint16_t);
-int mlx5_rx_intr_enable(struct rte_eth_dev *dev, uint16_t rx_queue_id);
-int mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id);
+
+/* Vectorized version of mlx5_rxtx.c */
+int priv_check_raw_vec_tx_support(struct priv *);
+int priv_check_vec_tx_support(struct priv *);
+int rxq_check_vec_support(struct rxq *);
+int priv_check_vec_rx_support(struct priv *);
+void priv_prep_vec_rx_function(struct priv *);
+uint16_t mlx5_tx_burst_raw_vec(void *, struct rte_mbuf **, uint16_t);
+uint16_t mlx5_tx_burst_vec(void *, struct rte_mbuf **, uint16_t);
+uint16_t mlx5_rx_burst_vec(void *, struct rte_mbuf **, uint16_t);
 
 /* mlx5_mr.c */
 
@@ -342,4 +359,254 @@ struct ibv_mr *mlx5_mp2mr(struct ibv_pd *, struct rte_mempool *);
 void txq_mp2mr_iter(struct rte_mempool *, void *);
 uint32_t txq_mp2mr_reg(struct txq *, struct rte_mempool *, unsigned int);
 
+#ifndef NDEBUG
+/**
+ * Verify or set magic value in CQE.
+ *
+ * @param cqe
+ *   Pointer to CQE.
+ *
+ * @return
+ *   0 the first time.
+ */
+static inline int
+check_cqe_seen(volatile struct mlx5_cqe *cqe)
+{
+       static const uint8_t magic[] = "seen";
+       volatile uint8_t (*buf)[sizeof(cqe->rsvd0)] = &cqe->rsvd0;
+       int ret = 1;
+       unsigned int i;
+
+       for (i = 0; i < sizeof(magic) && i < sizeof(*buf); ++i)
+               if (!ret || (*buf)[i] != magic[i]) {
+                       ret = 0;
+                       (*buf)[i] = magic[i];
+               }
+       return ret;
+}
+#endif /* NDEBUG */
+
+/**
+ * Check whether CQE is valid.
+ *
+ * @param cqe
+ *   Pointer to CQE.
+ * @param cqes_n
+ *   Size of completion queue.
+ * @param ci
+ *   Consumer index.
+ *
+ * @return
+ *   0 on success, 1 on failure.
+ */
+static __rte_always_inline int
+check_cqe(volatile struct mlx5_cqe *cqe,
+         unsigned int cqes_n, const uint16_t ci)
+{
+       uint16_t idx = ci & cqes_n;
+       uint8_t op_own = cqe->op_own;
+       uint8_t op_owner = MLX5_CQE_OWNER(op_own);
+       uint8_t op_code = MLX5_CQE_OPCODE(op_own);
+
+       if (unlikely((op_owner != (!!(idx))) || (op_code == MLX5_CQE_INVALID)))
+               return 1; /* No CQE. */
+#ifndef NDEBUG
+       if ((op_code == MLX5_CQE_RESP_ERR) ||
+           (op_code == MLX5_CQE_REQ_ERR)) {
+               volatile struct mlx5_err_cqe *err_cqe = (volatile void *)cqe;
+               uint8_t syndrome = err_cqe->syndrome;
+
+               if ((syndrome == MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR) ||
+                   (syndrome == MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR))
+                       return 0;
+               if (!check_cqe_seen(cqe))
+                       ERROR("unexpected CQE error %u (0x%02x)"
+                             " syndrome 0x%02x",
+                             op_code, op_code, syndrome);
+               return 1;
+       } else if ((op_code != MLX5_CQE_RESP_SEND) &&
+                  (op_code != MLX5_CQE_REQ)) {
+               if (!check_cqe_seen(cqe))
+                       ERROR("unexpected CQE opcode %u (0x%02x)",
+                             op_code, op_code);
+               return 1;
+       }
+#endif /* NDEBUG */
+       return 0;
+}
+
+/**
+ * Return the address of the WQE.
+ *
+ * @param txq
+ *   Pointer to TX queue structure.
+ * @param  wqe_ci
+ *   WQE consumer index.
+ *
+ * @return
+ *   WQE address.
+ */
+static inline uintptr_t *
+tx_mlx5_wqe(struct txq *txq, uint16_t ci)
+{
+       ci &= ((1 << txq->wqe_n) - 1);
+       return (uintptr_t *)((uintptr_t)txq->wqes + ci * MLX5_WQE_SIZE);
+}
+
+/**
+ * Manage TX completions.
+ *
+ * When sending a burst, mlx5_tx_burst() posts several WRs.
+ *
+ * @param txq
+ *   Pointer to TX queue structure.
+ */
+static __rte_always_inline void
+mlx5_tx_complete(struct txq *txq)
+{
+       const uint16_t elts_n = 1 << txq->elts_n;
+       const uint16_t elts_m = elts_n - 1;
+       const unsigned int cqe_n = 1 << txq->cqe_n;
+       const unsigned int cqe_cnt = cqe_n - 1;
+       uint16_t elts_free = txq->elts_tail;
+       uint16_t elts_tail;
+       uint16_t cq_ci = txq->cq_ci;
+       volatile struct mlx5_cqe *cqe = NULL;
+       volatile struct mlx5_wqe_ctrl *ctrl;
+       struct rte_mbuf *m, *free[elts_n];
+       struct rte_mempool *pool = NULL;
+       unsigned int blk_n = 0;
+
+       cqe = &(*txq->cqes)[cq_ci & cqe_cnt];
+       if (unlikely(check_cqe(cqe, cqe_n, cq_ci)))
+               return;
+#ifndef NDEBUG
+       if ((MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_RESP_ERR) ||
+           (MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_REQ_ERR)) {
+               if (!check_cqe_seen(cqe))
+                       ERROR("unexpected error CQE, TX stopped");
+               return;
+       }
+#endif /* NDEBUG */
+       ++cq_ci;
+       txq->wqe_pi = ntohs(cqe->wqe_counter);
+       ctrl = (volatile struct mlx5_wqe_ctrl *)
+               tx_mlx5_wqe(txq, txq->wqe_pi);
+       elts_tail = ctrl->ctrl3;
+       assert((elts_tail & elts_m) < (1 << txq->wqe_n));
+       /* Free buffers. */
+       while (elts_free != elts_tail) {
+               m = rte_pktmbuf_prefree_seg((*txq->elts)[elts_free++ & elts_m]);
+               if (likely(m != NULL)) {
+                       if (likely(m->pool == pool)) {
+                               free[blk_n++] = m;
+                       } else {
+                               if (likely(pool != NULL))
+                                       rte_mempool_put_bulk(pool,
+                                                            (void *)free,
+                                                            blk_n);
+                               free[0] = m;
+                               pool = m->pool;
+                               blk_n = 1;
+                       }
+               }
+       }
+       if (blk_n)
+               rte_mempool_put_bulk(pool, (void *)free, blk_n);
+#ifndef NDEBUG
+       elts_free = txq->elts_tail;
+       /* Poisoning. */
+       while (elts_free != elts_tail) {
+               memset(&(*txq->elts)[elts_free & elts_m],
+                      0x66,
+                      sizeof((*txq->elts)[elts_free & elts_m]));
+               ++elts_free;
+       }
+#endif
+       txq->cq_ci = cq_ci;
+       txq->elts_tail = elts_tail;
+       /* Update the consumer index. */
+       rte_wmb();
+       *txq->cq_db = htonl(cq_ci);
+}
+
+/**
+ * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which
+ * the cloned mbuf is allocated is returned instead.
+ *
+ * @param buf
+ *   Pointer to mbuf.
+ *
+ * @return
+ *   Memory pool where data is located for given mbuf.
+ */
+static struct rte_mempool *
+mlx5_tx_mb2mp(struct rte_mbuf *buf)
+{
+       if (unlikely(RTE_MBUF_INDIRECT(buf)))
+               return rte_mbuf_from_indirect(buf)->pool;
+       return buf->pool;
+}
+
+/**
+ * Get Memory Region (MR) <-> rte_mbuf association from txq->mp2mr[].
+ * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full,
+ * remove an entry first.
+ *
+ * @param txq
+ *   Pointer to TX queue structure.
+ * @param[in] mp
+ *   Memory Pool for which a Memory Region lkey must be returned.
+ *
+ * @return
+ *   mr->lkey on success, (uint32_t)-1 on failure.
+ */
+static __rte_always_inline uint32_t
+mlx5_tx_mb2mr(struct txq *txq, struct rte_mbuf *mb)
+{
+       uint16_t i = txq->mr_cache_idx;
+       uintptr_t addr = rte_pktmbuf_mtod(mb, uintptr_t);
+
+       assert(i < RTE_DIM(txq->mp2mr));
+       if (likely(txq->mp2mr[i].start <= addr && txq->mp2mr[i].end >= addr))
+               return txq->mp2mr[i].lkey;
+       for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) {
+               if (unlikely(txq->mp2mr[i].mr == NULL)) {
+                       /* Unknown MP, add a new MR for it. */
+                       break;
+               }
+               if (txq->mp2mr[i].start <= addr &&
+                   txq->mp2mr[i].end >= addr) {
+                       assert(txq->mp2mr[i].lkey != (uint32_t)-1);
+                       assert(htonl(txq->mp2mr[i].mr->lkey) ==
+                              txq->mp2mr[i].lkey);
+                       txq->mr_cache_idx = i;
+                       return txq->mp2mr[i].lkey;
+               }
+       }
+       txq->mr_cache_idx = 0;
+       return txq_mp2mr_reg(txq, mlx5_tx_mb2mp(mb), i);
+}
+
+/**
+ * Ring TX queue doorbell.
+ *
+ * @param txq
+ *   Pointer to TX queue structure.
+ * @param wqe
+ *   Pointer to the last WQE posted in the NIC.
+ */
+static __rte_always_inline void
+mlx5_tx_dbrec(struct txq *txq, volatile struct mlx5_wqe *wqe)
+{
+       uint64_t *dst = (uint64_t *)((uintptr_t)txq->bf_reg);
+       volatile uint64_t *src = ((volatile uint64_t *)wqe);
+
+       rte_wmb();
+       *txq->qp_db = htonl(txq->wqe_ci);
+       /* Ensure ordering between DB record and BF copy. */
+       rte_wmb();
+       *dst = *src;
+}
+
 #endif /* RTE_PMD_MLX5_RXTX_H_ */