30772791afc4d4f023460f0f90b5345877a147df
[dpdk.git] / lib / power / rte_power_pmd_mgmt.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4
5 #include <rte_lcore.h>
6 #include <rte_cycles.h>
7 #include <rte_cpuflags.h>
8 #include <rte_malloc.h>
9 #include <rte_ethdev.h>
10 #include <rte_power_intrinsics.h>
11
12 #include "rte_power_pmd_mgmt.h"
13
14 #define EMPTYPOLL_MAX  512
15
16 /* store some internal state */
17 static struct pmd_conf_data {
18         /** what do we support? */
19         struct rte_cpu_intrinsics intrinsics_support;
20         /** pre-calculated tsc diff for 1us */
21         uint64_t tsc_per_us;
22         /** how many rte_pause can we fit in a microsecond? */
23         uint64_t pause_per_us;
24 } global_data;
25
26 /**
27  * Possible power management states of an ethdev port.
28  */
29 enum pmd_mgmt_state {
30         /** Device power management is disabled. */
31         PMD_MGMT_DISABLED = 0,
32         /** Device power management is enabled. */
33         PMD_MGMT_ENABLED
34 };
35
36 union queue {
37         uint32_t val;
38         struct {
39                 uint16_t portid;
40                 uint16_t qid;
41         };
42 };
43
44 struct queue_list_entry {
45         TAILQ_ENTRY(queue_list_entry) next;
46         union queue queue;
47         uint64_t n_empty_polls;
48         uint64_t n_sleeps;
49         const struct rte_eth_rxtx_callback *cb;
50 };
51
52 struct pmd_core_cfg {
53         TAILQ_HEAD(queue_list_head, queue_list_entry) head;
54         /**< List of queues associated with this lcore */
55         size_t n_queues;
56         /**< How many queues are in the list? */
57         volatile enum pmd_mgmt_state pwr_mgmt_state;
58         /**< State of power management for this queue */
59         enum rte_power_pmd_mgmt_type cb_mode;
60         /**< Callback mode for this queue */
61         uint64_t n_queues_ready_to_sleep;
62         /**< Number of queues ready to enter power optimized state */
63         uint64_t sleep_target;
64         /**< Prevent a queue from triggering sleep multiple times */
65 } __rte_cache_aligned;
66 static struct pmd_core_cfg lcore_cfgs[RTE_MAX_LCORE];
67
68 static inline bool
69 queue_equal(const union queue *l, const union queue *r)
70 {
71         return l->val == r->val;
72 }
73
74 static inline void
75 queue_copy(union queue *dst, const union queue *src)
76 {
77         dst->val = src->val;
78 }
79
80 static struct queue_list_entry *
81 queue_list_find(const struct pmd_core_cfg *cfg, const union queue *q)
82 {
83         struct queue_list_entry *cur;
84
85         TAILQ_FOREACH(cur, &cfg->head, next) {
86                 if (queue_equal(&cur->queue, q))
87                         return cur;
88         }
89         return NULL;
90 }
91
92 static int
93 queue_list_add(struct pmd_core_cfg *cfg, const union queue *q)
94 {
95         struct queue_list_entry *qle;
96
97         /* is it already in the list? */
98         if (queue_list_find(cfg, q) != NULL)
99                 return -EEXIST;
100
101         qle = malloc(sizeof(*qle));
102         if (qle == NULL)
103                 return -ENOMEM;
104         memset(qle, 0, sizeof(*qle));
105
106         queue_copy(&qle->queue, q);
107         TAILQ_INSERT_TAIL(&cfg->head, qle, next);
108         cfg->n_queues++;
109
110         return 0;
111 }
112
113 static struct queue_list_entry *
114 queue_list_take(struct pmd_core_cfg *cfg, const union queue *q)
115 {
116         struct queue_list_entry *found;
117
118         found = queue_list_find(cfg, q);
119         if (found == NULL)
120                 return NULL;
121
122         TAILQ_REMOVE(&cfg->head, found, next);
123         cfg->n_queues--;
124
125         /* freeing is responsibility of the caller */
126         return found;
127 }
128
129 static void
130 calc_tsc(void)
131 {
132         const uint64_t hz = rte_get_timer_hz();
133         const uint64_t tsc_per_us = hz / US_PER_S; /* 1us */
134
135         global_data.tsc_per_us = tsc_per_us;
136
137         /* only do this if we don't have tpause */
138         if (!global_data.intrinsics_support.power_pause) {
139                 const uint64_t start = rte_rdtsc_precise();
140                 const uint32_t n_pauses = 10000;
141                 double us, us_per_pause;
142                 uint64_t end;
143                 unsigned int i;
144
145                 /* estimate number of rte_pause() calls per us*/
146                 for (i = 0; i < n_pauses; i++)
147                         rte_pause();
148
149                 end = rte_rdtsc_precise();
150                 us = (end - start) / (double)tsc_per_us;
151                 us_per_pause = us / n_pauses;
152
153                 global_data.pause_per_us = (uint64_t)(1.0 / us_per_pause);
154         }
155 }
156
157 static inline void
158 queue_reset(struct pmd_core_cfg *cfg, struct queue_list_entry *qcfg)
159 {
160         const bool is_ready_to_sleep = qcfg->n_sleeps == cfg->sleep_target;
161
162         /* reset empty poll counter for this queue */
163         qcfg->n_empty_polls = 0;
164         /* reset the queue sleep counter as well */
165         qcfg->n_sleeps = 0;
166         /* remove the queue from list of queues ready to sleep */
167         if (is_ready_to_sleep)
168                 cfg->n_queues_ready_to_sleep--;
169         /*
170          * no need change the lcore sleep target counter because this lcore will
171          * reach the n_sleeps anyway, and the other cores are already counted so
172          * there's no need to do anything else.
173          */
174 }
175
176 static inline bool
177 queue_can_sleep(struct pmd_core_cfg *cfg, struct queue_list_entry *qcfg)
178 {
179         /* this function is called - that means we have an empty poll */
180         qcfg->n_empty_polls++;
181
182         /* if we haven't reached threshold for empty polls, we can't sleep */
183         if (qcfg->n_empty_polls <= EMPTYPOLL_MAX)
184                 return false;
185
186         /*
187          * we've reached a point where we are able to sleep, but we still need
188          * to check if this queue has already been marked for sleeping.
189          */
190         if (qcfg->n_sleeps == cfg->sleep_target)
191                 return true;
192
193         /* mark this queue as ready for sleep */
194         qcfg->n_sleeps = cfg->sleep_target;
195         cfg->n_queues_ready_to_sleep++;
196
197         return true;
198 }
199
200 static inline bool
201 lcore_can_sleep(struct pmd_core_cfg *cfg)
202 {
203         /* are all queues ready to sleep? */
204         if (cfg->n_queues_ready_to_sleep != cfg->n_queues)
205                 return false;
206
207         /* we've reached an iteration where we can sleep, reset sleep counter */
208         cfg->n_queues_ready_to_sleep = 0;
209         cfg->sleep_target++;
210         /*
211          * we do not reset any individual queue empty poll counters, because
212          * we want to keep sleeping on every poll until we actually get traffic.
213          */
214
215         return true;
216 }
217
218 static uint16_t
219 clb_umwait(uint16_t port_id, uint16_t qidx, struct rte_mbuf **pkts __rte_unused,
220                 uint16_t nb_rx, uint16_t max_pkts __rte_unused, void *arg)
221 {
222         struct queue_list_entry *queue_conf = arg;
223
224         /* this callback can't do more than one queue, omit multiqueue logic */
225         if (unlikely(nb_rx == 0)) {
226                 queue_conf->n_empty_polls++;
227                 if (unlikely(queue_conf->n_empty_polls > EMPTYPOLL_MAX)) {
228                         struct rte_power_monitor_cond pmc;
229                         int ret;
230
231                         /* use monitoring condition to sleep */
232                         ret = rte_eth_get_monitor_addr(port_id, qidx,
233                                         &pmc);
234                         if (ret == 0)
235                                 rte_power_monitor(&pmc, UINT64_MAX);
236                 }
237         } else
238                 queue_conf->n_empty_polls = 0;
239
240         return nb_rx;
241 }
242
243 static uint16_t
244 clb_pause(uint16_t port_id __rte_unused, uint16_t qidx __rte_unused,
245                 struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
246                 uint16_t max_pkts __rte_unused, void *arg)
247 {
248         const unsigned int lcore = rte_lcore_id();
249         struct queue_list_entry *queue_conf = arg;
250         struct pmd_core_cfg *lcore_conf;
251         const bool empty = nb_rx == 0;
252
253         lcore_conf = &lcore_cfgs[lcore];
254
255         if (likely(!empty))
256                 /* early exit */
257                 queue_reset(lcore_conf, queue_conf);
258         else {
259                 /* can this queue sleep? */
260                 if (!queue_can_sleep(lcore_conf, queue_conf))
261                         return nb_rx;
262
263                 /* can this lcore sleep? */
264                 if (!lcore_can_sleep(lcore_conf))
265                         return nb_rx;
266
267                 /* sleep for 1 microsecond, use tpause if we have it */
268                 if (global_data.intrinsics_support.power_pause) {
269                         const uint64_t cur = rte_rdtsc();
270                         const uint64_t wait_tsc =
271                                         cur + global_data.tsc_per_us;
272                         rte_power_pause(wait_tsc);
273                 } else {
274                         uint64_t i;
275                         for (i = 0; i < global_data.pause_per_us; i++)
276                                 rte_pause();
277                 }
278         }
279
280         return nb_rx;
281 }
282
283 static uint16_t
284 clb_scale_freq(uint16_t port_id __rte_unused, uint16_t qidx __rte_unused,
285                 struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
286                 uint16_t max_pkts __rte_unused, void *arg)
287 {
288         const unsigned int lcore = rte_lcore_id();
289         const bool empty = nb_rx == 0;
290         struct pmd_core_cfg *lcore_conf = &lcore_cfgs[lcore];
291         struct queue_list_entry *queue_conf = arg;
292
293         if (likely(!empty)) {
294                 /* early exit */
295                 queue_reset(lcore_conf, queue_conf);
296
297                 /* scale up freq immediately */
298                 rte_power_freq_max(rte_lcore_id());
299         } else {
300                 /* can this queue sleep? */
301                 if (!queue_can_sleep(lcore_conf, queue_conf))
302                         return nb_rx;
303
304                 /* can this lcore sleep? */
305                 if (!lcore_can_sleep(lcore_conf))
306                         return nb_rx;
307
308                 rte_power_freq_min(rte_lcore_id());
309         }
310
311         return nb_rx;
312 }
313
314 static int
315 queue_stopped(const uint16_t port_id, const uint16_t queue_id)
316 {
317         struct rte_eth_rxq_info qinfo;
318
319         if (rte_eth_rx_queue_info_get(port_id, queue_id, &qinfo) < 0)
320                 return -1;
321
322         return qinfo.queue_state == RTE_ETH_QUEUE_STATE_STOPPED;
323 }
324
325 static int
326 cfg_queues_stopped(struct pmd_core_cfg *queue_cfg)
327 {
328         const struct queue_list_entry *entry;
329
330         TAILQ_FOREACH(entry, &queue_cfg->head, next) {
331                 const union queue *q = &entry->queue;
332                 int ret = queue_stopped(q->portid, q->qid);
333                 if (ret != 1)
334                         return ret;
335         }
336         return 1;
337 }
338
339 static int
340 check_scale(unsigned int lcore)
341 {
342         enum power_management_env env;
343
344         /* only PSTATE and ACPI modes are supported */
345         if (!rte_power_check_env_supported(PM_ENV_ACPI_CPUFREQ) &&
346             !rte_power_check_env_supported(PM_ENV_PSTATE_CPUFREQ)) {
347                 RTE_LOG(DEBUG, POWER, "Neither ACPI nor PSTATE modes are supported\n");
348                 return -ENOTSUP;
349         }
350         /* ensure we could initialize the power library */
351         if (rte_power_init(lcore))
352                 return -EINVAL;
353
354         /* ensure we initialized the correct env */
355         env = rte_power_get_env();
356         if (env != PM_ENV_ACPI_CPUFREQ && env != PM_ENV_PSTATE_CPUFREQ) {
357                 RTE_LOG(DEBUG, POWER, "Neither ACPI nor PSTATE modes were initialized\n");
358                 return -ENOTSUP;
359         }
360
361         /* we're done */
362         return 0;
363 }
364
365 static int
366 check_monitor(struct pmd_core_cfg *cfg, const union queue *qdata)
367 {
368         struct rte_power_monitor_cond dummy;
369
370         /* check if rte_power_monitor is supported */
371         if (!global_data.intrinsics_support.power_monitor) {
372                 RTE_LOG(DEBUG, POWER, "Monitoring intrinsics are not supported\n");
373                 return -ENOTSUP;
374         }
375
376         if (cfg->n_queues > 0) {
377                 RTE_LOG(DEBUG, POWER, "Monitoring multiple queues is not supported\n");
378                 return -ENOTSUP;
379         }
380
381         /* check if the device supports the necessary PMD API */
382         if (rte_eth_get_monitor_addr(qdata->portid, qdata->qid,
383                         &dummy) == -ENOTSUP) {
384                 RTE_LOG(DEBUG, POWER, "The device does not support rte_eth_get_monitor_addr\n");
385                 return -ENOTSUP;
386         }
387
388         /* we're done */
389         return 0;
390 }
391
392 int
393 rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id, uint16_t port_id,
394                 uint16_t queue_id, enum rte_power_pmd_mgmt_type mode)
395 {
396         const union queue qdata = {.portid = port_id, .qid = queue_id};
397         struct pmd_core_cfg *lcore_cfg;
398         struct queue_list_entry *queue_cfg;
399         struct rte_eth_dev_info info;
400         rte_rx_callback_fn clb;
401         int ret;
402
403         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
404
405         if (queue_id >= RTE_MAX_QUEUES_PER_PORT || lcore_id >= RTE_MAX_LCORE) {
406                 ret = -EINVAL;
407                 goto end;
408         }
409
410         if (rte_eth_dev_info_get(port_id, &info) < 0) {
411                 ret = -EINVAL;
412                 goto end;
413         }
414
415         /* check if queue id is valid */
416         if (queue_id >= info.nb_rx_queues) {
417                 ret = -EINVAL;
418                 goto end;
419         }
420
421         /* check if the queue is stopped */
422         ret = queue_stopped(port_id, queue_id);
423         if (ret != 1) {
424                 /* error means invalid queue, 0 means queue wasn't stopped */
425                 ret = ret < 0 ? -EINVAL : -EBUSY;
426                 goto end;
427         }
428
429         lcore_cfg = &lcore_cfgs[lcore_id];
430
431         /* check if other queues are stopped as well */
432         ret = cfg_queues_stopped(lcore_cfg);
433         if (ret != 1) {
434                 /* error means invalid queue, 0 means queue wasn't stopped */
435                 ret = ret < 0 ? -EINVAL : -EBUSY;
436                 goto end;
437         }
438
439         /* if callback was already enabled, check current callback type */
440         if (lcore_cfg->pwr_mgmt_state != PMD_MGMT_DISABLED &&
441                         lcore_cfg->cb_mode != mode) {
442                 ret = -EINVAL;
443                 goto end;
444         }
445
446         /* we need this in various places */
447         rte_cpu_get_intrinsics_support(&global_data.intrinsics_support);
448
449         switch (mode) {
450         case RTE_POWER_MGMT_TYPE_MONITOR:
451                 /* check if we can add a new queue */
452                 ret = check_monitor(lcore_cfg, &qdata);
453                 if (ret < 0)
454                         goto end;
455
456                 clb = clb_umwait;
457                 break;
458         case RTE_POWER_MGMT_TYPE_SCALE:
459                 /* check if we can add a new queue */
460                 ret = check_scale(lcore_id);
461                 if (ret < 0)
462                         goto end;
463                 clb = clb_scale_freq;
464                 break;
465         case RTE_POWER_MGMT_TYPE_PAUSE:
466                 /* figure out various time-to-tsc conversions */
467                 if (global_data.tsc_per_us == 0)
468                         calc_tsc();
469
470                 clb = clb_pause;
471                 break;
472         default:
473                 RTE_LOG(DEBUG, POWER, "Invalid power management type\n");
474                 ret = -EINVAL;
475                 goto end;
476         }
477         /* add this queue to the list */
478         ret = queue_list_add(lcore_cfg, &qdata);
479         if (ret < 0) {
480                 RTE_LOG(DEBUG, POWER, "Failed to add queue to list: %s\n",
481                                 strerror(-ret));
482                 goto end;
483         }
484         /* new queue is always added last */
485         queue_cfg = TAILQ_LAST(&lcore_cfg->head, queue_list_head);
486
487         /* when enabling first queue, ensure sleep target is not 0 */
488         if (lcore_cfg->n_queues == 1 && lcore_cfg->sleep_target == 0)
489                 lcore_cfg->sleep_target = 1;
490
491         /* initialize data before enabling the callback */
492         if (lcore_cfg->n_queues == 1) {
493                 lcore_cfg->cb_mode = mode;
494                 lcore_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
495         }
496         queue_cfg->cb = rte_eth_add_rx_callback(port_id, queue_id,
497                         clb, queue_cfg);
498
499         ret = 0;
500 end:
501         return ret;
502 }
503
504 int
505 rte_power_ethdev_pmgmt_queue_disable(unsigned int lcore_id,
506                 uint16_t port_id, uint16_t queue_id)
507 {
508         const union queue qdata = {.portid = port_id, .qid = queue_id};
509         struct pmd_core_cfg *lcore_cfg;
510         struct queue_list_entry *queue_cfg;
511         int ret;
512
513         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
514
515         if (lcore_id >= RTE_MAX_LCORE || queue_id >= RTE_MAX_QUEUES_PER_PORT)
516                 return -EINVAL;
517
518         /* check if the queue is stopped */
519         ret = queue_stopped(port_id, queue_id);
520         if (ret != 1) {
521                 /* error means invalid queue, 0 means queue wasn't stopped */
522                 return ret < 0 ? -EINVAL : -EBUSY;
523         }
524
525         /* no need to check queue id as wrong queue id would not be enabled */
526         lcore_cfg = &lcore_cfgs[lcore_id];
527
528         /* check if other queues are stopped as well */
529         ret = cfg_queues_stopped(lcore_cfg);
530         if (ret != 1) {
531                 /* error means invalid queue, 0 means queue wasn't stopped */
532                 return ret < 0 ? -EINVAL : -EBUSY;
533         }
534
535         if (lcore_cfg->pwr_mgmt_state != PMD_MGMT_ENABLED)
536                 return -EINVAL;
537
538         /*
539          * There is no good/easy way to do this without race conditions, so we
540          * are just going to throw our hands in the air and hope that the user
541          * has read the documentation and has ensured that ports are stopped at
542          * the time we enter the API functions.
543          */
544         queue_cfg = queue_list_take(lcore_cfg, &qdata);
545         if (queue_cfg == NULL)
546                 return -ENOENT;
547
548         /* if we've removed all queues from the lists, set state to disabled */
549         if (lcore_cfg->n_queues == 0)
550                 lcore_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
551
552         switch (lcore_cfg->cb_mode) {
553         case RTE_POWER_MGMT_TYPE_MONITOR: /* fall-through */
554         case RTE_POWER_MGMT_TYPE_PAUSE:
555                 rte_eth_remove_rx_callback(port_id, queue_id, queue_cfg->cb);
556                 break;
557         case RTE_POWER_MGMT_TYPE_SCALE:
558                 rte_power_freq_max(lcore_id);
559                 rte_eth_remove_rx_callback(port_id, queue_id, queue_cfg->cb);
560                 rte_power_exit(lcore_id);
561                 break;
562         }
563         /*
564          * the API doc mandates that the user stops all processing on affected
565          * ports before calling any of these API's, so we can assume that the
566          * callbacks can be freed. we're intentionally casting away const-ness.
567          */
568         rte_free((void *)queue_cfg->cb);
569         free(queue_cfg);
570
571         return 0;
572 }
573
574 RTE_INIT(rte_power_ethdev_pmgmt_init) {
575         size_t i;
576
577         /* initialize all tailqs */
578         for (i = 0; i < RTE_DIM(lcore_cfgs); i++) {
579                 struct pmd_core_cfg *cfg = &lcore_cfgs[i];
580                 TAILQ_INIT(&cfg->head);
581         }
582 }