net/sfc: optimize getting number of SW stats
[dpdk.git] / drivers / net / sfc / sfc_sw_stats.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2021 Xilinx, Inc.
4  */
5 #include <rte_dev.h>
6 #include <rte_bitmap.h>
7
8 #include "sfc.h"
9 #include "sfc_rx.h"
10 #include "sfc_tx.h"
11 #include "sfc_sw_stats.h"
12
13 enum sfc_sw_stats_type {
14         SFC_SW_STATS_RX,
15         SFC_SW_STATS_TX,
16 };
17
18 typedef uint64_t sfc_get_sw_stat_val_t(struct sfc_adapter *sa, uint16_t qid);
19
20 struct sfc_sw_stat_descr {
21         const char *name;
22         enum sfc_sw_stats_type type;
23         sfc_get_sw_stat_val_t *get_val;
24 };
25
26 static sfc_get_sw_stat_val_t sfc_get_sw_stat_val_rx_dbells;
27 static uint64_t
28 sfc_get_sw_stat_val_rx_dbells(struct sfc_adapter *sa, uint16_t qid)
29 {
30         struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
31         struct sfc_rxq_info *rxq_info;
32
33         rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid);
34         if (rxq_info->state & SFC_RXQ_INITIALIZED)
35                 return rxq_info->dp->dpq.rx_dbells;
36         return 0;
37 }
38
39 static sfc_get_sw_stat_val_t sfc_get_sw_stat_val_tx_dbells;
40 static uint64_t
41 sfc_get_sw_stat_val_tx_dbells(struct sfc_adapter *sa, uint16_t qid)
42 {
43         struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
44         struct sfc_txq_info *txq_info;
45
46         txq_info = sfc_txq_info_by_ethdev_qid(sas, qid);
47         if (txq_info->state & SFC_TXQ_INITIALIZED)
48                 return txq_info->dp->dpq.tx_dbells;
49         return 0;
50 }
51
52 const struct sfc_sw_stat_descr sfc_sw_stats_descr[] = {
53         {
54                 .name = "dbells",
55                 .type = SFC_SW_STATS_RX,
56                 .get_val  = sfc_get_sw_stat_val_rx_dbells,
57         },
58         {
59                 .name = "dbells",
60                 .type = SFC_SW_STATS_TX,
61                 .get_val  = sfc_get_sw_stat_val_tx_dbells,
62         }
63 };
64
65 static int
66 sfc_sw_stat_get_name(struct sfc_adapter *sa,
67                      const struct sfc_sw_stat_descr *sw_stat, char *name,
68                      size_t name_size, unsigned int id_off)
69 {
70         const char *prefix;
71         int ret;
72
73         switch (sw_stat->type) {
74         case SFC_SW_STATS_RX:
75                 prefix = "rx";
76                 break;
77         case SFC_SW_STATS_TX:
78                 prefix = "tx";
79                 break;
80         default:
81                 sfc_err(sa, "%s: unknown software statistics type %d",
82                         __func__, sw_stat->type);
83                 return -EINVAL;
84         }
85
86         if (id_off == 0) {
87                 ret = snprintf(name, name_size, "%s_%s", prefix,
88                                                          sw_stat->name);
89                 if (ret < 0 || ret >= (int)name_size) {
90                         sfc_err(sa, "%s: failed to fill xstat name %s_%s, err %d",
91                                 __func__, prefix, sw_stat->name, ret);
92                         return ret > 0 ? -EINVAL : ret;
93                 }
94         } else {
95                 uint16_t qid = id_off - 1;
96                 ret = snprintf(name, name_size, "%s_q%u_%s", prefix, qid,
97                                                         sw_stat->name);
98                 if (ret < 0 || ret >= (int)name_size) {
99                         sfc_err(sa, "%s: failed to fill xstat name %s_q%u_%s, err %d",
100                                 __func__, prefix, qid, sw_stat->name, ret);
101                         return ret > 0 ? -EINVAL : ret;
102                 }
103         }
104
105         return 0;
106 }
107
108 static unsigned int
109 sfc_sw_stat_get_queue_count(struct sfc_adapter *sa,
110                             const struct sfc_sw_stat_descr *sw_stat)
111 {
112         struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
113
114         switch (sw_stat->type) {
115         case SFC_SW_STATS_RX:
116                 return sas->ethdev_rxq_count;
117         case SFC_SW_STATS_TX:
118                 return sas->ethdev_txq_count;
119         default:
120                 sfc_err(sa, "%s: unknown software statistics type %d",
121                         __func__, sw_stat->type);
122                 return 0;
123         }
124 }
125
126 static unsigned int
127 sfc_sw_xstat_per_queue_get_count(unsigned int nb_queues)
128 {
129         /* Take into account the total xstat of all queues */
130         return nb_queues > 0 ? 1 + nb_queues : 0;
131 }
132
133 static unsigned int
134 sfc_sw_xstat_get_nb_supported(struct sfc_adapter *sa,
135                               const struct sfc_sw_stat_descr *sw_stat)
136 {
137         unsigned int nb_queues;
138
139         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
140         return sfc_sw_xstat_per_queue_get_count(nb_queues);
141 }
142
143 static int
144 sfc_sw_stat_get_names(struct sfc_adapter *sa,
145                       const struct sfc_sw_stat_descr *sw_stat,
146                       struct rte_eth_xstat_name *xstats_names,
147                       unsigned int xstats_names_sz,
148                       unsigned int *nb_written,
149                       unsigned int *nb_supported)
150 {
151         const size_t name_size = sizeof(xstats_names[0].name);
152         unsigned int id_base = *nb_supported;
153         unsigned int nb_queues;
154         unsigned int qid;
155         int rc;
156
157         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
158         if (nb_queues == 0)
159                 return 0;
160         *nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
161
162         /*
163          * The order of each software xstat type is the total xstat
164          * followed by per-queue xstats.
165          */
166         if (*nb_written < xstats_names_sz) {
167                 rc = sfc_sw_stat_get_name(sa, sw_stat,
168                                           xstats_names[*nb_written].name,
169                                           name_size, *nb_written - id_base);
170                 if (rc != 0)
171                         return rc;
172                 (*nb_written)++;
173         }
174
175         for (qid = 0; qid < nb_queues; ++qid) {
176                 if (*nb_written < xstats_names_sz) {
177                         rc = sfc_sw_stat_get_name(sa, sw_stat,
178                                               xstats_names[*nb_written].name,
179                                               name_size, *nb_written - id_base);
180                         if (rc != 0)
181                                 return rc;
182                         (*nb_written)++;
183                 }
184         }
185
186         return 0;
187 }
188
189 static int
190 sfc_sw_xstat_get_names_by_id(struct sfc_adapter *sa,
191                              const struct sfc_sw_stat_descr *sw_stat,
192                              const uint64_t *ids,
193                              struct rte_eth_xstat_name *xstats_names,
194                              unsigned int size,
195                              unsigned int *nb_supported)
196 {
197         const size_t name_size = sizeof(xstats_names[0].name);
198         unsigned int id_base = *nb_supported;
199         unsigned int nb_queues;
200         unsigned int i;
201         int rc;
202
203         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
204         if (nb_queues == 0)
205                 return 0;
206         *nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
207
208         /*
209          * The order of each software xstat type is the total xstat
210          * followed by per-queue xstats.
211          */
212         for (i = 0; i < size; i++) {
213                 if (id_base <= ids[i] && ids[i] <= id_base + nb_queues) {
214                         rc = sfc_sw_stat_get_name(sa, sw_stat,
215                                                   xstats_names[i].name,
216                                                   name_size, ids[i] - id_base);
217                         if (rc != 0)
218                                 return rc;
219                 }
220         }
221
222         return 0;
223 }
224
225 static void
226 sfc_sw_xstat_get_values(struct sfc_adapter *sa,
227                         const struct sfc_sw_stat_descr *sw_stat,
228                         struct rte_eth_xstat *xstats,
229                         unsigned int xstats_size,
230                         unsigned int *nb_written,
231                         unsigned int *nb_supported)
232 {
233         unsigned int qid;
234         uint64_t value;
235         struct rte_eth_xstat *total_xstat;
236         bool count_total_value = false;
237         unsigned int nb_queues;
238
239         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
240         if (nb_queues == 0)
241                 return;
242         *nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
243
244         /*
245          * The order of each software xstat type is the total xstat
246          * followed by per-queue xstats.
247          */
248         if (*nb_written < xstats_size) {
249                 count_total_value = true;
250                 total_xstat = &xstats[*nb_written];
251                 xstats[*nb_written].id = *nb_written;
252                 xstats[*nb_written].value = 0;
253                 (*nb_written)++;
254         }
255
256         for (qid = 0; qid < nb_queues; ++qid) {
257                 value = sw_stat->get_val(sa, qid);
258
259                 if (*nb_written < xstats_size) {
260                         xstats[*nb_written].id = *nb_written;
261                         xstats[*nb_written].value = value;
262                         (*nb_written)++;
263                 }
264
265                 if (count_total_value)
266                         total_xstat->value += value;
267         }
268 }
269
270 static void
271 sfc_sw_xstat_get_values_by_id(struct sfc_adapter *sa,
272                               const struct sfc_sw_stat_descr *sw_stat,
273                               const uint64_t *ids,
274                               uint64_t *values,
275                               unsigned int ids_size,
276                               unsigned int *nb_supported)
277 {
278         rte_spinlock_t *bmp_lock = &sa->sw_stats.queues_bitmap_lock;
279         struct rte_bitmap *bmp = sa->sw_stats.queues_bitmap;
280         unsigned int id_base = *nb_supported;
281         bool count_total_value = false;
282         unsigned int total_value_idx;
283         uint64_t total_value = 0;
284         unsigned int i, qid;
285         unsigned int nb_queues;
286
287
288         rte_spinlock_lock(bmp_lock);
289         rte_bitmap_reset(bmp);
290
291         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
292         if (nb_queues == 0)
293                 goto unlock;
294         *nb_supported += sfc_sw_xstat_per_queue_get_count(nb_queues);
295
296         /*
297          * The order of each software xstat type is the total xstat
298          * followed by per-queue xstats.
299          */
300         for (i = 0; i < ids_size; i++) {
301                 if (id_base <= ids[i] && ids[i] <= (id_base + nb_queues)) {
302                         if (ids[i] == id_base) { /* Accumulative value */
303                                 count_total_value = true;
304                                 total_value_idx = i;
305                                 continue;
306                         }
307                         qid = ids[i] - id_base - 1;
308                         values[i] = sw_stat->get_val(sa, qid);
309                         total_value += values[i];
310
311                         rte_bitmap_set(bmp, qid);
312                 }
313         }
314
315         if (count_total_value) {
316                 values[total_value_idx] = 0;
317                 for (qid = 0; qid < nb_queues; ++qid) {
318                         if (rte_bitmap_get(bmp, qid) != 0)
319                                 continue;
320                         values[total_value_idx] += sw_stat->get_val(sa, qid);
321                 }
322                 values[total_value_idx] += total_value;
323         }
324
325 unlock:
326         rte_spinlock_unlock(bmp_lock);
327 }
328
329 unsigned int
330 sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa)
331 {
332         SFC_ASSERT(sfc_adapter_is_locked(sa));
333         return sa->sw_stats.xstats_count;
334 }
335
336 void
337 sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
338                        struct rte_eth_xstat *xstats,
339                        unsigned int xstats_count,
340                        unsigned int *nb_written,
341                        unsigned int *nb_supported)
342 {
343         uint64_t *reset_vals = sa->sw_stats.reset_vals;
344         unsigned int sw_xstats_offset;
345         unsigned int i;
346
347         sfc_adapter_lock(sa);
348
349         sw_xstats_offset = *nb_supported;
350
351         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
352                 sfc_sw_xstat_get_values(sa, &sfc_sw_stats_descr[i], xstats,
353                                         xstats_count, nb_written, nb_supported);
354         }
355
356         for (i = sw_xstats_offset; i < *nb_written; i++)
357                 xstats[i].value -= reset_vals[i - sw_xstats_offset];
358
359         sfc_adapter_unlock(sa);
360 }
361
362 int
363 sfc_sw_xstats_get_names(struct sfc_adapter *sa,
364                         struct rte_eth_xstat_name *xstats_names,
365                         unsigned int xstats_count,
366                         unsigned int *nb_written,
367                         unsigned int *nb_supported)
368 {
369         unsigned int i;
370         int ret;
371
372         sfc_adapter_lock(sa);
373
374         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
375                 ret = sfc_sw_stat_get_names(sa, &sfc_sw_stats_descr[i],
376                                             xstats_names, xstats_count,
377                                             nb_written, nb_supported);
378                 if (ret != 0) {
379                         sfc_adapter_unlock(sa);
380                         return ret;
381                 }
382         }
383
384         sfc_adapter_unlock(sa);
385
386         return 0;
387 }
388
389 void
390 sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa,
391                              const uint64_t *ids,
392                              uint64_t *values,
393                              unsigned int n,
394                              unsigned int *nb_supported)
395 {
396         uint64_t *reset_vals = sa->sw_stats.reset_vals;
397         unsigned int sw_xstats_offset;
398         unsigned int i;
399
400         sfc_adapter_lock(sa);
401
402         sw_xstats_offset = *nb_supported;
403
404         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
405                 sfc_sw_xstat_get_values_by_id(sa, &sfc_sw_stats_descr[i], ids,
406                                               values, n, nb_supported);
407         }
408
409         for (i = 0; i < n; i++) {
410                 if (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported)
411                         values[i] -= reset_vals[ids[i] - sw_xstats_offset];
412         }
413
414         sfc_adapter_unlock(sa);
415 }
416
417 int
418 sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa,
419                               const uint64_t *ids,
420                               struct rte_eth_xstat_name *xstats_names,
421                               unsigned int size,
422                               unsigned int *nb_supported)
423 {
424         unsigned int i;
425         int ret;
426
427         sfc_adapter_lock(sa);
428
429         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
430                 ret = sfc_sw_xstat_get_names_by_id(sa, &sfc_sw_stats_descr[i],
431                                                    ids, xstats_names, size,
432                                                    nb_supported);
433                 if (ret != 0) {
434                         sfc_adapter_unlock(sa);
435                         SFC_ASSERT(ret < 0);
436                         return ret;
437                 }
438         }
439
440         sfc_adapter_unlock(sa);
441
442         return 0;
443 }
444
445 static void
446 sfc_sw_xstat_reset(struct sfc_adapter *sa,
447                    const struct sfc_sw_stat_descr *sw_stat,
448                    uint64_t *reset_vals)
449 {
450         unsigned int nb_queues;
451         unsigned int qid;
452         uint64_t *total_xstat_reset;
453
454         SFC_ASSERT(sfc_adapter_is_locked(sa));
455
456         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
457         if (nb_queues == 0)
458                 return;
459
460         /*
461          * The order of each software xstat type is the total xstat
462          * followed by per-queue xstats.
463          */
464         total_xstat_reset = reset_vals;
465         *total_xstat_reset = 0;
466         reset_vals++;
467
468         for (qid = 0; qid < nb_queues; ++qid) {
469                 reset_vals[qid] = sw_stat->get_val(sa, qid);
470                 *total_xstat_reset += reset_vals[qid];
471         }
472 }
473
474 void
475 sfc_sw_xstats_reset(struct sfc_adapter *sa)
476 {
477         uint64_t *reset_vals = sa->sw_stats.reset_vals;
478         const struct sfc_sw_stat_descr *sw_stat;
479         unsigned int i;
480
481         SFC_ASSERT(sfc_adapter_is_locked(sa));
482
483         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
484                 sw_stat = &sfc_sw_stats_descr[i];
485                 sfc_sw_xstat_reset(sa, sw_stat, reset_vals);
486                 reset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_stat);
487         }
488 }
489
490 int
491 sfc_sw_xstats_configure(struct sfc_adapter *sa)
492 {
493         uint64_t **reset_vals = &sa->sw_stats.reset_vals;
494         size_t nb_supported = 0;
495         unsigned int i;
496
497         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++)
498                 nb_supported += sfc_sw_xstat_get_nb_supported(sa,
499                                                         &sfc_sw_stats_descr[i]);
500         sa->sw_stats.xstats_count = nb_supported;
501
502         *reset_vals = rte_realloc(*reset_vals,
503                                   nb_supported * sizeof(**reset_vals), 0);
504         if (*reset_vals == NULL)
505                 return ENOMEM;
506
507         memset(*reset_vals, 0, nb_supported * sizeof(**reset_vals));
508
509         return 0;
510 }
511
512 static void
513 sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa)
514 {
515         rte_bitmap_free(sa->sw_stats.queues_bitmap);
516         rte_free(sa->sw_stats.queues_bitmap_mem);
517 }
518
519 static int
520 sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa)
521 {
522         struct rte_bitmap **queues_bitmap = &sa->sw_stats.queues_bitmap;
523         void **queues_bitmap_mem = &sa->sw_stats.queues_bitmap_mem;
524         uint32_t bmp_size;
525         int rc;
526
527         bmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT);
528         *queues_bitmap_mem = NULL;
529         *queues_bitmap = NULL;
530
531         *queues_bitmap_mem = rte_calloc_socket("bitmap_mem", bmp_size, 1, 0,
532                                                sa->socket_id);
533         if (*queues_bitmap_mem == NULL)
534                 return ENOMEM;
535
536         *queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT,
537                                          *queues_bitmap_mem, bmp_size);
538         if (*queues_bitmap == NULL) {
539                 rc = EINVAL;
540                 goto fail;
541         }
542
543         rte_spinlock_init(&sa->sw_stats.queues_bitmap_lock);
544         return 0;
545
546 fail:
547         sfc_sw_xstats_free_queues_bitmap(sa);
548         return rc;
549 }
550
551 int
552 sfc_sw_xstats_init(struct sfc_adapter *sa)
553 {
554         sa->sw_stats.xstats_count = 0;
555         sa->sw_stats.reset_vals = NULL;
556
557         return sfc_sw_xstats_alloc_queues_bitmap(sa);
558 }
559
560 void
561 sfc_sw_xstats_close(struct sfc_adapter *sa)
562 {
563         sfc_sw_xstats_free_queues_bitmap(sa);
564         rte_free(sa->sw_stats.reset_vals);
565         sa->sw_stats.reset_vals = NULL;
566         sa->sw_stats.xstats_count = 0;
567 }