LCOV - code coverage report
Current view: top level - lib/power - rte_power_pmd_mgmt.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 7 252 2.8 %
Date: 2025-03-01 20:23:48 Functions: 1 23 4.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 2 203 1.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2020 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <stdlib.h>
       6                 :            : 
       7                 :            : #include <rte_lcore.h>
       8                 :            : #include <rte_lcore_var.h>
       9                 :            : #include <rte_cycles.h>
      10                 :            : #include <rte_cpuflags.h>
      11                 :            : #include <rte_malloc.h>
      12                 :            : #include <rte_ethdev.h>
      13                 :            : #include <rte_power_intrinsics.h>
      14                 :            : 
      15                 :            : #include "rte_power_pmd_mgmt.h"
      16                 :            : #include "power_common.h"
      17                 :            : 
      18                 :            : unsigned int emptypoll_max;
      19                 :            : unsigned int pause_duration;
      20                 :            : unsigned int scale_freq_min[RTE_MAX_LCORE];
      21                 :            : unsigned int scale_freq_max[RTE_MAX_LCORE];
      22                 :            : 
      23                 :            : /* store some internal state */
      24                 :            : static struct pmd_conf_data {
      25                 :            :         /** what do we support? */
      26                 :            :         struct rte_cpu_intrinsics intrinsics_support;
      27                 :            :         /** pre-calculated tsc diff for 1us */
      28                 :            :         uint64_t tsc_per_us;
      29                 :            :         /** how many rte_pause can we fit in a microsecond? */
      30                 :            :         uint64_t pause_per_us;
      31                 :            : } global_data;
      32                 :            : 
      33                 :            : /**
      34                 :            :  * Possible power management states of an ethdev port.
      35                 :            :  */
      36                 :            : enum pmd_mgmt_state {
      37                 :            :         /** Device power management is disabled. */
      38                 :            :         PMD_MGMT_DISABLED = 0,
      39                 :            :         /** Device power management is enabled. */
      40                 :            :         PMD_MGMT_ENABLED
      41                 :            : };
      42                 :            : 
      43                 :            : union queue {
      44                 :            :         uint32_t val;
      45                 :            :         struct {
      46                 :            :                 uint16_t portid;
      47                 :            :                 uint16_t qid;
      48                 :            :         };
      49                 :            : };
      50                 :            : 
      51                 :            : struct queue_list_entry {
      52                 :            :         TAILQ_ENTRY(queue_list_entry) next;
      53                 :            :         union queue queue;
      54                 :            :         uint64_t n_empty_polls;
      55                 :            :         uint64_t n_sleeps;
      56                 :            :         const struct rte_eth_rxtx_callback *cb;
      57                 :            : };
      58                 :            : 
      59                 :            : struct pmd_core_cfg {
      60                 :            :         TAILQ_HEAD(queue_list_head, queue_list_entry) head;
      61                 :            :         /**< List of queues associated with this lcore */
      62                 :            :         size_t n_queues;
      63                 :            :         /**< How many queues are in the list? */
      64                 :            :         volatile enum pmd_mgmt_state pwr_mgmt_state;
      65                 :            :         /**< State of power management for this queue */
      66                 :            :         enum rte_power_pmd_mgmt_type cb_mode;
      67                 :            :         /**< Callback mode for this queue */
      68                 :            :         uint64_t n_queues_ready_to_sleep;
      69                 :            :         /**< Number of queues ready to enter power optimized state */
      70                 :            :         uint64_t sleep_target;
      71                 :            :         /**< Prevent a queue from triggering sleep multiple times */
      72                 :            : };
      73                 :            : static RTE_LCORE_VAR_HANDLE(struct pmd_core_cfg, lcore_cfgs);
      74                 :            : 
      75                 :            : static void
      76                 :          0 : init_lcore_cfgs(void)
      77                 :            : {
      78                 :            :         struct pmd_core_cfg *lcore_cfg;
      79                 :            :         unsigned int lcore_id;
      80                 :            : 
      81         [ #  # ]:          0 :         if (lcore_cfgs != NULL)
      82                 :            :                 return;
      83                 :            : 
      84                 :          0 :         RTE_LCORE_VAR_ALLOC(lcore_cfgs);
      85                 :            : 
      86                 :            :         /* initialize all tailqs */
      87         [ #  # ]:          0 :         RTE_LCORE_VAR_FOREACH(lcore_id, lcore_cfg, lcore_cfgs)
      88                 :          0 :                 TAILQ_INIT(&lcore_cfg->head);
      89                 :            : }
      90                 :            : 
      91                 :            : static inline bool
      92                 :            : queue_equal(const union queue *l, const union queue *r)
      93                 :            : {
      94                 :          0 :         return l->val == r->val;
      95                 :            : }
      96                 :            : 
      97                 :            : static inline void
      98                 :            : queue_copy(union queue *dst, const union queue *src)
      99                 :            : {
     100                 :          0 :         dst->val = src->val;
     101                 :            : }
     102                 :            : 
     103                 :            : static struct queue_list_entry *
     104                 :            : queue_list_find(const struct pmd_core_cfg *cfg, const union queue *q)
     105                 :            : {
     106                 :            :         struct queue_list_entry *cur;
     107                 :            : 
     108   [ #  #  #  # ]:          0 :         TAILQ_FOREACH(cur, &cfg->head, next) {
     109   [ #  #  #  # ]:          0 :                 if (queue_equal(&cur->queue, q))
     110                 :            :                         return cur;
     111                 :            :         }
     112                 :            :         return NULL;
     113                 :            : }
     114                 :            : 
     115                 :            : static int
     116                 :          0 : queue_list_add(struct pmd_core_cfg *cfg, const union queue *q)
     117                 :            : {
     118                 :            :         struct queue_list_entry *qle;
     119                 :            : 
     120                 :            :         /* is it already in the list? */
     121         [ #  # ]:          0 :         if (queue_list_find(cfg, q) != NULL)
     122                 :            :                 return -EEXIST;
     123                 :            : 
     124                 :          0 :         qle = malloc(sizeof(*qle));
     125         [ #  # ]:          0 :         if (qle == NULL)
     126                 :            :                 return -ENOMEM;
     127                 :            :         memset(qle, 0, sizeof(*qle));
     128                 :            : 
     129                 :            :         queue_copy(&qle->queue, q);
     130                 :          0 :         TAILQ_INSERT_TAIL(&cfg->head, qle, next);
     131                 :          0 :         cfg->n_queues++;
     132                 :            : 
     133                 :          0 :         return 0;
     134                 :            : }
     135                 :            : 
     136                 :            : static struct queue_list_entry *
     137                 :          0 : queue_list_take(struct pmd_core_cfg *cfg, const union queue *q)
     138                 :            : {
     139                 :            :         struct queue_list_entry *found;
     140                 :            : 
     141                 :            :         found = queue_list_find(cfg, q);
     142         [ #  # ]:          0 :         if (found == NULL)
     143                 :            :                 return NULL;
     144                 :            : 
     145         [ #  # ]:          0 :         TAILQ_REMOVE(&cfg->head, found, next);
     146                 :          0 :         cfg->n_queues--;
     147                 :            : 
     148                 :            :         /* freeing is responsibility of the caller */
     149                 :          0 :         return found;
     150                 :            : }
     151                 :            : 
     152                 :            : static inline int
     153                 :          0 : get_monitor_addresses(struct pmd_core_cfg *cfg,
     154                 :            :                 struct rte_power_monitor_cond *pmc, size_t len)
     155                 :            : {
     156                 :            :         const struct queue_list_entry *qle;
     157                 :            :         size_t i = 0;
     158                 :            :         int ret;
     159                 :            : 
     160         [ #  # ]:          0 :         TAILQ_FOREACH(qle, &cfg->head, next) {
     161                 :            :                 const union queue *q = &qle->queue;
     162                 :            :                 struct rte_power_monitor_cond *cur;
     163                 :            : 
     164                 :            :                 /* attempted out of bounds access */
     165         [ #  # ]:          0 :                 if (i >= len) {
     166                 :          0 :                         POWER_LOG(ERR, "Too many queues being monitored");
     167                 :          0 :                         return -1;
     168                 :            :                 }
     169                 :            : 
     170                 :          0 :                 cur = &pmc[i++];
     171                 :          0 :                 ret = rte_eth_get_monitor_addr(q->portid, q->qid, cur);
     172         [ #  # ]:          0 :                 if (ret < 0)
     173                 :          0 :                         return ret;
     174                 :            :         }
     175                 :            :         return 0;
     176                 :            : }
     177                 :            : 
     178                 :            : static void
     179                 :          0 : calc_tsc(void)
     180                 :            : {
     181                 :            :         const uint64_t hz = rte_get_timer_hz();
     182                 :          0 :         const uint64_t tsc_per_us = hz / US_PER_S; /* 1us */
     183                 :            : 
     184                 :          0 :         global_data.tsc_per_us = tsc_per_us;
     185                 :            : 
     186                 :            :         /* only do this if we don't have tpause */
     187         [ #  # ]:          0 :         if (!global_data.intrinsics_support.power_pause) {
     188                 :            :                 const uint64_t start = rte_rdtsc_precise();
     189                 :            :                 const uint32_t n_pauses = 10000;
     190                 :            :                 double us, us_per_pause;
     191                 :            :                 uint64_t end;
     192                 :            :                 unsigned int i;
     193                 :            : 
     194                 :            :                 /* estimate number of rte_pause() calls per us*/
     195         [ #  # ]:          0 :                 for (i = 0; i < n_pauses; i++)
     196                 :            :                         rte_pause();
     197                 :            : 
     198                 :            :                 end = rte_rdtsc_precise();
     199                 :          0 :                 us = (end - start) / (double)tsc_per_us;
     200                 :          0 :                 us_per_pause = us / n_pauses;
     201                 :            : 
     202                 :          0 :                 global_data.pause_per_us = (uint64_t)(1.0 / us_per_pause);
     203                 :            :         }
     204                 :          0 : }
     205                 :            : 
     206                 :            : static inline void
     207                 :            : queue_reset(struct pmd_core_cfg *cfg, struct queue_list_entry *qcfg)
     208                 :            : {
     209                 :          0 :         const bool is_ready_to_sleep = qcfg->n_sleeps == cfg->sleep_target;
     210                 :            : 
     211                 :            :         /* reset empty poll counter for this queue */
     212                 :          0 :         qcfg->n_empty_polls = 0;
     213                 :            :         /* reset the queue sleep counter as well */
     214                 :          0 :         qcfg->n_sleeps = 0;
     215                 :            :         /* remove the queue from list of queues ready to sleep */
     216   [ #  #  #  #  :          0 :         if (is_ready_to_sleep)
                   #  # ]
     217                 :          0 :                 cfg->n_queues_ready_to_sleep--;
     218                 :            :         /*
     219                 :            :          * no need change the lcore sleep target counter because this lcore will
     220                 :            :          * reach the n_sleeps anyway, and the other cores are already counted so
     221                 :            :          * there's no need to do anything else.
     222                 :            :          */
     223                 :            : }
     224                 :            : 
     225                 :            : static inline bool
     226                 :            : queue_can_sleep(struct pmd_core_cfg *cfg, struct queue_list_entry *qcfg)
     227                 :            : {
     228                 :            :         /* this function is called - that means we have an empty poll */
     229                 :          0 :         qcfg->n_empty_polls++;
     230                 :            : 
     231                 :            :         /* if we haven't reached threshold for empty polls, we can't sleep */
     232   [ #  #  #  # ]:          0 :         if (qcfg->n_empty_polls <= emptypoll_max)
     233                 :            :                 return false;
     234                 :            : 
     235                 :            :         /*
     236                 :            :          * we've reached a point where we are able to sleep, but we still need
     237                 :            :          * to check if this queue has already been marked for sleeping.
     238                 :            :          */
     239   [ #  #  #  #  :          0 :         if (qcfg->n_sleeps == cfg->sleep_target)
                   #  # ]
     240                 :            :                 return true;
     241                 :            : 
     242                 :            :         /* mark this queue as ready for sleep */
     243                 :          0 :         qcfg->n_sleeps = cfg->sleep_target;
     244                 :          0 :         cfg->n_queues_ready_to_sleep++;
     245                 :            : 
     246                 :            :         return true;
     247                 :            : }
     248                 :            : 
     249                 :            : static inline bool
     250                 :            : lcore_can_sleep(struct pmd_core_cfg *cfg)
     251                 :            : {
     252                 :            :         /* are all queues ready to sleep? */
     253   [ #  #  #  #  :          0 :         if (cfg->n_queues_ready_to_sleep != cfg->n_queues)
                   #  # ]
     254                 :            :                 return false;
     255                 :            : 
     256                 :            :         /* we've reached an iteration where we can sleep, reset sleep counter */
     257                 :          0 :         cfg->n_queues_ready_to_sleep = 0;
     258                 :          0 :         cfg->sleep_target++;
     259                 :            :         /*
     260                 :            :          * we do not reset any individual queue empty poll counters, because
     261                 :            :          * we want to keep sleeping on every poll until we actually get traffic.
     262                 :            :          */
     263                 :            : 
     264                 :            :         return true;
     265                 :            : }
     266                 :            : 
     267                 :            : static uint16_t
     268                 :          0 : clb_multiwait(uint16_t port_id __rte_unused, uint16_t qidx __rte_unused,
     269                 :            :                 struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
     270                 :            :                 uint16_t max_pkts __rte_unused, void *arg)
     271                 :            : {
     272                 :            :         struct queue_list_entry *queue_conf = arg;
     273                 :            :         struct pmd_core_cfg *lcore_conf;
     274                 :            :         const bool empty = nb_rx == 0;
     275                 :            : 
     276         [ #  # ]:          0 :         lcore_conf = RTE_LCORE_VAR(lcore_cfgs);
     277                 :            : 
     278                 :            :         /* early exit */
     279         [ #  # ]:          0 :         if (likely(!empty))
     280                 :            :                 /* early exit */
     281                 :            :                 queue_reset(lcore_conf, queue_conf);
     282                 :          0 :         else {
     283         [ #  # ]:          0 :                 struct rte_power_monitor_cond pmc[lcore_conf->n_queues];
     284                 :            :                 int ret;
     285                 :            : 
     286                 :            :                 /* can this queue sleep? */
     287                 :            :                 if (!queue_can_sleep(lcore_conf, queue_conf))
     288                 :          0 :                         return nb_rx;
     289                 :            : 
     290                 :            :                 /* can this lcore sleep? */
     291                 :            :                 if (!lcore_can_sleep(lcore_conf))
     292                 :            :                         return nb_rx;
     293                 :            : 
     294                 :            :                 /* gather all monitoring conditions */
     295                 :          0 :                 ret = get_monitor_addresses(lcore_conf, pmc,
     296                 :            :                                 lcore_conf->n_queues);
     297         [ #  # ]:          0 :                 if (ret < 0)
     298                 :            :                         return nb_rx;
     299                 :            : 
     300                 :          0 :                 rte_power_monitor_multi(pmc, lcore_conf->n_queues, UINT64_MAX);
     301                 :            :         }
     302                 :            : 
     303                 :            :         return nb_rx;
     304                 :            : }
     305                 :            : 
     306                 :            : static uint16_t
     307                 :          0 : clb_umwait(uint16_t port_id, uint16_t qidx, struct rte_mbuf **pkts __rte_unused,
     308                 :            :                 uint16_t nb_rx, uint16_t max_pkts __rte_unused, void *arg)
     309                 :            : {
     310                 :            :         struct queue_list_entry *queue_conf = arg;
     311                 :            : 
     312                 :            :         /* this callback can't do more than one queue, omit multiqueue logic */
     313         [ #  # ]:          0 :         if (unlikely(nb_rx == 0)) {
     314                 :          0 :                 queue_conf->n_empty_polls++;
     315         [ #  # ]:          0 :                 if (unlikely(queue_conf->n_empty_polls > emptypoll_max)) {
     316                 :            :                         struct rte_power_monitor_cond pmc;
     317                 :            :                         int ret;
     318                 :            : 
     319                 :            :                         /* use monitoring condition to sleep */
     320                 :          0 :                         ret = rte_eth_get_monitor_addr(port_id, qidx,
     321                 :            :                                         &pmc);
     322         [ #  # ]:          0 :                         if (ret == 0)
     323                 :          0 :                                 rte_power_monitor(&pmc, UINT64_MAX);
     324                 :            :                 }
     325                 :            :         } else
     326                 :          0 :                 queue_conf->n_empty_polls = 0;
     327                 :            : 
     328                 :          0 :         return nb_rx;
     329                 :            : }
     330                 :            : 
     331                 :            : static uint16_t
     332                 :          0 : clb_pause(uint16_t port_id __rte_unused, uint16_t qidx __rte_unused,
     333                 :            :                 struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
     334                 :            :                 uint16_t max_pkts __rte_unused, void *arg)
     335                 :            : {
     336                 :            :         struct queue_list_entry *queue_conf = arg;
     337                 :            :         struct pmd_core_cfg *lcore_conf;
     338                 :            :         const bool empty = nb_rx == 0;
     339                 :          0 :         uint32_t pause_duration = rte_power_pmd_mgmt_get_pause_duration();
     340                 :            : 
     341         [ #  # ]:          0 :         lcore_conf = RTE_LCORE_VAR(lcore_cfgs);
     342                 :            : 
     343         [ #  # ]:          0 :         if (likely(!empty))
     344                 :            :                 /* early exit */
     345                 :            :                 queue_reset(lcore_conf, queue_conf);
     346                 :            :         else {
     347                 :            :                 /* can this queue sleep? */
     348                 :            :                 if (!queue_can_sleep(lcore_conf, queue_conf))
     349                 :            :                         return nb_rx;
     350                 :            : 
     351                 :            :                 /* can this lcore sleep? */
     352                 :            :                 if (!lcore_can_sleep(lcore_conf))
     353                 :            :                         return nb_rx;
     354                 :            : 
     355                 :            :                 /* sleep for 1 microsecond, use tpause if we have it */
     356         [ #  # ]:          0 :                 if (global_data.intrinsics_support.power_pause) {
     357                 :            :                         const uint64_t cur = rte_rdtsc();
     358                 :          0 :                         const uint64_t wait_tsc =
     359                 :          0 :                                         cur + global_data.tsc_per_us * pause_duration;
     360                 :          0 :                         rte_power_pause(wait_tsc);
     361                 :            :                 } else {
     362                 :            :                         uint64_t i;
     363         [ #  # ]:          0 :                         for (i = 0; i < global_data.pause_per_us * pause_duration; i++)
     364                 :            :                                 rte_pause();
     365                 :            :                 }
     366                 :            :         }
     367                 :            : 
     368                 :            :         return nb_rx;
     369                 :            : }
     370                 :            : 
     371                 :            : static uint16_t
     372                 :          0 : clb_scale_freq(uint16_t port_id __rte_unused, uint16_t qidx __rte_unused,
     373                 :            :                 struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
     374                 :            :                 uint16_t max_pkts __rte_unused, void *arg)
     375                 :            : {
     376                 :            :         const bool empty = nb_rx == 0;
     377         [ #  # ]:          0 :         struct pmd_core_cfg *lcore_conf = RTE_LCORE_VAR(lcore_cfgs);
     378                 :            :         struct queue_list_entry *queue_conf = arg;
     379                 :            : 
     380         [ #  # ]:          0 :         if (likely(!empty)) {
     381                 :            :                 /* early exit */
     382                 :            :                 queue_reset(lcore_conf, queue_conf);
     383                 :            : 
     384                 :            :                 /* scale up freq immediately */
     385                 :          0 :                 rte_power_freq_max(rte_lcore_id());
     386                 :            :         } else {
     387                 :            :                 /* can this queue sleep? */
     388                 :            :                 if (!queue_can_sleep(lcore_conf, queue_conf))
     389                 :            :                         return nb_rx;
     390                 :            : 
     391                 :            :                 /* can this lcore sleep? */
     392                 :            :                 if (!lcore_can_sleep(lcore_conf))
     393                 :            :                         return nb_rx;
     394                 :            : 
     395                 :          0 :                 rte_power_freq_min(rte_lcore_id());
     396                 :            :         }
     397                 :            : 
     398                 :            :         return nb_rx;
     399                 :            : }
     400                 :            : 
     401                 :            : static int
     402                 :            : queue_stopped(const uint16_t port_id, const uint16_t queue_id)
     403                 :            : {
     404                 :            :         struct rte_eth_rxq_info qinfo;
     405                 :            : 
     406                 :          0 :         int ret = rte_eth_rx_queue_info_get(port_id, queue_id, &qinfo);
     407   [ #  #  #  #  :          0 :         if (ret < 0) {
                   #  # ]
     408   [ #  #  #  #  :          0 :                 if (ret == -ENOTSUP)
                   #  # ]
     409                 :            :                         return 1;
     410                 :            :                 else
     411                 :            :                         return -1;
     412                 :            :         }
     413                 :            : 
     414                 :          0 :         return qinfo.queue_state == RTE_ETH_QUEUE_STATE_STOPPED;
     415                 :            : }
     416                 :            : 
     417                 :            : static int
     418                 :          0 : cfg_queues_stopped(struct pmd_core_cfg *queue_cfg)
     419                 :            : {
     420                 :            :         const struct queue_list_entry *entry;
     421                 :            : 
     422         [ #  # ]:          0 :         TAILQ_FOREACH(entry, &queue_cfg->head, next) {
     423                 :            :                 const union queue *q = &entry->queue;
     424                 :          0 :                 int ret = queue_stopped(q->portid, q->qid);
     425         [ #  # ]:          0 :                 if (ret != 1)
     426                 :          0 :                         return ret;
     427                 :            :         }
     428                 :            :         return 1;
     429                 :            : }
     430                 :            : 
     431                 :            : static int
     432                 :          0 : check_scale(unsigned int lcore)
     433                 :            : {
     434                 :            :         enum power_management_env env;
     435                 :            : 
     436                 :            :         /* only PSTATE, AMD-PSTATE, ACPI and CPPC modes are supported */
     437   [ #  #  #  # ]:          0 :         if (!rte_power_check_env_supported(PM_ENV_ACPI_CPUFREQ) &&
     438         [ #  # ]:          0 :                         !rte_power_check_env_supported(PM_ENV_PSTATE_CPUFREQ) &&
     439         [ #  # ]:          0 :                         !rte_power_check_env_supported(PM_ENV_AMD_PSTATE_CPUFREQ) &&
     440                 :          0 :                         !rte_power_check_env_supported(PM_ENV_CPPC_CPUFREQ)) {
     441                 :          0 :                 POWER_LOG(DEBUG, "Only ACPI, PSTATE, AMD-PSTATE, or CPPC modes are supported");
     442                 :          0 :                 return -ENOTSUP;
     443                 :            :         }
     444                 :            :         /* ensure we could initialize the power library */
     445         [ #  # ]:          0 :         if (rte_power_init(lcore))
     446                 :            :                 return -EINVAL;
     447                 :            : 
     448                 :            :         /* ensure we initialized the correct env */
     449                 :          0 :         env = rte_power_get_env();
     450         [ #  # ]:          0 :         if (env != PM_ENV_ACPI_CPUFREQ && env != PM_ENV_PSTATE_CPUFREQ &&
     451         [ #  # ]:          0 :                         env != PM_ENV_AMD_PSTATE_CPUFREQ && env != PM_ENV_CPPC_CPUFREQ) {
     452                 :          0 :                 POWER_LOG(DEBUG, "Unable to initialize ACPI, PSTATE, AMD-PSTATE, or CPPC modes");
     453                 :          0 :                 return -ENOTSUP;
     454                 :            :         }
     455                 :            : 
     456                 :            :         /* we're done */
     457                 :            :         return 0;
     458                 :            : }
     459                 :            : 
     460                 :            : static int
     461                 :          0 : check_monitor(struct pmd_core_cfg *cfg, const union queue *qdata)
     462                 :            : {
     463                 :            :         struct rte_power_monitor_cond dummy;
     464                 :            :         bool multimonitor_supported;
     465                 :            : 
     466                 :            :         /* check if rte_power_monitor is supported */
     467         [ #  # ]:          0 :         if (!global_data.intrinsics_support.power_monitor) {
     468                 :          0 :                 POWER_LOG(DEBUG, "Monitoring intrinsics are not supported");
     469                 :          0 :                 return -ENOTSUP;
     470                 :            :         }
     471                 :            :         /* check if multi-monitor is supported */
     472                 :            :         multimonitor_supported =
     473                 :          0 :                         global_data.intrinsics_support.power_monitor_multi;
     474                 :            : 
     475                 :            :         /* if we're adding a new queue, do we support multiple queues? */
     476   [ #  #  #  # ]:          0 :         if (cfg->n_queues > 0 && !multimonitor_supported) {
     477                 :          0 :                 POWER_LOG(DEBUG, "Monitoring multiple queues is not supported");
     478                 :          0 :                 return -ENOTSUP;
     479                 :            :         }
     480                 :            : 
     481                 :            :         /* check if the device supports the necessary PMD API */
     482         [ #  # ]:          0 :         if (rte_eth_get_monitor_addr(qdata->portid, qdata->qid,
     483                 :            :                         &dummy) == -ENOTSUP) {
     484                 :          0 :                 POWER_LOG(DEBUG, "The device does not support rte_eth_get_monitor_addr");
     485                 :          0 :                 return -ENOTSUP;
     486                 :            :         }
     487                 :            : 
     488                 :            :         /* we're done */
     489                 :            :         return 0;
     490                 :            : }
     491                 :            : 
     492                 :            : static inline rte_rx_callback_fn
     493                 :            : get_monitor_callback(void)
     494                 :            : {
     495                 :          0 :         return global_data.intrinsics_support.power_monitor_multi ?
     496         [ #  # ]:          0 :                 clb_multiwait : clb_umwait;
     497                 :            : }
     498                 :            : 
     499                 :            : int
     500                 :          0 : rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id, uint16_t port_id,
     501                 :            :                 uint16_t queue_id, enum rte_power_pmd_mgmt_type mode)
     502                 :            : {
     503                 :          0 :         const union queue qdata = {.portid = port_id, .qid = queue_id};
     504                 :            :         struct pmd_core_cfg *lcore_cfg;
     505                 :            :         struct queue_list_entry *queue_cfg;
     506                 :            :         struct rte_eth_dev_info info;
     507                 :            :         rte_rx_callback_fn clb;
     508                 :            :         int ret;
     509                 :            : 
     510         [ #  # ]:          0 :         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
     511                 :            : 
     512         [ #  # ]:          0 :         if (queue_id >= RTE_MAX_QUEUES_PER_PORT || lcore_id >= RTE_MAX_LCORE) {
     513                 :            :                 ret = -EINVAL;
     514                 :          0 :                 goto end;
     515                 :            :         }
     516                 :            : 
     517         [ #  # ]:          0 :         if (rte_eth_dev_info_get(port_id, &info) < 0) {
     518                 :            :                 ret = -EINVAL;
     519                 :          0 :                 goto end;
     520                 :            :         }
     521                 :            : 
     522                 :            :         /* check if queue id is valid */
     523         [ #  # ]:          0 :         if (queue_id >= info.nb_rx_queues) {
     524                 :            :                 ret = -EINVAL;
     525                 :          0 :                 goto end;
     526                 :            :         }
     527                 :            : 
     528                 :            :         /* check if the queue is stopped */
     529                 :          0 :         ret = queue_stopped(port_id, queue_id);
     530         [ #  # ]:          0 :         if (ret != 1) {
     531                 :            :                 /* error means invalid queue, 0 means queue wasn't stopped */
     532         [ #  # ]:          0 :                 ret = ret < 0 ? -EINVAL : -EBUSY;
     533                 :          0 :                 goto end;
     534                 :            :         }
     535                 :            : 
     536                 :          0 :         init_lcore_cfgs();
     537                 :          0 :         lcore_cfg = RTE_LCORE_VAR_LCORE(lcore_id, lcore_cfgs);
     538                 :            : 
     539                 :            :         /* check if other queues are stopped as well */
     540                 :          0 :         ret = cfg_queues_stopped(lcore_cfg);
     541         [ #  # ]:          0 :         if (ret != 1) {
     542                 :            :                 /* error means invalid queue, 0 means queue wasn't stopped */
     543         [ #  # ]:          0 :                 ret = ret < 0 ? -EINVAL : -EBUSY;
     544                 :          0 :                 goto end;
     545                 :            :         }
     546                 :            : 
     547                 :            :         /* if callback was already enabled, check current callback type */
     548         [ #  # ]:          0 :         if (lcore_cfg->pwr_mgmt_state != PMD_MGMT_DISABLED &&
     549         [ #  # ]:          0 :                         lcore_cfg->cb_mode != mode) {
     550                 :            :                 ret = -EINVAL;
     551                 :          0 :                 goto end;
     552                 :            :         }
     553                 :            : 
     554                 :            :         /* we need this in various places */
     555                 :          0 :         rte_cpu_get_intrinsics_support(&global_data.intrinsics_support);
     556                 :            : 
     557   [ #  #  #  # ]:          0 :         switch (mode) {
     558                 :          0 :         case RTE_POWER_MGMT_TYPE_MONITOR:
     559                 :            :                 /* check if we can add a new queue */
     560                 :          0 :                 ret = check_monitor(lcore_cfg, &qdata);
     561         [ #  # ]:          0 :                 if (ret < 0)
     562                 :          0 :                         goto end;
     563                 :            : 
     564                 :            :                 clb = get_monitor_callback();
     565                 :            :                 break;
     566                 :          0 :         case RTE_POWER_MGMT_TYPE_SCALE:
     567                 :            :                 clb = clb_scale_freq;
     568                 :            : 
     569                 :            :                 /* we only have to check this when enabling first queue */
     570         [ #  # ]:          0 :                 if (lcore_cfg->pwr_mgmt_state != PMD_MGMT_DISABLED)
     571                 :            :                         break;
     572                 :            :                 /* check if we can add a new queue */
     573                 :          0 :                 ret = check_scale(lcore_id);
     574         [ #  # ]:          0 :                 if (ret < 0)
     575                 :          0 :                         goto end;
     576                 :            :                 break;
     577                 :          0 :         case RTE_POWER_MGMT_TYPE_PAUSE:
     578                 :            :                 /* figure out various time-to-tsc conversions */
     579         [ #  # ]:          0 :                 if (global_data.tsc_per_us == 0)
     580                 :          0 :                         calc_tsc();
     581                 :            : 
     582                 :            :                 clb = clb_pause;
     583                 :            :                 break;
     584                 :          0 :         default:
     585                 :          0 :                 POWER_LOG(DEBUG, "Invalid power management type");
     586                 :            :                 ret = -EINVAL;
     587                 :          0 :                 goto end;
     588                 :            :         }
     589                 :            :         /* add this queue to the list */
     590                 :          0 :         ret = queue_list_add(lcore_cfg, &qdata);
     591         [ #  # ]:          0 :         if (ret < 0) {
     592                 :          0 :                 POWER_LOG(DEBUG, "Failed to add queue to list: %s",
     593                 :            :                                 strerror(-ret));
     594                 :          0 :                 goto end;
     595                 :            :         }
     596                 :            :         /* new queue is always added last */
     597                 :          0 :         queue_cfg = TAILQ_LAST(&lcore_cfg->head, queue_list_head);
     598                 :            : 
     599                 :            :         /* when enabling first queue, ensure sleep target is not 0 */
     600   [ #  #  #  # ]:          0 :         if (lcore_cfg->n_queues == 1 && lcore_cfg->sleep_target == 0)
     601                 :          0 :                 lcore_cfg->sleep_target = 1;
     602                 :            : 
     603                 :            :         /* initialize data before enabling the callback */
     604         [ #  # ]:          0 :         if (lcore_cfg->n_queues == 1) {
     605                 :          0 :                 lcore_cfg->cb_mode = mode;
     606                 :          0 :                 lcore_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
     607                 :            :         }
     608                 :          0 :         queue_cfg->cb = rte_eth_add_rx_callback(port_id, queue_id,
     609                 :            :                         clb, queue_cfg);
     610                 :            : 
     611                 :            :         ret = 0;
     612                 :            : end:
     613                 :            :         return ret;
     614                 :            : }
     615                 :            : 
     616                 :            : int
     617                 :          0 : rte_power_ethdev_pmgmt_queue_disable(unsigned int lcore_id,
     618                 :            :                 uint16_t port_id, uint16_t queue_id)
     619                 :            : {
     620                 :          0 :         const union queue qdata = {.portid = port_id, .qid = queue_id};
     621                 :            :         struct pmd_core_cfg *lcore_cfg;
     622                 :            :         struct queue_list_entry *queue_cfg;
     623                 :            :         int ret;
     624                 :            : 
     625         [ #  # ]:          0 :         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
     626                 :            : 
     627         [ #  # ]:          0 :         if (lcore_id >= RTE_MAX_LCORE || queue_id >= RTE_MAX_QUEUES_PER_PORT)
     628                 :            :                 return -EINVAL;
     629                 :            : 
     630                 :            :         /* check if the queue is stopped */
     631                 :          0 :         ret = queue_stopped(port_id, queue_id);
     632         [ #  # ]:          0 :         if (ret != 1) {
     633                 :            :                 /* error means invalid queue, 0 means queue wasn't stopped */
     634         [ #  # ]:          0 :                 return ret < 0 ? -EINVAL : -EBUSY;
     635                 :            :         }
     636                 :            : 
     637                 :            :         /* no need to check queue id as wrong queue id would not be enabled */
     638                 :            : 
     639                 :          0 :         init_lcore_cfgs();
     640                 :          0 :         lcore_cfg = RTE_LCORE_VAR_LCORE(lcore_id, lcore_cfgs);
     641                 :            : 
     642                 :            :         /* check if other queues are stopped as well */
     643                 :          0 :         ret = cfg_queues_stopped(lcore_cfg);
     644         [ #  # ]:          0 :         if (ret != 1) {
     645                 :            :                 /* error means invalid queue, 0 means queue wasn't stopped */
     646         [ #  # ]:          0 :                 return ret < 0 ? -EINVAL : -EBUSY;
     647                 :            :         }
     648                 :            : 
     649         [ #  # ]:          0 :         if (lcore_cfg->pwr_mgmt_state != PMD_MGMT_ENABLED)
     650                 :            :                 return -EINVAL;
     651                 :            : 
     652                 :            :         /*
     653                 :            :          * There is no good/easy way to do this without race conditions, so we
     654                 :            :          * are just going to throw our hands in the air and hope that the user
     655                 :            :          * has read the documentation and has ensured that ports are stopped at
     656                 :            :          * the time we enter the API functions.
     657                 :            :          */
     658                 :          0 :         queue_cfg = queue_list_take(lcore_cfg, &qdata);
     659         [ #  # ]:          0 :         if (queue_cfg == NULL)
     660                 :            :                 return -ENOENT;
     661                 :            : 
     662                 :            :         /* if we've removed all queues from the lists, set state to disabled */
     663         [ #  # ]:          0 :         if (lcore_cfg->n_queues == 0)
     664                 :          0 :                 lcore_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
     665                 :            : 
     666      [ #  #  # ]:          0 :         switch (lcore_cfg->cb_mode) {
     667                 :          0 :         case RTE_POWER_MGMT_TYPE_MONITOR: /* fall-through */
     668                 :            :         case RTE_POWER_MGMT_TYPE_PAUSE:
     669                 :          0 :                 rte_eth_remove_rx_callback(port_id, queue_id, queue_cfg->cb);
     670                 :          0 :                 break;
     671                 :          0 :         case RTE_POWER_MGMT_TYPE_SCALE:
     672                 :          0 :                 rte_eth_remove_rx_callback(port_id, queue_id, queue_cfg->cb);
     673                 :            :                 /* disable power library on this lcore if this was last queue */
     674         [ #  # ]:          0 :                 if (lcore_cfg->pwr_mgmt_state == PMD_MGMT_DISABLED) {
     675                 :          0 :                         rte_power_freq_max(lcore_id);
     676                 :          0 :                         rte_power_exit(lcore_id);
     677                 :            :                 }
     678                 :            :                 break;
     679                 :            :         }
     680                 :            :         /*
     681                 :            :          * the API doc mandates that the user stops all processing on affected
     682                 :            :          * ports before calling any of these API's, so we can assume that the
     683                 :            :          * callbacks can be freed. we're intentionally casting away const-ness.
     684                 :            :          */
     685                 :          0 :         rte_free((void *)(uintptr_t)queue_cfg->cb);
     686                 :          0 :         free(queue_cfg);
     687                 :            : 
     688                 :          0 :         return 0;
     689                 :            : }
     690                 :            : 
     691                 :            : void
     692                 :          0 : rte_power_pmd_mgmt_set_emptypoll_max(unsigned int max)
     693                 :            : {
     694                 :          0 :         emptypoll_max = max;
     695                 :          0 : }
     696                 :            : 
     697                 :            : unsigned int
     698                 :          0 : rte_power_pmd_mgmt_get_emptypoll_max(void)
     699                 :            : {
     700                 :          0 :         return emptypoll_max;
     701                 :            : }
     702                 :            : 
     703                 :            : int
     704                 :          0 : rte_power_pmd_mgmt_set_pause_duration(unsigned int duration)
     705                 :            : {
     706         [ #  # ]:          0 :         if (duration == 0) {
     707                 :          0 :                 POWER_LOG(ERR, "Pause duration must be greater than 0, value unchanged");
     708                 :          0 :                 return -EINVAL;
     709                 :            :         }
     710                 :          0 :         pause_duration = duration;
     711                 :            : 
     712                 :          0 :         return 0;
     713                 :            : }
     714                 :            : 
     715                 :            : unsigned int
     716                 :          0 : rte_power_pmd_mgmt_get_pause_duration(void)
     717                 :            : {
     718                 :          0 :         return pause_duration;
     719                 :            : }
     720                 :            : 
     721                 :            : int
     722                 :          0 : rte_power_pmd_mgmt_set_scaling_freq_min(unsigned int lcore, unsigned int min)
     723                 :            : {
     724         [ #  # ]:          0 :         if (lcore >= RTE_MAX_LCORE) {
     725                 :          0 :                 POWER_LOG(ERR, "Invalid lcore ID: %u", lcore);
     726                 :          0 :                 return -EINVAL;
     727                 :            :         }
     728                 :            : 
     729         [ #  # ]:          0 :         if (min > scale_freq_max[lcore]) {
     730                 :          0 :                 POWER_LOG(ERR, "Invalid min frequency: Cannot be greater than max frequency");
     731                 :          0 :                 return -EINVAL;
     732                 :            :         }
     733                 :          0 :         scale_freq_min[lcore] = min;
     734                 :            : 
     735                 :          0 :         return 0;
     736                 :            : }
     737                 :            : 
     738                 :            : int
     739                 :          0 : rte_power_pmd_mgmt_set_scaling_freq_max(unsigned int lcore, unsigned int max)
     740                 :            : {
     741         [ #  # ]:          0 :         if (lcore >= RTE_MAX_LCORE) {
     742                 :          0 :                 POWER_LOG(ERR, "Invalid lcore ID: %u", lcore);
     743                 :          0 :                 return -EINVAL;
     744                 :            :         }
     745                 :            : 
     746                 :            :         /* Zero means 'not set'. Use UINT32_MAX to enable RTE_MIN/MAX macro use when scaling. */
     747         [ #  # ]:          0 :         if (max == 0)
     748                 :            :                 max = UINT32_MAX;
     749         [ #  # ]:          0 :         if (max < scale_freq_min[lcore]) {
     750                 :          0 :                 POWER_LOG(ERR, "Invalid max frequency: Cannot be less than min frequency");
     751                 :          0 :                 return -EINVAL;
     752                 :            :         }
     753                 :            : 
     754                 :          0 :         scale_freq_max[lcore] = max;
     755                 :            : 
     756                 :          0 :         return 0;
     757                 :            : }
     758                 :            : 
     759                 :            : int
     760                 :          0 : rte_power_pmd_mgmt_get_scaling_freq_min(unsigned int lcore)
     761                 :            : {
     762         [ #  # ]:          0 :         if (lcore >= RTE_MAX_LCORE) {
     763                 :          0 :                 POWER_LOG(ERR, "Invalid lcore ID: %u", lcore);
     764                 :          0 :                 return -EINVAL;
     765                 :            :         }
     766                 :            : 
     767         [ #  # ]:          0 :         if (scale_freq_max[lcore] == 0)
     768                 :          0 :                 POWER_LOG(DEBUG, "Scaling freq min config not set. Using sysfs min freq.");
     769                 :            : 
     770                 :          0 :         return scale_freq_min[lcore];
     771                 :            : }
     772                 :            : 
     773                 :            : int
     774                 :          0 : rte_power_pmd_mgmt_get_scaling_freq_max(unsigned int lcore)
     775                 :            : {
     776         [ #  # ]:          0 :         if (lcore >= RTE_MAX_LCORE) {
     777                 :          0 :                 POWER_LOG(ERR, "Invalid lcore ID: %u", lcore);
     778                 :          0 :                 return -EINVAL;
     779                 :            :         }
     780                 :            : 
     781         [ #  # ]:          0 :         if (scale_freq_max[lcore] == UINT32_MAX) {
     782                 :          0 :                 POWER_LOG(DEBUG, "Scaling freq max config not set. Using sysfs max freq.");
     783                 :          0 :                 return 0;
     784                 :            :         }
     785                 :            : 
     786                 :          0 :         return scale_freq_max[lcore];
     787                 :            : }
     788                 :            : 
     789                 :        252 : RTE_INIT(rte_power_ethdev_pmgmt_init) {
     790                 :            :         int i;
     791                 :            : 
     792                 :            :         /* initialize config defaults */
     793                 :        252 :         emptypoll_max = 512;
     794                 :        252 :         pause_duration = 1;
     795                 :            :         /* scaling defaults out of range to ensure not used unless set by user or app */
     796         [ +  + ]:      32508 :         for (i = 0; i < RTE_MAX_LCORE; i++) {
     797                 :      32256 :                 scale_freq_min[i] = 0;
     798                 :      32256 :                 scale_freq_max[i] = UINT32_MAX;
     799                 :            :         }
     800                 :        252 : }

Generated by: LCOV version 1.14