2b8b1b56e95a26dafcb6eb2d316e9e7015b9f22b
[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_xstat_val_t(struct sfc_adapter *sa, uint16_t qid);
19
20 struct sfc_sw_xstat_descr {
21         const char *name;
22         enum sfc_sw_stats_type type;
23         sfc_get_sw_xstat_val_t *get_val;
24 };
25
26 static sfc_get_sw_xstat_val_t sfc_get_sw_xstat_val_rx_dbells;
27 static uint64_t
28 sfc_get_sw_xstat_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_xstat_val_t sfc_get_sw_xstat_val_tx_dbells;
40 static uint64_t
41 sfc_get_sw_xstat_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 struct sfc_sw_xstat_descr sfc_sw_stats_descr[] = {
53         {
54                 .name = "dbells",
55                 .type = SFC_SW_STATS_RX,
56                 .get_val  = sfc_get_sw_xstat_val_rx_dbells,
57         },
58         {
59                 .name = "dbells",
60                 .type = SFC_SW_STATS_TX,
61                 .get_val  = sfc_get_sw_xstat_val_tx_dbells,
62         }
63 };
64
65 static int
66 sfc_sw_stat_get_name(struct sfc_adapter *sa,
67                      const struct sfc_sw_xstat_descr *sw_xstat, char *name,
68                      size_t name_size, unsigned int id_off)
69 {
70         const char *prefix;
71         int ret;
72
73         switch (sw_xstat->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_xstat->type);
83                 return -EINVAL;
84         }
85
86         if (id_off == 0) {
87                 ret = snprintf(name, name_size, "%s_%s", prefix,
88                                                          sw_xstat->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_xstat->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_xstat->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_xstat->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_xstat_descr *sw_xstat)
111 {
112         struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
113
114         switch (sw_xstat->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_xstat->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 accumulative 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_xstat_descr *sw_xstat)
136 {
137         unsigned int nb_queues;
138
139         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
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_xstat_descr *sw_xstat,
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_xstat);
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 accumulative xstat
164          * followed by per-queue xstats.
165          */
166         if (*nb_written < xstats_names_sz) {
167                 rc = sfc_sw_stat_get_name(sa, sw_xstat,
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_xstat,
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_xstat_descr *sw_xstat,
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_xstat);
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 accumulative 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_xstat,
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_xstat_descr *sw_xstat,
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 *accum_xstat;
236         bool count_accum_value = false;
237         unsigned int nb_queues;
238
239         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
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 accumulative xstat
246          * followed by per-queue xstats.
247          */
248         if (*nb_written < xstats_size) {
249                 count_accum_value = true;
250                 accum_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_xstat->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_accum_value)
266                         accum_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_xstat_descr *sw_xstat,
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_xstats.queues_bitmap_lock;
279         struct rte_bitmap *bmp = sa->sw_xstats.queues_bitmap;
280         unsigned int id_base = *nb_supported;
281         bool count_accum_value = false;
282         unsigned int accum_value_idx;
283         uint64_t accum_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_xstat);
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 accumulative 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_accum_value = true;
304                                 accum_value_idx = i;
305                                 continue;
306                         }
307                         qid = ids[i] - id_base - 1;
308                         values[i] = sw_xstat->get_val(sa, qid);
309                         accum_value += values[i];
310
311                         rte_bitmap_set(bmp, qid);
312                 }
313         }
314
315         if (count_accum_value) {
316                 values[accum_value_idx] = 0;
317                 for (qid = 0; qid < nb_queues; ++qid) {
318                         if (rte_bitmap_get(bmp, qid) != 0)
319                                 continue;
320                         values[accum_value_idx] += sw_xstat->get_val(sa, qid);
321                 }
322                 values[accum_value_idx] += accum_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         unsigned int nb_supported = 0;
333         unsigned int i;
334
335         SFC_ASSERT(sfc_adapter_is_locked(sa));
336
337         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
338                 nb_supported += sfc_sw_xstat_get_nb_supported(sa,
339                                                         &sfc_sw_stats_descr[i]);
340         }
341
342         return nb_supported;
343 }
344
345 void
346 sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
347                        struct rte_eth_xstat *xstats,
348                        unsigned int xstats_count,
349                        unsigned int *nb_written,
350                        unsigned int *nb_supported)
351 {
352         uint64_t *reset_vals = sa->sw_xstats.reset_vals;
353         unsigned int sw_xstats_offset;
354         unsigned int i;
355
356         sfc_adapter_lock(sa);
357
358         sw_xstats_offset = *nb_supported;
359
360         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
361                 sfc_sw_xstat_get_values(sa, &sfc_sw_stats_descr[i], xstats,
362                                         xstats_count, nb_written, nb_supported);
363         }
364
365         for (i = sw_xstats_offset; i < *nb_written; i++)
366                 xstats[i].value -= reset_vals[i - sw_xstats_offset];
367
368         sfc_adapter_unlock(sa);
369 }
370
371 int
372 sfc_sw_xstats_get_names(struct sfc_adapter *sa,
373                         struct rte_eth_xstat_name *xstats_names,
374                         unsigned int xstats_count,
375                         unsigned int *nb_written,
376                         unsigned int *nb_supported)
377 {
378         unsigned int i;
379         int ret;
380
381         sfc_adapter_lock(sa);
382
383         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
384                 ret = sfc_sw_stat_get_names(sa, &sfc_sw_stats_descr[i],
385                                             xstats_names, xstats_count,
386                                             nb_written, nb_supported);
387                 if (ret != 0) {
388                         sfc_adapter_unlock(sa);
389                         return ret;
390                 }
391         }
392
393         sfc_adapter_unlock(sa);
394
395         return 0;
396 }
397
398 void
399 sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa,
400                              const uint64_t *ids,
401                              uint64_t *values,
402                              unsigned int n,
403                              unsigned int *nb_supported)
404 {
405         uint64_t *reset_vals = sa->sw_xstats.reset_vals;
406         unsigned int sw_xstats_offset;
407         unsigned int i;
408
409         sfc_adapter_lock(sa);
410
411         sw_xstats_offset = *nb_supported;
412
413         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
414                 sfc_sw_xstat_get_values_by_id(sa, &sfc_sw_stats_descr[i], ids,
415                                               values, n, nb_supported);
416         }
417
418         for (i = 0; i < n; i++) {
419                 if (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported)
420                         values[i] -= reset_vals[ids[i] - sw_xstats_offset];
421         }
422
423         sfc_adapter_unlock(sa);
424 }
425
426 int
427 sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa,
428                               const uint64_t *ids,
429                               struct rte_eth_xstat_name *xstats_names,
430                               unsigned int size,
431                               unsigned int *nb_supported)
432 {
433         unsigned int i;
434         int ret;
435
436         sfc_adapter_lock(sa);
437
438         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
439                 ret = sfc_sw_xstat_get_names_by_id(sa, &sfc_sw_stats_descr[i],
440                                                    ids, xstats_names, size,
441                                                    nb_supported);
442                 if (ret != 0) {
443                         sfc_adapter_unlock(sa);
444                         SFC_ASSERT(ret < 0);
445                         return ret;
446                 }
447         }
448
449         sfc_adapter_unlock(sa);
450
451         return 0;
452 }
453
454 static void
455 sfc_sw_xstat_reset(struct sfc_adapter *sa, struct sfc_sw_xstat_descr *sw_xstat,
456                    uint64_t *reset_vals)
457 {
458         unsigned int nb_queues;
459         unsigned int qid;
460         uint64_t *accum_xstat_reset;
461
462         SFC_ASSERT(sfc_adapter_is_locked(sa));
463
464         nb_queues = sfc_sw_stat_get_queue_count(sa, sw_xstat);
465         if (nb_queues == 0)
466                 return;
467
468         /*
469          * The order of each software xstat type is the accumulative xstat
470          * followed by per-queue xstats.
471          */
472         accum_xstat_reset = reset_vals;
473         *accum_xstat_reset = 0;
474         reset_vals++;
475
476         for (qid = 0; qid < nb_queues; ++qid) {
477                 reset_vals[qid] = sw_xstat->get_val(sa, qid);
478                 *accum_xstat_reset += reset_vals[qid];
479         }
480 }
481
482 void
483 sfc_sw_xstats_reset(struct sfc_adapter *sa)
484 {
485         uint64_t *reset_vals = sa->sw_xstats.reset_vals;
486         struct sfc_sw_xstat_descr *sw_xstat;
487         unsigned int i;
488
489         SFC_ASSERT(sfc_adapter_is_locked(sa));
490
491         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
492                 sw_xstat = &sfc_sw_stats_descr[i];
493                 sfc_sw_xstat_reset(sa, sw_xstat, reset_vals);
494                 reset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_xstat);
495         }
496 }
497
498 int
499 sfc_sw_xstats_configure(struct sfc_adapter *sa)
500 {
501         uint64_t **reset_vals = &sa->sw_xstats.reset_vals;
502         size_t nb_supported = 0;
503         unsigned int i;
504
505         for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++)
506                 nb_supported += sfc_sw_xstat_get_nb_supported(sa,
507                                                         &sfc_sw_stats_descr[i]);
508
509         *reset_vals = rte_realloc(*reset_vals,
510                                   nb_supported * sizeof(**reset_vals), 0);
511         if (*reset_vals == NULL)
512                 return ENOMEM;
513
514         memset(*reset_vals, 0, nb_supported * sizeof(**reset_vals));
515
516         return 0;
517 }
518
519 static void
520 sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa)
521 {
522         rte_bitmap_free(sa->sw_xstats.queues_bitmap);
523         rte_free(sa->sw_xstats.queues_bitmap_mem);
524 }
525
526 static int
527 sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa)
528 {
529         struct rte_bitmap **queues_bitmap = &sa->sw_xstats.queues_bitmap;
530         void **queues_bitmap_mem = &sa->sw_xstats.queues_bitmap_mem;
531         uint32_t bmp_size;
532         int rc;
533
534         bmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT);
535         *queues_bitmap_mem = NULL;
536         *queues_bitmap = NULL;
537
538         *queues_bitmap_mem = rte_calloc_socket("bitmap_mem", bmp_size, 1, 0,
539                                                sa->socket_id);
540         if (*queues_bitmap_mem == NULL)
541                 return ENOMEM;
542
543         *queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT,
544                                          *queues_bitmap_mem, bmp_size);
545         if (*queues_bitmap == NULL) {
546                 rc = EINVAL;
547                 goto fail;
548         }
549
550         rte_spinlock_init(&sa->sw_xstats.queues_bitmap_lock);
551         return 0;
552
553 fail:
554         sfc_sw_xstats_free_queues_bitmap(sa);
555         return rc;
556 }
557
558 int
559 sfc_sw_xstats_init(struct sfc_adapter *sa)
560 {
561         sa->sw_xstats.reset_vals = NULL;
562
563         return sfc_sw_xstats_alloc_queues_bitmap(sa);
564 }
565
566 void
567 sfc_sw_xstats_close(struct sfc_adapter *sa)
568 {
569         rte_free(sa->sw_xstats.reset_vals);
570         sa->sw_xstats.reset_vals = NULL;
571
572         sfc_sw_xstats_free_queues_bitmap(sa);
573 }