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

Generated by: LCOV version 1.14