net/sfc: prepare not having some SW stats on adapter
[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         struct sfc_sw_stats *sw_stats = &sa->sw_stats;
345         unsigned int sw_xstats_offset;
346         unsigned int i;
347
348         sfc_adapter_lock(sa);
349
350         sw_xstats_offset = *nb_supported;
351
352         for (i = 0; i < sw_stats->xstats_count; i++) {
353                 sfc_sw_xstat_get_values(sa, sw_stats->supp[i].descr, xstats,
354                                         xstats_count, nb_written, nb_supported);
355         }
356
357         for (i = sw_xstats_offset; i < *nb_written; i++)
358                 xstats[i].value -= reset_vals[i - sw_xstats_offset];
359
360         sfc_adapter_unlock(sa);
361 }
362
363 int
364 sfc_sw_xstats_get_names(struct sfc_adapter *sa,
365                         struct rte_eth_xstat_name *xstats_names,
366                         unsigned int xstats_count,
367                         unsigned int *nb_written,
368                         unsigned int *nb_supported)
369 {
370         struct sfc_sw_stats *sw_stats = &sa->sw_stats;
371         unsigned int i;
372         int ret;
373
374         sfc_adapter_lock(sa);
375
376         for (i = 0; i < sw_stats->supp_count; i++) {
377                 ret = sfc_sw_stat_get_names(sa, sw_stats->supp[i].descr,
378                                             xstats_names, xstats_count,
379                                             nb_written, nb_supported);
380                 if (ret != 0) {
381                         sfc_adapter_unlock(sa);
382                         return ret;
383                 }
384         }
385
386         sfc_adapter_unlock(sa);
387
388         return 0;
389 }
390
391 void
392 sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa,
393                              const uint64_t *ids,
394                              uint64_t *values,
395                              unsigned int n,
396                              unsigned int *nb_supported)
397 {
398         uint64_t *reset_vals = sa->sw_stats.reset_vals;
399         struct sfc_sw_stats *sw_stats = &sa->sw_stats;
400         unsigned int sw_xstats_offset;
401         unsigned int i;
402
403         sfc_adapter_lock(sa);
404
405         sw_xstats_offset = *nb_supported;
406
407         for (i = 0; i < sw_stats->supp_count; i++) {
408                 sfc_sw_xstat_get_values_by_id(sa, sw_stats->supp[i].descr, ids,
409                                               values, n, nb_supported);
410         }
411
412         for (i = 0; i < n; i++) {
413                 if (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported)
414                         values[i] -= reset_vals[ids[i] - sw_xstats_offset];
415         }
416
417         sfc_adapter_unlock(sa);
418 }
419
420 int
421 sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa,
422                               const uint64_t *ids,
423                               struct rte_eth_xstat_name *xstats_names,
424                               unsigned int size,
425                               unsigned int *nb_supported)
426 {
427         struct sfc_sw_stats *sw_stats = &sa->sw_stats;
428         unsigned int i;
429         int ret;
430
431         sfc_adapter_lock(sa);
432
433         for (i = 0; i < sw_stats->supp_count; i++) {
434                 ret = sfc_sw_xstat_get_names_by_id(sa, sw_stats->supp[i].descr,
435                                                    ids, xstats_names, size,
436                                                    nb_supported);
437                 if (ret != 0) {
438                         sfc_adapter_unlock(sa);
439                         SFC_ASSERT(ret < 0);
440                         return ret;
441                 }
442         }
443
444         sfc_adapter_unlock(sa);
445
446         return 0;
447 }
448
449 static void
450 sfc_sw_xstat_reset(struct sfc_adapter *sa,
451                    const struct sfc_sw_stat_descr *sw_stat,
452                    uint64_t *reset_vals)
453 {
454         unsigned int nb_queues;
455         unsigned int qid;
456         uint64_t *total_xstat_reset;
457
458         SFC_ASSERT(sfc_adapter_is_locked(sa));
459
460         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
461         if (nb_queues == 0)
462                 return;
463
464         /*
465          * The order of each software xstat type is the total xstat
466          * followed by per-queue xstats.
467          */
468         total_xstat_reset = reset_vals;
469         *total_xstat_reset = 0;
470         reset_vals++;
471
472         for (qid = 0; qid < nb_queues; ++qid) {
473                 reset_vals[qid] = sw_stat->get_val(sa, qid);
474                 *total_xstat_reset += reset_vals[qid];
475         }
476 }
477
478 void
479 sfc_sw_xstats_reset(struct sfc_adapter *sa)
480 {
481         uint64_t *reset_vals = sa->sw_stats.reset_vals;
482         struct sfc_sw_stats *sw_stats = &sa->sw_stats;
483         unsigned int i;
484
485         SFC_ASSERT(sfc_adapter_is_locked(sa));
486
487         for (i = 0; i < sw_stats->supp_count; i++) {
488                 sfc_sw_xstat_reset(sa, sw_stats->supp[i].descr, reset_vals);
489                 reset_vals += sfc_sw_xstat_get_nb_supported(sa,
490                                                        sw_stats->supp[i].descr);
491         }
492 }
493
494 int
495 sfc_sw_xstats_configure(struct sfc_adapter *sa)
496 {
497         uint64_t **reset_vals = &sa->sw_stats.reset_vals;
498         struct sfc_sw_stats *sw_stats = &sa->sw_stats;
499         size_t nb_supported = 0;
500         unsigned int i;
501         int rc;
502
503         sw_stats->supp_count = RTE_DIM(sfc_sw_stats_descr);
504         if (sw_stats->supp == NULL) {
505                 sw_stats->supp = rte_malloc(NULL, sw_stats->supp_count *
506                                             sizeof(*sw_stats->supp), 0);
507                 if (sw_stats->supp == NULL)
508                         return -ENOMEM;
509         }
510         for (i = 0; i < sw_stats->supp_count; i++)
511                 sw_stats->supp[i].descr = &sfc_sw_stats_descr[i];
512
513         for (i = 0; i < sw_stats->supp_count; i++)
514                 nb_supported += sfc_sw_xstat_get_nb_supported(sa,
515                                                        sw_stats->supp[i].descr);
516         sa->sw_stats.xstats_count = nb_supported;
517
518         *reset_vals = rte_realloc(*reset_vals,
519                                   nb_supported * sizeof(**reset_vals), 0);
520         if (*reset_vals == NULL) {
521                 rc = -ENOMEM;
522                 goto fail_reset_vals;
523         }
524
525         memset(*reset_vals, 0, nb_supported * sizeof(**reset_vals));
526
527         return 0;
528
529 fail_reset_vals:
530         sa->sw_stats.xstats_count = 0;
531         rte_free(sw_stats->supp);
532         sw_stats->supp = NULL;
533         sw_stats->supp_count = 0;
534
535         return rc;
536 }
537
538 static void
539 sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa)
540 {
541         rte_bitmap_free(sa->sw_stats.queues_bitmap);
542         rte_free(sa->sw_stats.queues_bitmap_mem);
543 }
544
545 static int
546 sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa)
547 {
548         struct rte_bitmap **queues_bitmap = &sa->sw_stats.queues_bitmap;
549         void **queues_bitmap_mem = &sa->sw_stats.queues_bitmap_mem;
550         uint32_t bmp_size;
551         int rc;
552
553         bmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT);
554         *queues_bitmap_mem = NULL;
555         *queues_bitmap = NULL;
556
557         *queues_bitmap_mem = rte_calloc_socket("bitmap_mem", bmp_size, 1, 0,
558                                                sa->socket_id);
559         if (*queues_bitmap_mem == NULL)
560                 return ENOMEM;
561
562         *queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT,
563                                          *queues_bitmap_mem, bmp_size);
564         if (*queues_bitmap == NULL) {
565                 rc = EINVAL;
566                 goto fail;
567         }
568
569         rte_spinlock_init(&sa->sw_stats.queues_bitmap_lock);
570         return 0;
571
572 fail:
573         sfc_sw_xstats_free_queues_bitmap(sa);
574         return rc;
575 }
576
577 int
578 sfc_sw_xstats_init(struct sfc_adapter *sa)
579 {
580         sa->sw_stats.xstats_count = 0;
581         sa->sw_stats.supp = NULL;
582         sa->sw_stats.supp_count = 0;
583         sa->sw_stats.reset_vals = NULL;
584
585         return sfc_sw_xstats_alloc_queues_bitmap(sa);
586 }
587
588 void
589 sfc_sw_xstats_close(struct sfc_adapter *sa)
590 {
591         sfc_sw_xstats_free_queues_bitmap(sa);
592         rte_free(sa->sw_stats.reset_vals);
593         sa->sw_stats.reset_vals = NULL;
594         rte_free(sa->sw_stats.supp);
595         sa->sw_stats.supp = NULL;
596         sa->sw_stats.supp_count = 0;
597         sa->sw_stats.xstats_count = 0;
598 }