233 lines
8.0 KiB
Diff
233 lines
8.0 KiB
Diff
From cbc5e1d4d611dfb24ed1f444ed5a2acad1aaded2 Mon Sep 17 00:00:00 2001
|
|
From: Amy Ousterhout <aousterh@mit.edu>
|
|
Date: Wed, 28 Feb 2018 20:12:41 -0500
|
|
Subject: [PATCH] enable mlx4 tx memory registration using explicit start and
|
|
end addrs specified in mbufs, instead of inferring these from mempools
|
|
|
|
Detect/handle reuse of shared memory virtual addresses
|
|
---
|
|
drivers/net/mlx4/mlx4.h | 10 ++++++-
|
|
drivers/net/mlx4/mlx4_mr.c | 70 ++++++++++++++++++++++++++++++++++++++++++--
|
|
drivers/net/mlx4/mlx4_rxq.c | 2 +-
|
|
drivers/net/mlx4/mlx4_rxtx.c | 2 +-
|
|
drivers/net/mlx4/mlx4_rxtx.h | 46 +++++++++++++++++++++++++++++
|
|
5 files changed, 124 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
|
|
index 19c8a223d..869610981 100644
|
|
--- a/drivers/net/mlx4/mlx4.h
|
|
+++ b/drivers/net/mlx4/mlx4.h
|
|
@@ -156,9 +156,17 @@ int mlx4_rx_intr_enable(struct rte_eth_dev *dev, uint16_t idx);
|
|
|
|
/* mlx4_mr.c */
|
|
|
|
-struct mlx4_mr *mlx4_mr_get(struct priv *priv, struct rte_mempool *mp);
|
|
+struct mem_info {
|
|
+ uintptr_t uniqid;
|
|
+ uintptr_t start_addr;
|
|
+ uintptr_t end_addr;
|
|
+};
|
|
+
|
|
+struct mlx4_mr *mlx4_mr_get(struct priv *priv, struct rte_mempool *mp, struct mem_info *m);
|
|
void mlx4_mr_put(struct mlx4_mr *mr);
|
|
uint32_t mlx4_txq_add_mr(struct txq *txq, struct rte_mempool *mp,
|
|
uint32_t i);
|
|
+uint32_t mlx4_txq_add_mr_from_mem_info(struct txq *txq, struct mem_info *m,
|
|
+ uint32_t i);
|
|
|
|
#endif /* RTE_PMD_MLX4_H_ */
|
|
diff --git a/drivers/net/mlx4/mlx4_mr.c b/drivers/net/mlx4/mlx4_mr.c
|
|
index 9a1e4de3d..d2e2462c6 100644
|
|
--- a/drivers/net/mlx4/mlx4_mr.c
|
|
+++ b/drivers/net/mlx4/mlx4_mr.c
|
|
@@ -120,11 +120,14 @@ mlx4_check_mempool(struct rte_mempool *mp, uintptr_t *start, uintptr_t *end)
|
|
* @param mp
|
|
* Pointer to memory pool.
|
|
*
|
|
+ * @param m
|
|
+ * Auxiliary info about memory region - use this instead of mempool if non-NULL
|
|
+ *
|
|
* @return
|
|
* Memory region pointer, NULL in case of error and rte_errno is set.
|
|
*/
|
|
struct mlx4_mr *
|
|
-mlx4_mr_get(struct priv *priv, struct rte_mempool *mp)
|
|
+mlx4_mr_get(struct priv *priv, struct rte_mempool *mp, struct mem_info *m)
|
|
{
|
|
const struct rte_memseg *ms = rte_eal_get_physmem_layout();
|
|
uintptr_t start;
|
|
@@ -132,7 +135,15 @@ mlx4_mr_get(struct priv *priv, struct rte_mempool *mp)
|
|
unsigned int i;
|
|
struct mlx4_mr *mr;
|
|
|
|
- if (mlx4_check_mempool(mp, &start, &end) != 0) {
|
|
+ if (m != NULL) {
|
|
+ start = m->start_addr;
|
|
+ end = m->end_addr;
|
|
+
|
|
+ /* this is really ugly, but the pointer to the mempool is used
|
|
+ * only as an identifier... we use the memory region start addr
|
|
+ * instead.*/
|
|
+ mp = (struct rte_mempool *) m->start_addr;
|
|
+ } else if (mlx4_check_mempool(mp, &start, &end) != 0) {
|
|
rte_errno = EINVAL;
|
|
ERROR("mempool %p: not virtually contiguous",
|
|
(void *)mp);
|
|
@@ -241,7 +252,7 @@ mlx4_txq_add_mr(struct txq *txq, struct rte_mempool *mp, uint32_t i)
|
|
/* Add a new entry, register MR first. */
|
|
DEBUG("%p: discovered new memory pool \"%s\" (%p)",
|
|
(void *)txq, mp->name, (void *)mp);
|
|
- mr = mlx4_mr_get(txq->priv, mp);
|
|
+ mr = mlx4_mr_get(txq->priv, mp, NULL);
|
|
if (unlikely(mr == NULL)) {
|
|
DEBUG("%p: unable to configure MR, mlx4_mr_get() failed",
|
|
(void *)txq);
|
|
@@ -264,3 +275,56 @@ mlx4_txq_add_mr(struct txq *txq, struct rte_mempool *mp, uint32_t i)
|
|
(void *)txq, mp->name, (void *)mp, txq->mp2mr[i].lkey);
|
|
return txq->mp2mr[i].lkey;
|
|
}
|
|
+
|
|
+
|
|
+/**
|
|
+ * Add memory region (MR) <-> memory id association to txq->id2mr[].
|
|
+ * If id2mr[] is full, remove an entry first.
|
|
+ *
|
|
+ * @param txq
|
|
+ * Pointer to Tx queue structure.
|
|
+ * @param[in] mem_info
|
|
+ * Info about region for which a memory region lkey must be added.
|
|
+ * @param[in] i
|
|
+ * Index in memory pool (MP) where to add memory region (MR).
|
|
+ *
|
|
+ * @return
|
|
+ * Added mr->lkey on success, (uint32_t)-1 on failure.
|
|
+ */
|
|
+uint32_t
|
|
+mlx4_txq_add_mr_from_mem_info(struct txq *txq, struct mem_info *m, uint32_t i)
|
|
+{
|
|
+ struct mlx4_mr *mr;
|
|
+
|
|
+ if (i != RTE_DIM(txq->mp2mr) && txq->id2mr[i].id != 0) {
|
|
+ /* Need to replace an existing entry. */
|
|
+ DEBUG("%p: replacing possibly stale MR", (void *)txq);
|
|
+ mlx4_mr_put(txq->id2mr[i].mr); // Hopefully refcnt is 1
|
|
+ }
|
|
+
|
|
+ /* Add a new entry, register MR first. */
|
|
+ DEBUG("%p: discovered new mem info", (void *)txq);
|
|
+ mr = mlx4_mr_get(txq->priv, NULL, m);
|
|
+ if (unlikely(mr == NULL)) {
|
|
+ DEBUG("%p: unable to configure MR, mlx4_mr_get() failed",
|
|
+ (void *)txq);
|
|
+ return (uint32_t)-1;
|
|
+ }
|
|
+ if (unlikely(i == RTE_DIM(txq->id2mr))) {
|
|
+ /* Table is full, remove oldest entry. */
|
|
+ DEBUG("%p: MR <-> ID table full, dropping oldest entry.",
|
|
+ (void *)txq);
|
|
+ --i;
|
|
+ mlx4_mr_put(txq->id2mr[0].mr);
|
|
+ memmove(&txq->id2mr[0], &txq->id2mr[1],
|
|
+ (sizeof(txq->id2mr) - sizeof(txq->id2mr[0])));
|
|
+ }
|
|
+ /* Store the new entry. */
|
|
+ txq->id2mr[i].id = m->uniqid;
|
|
+ txq->id2mr[i].mr = mr;
|
|
+ txq->id2mr[i].lkey = mr->lkey;
|
|
+ DEBUG("%p: new MR lkey for mem_info %p %p: 0x%08" PRIu32,
|
|
+ (void *)txq, (void *) m->start_addr, (void *) m->end_addr,
|
|
+ txq->id2mr[i].lkey);
|
|
+ return txq->id2mr[i].lkey;
|
|
+}
|
|
diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
|
|
index 7a036ed83..f80c70616 100644
|
|
--- a/drivers/net/mlx4/mlx4_rxq.c
|
|
+++ b/drivers/net/mlx4/mlx4_rxq.c
|
|
@@ -848,7 +848,7 @@ mlx4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
|
|
goto error;
|
|
}
|
|
/* Use the entire Rx mempool as the memory region. */
|
|
- rxq->mr = mlx4_mr_get(priv, mp);
|
|
+ rxq->mr = mlx4_mr_get(priv, mp, NULL);
|
|
if (!rxq->mr) {
|
|
ERROR("%p: MR creation failure: %s",
|
|
(void *)dev, strerror(rte_errno));
|
|
diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
|
|
index 8ca8b77cc..ae86d5f90 100644
|
|
--- a/drivers/net/mlx4/mlx4_rxtx.c
|
|
+++ b/drivers/net/mlx4/mlx4_rxtx.c
|
|
@@ -611,7 +611,7 @@ mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
|
|
elt->buf = NULL;
|
|
break;
|
|
}
|
|
- lkey = mlx4_txq_mp2mr(txq, mlx4_txq_mb2mp(buf));
|
|
+ lkey = mlx4_txq_buf2mr(txq, buf);
|
|
if (unlikely(lkey == (uint32_t)-1)) {
|
|
/* MR does not exist. */
|
|
DEBUG("%p: unable to get MP <-> MR association",
|
|
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
|
|
index c12bd39a9..e7645e932 100644
|
|
--- a/drivers/net/mlx4/mlx4_rxtx.h
|
|
+++ b/drivers/net/mlx4/mlx4_rxtx.h
|
|
@@ -113,6 +113,11 @@ struct txq {
|
|
struct mlx4_mr *mr; /**< Memory region (for mp). */
|
|
uint32_t lkey; /**< mr->lkey copy. */
|
|
} mp2mr[MLX4_PMD_TX_MP_CACHE]; /**< MP to MR translation table. */
|
|
+ struct {
|
|
+ uintptr_t id; /**< id of mem region (proc->uniqid). */
|
|
+ struct mlx4_mr *mr; /**< Memory region. */
|
|
+ uint32_t lkey; /**< mr->lkey copy. */
|
|
+ } id2mr[MLX4_PMD_TX_MP_CACHE]; /**< id to MR translation table. */
|
|
struct priv *priv; /**< Back pointer to private data. */
|
|
unsigned int socket; /**< CPU socket ID for allocations. */
|
|
struct ibv_cq *cq; /**< Completion queue. */
|
|
@@ -190,4 +195,45 @@ mlx4_txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
|
|
return mlx4_txq_add_mr(txq, mp, i);
|
|
}
|
|
|
|
+#define __max(x,y) ((x) > (y) ? (x) : (y))
|
|
+#define __min(x,y) ((x) < (y) ? (x) : (y))
|
|
+/**
|
|
+ * Get memory region (MR) <-> buffer association from txq->id2mr[].
|
|
+ * Call mlx4_txq_add_mr() if buffer's memory region is not registered yet.
|
|
+ *
|
|
+ * @param txq
|
|
+ * Pointer to Tx queue structure.
|
|
+ * @param[in] buf
|
|
+ * Buffer for which a memory region lkey must be returned.
|
|
+ *
|
|
+ * @return
|
|
+ * mr->lkey on success, (uint32_t)-1 on failure.
|
|
+ */
|
|
+static inline uint32_t
|
|
+mlx4_txq_buf2mr(struct txq *txq, struct rte_mbuf *buf)
|
|
+{
|
|
+ unsigned int i;
|
|
+ struct mem_info *m = (struct mem_info *)(((char *)buf) +
|
|
+ sizeof(struct rte_mbuf));
|
|
+
|
|
+ for (i = 0; (i != RTE_DIM(txq->id2mr)); ++i) {
|
|
+ if (unlikely(txq->id2mr[i].id == 0)) {
|
|
+ /* Unknown region, add a new MR for it. */
|
|
+ break;
|
|
+ }
|
|
+ if (txq->id2mr[i].id == m->uniqid) {
|
|
+ /* Found region. */
|
|
+ return txq->id2mr[i].lkey;
|
|
+ }
|
|
+ if (__max(txq->id2mr[i].mr->start, m->start_addr) <
|
|
+ __min(txq->id2mr[i].mr->end, m->end_addr)) {
|
|
+ /* Recreate lkey/mr for previously mapped regions */
|
|
+ return mlx4_txq_add_mr_from_mem_info(txq, m, i);
|
|
+ }
|
|
+ }
|
|
+ return mlx4_txq_add_mr_from_mem_info(txq, m, i);
|
|
+}
|
|
+
|
|
+#undef __max
|
|
+#undef __min
|
|
#endif /* MLX4_RXTX_H_ */
|
|
--
|
|
2.14.1
|
|
|