Hi, Konstantin

Thanks for your reviewing and sorry for my delayed response.
For your comments, we put forward several improvement plans below.

Best Regards
Feifei

> -----邮件原件-----
> 发件人: Konstantin Ananyev <konstantin.v.anan...@yandex.ru>
> 发送时间: Thursday, February 2, 2023 10:33 PM
> 收件人: Feifei Wang <feifei.wa...@arm.com>; tho...@monjalon.net;
> Ferruh Yigit <ferruh.yi...@amd.com>; Andrew Rybchenko
> <andrew.rybche...@oktetlabs.ru>
> 抄送: dev@dpdk.org; nd <n...@arm.com>; Honnappa Nagarahalli
> <honnappa.nagaraha...@arm.com>; Ruifeng Wang
> <ruifeng.w...@arm.com>
> 主题: Re: [PATCH v3 1/3] ethdev: enable direct rearm with separate API
> 
> Hi Feifei,
> 
> > Add 'tx_fill_sw_ring' and 'rx_flush_descriptor' API into direct rearm
> > mode for separate Rx and Tx Operation. And this can support different
> > multiple sources in direct rearm mode. For examples, Rx driver is
> > ixgbe, and Tx driver is i40e.
> 
> 
> Thanks for your effort and thanks for taking comments provided into
> consideration.
> That approach looks much better then previous ones.
> Few nits below.
> Konstantin
> 
> > Suggested-by: Honnappa Nagarahalli <honnappa.nagaraha...@arm.com>
> > Suggested-by: Ruifeng Wang <ruifeng.w...@arm.com>
> > Signed-off-by: Feifei Wang <feifei.wa...@arm.com>
> > Reviewed-by: Ruifeng Wang <ruifeng.w...@arm.com>
> > Reviewed-by: Honnappa Nagarahalli <honnappa.nagaraha...@arm.com>
> > ---
> >   lib/ethdev/ethdev_driver.h   |  10 ++
> >   lib/ethdev/ethdev_private.c  |   2 +
> >   lib/ethdev/rte_ethdev.c      |  52 +++++++++++
> >   lib/ethdev/rte_ethdev.h      | 174
> +++++++++++++++++++++++++++++++++++
> >   lib/ethdev/rte_ethdev_core.h |  11 +++
> >   lib/ethdev/version.map       |   6 ++
> >   6 files changed, 255 insertions(+)
> >
> > diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
> > index 6a550cfc83..bc539ec862 100644
> > --- a/lib/ethdev/ethdev_driver.h
> > +++ b/lib/ethdev/ethdev_driver.h
> > @@ -59,6 +59,10 @@ struct rte_eth_dev {
> >     eth_rx_descriptor_status_t rx_descriptor_status;
> >     /** Check the status of a Tx descriptor */
> >     eth_tx_descriptor_status_t tx_descriptor_status;
> > +   /** Fill Rx sw-ring with Tx buffers in direct rearm mode */
> > +   eth_tx_fill_sw_ring_t tx_fill_sw_ring;
> > +   /** Flush Rx descriptor in direct rearm mode */
> > +   eth_rx_flush_descriptor_t rx_flush_descriptor;
> >
> >     /**
> >      * Device data that is shared between primary and secondary
> > processes @@ -504,6 +508,10 @@ typedef void
> (*eth_rxq_info_get_t)(struct rte_eth_dev *dev,
> >   typedef void (*eth_txq_info_get_t)(struct rte_eth_dev *dev,
> >     uint16_t tx_queue_id, struct rte_eth_txq_info *qinfo);
> >
> > +/**< @internal Get rearm data for a receive queue of an Ethernet
> > +device. */ typedef void (*eth_rxq_rearm_data_get_t)(struct rte_eth_dev
> *dev,
> > +   uint16_t tx_queue_id, struct rte_eth_rxq_rearm_data
> > +*rxq_rearm_data);
> > +
> >   typedef int (*eth_burst_mode_get_t)(struct rte_eth_dev *dev,
> >     uint16_t queue_id, struct rte_eth_burst_mode *mode);
> >
> > @@ -1215,6 +1223,8 @@ struct eth_dev_ops {
> >     eth_rxq_info_get_t         rxq_info_get;
> >     /** Retrieve Tx queue information */
> >     eth_txq_info_get_t         txq_info_get;
> > +   /** Get Rx queue rearm data */
> > +   eth_rxq_rearm_data_get_t   rxq_rearm_data_get;
> >     eth_burst_mode_get_t       rx_burst_mode_get; /**< Get Rx burst
> mode */
> >     eth_burst_mode_get_t       tx_burst_mode_get; /**< Get Tx burst
> mode */
> >     eth_fw_version_get_t       fw_version_get; /**< Get firmware version
> */
> > diff --git a/lib/ethdev/ethdev_private.c b/lib/ethdev/ethdev_private.c
> > index 48090c879a..c5dd5e30f6 100644
> > --- a/lib/ethdev/ethdev_private.c
> > +++ b/lib/ethdev/ethdev_private.c
> > @@ -276,6 +276,8 @@ eth_dev_fp_ops_setup(struct rte_eth_fp_ops *fpo,
> >     fpo->rx_queue_count = dev->rx_queue_count;
> >     fpo->rx_descriptor_status = dev->rx_descriptor_status;
> >     fpo->tx_descriptor_status = dev->tx_descriptor_status;
> > +   fpo->tx_fill_sw_ring = dev->tx_fill_sw_ring;
> > +   fpo->rx_flush_descriptor = dev->rx_flush_descriptor;
> >
> >     fpo->rxq.data = dev->data->rx_queues;
> >     fpo->rxq.clbk = (void **)(uintptr_t)dev->post_rx_burst_cbs;
> > diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c index
> > 5d5e18db1e..2af5cb42fe 100644
> > --- a/lib/ethdev/rte_ethdev.c
> > +++ b/lib/ethdev/rte_ethdev.c
> > @@ -3282,6 +3282,21 @@
> rte_eth_dev_set_rx_queue_stats_mapping(uint16_t port_id, uint16_t
> rx_queue_id,
> >                                             stat_idx, STAT_QMAP_RX));
> >   }
> >
> > +int
> > +rte_eth_dev_direct_rearm(uint16_t rx_port_id, uint16_t rx_queue_id,
> > +           uint16_t tx_port_id, uint16_t tx_rx_queue_id,
> > +           struct rte_eth_rxq_rearm_data *rxq_rearm_data) {
> > +   int nb_rearm = 0;
> > +
> > +   nb_rearm = rte_eth_tx_fill_sw_ring(tx_port_id, tx_rx_queue_id,
> > +rxq_rearm_data);
> > +
> > +   if (nb_rearm > 0)
> > +           return rte_eth_rx_flush_descriptor(rx_port_id, rx_queue_id,
> > +nb_rearm);
> > +
> > +   return 0;
> > +}
> > +
> >   int
> >   rte_eth_dev_fw_version_get(uint16_t port_id, char *fw_version, size_t
> fw_size)
> >   {
> > @@ -5323,6 +5338,43 @@ rte_eth_tx_queue_info_get(uint16_t port_id,
> uint16_t queue_id,
> >     return 0;
> >   }
> >
> > +int
> > +rte_eth_rx_queue_rearm_data_get(uint16_t port_id, uint16_t queue_id,
> > +           struct rte_eth_rxq_rearm_data *rxq_rearm_data) {
> > +   struct rte_eth_dev *dev;
> > +
> > +   RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
> > +   dev = &rte_eth_devices[port_id];
> > +
> > +   if (queue_id >= dev->data->nb_rx_queues) {
> > +           RTE_ETHDEV_LOG(ERR, "Invalid Rx queue_id=%u\n",
> queue_id);
> > +           return -EINVAL;
> > +   }
> > +
> > +   if (rxq_rearm_data == NULL) {
> > +           RTE_ETHDEV_LOG(ERR, "Cannot get ethdev port %u Rx
> queue %u rearm data to NULL\n",
> > +                   port_id, queue_id);
> > +           return -EINVAL;
> > +   }
> > +
> > +   if (dev->data->rx_queues == NULL ||
> > +                   dev->data->rx_queues[queue_id] == NULL) {
> > +           RTE_ETHDEV_LOG(ERR,
> > +                      "Rx queue %"PRIu16" of device with port_id=%"
> > +                      PRIu16" has not been setup\n",
> > +                      queue_id, port_id);
> > +           return -EINVAL;
> > +   }
> > +
> > +   if (*dev->dev_ops->rxq_rearm_data_get == NULL)
> > +           return -ENOTSUP;
> > +
> > +   dev->dev_ops->rxq_rearm_data_get(dev, queue_id,
> rxq_rearm_data);
> > +
> > +   return 0;
> > +}
> > +
> >   int
> >   rte_eth_rx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
> >                       struct rte_eth_burst_mode *mode) diff --git
> > a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index
> > c129ca1eaf..381c3d535f 100644
> > --- a/lib/ethdev/rte_ethdev.h
> > +++ b/lib/ethdev/rte_ethdev.h
> > @@ -1818,6 +1818,17 @@ struct rte_eth_txq_info {
> >     uint8_t queue_state;        /**< one of RTE_ETH_QUEUE_STATE_*. */
> >   } __rte_cache_min_aligned;
> >
> > +/**
> > + * @internal
> > + * Structure used to hold pointers to internal ethdev Rx rearm data.
> > + * The main purpose is to load Rx queue rearm data in direct rearm mode.
> > + */
> 
> I think this structure owes a lot more expalantion.
> What each fields suppose to do and what are the constraints, etc.
> 
> In general, more doc will be needed to explain that feature.

You are right. We will add more explanation for it and also update the doc
To explain the feature.

> > +struct rte_eth_rxq_rearm_data {
> > +   void *rx_sw_ring;
> 
> That's misleading, we always suppose to store mbufs ptrs here, so why not
> be direct:
> struct rte_mbuf **rx_sw_ring;
> 
Agree.
> > +   uint16_t *rearm_start;
> > +   uint16_t *rearm_nb;
> 
> I know that for Intel NICs uint16_t is sufficient, wonder would it always be
> for other vendors?
> Another thing to consider the case when ring position wrapping?
> Again I know that it is not required for Intel NICs, but would it be 
> sufficient
> for API that supposed to be general?
> 
For this, we re-define this structure:
rte_eth_rxq_rearm_data {
        void *rx_sw_ring;
        uint16_t *rearm_start;
        uint16_t *rearm_nb;
}
->
struct *rxq_recycle_info {
        rte_mbuf **buf_ring;
        uint16_t *offset = (uint16 *)(&rq->ci);
        uint16_t *end;
        uint16_t ring_size; 

}
For the new structure, *offset is a pointer for rearm-start index of
Rx buffer ring (consumer index). *end is a pointer for rearm-end index
Of Rx buffer ring (producer index).

1. we look up different pmds,  some pmds using 'uint_16t' as index size like 
intel PMD,
some pmds using 'uint32_t' as index size like MLX5 or thunderx PMD. 
For pmd using 'uint32_t', rearm starts at 'buf_ring[offset & (ring_size -1)]', 
and 'uint16_t'
is enough for ring size.

2. Good question. In general path, there is a constraint that  'nb_rearm < 
ring_size - rq->ci',
This can ensure no ring wrapping in rearm. Thus in direct-rearm, we will refer 
to this to
solve ring wrapping.

> 
> > +} __rte_cache_min_aligned;
> > +
> >   /* Generic Burst mode flag definition, values can be ORed. */
> >
> >   /**
> > @@ -3184,6 +3195,34 @@ int
> rte_eth_dev_set_rx_queue_stats_mapping(uint16_t port_id,
> >                                        uint16_t rx_queue_id,
> >                                        uint8_t stat_idx);
> >
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> > +notice
> > + *
> > + * Directly put Tx freed buffers into Rx sw-ring and flush desc.
> > + *
> > + * @param rx_port_id
> > + *   Port identifying the receive side.
> > + * @param rx_queue_id
> > + *   The index of the receive queue identifying the receive side.
> > + *   The value must be in the range [0, nb_rx_queue - 1] previously
> supplied
> > + *   to rte_eth_dev_configure().
> > + * @param tx_port_id
> > + *   Port identifying the transmit side.
> > + * @param tx_queue_id
> > + *   The index of the transmit queue identifying the transmit side.
> > + *   The value must be in the range [0, nb_tx_queue - 1] previously
> supplied
> > + *   to rte_eth_dev_configure().
> > + * @param rxq_rearm_data
> > + *   A pointer to a structure of type *rte_eth_txq_rearm_data* to be 
> > filled.
> > + * @return
> > + *   - 0: Success
> > + */
> > +__rte_experimental
> > +int rte_eth_dev_direct_rearm(uint16_t rx_port_id, uint16_t rx_queue_id,
> > +           uint16_t tx_port_id, uint16_t tx_queue_id,
> > +           struct rte_eth_rxq_rearm_data *rxq_rearm_data);
> 
> 
> I think we need one more parameter for that function 'uint16_t offset'
> or so.
> So _rearm_ will start to populate rx_sw_ring from *rearm_start + offset
> position. That way we can support populating from different sources.
> Or should 'offset' be part of truct rte_eth_rxq_rearm_data?
> 
Agree, please see above, we will do the change in the structure.
> > +
> >   /**
> >    * Retrieve the Ethernet address of an Ethernet device.
> >    *
> > @@ -4782,6 +4821,27 @@ int rte_eth_rx_queue_info_get(uint16_t
> port_id, uint16_t queue_id,
> >   int rte_eth_tx_queue_info_get(uint16_t port_id, uint16_t queue_id,
> >     struct rte_eth_txq_info *qinfo);
> >
> > +/**
> > + * Get rearm data about given ports's Rx queue.
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @param queue_id
> > + *   The Rx queue on the Ethernet device for which rearm data
> > + *   will be got.
> > + * @param rxq_rearm_data
> > + *   A pointer to a structure of type *rte_eth_txq_rearm_data* to be 
> > filled.
> > + *
> > + * @return
> > + *   - 0: Success
> > + *   - -ENODEV:  If *port_id* is invalid.
> > + *   - -ENOTSUP: routine is not supported by the device PMD.
> > + *   - -EINVAL:  The queue_id is out of range.
> > + */
> > +__rte_experimental
> > +int rte_eth_rx_queue_rearm_data_get(uint16_t port_id, uint16_t
> queue_id,
> > +           struct rte_eth_rxq_rearm_data *rxq_rearm_data);
> > +
> >   /**
> >    * Retrieve information about the Rx packet burst mode.
> >    *
> > @@ -6103,6 +6163,120 @@ static inline int
> rte_eth_tx_descriptor_status(uint16_t port_id,
> >     return (*p->tx_descriptor_status)(qd, offset);
> >   }
> >
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> > +notice
> > + *
> > + * Fill Rx sw-ring with Tx buffers in direct rearm mode.
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @param queue_id
> > + *   The index of the transmit queue.
> > + *   The value must be in the range [0, nb_tx_queue - 1] previously
> supplied
> > + *   to rte_eth_dev_configure().
> > + * @param rxq_rearm_data
> > + *   A pointer to a structure of type *rte_eth_rxq_rearm_data* to be filled
> with
> > + *   the rearm data of a receive queue.
> > + * @return
> > + *   - The number buffers correct to be filled in the Rx sw-ring.
> > + *   - (-EINVAL) bad port or queue.
> > + *   - (-ENODEV) bad port.
> > + *   - (-ENOTSUP) if the device does not support this function.
> > + *
> > + */
> > +__rte_experimental
> > +static inline int rte_eth_tx_fill_sw_ring(uint16_t port_id,
> > +   uint16_t queue_id, struct rte_eth_rxq_rearm_data *rxq_rearm_data)
> {
> > +   struct rte_eth_fp_ops *p;
> > +   void *qd;
> > +
> > +#ifdef RTE_ETHDEV_DEBUG_TX
> > +   if (port_id >= RTE_MAX_ETHPORTS ||
> > +                   queue_id >= RTE_MAX_QUEUES_PER_PORT) {
> > +           RTE_ETHDEV_LOG(ERR,
> > +                   "Invalid port_id=%u or queue_id=%u\n",
> > +                   port_id, queue_id);
> > +           return -EINVAL;
> > +   }
> > +#endif
> > +
> > +   p = &rte_eth_fp_ops[port_id];
> > +   qd = p->txq.data[queue_id];
> > +
> > +#ifdef RTE_ETHDEV_DEBUG_TX
> > +   RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
> > +
> > +   if (qd == NULL) {
> > +           RTE_ETHDEV_LOG(ERR, "Invalid Tx queue_id=%u for
> port_id=%u\n",
> > +                   queue_id, port_id);
> > +           return -ENODEV;
> > +   }
> > +#endif
> > +
> > +   if (p->tx_fill_sw_ring == NULL)
> > +           return -ENOTSUP;
> > +
> > +   return p->tx_fill_sw_ring(qd, rxq_rearm_data); }
> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> > +notice
> > + *
> > + *  Flush Rx descriptor in direct rearm mode.
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @param queue_id
> > + *   The index of the receive queue.
> > + *   The value must be in the range [0, nb_rx_queue - 1] previously
> supplied
> > + *   to rte_eth_dev_configure().
> > + *@param nb_rearm
> > + *   The number of Rx sw-ring buffers need to be flushed.
> > + * @return
> > + *   - (0) if successful.
> > + *   - (-EINVAL) bad port or queue.
> > + *   - (-ENODEV) bad port.
> > + *   - (-ENOTSUP) if the device does not support this function.
> > + */
> > +__rte_experimental
> > +static inline int rte_eth_rx_flush_descriptor(uint16_t port_id,
> > +   uint16_t queue_id, uint16_t nb_rearm) {
> > +   struct rte_eth_fp_ops *p;
> > +   void *qd;
> > +
> > +#ifdef RTE_ETHDEV_DEBUG_RX
> > +   if (port_id >= RTE_MAX_ETHPORTS ||
> > +                   queue_id >= RTE_MAX_QUEUES_PER_PORT) {
> > +           RTE_ETHDEV_LOG(ERR,
> > +                   "Invalid port_id=%u or queue_id=%u\n",
> > +                   port_id, queue_id);
> > +           return -EINVAL;
> > +   }
> > +#endif
> > +
> > +   p = &rte_eth_fp_ops[port_id];
> > +   qd = p->rxq.data[queue_id];
> > +
> > +#ifdef RTE_ETHDEV_DEBUG_RX
> > +   RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
> > +
> > +   if (qd == NULL) {
> > +           RTE_ETHDEV_LOG(ERR, "Invalid Rx queue_id=%u for
> port_id=%u\n",
> > +                   queue_id, port_id);
> > +           return -ENODEV;
> > +   }
> > +#endif
> > +
> > +   if (p->rx_flush_descriptor == NULL)
> > +           return -ENOTSUP;
> > +
> > +   return p->rx_flush_descriptor(qd, nb_rearm); }
> > +
> >   /**
> >    * @internal
> >    * Helper routine for rte_eth_tx_burst().
> > diff --git a/lib/ethdev/rte_ethdev_core.h
> > b/lib/ethdev/rte_ethdev_core.h index dcf8adab92..5ecb57f6f0 100644
> > --- a/lib/ethdev/rte_ethdev_core.h
> > +++ b/lib/ethdev/rte_ethdev_core.h
> > @@ -56,6 +56,13 @@ typedef int (*eth_rx_descriptor_status_t)(void *rxq,
> uint16_t offset);
> >   /** @internal Check the status of a Tx descriptor */
> >   typedef int (*eth_tx_descriptor_status_t)(void *txq, uint16_t
> > offset);
> >
> > +/** @internal Fill Rx sw-ring with Tx buffers in direct rearm mode */
> > +typedef int (*eth_tx_fill_sw_ring_t)(void *txq,
> > +           struct rte_eth_rxq_rearm_data *rxq_rearm_data);
> > +
> > +/** @internal Flush Rx descriptor in direct rearm mode */ typedef int
> > +(*eth_rx_flush_descriptor_t)(void *rxq, uint16_t nb_rearm);
> > +
> >   /**
> >    * @internal
> >    * Structure used to hold opaque pointers to internal ethdev Rx/Tx
> > @@ -90,6 +97,8 @@ struct rte_eth_fp_ops {
> >     eth_rx_queue_count_t rx_queue_count;
> >     /** Check the status of a Rx descriptor. */
> >     eth_rx_descriptor_status_t rx_descriptor_status;
> > +   /** Flush Rx descriptor in direct rearm mode */
> > +   eth_rx_flush_descriptor_t rx_flush_descriptor;
> >     /** Rx queues data. */
> >     struct rte_ethdev_qdata rxq;
> >     uintptr_t reserved1[3];
> > @@ -106,6 +115,8 @@ struct rte_eth_fp_ops {
> >     eth_tx_prep_t tx_pkt_prepare;
> >     /** Check the status of a Tx descriptor. */
> >     eth_tx_descriptor_status_t tx_descriptor_status;
> > +   /** Fill Rx sw-ring with Tx buffers in direct rearm mode */
> > +   eth_tx_fill_sw_ring_t tx_fill_sw_ring;
> >     /** Tx queues data. */
> >     struct rte_ethdev_qdata txq;
> >     uintptr_t reserved2[3];
> > diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map index
> > 17201fbe0f..f39f02a69b 100644
> > --- a/lib/ethdev/version.map
> > +++ b/lib/ethdev/version.map
> > @@ -298,6 +298,12 @@ EXPERIMENTAL {
> >     rte_flow_get_q_aged_flows;
> >     rte_mtr_meter_policy_get;
> >     rte_mtr_meter_profile_get;
> > +
> > +   # added in 23.03
> > +   rte_eth_dev_direct_rearm;
> > +   rte_eth_rx_flush_descriptor;
> > +   rte_eth_rx_queue_rearm_data_get;
> > +   rte_eth_tx_fill_sw_ring;
> >   };
> >
> >   INTERNAL {

Reply via email to