The NTB rawdev framework was written around the Intel back-to-back topology and the built-in scratchpad handshake protocol. To allow other vendors to plug into the same framework, add vendor-neutral hooks and make the common code dispatch through them:
- Add NTB_TOPO_PRI/NTB_TOPO_SEC topology types for hardware that uses a primary/secondary topology instead of back-to-back. - Add optional ntb_dev_ops hooks: interrupt_handler (vendor-specific MSI-X handler), dev_handshake (vendor-specific link handshake) and read_peer_config (vendor-specific peer-config read at start). When a hook is NULL the common code keeps using the existing built-in path, so the Intel driver is unaffected. - 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 | 94 ++++++++++++++++++++++++++++--------------- drivers/raw/ntb/ntb.h | 18 +++++++++ 2 files changed, 80 insertions(+), 32 deletions(-) diff --git a/drivers/raw/ntb/ntb.c b/drivers/raw/ntb/ntb.c index d54f2fb783..3a6a299081 100644 --- a/drivers/raw/ntb/ntb.c +++ b/drivers/raw/ntb/ntb.c @@ -746,6 +746,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; @@ -882,8 +887,13 @@ ntb_dev_configure(const struct rte_rawdev *dev, rte_rawdev_obj_t config, hw->ntb_xstats_off = rte_zmalloc("ntb_xstats_off", xstats_num * sizeof(uint64_t), 0); - /* Start handshake with the peer. */ - ret = ntb_handshake_work(dev); + /* Start handshake with the peer. Use the vendor-specific handshake + * if provided, otherwise the built-in scratchpad protocol. + */ + if (hw->ntb_ops->dev_handshake != NULL) + ret = (*hw->ntb_ops->dev_handshake)(dev); + else + ret = ntb_handshake_work(dev); if (ret < 0) { rte_free(hw->rx_queues); rte_free(hw->tx_queues); @@ -929,35 +939,44 @@ ntb_dev_start(struct rte_rawdev *dev) goto err_q_init; } - if (hw->ntb_ops->spad_read == NULL) { - ret = -ENOTSUP; - goto err_up; - } + /* Read/validate peer config. Use the vendor-specific reader if + * provided, otherwise the built-in scratchpad reads. + */ + if (hw->ntb_ops->read_peer_config != NULL) { + ret = (*hw->ntb_ops->read_peer_config)(dev); + if (ret < 0) + goto err_up; + } else { + if (hw->ntb_ops->spad_read == NULL) { + ret = -ENOTSUP; + goto err_up; + } - 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_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; - 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; + goto err_up; + } - hw->peer_used_mws = (*hw->ntb_ops->spad_read)(dev, SPAD_USED_MWS, 0); + 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; + 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; @@ -1057,8 +1076,13 @@ ntb_dev_close(struct rte_rawdev *dev) rte_intr_disable(intr_handle); /* Unregister callback func to eal lib */ - rte_intr_callback_unregister(intr_handle, - ntb_dev_intr_handler, dev); + if (hw->ntb_ops->interrupt_handler != NULL) + rte_intr_callback_unregister(intr_handle, + hw->ntb_ops->interrupt_handler, + dev); + else + rte_intr_callback_unregister(intr_handle, + ntb_dev_intr_handler, dev); return 0; } @@ -1409,9 +1433,15 @@ ntb_init_hw(struct rte_rawdev *dev, struct rte_pci_device *pci_dev) (*hw->ntb_ops->db_clear)(dev, hw->db_valid_mask); intr_handle = pci_dev->intr_handle; - /* Register callback func to eal lib */ - rte_intr_callback_register(intr_handle, - ntb_dev_intr_handler, dev); + /* Register callback func to eal lib. Use the vendor-specific handler + * if provided, otherwise fall back to the built-in handler. + */ + if (hw->ntb_ops->interrupt_handler != NULL) + rte_intr_callback_register(intr_handle, + hw->ntb_ops->interrupt_handler, dev); + else + rte_intr_callback_register(intr_handle, + ntb_dev_intr_handler, dev); ret = rte_intr_efd_enable(intr_handle, hw->db_cnt); if (ret) diff --git a/drivers/raw/ntb/ntb.h b/drivers/raw/ntb/ntb.h index 8c7a2230f9..270f9f9046 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 { @@ -100,6 +103,8 @@ 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]. + * @interrupt_handler: Vendor-specific interrupt handler. If NULL, the + * built-in handler is used. */ struct ntb_dev_ops { int (*ntb_dev_init)(const struct rte_rawdev *dev); @@ -119,6 +124,16 @@ 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); + void (*interrupt_handler)(void *param); + /* Optional vendor-specific handshake. If NULL, the built-in + * scratchpad handshake is used. Used by hardware (e.g. AMD) whose + * scratchpad layout differs from the built-in protocol. + */ + int (*dev_handshake)(const struct rte_rawdev *dev); + /* Optional vendor-specific peer-config read at device start. If NULL, + * the built-in scratchpad reads are used. + */ + int (*read_peer_config)(const struct rte_rawdev *dev); }; struct ntb_desc { @@ -208,6 +223,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; -- 2.34.1

