> Use the new multi-monitor intrinsic to allow monitoring multiple ethdev
> Rx queues while entering the energy efficient power state. The multi
> version will be used unconditionally if supported, and the UMWAIT one
> will only be used when multi-monitor is not supported by the hardware.
> 
> Signed-off-by: Anatoly Burakov <anatoly.bura...@intel.com>
> ---
> 
> Notes:
>     v4:
>     - Fix possible out of bounds access
>     - Added missing index increment
> 
>  doc/guides/prog_guide/power_man.rst |  9 ++--
>  lib/power/rte_power_pmd_mgmt.c      | 81 ++++++++++++++++++++++++++++-
>  2 files changed, 85 insertions(+), 5 deletions(-)
> 
> diff --git a/doc/guides/prog_guide/power_man.rst 
> b/doc/guides/prog_guide/power_man.rst
> index ec04a72108..94353ca012 100644
> --- a/doc/guides/prog_guide/power_man.rst
> +++ b/doc/guides/prog_guide/power_man.rst
> @@ -221,13 +221,16 @@ power saving whenever empty poll count reaches a 
> certain number.
>  The "monitor" mode is only supported in the following configurations and 
> scenarios:
> 
>  * If ``rte_cpu_get_intrinsics_support()`` function indicates that
> +  ``rte_power_monitor_multi()`` function is supported by the platform, then
> +  monitoring multiple Ethernet Rx queues for traffic will be supported.
> +
> +* If ``rte_cpu_get_intrinsics_support()`` function indicates that only
>    ``rte_power_monitor()`` is supported by the platform, then monitoring will 
> be
>    limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be
>    monitored from a different lcore).
> 
> -* If ``rte_cpu_get_intrinsics_support()`` function indicates that the
> -  ``rte_power_monitor()`` function is not supported, then monitor mode will 
> not
> -  be supported.
> +* If ``rte_cpu_get_intrinsics_support()`` function indicates that neither of 
> the
> +  two monitoring functions are supported, then monitor mode will not be 
> supported.
> 
>  * Not all Ethernet drivers support monitoring, even if the underlying
>    platform may support the necessary CPU instructions. Please refer to
> diff --git a/lib/power/rte_power_pmd_mgmt.c b/lib/power/rte_power_pmd_mgmt.c
> index fccfd236c2..2056996b9c 100644
> --- a/lib/power/rte_power_pmd_mgmt.c
> +++ b/lib/power/rte_power_pmd_mgmt.c
> @@ -124,6 +124,32 @@ queue_list_take(struct pmd_core_cfg *cfg, const union 
> queue *q)
>       return found;
>  }
> 
> +static inline int
> +get_monitor_addresses(struct pmd_core_cfg *cfg,
> +             struct rte_power_monitor_cond *pmc, size_t len)
> +{
> +     const struct queue_list_entry *qle;
> +     size_t i = 0;
> +     int ret;
> +
> +     TAILQ_FOREACH(qle, &cfg->head, next) {
> +             const union queue *q = &qle->queue;
> +             struct rte_power_monitor_cond *cur;
> +
> +             /* attempted out of bounds access */
> +             if (i >= len) {
> +                     RTE_LOG(ERR, POWER, "Too many queues being 
> monitored\n");
> +                     return -1;
> +             }
> +
> +             cur = &pmc[i++];
> +             ret = rte_eth_get_monitor_addr(q->portid, q->qid, cur);
> +             if (ret < 0)
> +                     return ret;
> +     }
> +     return 0;
> +}
> +
>  static void
>  calc_tsc(void)
>  {
> @@ -190,6 +216,45 @@ lcore_can_sleep(struct pmd_core_cfg *cfg)
>       return true;
>  }
> 
> +static uint16_t
> +clb_multiwait(uint16_t port_id __rte_unused, uint16_t qidx __rte_unused,
> +             struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
> +             uint16_t max_pkts __rte_unused, void *arg)
> +{
> +     const unsigned int lcore = rte_lcore_id();
> +     struct queue_list_entry *queue_conf = arg;
> +     struct pmd_core_cfg *lcore_conf;
> +     const bool empty = nb_rx == 0;
> +
> +     lcore_conf = &lcore_cfgs[lcore];
> +
> +     /* early exit */
> +     if (likely(!empty))
> +             /* early exit */
> +             queue_reset(lcore_conf, queue_conf);
> +     else {
> +             struct rte_power_monitor_cond pmc[RTE_MAX_ETHPORTS];

As discussed, I still think it needs to be pmc[lcore_conf->n_queues];
Or if VLA is not an option - alloca(), or dynamic lcore_conf->pmc[], or...

> +             int ret;
> +
> +             /* can this queue sleep? */
> +             if (!queue_can_sleep(lcore_conf, queue_conf))
> +                     return nb_rx;
> +
> +             /* can this lcore sleep? */
> +             if (!lcore_can_sleep(lcore_conf))
> +                     return nb_rx;
> +
> +             /* gather all monitoring conditions */
> +             ret = get_monitor_addresses(lcore_conf, pmc, RTE_DIM(pmc));
> +             if (ret < 0)
> +                     return nb_rx;
> +
> +             rte_power_monitor_multi(pmc, lcore_conf->n_queues, UINT64_MAX);
> +     }
> +
> +     return nb_rx;
> +}
> +
>  static uint16_t
>  clb_umwait(uint16_t port_id, uint16_t qidx, struct rte_mbuf **pkts 
> __rte_unused,
>               uint16_t nb_rx, uint16_t max_pkts __rte_unused, void *arg)
> @@ -341,14 +406,19 @@ static int
>  check_monitor(struct pmd_core_cfg *cfg, const union queue *qdata)
>  {
>       struct rte_power_monitor_cond dummy;
> +     bool multimonitor_supported;
> 
>       /* check if rte_power_monitor is supported */
>       if (!global_data.intrinsics_support.power_monitor) {
>               RTE_LOG(DEBUG, POWER, "Monitoring intrinsics are not 
> supported\n");
>               return -ENOTSUP;
>       }
> +     /* check if multi-monitor is supported */
> +     multimonitor_supported =
> +                     global_data.intrinsics_support.power_monitor_multi;
> 
> -     if (cfg->n_queues > 0) {
> +     /* if we're adding a new queue, do we support multiple queues? */
> +     if (cfg->n_queues > 0 && !multimonitor_supported) {
>               RTE_LOG(DEBUG, POWER, "Monitoring multiple queues is not 
> supported\n");
>               return -ENOTSUP;
>       }
> @@ -364,6 +434,13 @@ check_monitor(struct pmd_core_cfg *cfg, const union 
> queue *qdata)
>       return 0;
>  }
> 
> +static inline rte_rx_callback_fn
> +get_monitor_callback(void)
> +{
> +     return global_data.intrinsics_support.power_monitor_multi ?
> +             clb_multiwait : clb_umwait;
> +}
> +
>  int
>  rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id, uint16_t port_id,
>               uint16_t queue_id, enum rte_power_pmd_mgmt_type mode)
> @@ -428,7 +505,7 @@ rte_power_ethdev_pmgmt_queue_enable(unsigned int 
> lcore_id, uint16_t port_id,
>               if (ret < 0)
>                       goto end;
> 
> -             clb = clb_umwait;
> +             clb = get_monitor_callback();
>               break;
>       case RTE_POWER_MGMT_TYPE_SCALE:
>               /* check if we can add a new queue */
> --
> 2.25.1

Reply via email to