The NTB rawdev framework was written around the Intel back-to-back topology and the built-in scratchpad handshake protocol. Rework the common code so other vendors can plug into the same framework through a mandatory vendor ops table, without runtime op presence checks.
- Add NTB_TOPO_PRI/NTB_TOPO_SEC topology types for hardware that uses a primary/secondary topology instead of back-to-back. - Turn the link bring-up/tear-down logic into mandatory vendor ops: dev_handshake, peer_mw_validate, read_peer_config and link_cleanup. The former built-in scratchpad logic now lives in the Intel driver. - Drop the mw_set_trans op: programming the memory-window translation is a vendor-internal concern of the handshake, not a framework op. - Keep a single common interrupt handler and let it dispatch through the new ops, with an optional handle_hw_event op for vendor-specific hardware events (none for Intel). - Add a mem_align op and the rte_pmd_ntb_get_mem_align() API so an application can query the base-address alignment a memory window memzone needs, without embedding hardware-specific rules in the app. The Intel driver reports its memory-window size. - Add a pmd_private pointer to struct ntb_hw for vendor-specific state. - Guard the receive path against a malformed stream with no end-of-packet marker so it cannot overflow the descriptor ring. Signed-off-by: Raghavendra Ningoji <[email protected]> --- drivers/raw/ntb/ntb.c | 195 +++++++++------------------------ drivers/raw/ntb/ntb.h | 27 ++++- drivers/raw/ntb/ntb_hw_intel.c | 165 +++++++++++++++++++++++++++- drivers/raw/ntb/rte_pmd_ntb.h | 26 +++++ examples/ntb/ntb_fwd.c | 6 +- 5 files changed, 267 insertions(+), 152 deletions(-) diff --git a/drivers/raw/ntb/ntb.c b/drivers/raw/ntb/ntb.c index 874365748c..1015634c52 100644 --- a/drivers/raw/ntb/ntb.c +++ b/drivers/raw/ntb/ntb.c @@ -19,6 +19,7 @@ #include <rte_memcpy.h> #include <rte_rawdev.h> #include <rte_rawdev_pmd.h> +#include <eal_export.h> #include "ntb_hw_intel.h" #include "rte_pmd_ntb.h" @@ -41,103 +42,12 @@ static struct rte_rawdev_xstats_name ntb_xstats_names[] = { }; #define NTB_XSTATS_NUM RTE_DIM(ntb_xstats_names) -static inline void -ntb_link_cleanup(struct rte_rawdev *dev) -{ - struct ntb_hw *hw = dev->dev_private; - int status, i; - - /* Clean spad registers. */ - for (i = 0; i < hw->spad_cnt; i++) { - status = (*hw->ntb_ops->spad_write)(dev, i, 0, 0); - if (status) - NTB_LOG(ERR, "Failed to clean local spad."); - } - - /* Clear mw so that peer cannot access local memory.*/ - for (i = 0; i < hw->used_mw_num; i++) { - status = (*hw->ntb_ops->mw_set_trans)(dev, i, 0, 0); - if (status) - NTB_LOG(ERR, "Failed to clean mw."); - } -} - -static inline int -ntb_handshake_work(const struct rte_rawdev *dev) -{ - struct ntb_hw *hw = dev->dev_private; - uint32_t val; - int ret, i; - - /* Tell peer the mw info of local side. */ - ret = (*hw->ntb_ops->spad_write)(dev, SPAD_NUM_MWS, 1, hw->mw_cnt); - if (ret < 0) - return ret; - for (i = 0; i < hw->mw_cnt; i++) { - NTB_LOG(INFO, "Local %u mw size: 0x%"PRIx64"", i, - hw->mw_size[i]); - val = hw->mw_size[i] >> 32; - ret = (*hw->ntb_ops->spad_write)(dev, SPAD_MW0_SZ_H + 2 * i, - 1, val); - if (ret < 0) - return ret; - val = hw->mw_size[i]; - ret = (*hw->ntb_ops->spad_write)(dev, SPAD_MW0_SZ_L + 2 * i, - 1, val); - if (ret < 0) - return ret; - } - - /* Tell peer about the queue info and map memory to the peer. */ - ret = (*hw->ntb_ops->spad_write)(dev, SPAD_Q_SZ, 1, hw->queue_size); - if (ret < 0) - return ret; - ret = (*hw->ntb_ops->spad_write)(dev, SPAD_NUM_QPS, 1, - hw->queue_pairs); - if (ret < 0) - return ret; - ret = (*hw->ntb_ops->spad_write)(dev, SPAD_USED_MWS, 1, - hw->used_mw_num); - if (ret < 0) - return ret; - for (i = 0; i < hw->used_mw_num; i++) { - val = (uint64_t)(size_t)(hw->mz[i]->addr) >> 32; - ret = (*hw->ntb_ops->spad_write)(dev, SPAD_MW0_BA_H + 2 * i, - 1, val); - if (ret < 0) - return ret; - val = (uint64_t)(size_t)(hw->mz[i]->addr); - ret = (*hw->ntb_ops->spad_write)(dev, SPAD_MW0_BA_L + 2 * i, - 1, val); - if (ret < 0) - return ret; - } - - for (i = 0; i < hw->used_mw_num; i++) { - ret = (*hw->ntb_ops->mw_set_trans)(dev, i, hw->mz[i]->iova, - hw->mz[i]->len); - if (ret < 0) - return ret; - } - - /* Ring doorbell 0 to tell peer the device is ready. */ - ret = (*hw->ntb_ops->peer_db_set)(dev, 0); - if (ret < 0) - return ret; - - return 0; -} - static void ntb_dev_intr_handler(void *param) { struct rte_rawdev *dev = (struct rte_rawdev *)param; struct ntb_hw *hw = dev->dev_private; - uint32_t val_h, val_l; - uint64_t peer_mw_size; - uint64_t db_bits = 0; - uint8_t peer_mw_cnt; - int i = 0; + uint64_t db_bits; db_bits = (*hw->ntb_ops->db_read)(dev); if (!db_bits) @@ -156,36 +66,19 @@ ntb_dev_intr_handler(void *param) if (hw->peer_dev_up) return; - /* Check if mw setting on the peer is the same as local. */ - peer_mw_cnt = (*hw->ntb_ops->spad_read)(dev, SPAD_NUM_MWS, 0); - if (peer_mw_cnt != hw->mw_cnt) { - NTB_LOG(ERR, "Both mw cnt must be the same."); + /* Check that the peer memory-window layout matches local. */ + if ((*hw->ntb_ops->peer_mw_validate)(dev) < 0) return; - } - - for (i = 0; i < hw->mw_cnt; i++) { - val_h = (*hw->ntb_ops->spad_read) - (dev, SPAD_MW0_SZ_H + 2 * i, 0); - val_l = (*hw->ntb_ops->spad_read) - (dev, SPAD_MW0_SZ_L + 2 * i, 0); - peer_mw_size = ((uint64_t)val_h << 32) | val_l; - NTB_LOG(DEBUG, "Peer %u mw size: 0x%"PRIx64"", i, - peer_mw_size); - if (peer_mw_size != hw->mw_size[i]) { - NTB_LOG(ERR, "Mw config must be the same."); - return; - } - } hw->peer_dev_up = 1; /** - * Handshake with peer. Spad_write & mw_set_trans only works - * when both devices are up. So write spad again when db is - * received. And set db again for the later device who may miss - * the 1st db. + * Handshake with peer. Scratchpad and translation programming + * only takes effect when both devices are up, so run the + * handshake again on the doorbell and ring the peer so the + * device that came up second does not miss the first doorbell. */ - if (ntb_handshake_work(dev) < 0) { + if ((*hw->ntb_ops->dev_handshake)(dev) < 0) { NTB_LOG(ERR, "Handshake work failed."); return; } @@ -203,7 +96,7 @@ ntb_dev_intr_handler(void *param) (*hw->ntb_ops->db_clear)(dev, 2); /* Peer device will be down, So clean local side too. */ - ntb_link_cleanup(dev); + (*hw->ntb_ops->link_cleanup)(dev); hw->peer_dev_up = 0; /* Response peer's dev_stop request. */ @@ -221,6 +114,10 @@ ntb_dev_intr_handler(void *param) /* Clear other received doorbells. */ (*hw->ntb_ops->db_clear)(dev, db_bits); + + /* Let the vendor process any hardware-specific events. */ + if (hw->ntb_ops->handle_hw_event != NULL) + (*hw->ntb_ops->handle_hw_event)(dev); } static int @@ -709,6 +606,11 @@ ntb_dequeue_bufs(struct rte_rawdev *dev, for (nb_rx = 0; nb_rx < count; nb_rx++) { i = 0; while (true) { + if (unlikely(nb_mbufs >= rxq->nb_rx_desc)) { + NTB_LOG(ERR, "Malformed rx stream (no EOP); " + "aborting to avoid desc overflow."); + goto end_of_rx; + } rx_item = rxq->rx_used_ring + rxq->last_used; rxm_t = sw_ring[rxq->last_used].mbuf; rxm_t->data_len = rx_item->len; @@ -818,6 +720,26 @@ ntb_dev_info_get(struct rte_rawdev *dev, rte_rawdev_obj_t dev_info, return 0; } +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_ntb_get_mem_align, 26.11) +uint64_t +rte_pmd_ntb_get_mem_align(uint16_t dev_id, uint32_t mw_id, uint64_t mw_len) +{ + struct rte_rawdev *dev; + struct ntb_hw *hw; + + if (dev_id >= RTE_RAWDEV_MAX_DEVS) + return 0; + dev = rte_rawdev_pmd_get_dev(dev_id); + if (dev->dev_private == NULL) + return 0; + + hw = dev->dev_private; + if (mw_id >= hw->mw_cnt) + return RTE_CACHE_LINE_SIZE; + + return (*hw->ntb_ops->mem_align)(dev, mw_id, mw_len); +} + static int ntb_dev_configure(const struct rte_rawdev *dev, rte_rawdev_obj_t config, size_t config_size) @@ -846,7 +768,7 @@ ntb_dev_configure(const struct rte_rawdev *dev, rte_rawdev_obj_t config, sizeof(uint64_t), 0); /* Start handshake with the peer. */ - ret = ntb_handshake_work(dev); + ret = (*hw->ntb_ops->dev_handshake)(dev); if (ret < 0) { rte_free(hw->rx_queues); rte_free(hw->tx_queues); @@ -862,8 +784,6 @@ static int ntb_dev_start(struct rte_rawdev *dev) { struct ntb_hw *hw = dev->dev_private; - uint32_t peer_base_l, peer_val; - uint64_t peer_base_h; uint32_t i; int ret; @@ -892,31 +812,10 @@ ntb_dev_start(struct rte_rawdev *dev) goto err_q_init; } - peer_val = (*hw->ntb_ops->spad_read)(dev, SPAD_Q_SZ, 0); - if (peer_val != hw->queue_size) { - NTB_LOG(ERR, "Inconsistent queue size! (local: %u peer: %u)", - hw->queue_size, peer_val); - ret = -EINVAL; - goto err_up; - } - - peer_val = (*hw->ntb_ops->spad_read)(dev, SPAD_NUM_QPS, 0); - if (peer_val != hw->queue_pairs) { - NTB_LOG(ERR, "Inconsistent number of queues! (local: %u peer:" - " %u)", hw->queue_pairs, peer_val); - ret = -EINVAL; + /* Read and validate the peer configuration. */ + ret = (*hw->ntb_ops->read_peer_config)(dev); + if (ret < 0) goto err_up; - } - - hw->peer_used_mws = (*hw->ntb_ops->spad_read)(dev, SPAD_USED_MWS, 0); - - for (i = 0; i < hw->peer_used_mws; i++) { - peer_base_h = (*hw->ntb_ops->spad_read)(dev, - SPAD_MW0_BA_H + 2 * i, 0); - peer_base_l = (*hw->ntb_ops->spad_read)(dev, - SPAD_MW0_BA_L + 2 * i, 0); - hw->peer_mw_base[i] = (peer_base_h << 32) + peer_base_l; - } dev->started = 1; @@ -943,7 +842,7 @@ ntb_dev_stop(struct rte_rawdev *dev) if (!hw->peer_dev_up) goto clean; - ntb_link_cleanup(dev); + (*hw->ntb_ops->link_cleanup)(dev); /* Notify the peer that device will be down. */ status = (*hw->ntb_ops->peer_db_set)(dev, 1); @@ -1325,7 +1224,6 @@ ntb_vendor_ops_check(const struct ntb_hw *hw) { offsetof(struct ntb_dev_ops, member), #member } NTB_OPS_REQ(ntb_dev_init), NTB_OPS_REQ(get_peer_mw_addr), - NTB_OPS_REQ(mw_set_trans), NTB_OPS_REQ(ioremap), NTB_OPS_REQ(get_link_status), NTB_OPS_REQ(set_link), @@ -1336,6 +1234,11 @@ ntb_vendor_ops_check(const struct ntb_hw *hw) NTB_OPS_REQ(db_set_mask), NTB_OPS_REQ(peer_db_set), NTB_OPS_REQ(vector_bind), + NTB_OPS_REQ(dev_handshake), + NTB_OPS_REQ(peer_mw_validate), + NTB_OPS_REQ(read_peer_config), + NTB_OPS_REQ(link_cleanup), + NTB_OPS_REQ(mem_align), #undef NTB_OPS_REQ }; unsigned int i; diff --git a/drivers/raw/ntb/ntb.h b/drivers/raw/ntb/ntb.h index 8c7a2230f9..545f4c1425 100644 --- a/drivers/raw/ntb/ntb.h +++ b/drivers/raw/ntb/ntb.h @@ -42,6 +42,9 @@ enum ntb_topo { NTB_TOPO_NONE = 0, NTB_TOPO_B2B_USD, NTB_TOPO_B2B_DSD, + /* Primary/secondary topology (e.g. AMD NTB). */ + NTB_TOPO_PRI, + NTB_TOPO_SEC, }; enum ntb_link { @@ -88,7 +91,6 @@ enum ntb_spad_idx { * NTB device operations * @ntb_dev_init: Init ntb dev. * @get_peer_mw_addr: To get the addr of peer mw[mw_idx]. - * @mw_set_trans: Set translation of internal memory that remote can access. * @ioremap: Translate the remote host address to bar address. * @get_link_status: get link status, link speed and link width. * @set_link: Set local side up/down. @@ -100,12 +102,21 @@ enum ntb_spad_idx { * for those db bits. * @peer_db_set: Set doorbell bit to generate peer interrupt for that bit. * @vector_bind: Bind vector source [intr] to msix vector [msix]. + * @dev_handshake: Advertise the local configuration to the peer, program + * the memory-window translations and signal readiness. + * @peer_mw_validate: Validate that the peer's advertised memory-window + * layout matches the local one. + * @read_peer_config: Read and validate the peer configuration at start. + * @link_cleanup: Tear down the local scratchpad/translation state so the + * peer can no longer reach local memory. + * @mem_align: Base-address alignment required for a memory window memzone + * of a given length. + * @handle_hw_event: Optional. Process vendor-specific hardware events from + * the common interrupt handler. May be NULL. */ struct ntb_dev_ops { int (*ntb_dev_init)(const struct rte_rawdev *dev); void *(*get_peer_mw_addr)(const struct rte_rawdev *dev, int mw_idx); - int (*mw_set_trans)(const struct rte_rawdev *dev, int mw_idx, - uint64_t addr, uint64_t size); void *(*ioremap)(const struct rte_rawdev *dev, uint64_t addr); int (*get_link_status)(const struct rte_rawdev *dev); int (*set_link)(const struct rte_rawdev *dev, bool up); @@ -119,6 +130,13 @@ struct ntb_dev_ops { int (*peer_db_set)(const struct rte_rawdev *dev, uint8_t db_bit); int (*vector_bind)(const struct rte_rawdev *dev, uint8_t intr, uint8_t msix); + int (*dev_handshake)(const struct rte_rawdev *dev); + int (*peer_mw_validate)(const struct rte_rawdev *dev); + int (*read_peer_config)(const struct rte_rawdev *dev); + void (*link_cleanup)(const struct rte_rawdev *dev); + uint64_t (*mem_align)(const struct rte_rawdev *dev, uint32_t mw_id, + uint64_t mw_len); + void (*handle_hw_event)(const struct rte_rawdev *dev); }; struct ntb_desc { @@ -208,6 +226,9 @@ struct ntb_hw { const struct ntb_dev_ops *ntb_ops; + /* Vendor-specific hardware private data. */ + void *pmd_private; + struct rte_pci_device *pci_dev; char *hw_addr; diff --git a/drivers/raw/ntb/ntb_hw_intel.c b/drivers/raw/ntb/ntb_hw_intel.c index 956f411ea3..ed449255dd 100644 --- a/drivers/raw/ntb/ntb_hw_intel.c +++ b/drivers/raw/ntb/ntb_hw_intel.c @@ -11,6 +11,7 @@ #include <bus_pci_driver.h> #include <rte_rawdev.h> #include <rte_rawdev_pmd.h> +#include <rte_memzone.h> #include "ntb.h" #include "ntb_hw_intel.h" @@ -612,11 +613,168 @@ intel_ntb_vector_bind(const struct rte_rawdev *dev, uint8_t intr, uint8_t msix) return 0; } +/* Advertise the local configuration to the peer and program the memory + * windows. Scratchpad writes and translations only take effect once both + * sides are up, so this is also re-run from the ready doorbell. + */ +static int +intel_dev_handshake(const struct rte_rawdev *dev) +{ + struct ntb_hw *hw = dev->dev_private; + uint32_t val; + int ret, i; + + /* Tell peer the mw info of local side. */ + ret = intel_ntb_spad_write(dev, SPAD_NUM_MWS, 1, hw->mw_cnt); + if (ret < 0) + return ret; + for (i = 0; i < hw->mw_cnt; i++) { + NTB_LOG(INFO, "Local %u mw size: 0x%"PRIx64"", i, + hw->mw_size[i]); + val = hw->mw_size[i] >> 32; + ret = intel_ntb_spad_write(dev, SPAD_MW0_SZ_H + 2 * i, 1, val); + if (ret < 0) + return ret; + val = hw->mw_size[i]; + ret = intel_ntb_spad_write(dev, SPAD_MW0_SZ_L + 2 * i, 1, val); + if (ret < 0) + return ret; + } + + /* Tell peer about the queue info and map memory to the peer. */ + ret = intel_ntb_spad_write(dev, SPAD_Q_SZ, 1, hw->queue_size); + if (ret < 0) + return ret; + ret = intel_ntb_spad_write(dev, SPAD_NUM_QPS, 1, hw->queue_pairs); + if (ret < 0) + return ret; + ret = intel_ntb_spad_write(dev, SPAD_USED_MWS, 1, hw->used_mw_num); + if (ret < 0) + return ret; + for (i = 0; i < hw->used_mw_num; i++) { + val = (uint64_t)(size_t)(hw->mz[i]->addr) >> 32; + ret = intel_ntb_spad_write(dev, SPAD_MW0_BA_H + 2 * i, 1, val); + if (ret < 0) + return ret; + val = (uint64_t)(size_t)(hw->mz[i]->addr); + ret = intel_ntb_spad_write(dev, SPAD_MW0_BA_L + 2 * i, 1, val); + if (ret < 0) + return ret; + } + + for (i = 0; i < hw->used_mw_num; i++) { + ret = intel_ntb_mw_set_trans(dev, i, hw->mz[i]->iova, + hw->mz[i]->len); + if (ret < 0) + return ret; + } + + /* Ring doorbell 0 to tell peer the device is ready. */ + return intel_ntb_peer_db_set(dev, 0); +} + +/* Check that the peer advertises the same memory-window layout as local. */ +static int +intel_peer_mw_validate(const struct rte_rawdev *dev) +{ + struct ntb_hw *hw = dev->dev_private; + uint64_t peer_mw_size; + uint32_t val_h, val_l; + uint8_t peer_mw_cnt; + int i; + + peer_mw_cnt = intel_ntb_spad_read(dev, SPAD_NUM_MWS, 0); + if (peer_mw_cnt != hw->mw_cnt) { + NTB_LOG(ERR, "Both mw cnt must be the same."); + return -EINVAL; + } + + for (i = 0; i < hw->mw_cnt; i++) { + val_h = intel_ntb_spad_read(dev, SPAD_MW0_SZ_H + 2 * i, 0); + val_l = intel_ntb_spad_read(dev, SPAD_MW0_SZ_L + 2 * i, 0); + peer_mw_size = ((uint64_t)val_h << 32) | val_l; + NTB_LOG(DEBUG, "Peer %u mw size: 0x%"PRIx64"", i, peer_mw_size); + if (peer_mw_size != hw->mw_size[i]) { + NTB_LOG(ERR, "Mw config must be the same."); + return -EINVAL; + } + } + + return 0; +} + +/* Read and validate the peer configuration recorded in the scratchpad. */ +static int +intel_read_peer_config(const struct rte_rawdev *dev) +{ + struct ntb_hw *hw = dev->dev_private; + uint32_t peer_base_l, peer_val; + uint64_t peer_base_h; + int i; + + peer_val = intel_ntb_spad_read(dev, SPAD_Q_SZ, 0); + if (peer_val != hw->queue_size) { + NTB_LOG(ERR, "Inconsistent queue size! (local: %u peer: %u)", + hw->queue_size, peer_val); + return -EINVAL; + } + + peer_val = intel_ntb_spad_read(dev, SPAD_NUM_QPS, 0); + if (peer_val != hw->queue_pairs) { + NTB_LOG(ERR, "Inconsistent number of queues! (local: %u peer:" + " %u)", hw->queue_pairs, peer_val); + return -EINVAL; + } + + hw->peer_used_mws = intel_ntb_spad_read(dev, SPAD_USED_MWS, 0); + + for (i = 0; i < hw->peer_used_mws; i++) { + peer_base_h = intel_ntb_spad_read(dev, SPAD_MW0_BA_H + 2 * i, 0); + peer_base_l = intel_ntb_spad_read(dev, SPAD_MW0_BA_L + 2 * i, 0); + hw->peer_mw_base[i] = (peer_base_h << 32) + peer_base_l; + } + + return 0; +} + +/* Tear down the local scratchpad and translations so the peer can no + * longer reach local memory. + */ +static void +intel_link_cleanup(const struct rte_rawdev *dev) +{ + struct ntb_hw *hw = dev->dev_private; + int status, i; + + /* Clean spad registers. */ + for (i = 0; i < hw->spad_cnt; i++) { + status = intel_ntb_spad_write(dev, i, 0, 0); + if (status) + NTB_LOG(ERR, "Failed to clean local spad."); + } + + /* Clear mw so that peer cannot access local memory. */ + for (i = 0; i < hw->used_mw_num; i++) { + status = intel_ntb_mw_set_trans(dev, i, 0, 0); + if (status) + NTB_LOG(ERR, "Failed to clean mw."); + } +} + +static uint64_t +intel_ntb_get_mem_align(const struct rte_rawdev *dev, uint32_t mw_id, + uint64_t mw_len __rte_unused) +{ + struct ntb_hw *hw = dev->dev_private; + + /* The memzone base must be aligned to the memory window size. */ + return hw->mw_size[mw_id]; +} + /* operations for primary side of local ntb */ const struct ntb_dev_ops intel_ntb_ops = { .ntb_dev_init = intel_ntb_dev_init, .get_peer_mw_addr = intel_ntb_get_peer_mw_addr, - .mw_set_trans = intel_ntb_mw_set_trans, .ioremap = intel_ntb_ioremap, .get_link_status = intel_ntb_get_link_status, .set_link = intel_ntb_set_link, @@ -627,4 +785,9 @@ const struct ntb_dev_ops intel_ntb_ops = { .db_set_mask = intel_ntb_db_set_mask, .peer_db_set = intel_ntb_peer_db_set, .vector_bind = intel_ntb_vector_bind, + .dev_handshake = intel_dev_handshake, + .peer_mw_validate = intel_peer_mw_validate, + .read_peer_config = intel_read_peer_config, + .link_cleanup = intel_link_cleanup, + .mem_align = intel_ntb_get_mem_align, }; diff --git a/drivers/raw/ntb/rte_pmd_ntb.h b/drivers/raw/ntb/rte_pmd_ntb.h index 76da3be026..70c89dab11 100644 --- a/drivers/raw/ntb/rte_pmd_ntb.h +++ b/drivers/raw/ntb/rte_pmd_ntb.h @@ -7,6 +7,8 @@ #include <stdint.h> +#include <rte_compat.h> + /* App needs to set/get these attrs */ #define NTB_QUEUE_SZ_NAME "queue_size" #define NTB_QUEUE_NUM_NAME "queue_num" @@ -42,4 +44,28 @@ struct ntb_queue_conf { struct rte_mempool *rx_mp; }; +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Get the base-address alignment a memory window memzone must be reserved + * with. Some NTB hardware constrains the address a memory window can be + * translated to (for example, hardware that forms the peer target as + * (base | offset) needs the base aligned to a power of two >= the window + * length). Applications should reserve the memzone for memory window + * @p mw_id, of length @p mw_len, with at least the returned alignment. + * + * @param dev_id + * The identifier of the raw device. + * @param mw_id + * The memory window index. + * @param mw_len + * The length, in bytes, of the memzone to be reserved. + * @return + * The required base-address alignment in bytes, or 0 on error. + */ +__rte_experimental +uint64_t +rte_pmd_ntb_get_mem_align(uint16_t dev_id, uint32_t mw_id, uint64_t mw_len); + #endif /* _RTE_PMD_NTB_H_ */ diff --git a/examples/ntb/ntb_fwd.c b/examples/ntb/ntb_fwd.c index 33f3c1ef17..a187022718 100644 --- a/examples/ntb/ntb_fwd.c +++ b/examples/ntb/ntb_fwd.c @@ -1146,8 +1146,6 @@ ntb_mbuf_pool_create(uint16_t mbuf_seg_size, uint32_t nb_mbuf, if (!left_sz) break; snprintf(mz_name, sizeof(mz_name), "ntb_mw_%d", mz_id); - align = ntb_info.mw_size_align ? ntb_info.mw_size[mz_id] : - RTE_CACHE_LINE_SIZE; /* Reserve ntb header space on memzone 0. */ max_mz_len = mz_id ? ntb_info.mw_size[mz_id] : ntb_info.mw_size[mz_id] - ntb_info.ntb_hdr_size; @@ -1155,6 +1153,10 @@ ntb_mbuf_pool_create(uint16_t mbuf_seg_size, uint32_t nb_mbuf, (max_mz_len / total_elt_sz * total_elt_sz); if (!mz_len) continue; + /* Let the driver report the base-address alignment its + * hardware needs for a memory window of this length. + */ + align = rte_pmd_ntb_get_mem_align(dev_id, mz_id, mz_len); mz = rte_memzone_reserve_aligned(mz_name, mz_len, socket_id, RTE_MEMZONE_IOVA_CONTIG, align); if (mz == NULL) { -- 2.34.1

