xref: /dpdk/drivers/net/sfc/sfc_sw_stats.c (revision 1acb7f547455f636a6968cb3b4ca3870279dfece)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2021 Xilinx, Inc.
4  */
5 #include <dev_driver.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 #define SFC_SW_STAT_INVALID		UINT64_MAX
14 
15 #define SFC_SW_STATS_GROUP_SIZE_MAX	2U
16 #define SFC_SW_STAT_GOOD_PACKETS	"packets"
17 #define SFC_SW_STAT_GOOD_BYTES		"bytes"
18 
19 enum sfc_sw_stats_type {
20 	SFC_SW_STATS_RX,
21 	SFC_SW_STATS_TX,
22 };
23 
24 enum sfc_sw_stats_group_basic {
25 	SFC_SW_STATS_GROUP_BASIC_PKTS = 0,
26 	SFC_SW_STATS_GROUP_BASIC_BYTES,
27 	SFX_SW_STATS_GROUP_BASIC_MAX
28 };
29 
30 typedef void sfc_get_sw_stat_val_t(struct sfc_adapter *sa, uint16_t qid,
31 				   uint64_t *values, unsigned int values_count);
32 
33 struct sfc_sw_stat_descr {
34 	const char *name;
35 	enum sfc_sw_stats_type type;
36 	sfc_get_sw_stat_val_t *get_val;
37 	bool provide_total;
38 };
39 
40 static sfc_get_sw_stat_val_t sfc_sw_stat_get_rx_good_pkts_bytes;
41 static void
sfc_sw_stat_get_rx_good_pkts_bytes(struct sfc_adapter * sa,uint16_t qid,uint64_t * values,unsigned int values_count)42 sfc_sw_stat_get_rx_good_pkts_bytes(struct sfc_adapter *sa, uint16_t qid,
43 				   uint64_t *values,
44 				   unsigned int values_count)
45 {
46 	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
47 	struct sfc_rxq_info *rxq_info;
48 	union sfc_pkts_bytes qstats;
49 
50 	RTE_SET_USED(values_count);
51 	SFC_ASSERT(values_count == SFX_SW_STATS_GROUP_BASIC_MAX);
52 	rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid);
53 	if (rxq_info->state & SFC_RXQ_INITIALIZED) {
54 		sfc_pkts_bytes_get(&rxq_info->dp->dpq.stats, &qstats);
55 		values[SFC_SW_STATS_GROUP_BASIC_PKTS] = qstats.pkts;
56 		values[SFC_SW_STATS_GROUP_BASIC_BYTES] = qstats.bytes;
57 	} else {
58 		values[SFC_SW_STATS_GROUP_BASIC_PKTS] = 0;
59 		values[SFC_SW_STATS_GROUP_BASIC_BYTES] = 0;
60 	}
61 }
62 
63 static sfc_get_sw_stat_val_t sfc_sw_stat_get_tx_good_pkts_bytes;
64 static void
sfc_sw_stat_get_tx_good_pkts_bytes(struct sfc_adapter * sa,uint16_t qid,uint64_t * values,unsigned int values_count)65 sfc_sw_stat_get_tx_good_pkts_bytes(struct sfc_adapter *sa, uint16_t qid,
66 				   uint64_t *values,
67 				   unsigned int values_count)
68 {
69 	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
70 	struct sfc_txq_info *txq_info;
71 	union sfc_pkts_bytes qstats;
72 
73 	RTE_SET_USED(values_count);
74 	SFC_ASSERT(values_count == SFX_SW_STATS_GROUP_BASIC_MAX);
75 	txq_info = sfc_txq_info_by_ethdev_qid(sas, qid);
76 	if (txq_info->state & SFC_TXQ_INITIALIZED) {
77 		sfc_pkts_bytes_get(&txq_info->dp->dpq.stats, &qstats);
78 		values[SFC_SW_STATS_GROUP_BASIC_PKTS] = qstats.pkts;
79 		values[SFC_SW_STATS_GROUP_BASIC_BYTES] = qstats.bytes;
80 	} else {
81 		values[SFC_SW_STATS_GROUP_BASIC_PKTS] = 0;
82 		values[SFC_SW_STATS_GROUP_BASIC_BYTES] = 0;
83 	}
84 }
85 
86 static sfc_get_sw_stat_val_t sfc_get_sw_stat_val_rx_dbells;
87 static void
sfc_get_sw_stat_val_rx_dbells(struct sfc_adapter * sa,uint16_t qid,uint64_t * values,unsigned int values_count)88 sfc_get_sw_stat_val_rx_dbells(struct sfc_adapter *sa, uint16_t qid,
89 			       uint64_t *values, unsigned int values_count)
90 {
91 	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
92 	struct sfc_rxq_info *rxq_info;
93 
94 	RTE_SET_USED(values_count);
95 	SFC_ASSERT(values_count == 1);
96 	rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid);
97 	values[0] = rxq_info->state & SFC_RXQ_INITIALIZED ?
98 		    rxq_info->dp->dpq.dbells : 0;
99 }
100 
101 static sfc_get_sw_stat_val_t sfc_get_sw_stat_val_tx_dbells;
102 static void
sfc_get_sw_stat_val_tx_dbells(struct sfc_adapter * sa,uint16_t qid,uint64_t * values,unsigned int values_count)103 sfc_get_sw_stat_val_tx_dbells(struct sfc_adapter *sa, uint16_t qid,
104 			       uint64_t *values, unsigned int values_count)
105 {
106 	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
107 	struct sfc_txq_info *txq_info;
108 
109 	RTE_SET_USED(values_count);
110 	SFC_ASSERT(values_count == 1);
111 	txq_info = sfc_txq_info_by_ethdev_qid(sas, qid);
112 	values[0] = txq_info->state & SFC_TXQ_INITIALIZED ?
113 		    txq_info->dp->dpq.dbells : 0;
114 }
115 
116 /*
117  * SW stats can be grouped together. When stats are grouped the corresponding
118  * stats values for each queue are obtained during calling one get value
119  * callback. Stats of the same group are contiguous in the structure below.
120  * The start of the group is denoted by stat implementing get value callback.
121  */
122 const struct sfc_sw_stat_descr sfc_sw_stats_descr[] = {
123 	/* Group of Rx packets/bytes stats */
124 	{
125 		.name = SFC_SW_STAT_GOOD_PACKETS,
126 		.type = SFC_SW_STATS_RX,
127 		.get_val  = sfc_sw_stat_get_rx_good_pkts_bytes,
128 		.provide_total = false,
129 	},
130 	{
131 		.name = SFC_SW_STAT_GOOD_BYTES,
132 		.type = SFC_SW_STATS_RX,
133 		.get_val  = NULL,
134 		.provide_total = false,
135 	},
136 	/* Group of Tx packets/bytes stats */
137 	{
138 		.name = SFC_SW_STAT_GOOD_PACKETS,
139 		.type = SFC_SW_STATS_TX,
140 		.get_val  = sfc_sw_stat_get_tx_good_pkts_bytes,
141 		.provide_total = false,
142 	},
143 	{
144 		.name = SFC_SW_STAT_GOOD_BYTES,
145 		.type = SFC_SW_STATS_TX,
146 		.get_val  = NULL,
147 		.provide_total = false,
148 	},
149 	/* End of basic stats */
150 	{
151 		.name = "dbells",
152 		.type = SFC_SW_STATS_RX,
153 		.get_val  = sfc_get_sw_stat_val_rx_dbells,
154 		.provide_total = true,
155 	},
156 	{
157 		.name = "dbells",
158 		.type = SFC_SW_STATS_TX,
159 		.get_val  = sfc_get_sw_stat_val_tx_dbells,
160 		.provide_total = true,
161 	}
162 };
163 
164 static int
sfc_sw_stat_get_name(struct sfc_adapter * sa,const struct sfc_sw_stat_descr * sw_stat,char * name,size_t name_size,unsigned int id_off)165 sfc_sw_stat_get_name(struct sfc_adapter *sa,
166 		     const struct sfc_sw_stat_descr *sw_stat, char *name,
167 		     size_t name_size, unsigned int id_off)
168 {
169 	const char *prefix;
170 	int ret;
171 
172 	switch (sw_stat->type) {
173 	case SFC_SW_STATS_RX:
174 		prefix = "rx";
175 		break;
176 	case SFC_SW_STATS_TX:
177 		prefix = "tx";
178 		break;
179 	default:
180 		sfc_err(sa, "%s: unknown software statistics type %d",
181 			__func__, sw_stat->type);
182 		return -EINVAL;
183 	}
184 
185 	if (sw_stat->provide_total && id_off == 0) {
186 		ret = snprintf(name, name_size, "%s_%s", prefix,
187 							 sw_stat->name);
188 		if (ret < 0 || ret >= (int)name_size) {
189 			sfc_err(sa, "%s: failed to fill xstat name %s_%s, err %d",
190 				__func__, prefix, sw_stat->name, ret);
191 			return ret > 0 ? -EINVAL : ret;
192 		}
193 	} else {
194 		uint16_t qid = id_off - sw_stat->provide_total;
195 		ret = snprintf(name, name_size, "%s_q%u_%s", prefix, qid,
196 							sw_stat->name);
197 		if (ret < 0 || ret >= (int)name_size) {
198 			sfc_err(sa, "%s: failed to fill xstat name %s_q%u_%s, err %d",
199 				__func__, prefix, qid, sw_stat->name, ret);
200 			return ret > 0 ? -EINVAL : ret;
201 		}
202 	}
203 
204 	return 0;
205 }
206 
207 static unsigned int
sfc_sw_stat_get_queue_count(struct sfc_adapter * sa,const struct sfc_sw_stat_descr * sw_stat)208 sfc_sw_stat_get_queue_count(struct sfc_adapter *sa,
209 			    const struct sfc_sw_stat_descr *sw_stat)
210 {
211 	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
212 
213 	switch (sw_stat->type) {
214 	case SFC_SW_STATS_RX:
215 		return sas->ethdev_rxq_count;
216 	case SFC_SW_STATS_TX:
217 		return sas->ethdev_txq_count;
218 	default:
219 		sfc_err(sa, "%s: unknown software statistics type %d",
220 			__func__, sw_stat->type);
221 		return 0;
222 	}
223 }
224 
225 static unsigned int
sfc_sw_xstat_per_queue_get_count(const struct sfc_sw_stat_descr * sw_stat,unsigned int nb_queues)226 sfc_sw_xstat_per_queue_get_count(const struct sfc_sw_stat_descr *sw_stat,
227 				 unsigned int nb_queues)
228 {
229 	/* Take into account the total xstat of all queues */
230 	return nb_queues > 0 ? sw_stat->provide_total + nb_queues : 0;
231 }
232 
233 static unsigned int
sfc_sw_xstat_get_nb_supported(struct sfc_adapter * sa,const struct sfc_sw_stat_descr * sw_stat)234 sfc_sw_xstat_get_nb_supported(struct sfc_adapter *sa,
235 			      const struct sfc_sw_stat_descr *sw_stat)
236 {
237 	unsigned int nb_queues;
238 
239 	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
240 	return sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues);
241 }
242 
243 static int
sfc_sw_stat_get_names(struct sfc_adapter * sa,const struct sfc_sw_stat_descr * sw_stat,struct rte_eth_xstat_name * xstats_names,unsigned int xstats_names_sz,unsigned int * nb_written,unsigned int * nb_supported)244 sfc_sw_stat_get_names(struct sfc_adapter *sa,
245 		      const struct sfc_sw_stat_descr *sw_stat,
246 		      struct rte_eth_xstat_name *xstats_names,
247 		      unsigned int xstats_names_sz,
248 		      unsigned int *nb_written,
249 		      unsigned int *nb_supported)
250 {
251 	const size_t name_size = sizeof(xstats_names[0].name);
252 	unsigned int id_base = *nb_supported;
253 	unsigned int nb_queues;
254 	unsigned int qid;
255 	int rc;
256 
257 	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
258 	if (nb_queues == 0)
259 		return 0;
260 	*nb_supported += sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues);
261 
262 	/*
263 	 * The order of each software xstat type is the total xstat
264 	 * followed by per-queue xstats.
265 	 */
266 	if (*nb_written < xstats_names_sz && sw_stat->provide_total) {
267 		rc = sfc_sw_stat_get_name(sa, sw_stat,
268 					  xstats_names[*nb_written].name,
269 					  name_size, *nb_written - id_base);
270 		if (rc != 0)
271 			return rc;
272 		(*nb_written)++;
273 	}
274 
275 	for (qid = 0; qid < nb_queues; ++qid) {
276 		if (*nb_written < xstats_names_sz) {
277 			rc = sfc_sw_stat_get_name(sa, sw_stat,
278 					      xstats_names[*nb_written].name,
279 					      name_size, *nb_written - id_base);
280 			if (rc != 0)
281 				return rc;
282 			(*nb_written)++;
283 		}
284 	}
285 
286 	return 0;
287 }
288 
289 static int
sfc_sw_xstat_get_names_by_id(struct sfc_adapter * sa,const struct sfc_sw_stat_descr * sw_stat,const uint64_t * ids,struct rte_eth_xstat_name * xstats_names,unsigned int size,unsigned int * nb_supported)290 sfc_sw_xstat_get_names_by_id(struct sfc_adapter *sa,
291 			     const struct sfc_sw_stat_descr *sw_stat,
292 			     const uint64_t *ids,
293 			     struct rte_eth_xstat_name *xstats_names,
294 			     unsigned int size,
295 			     unsigned int *nb_supported)
296 {
297 	const size_t name_size = sizeof(xstats_names[0].name);
298 	unsigned int id_base = *nb_supported;
299 	unsigned int id_end;
300 	unsigned int nb_queues;
301 	unsigned int i;
302 	int rc;
303 
304 	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
305 	if (nb_queues == 0)
306 		return 0;
307 	*nb_supported += sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues);
308 
309 	/*
310 	 * The order of each software xstat type is the total xstat
311 	 * followed by per-queue xstats.
312 	 */
313 	id_end = id_base + sw_stat->provide_total + nb_queues;
314 	for (i = 0; i < size; i++) {
315 		if (id_base <= ids[i] && ids[i] < id_end) {
316 			rc = sfc_sw_stat_get_name(sa, sw_stat,
317 						  xstats_names[i].name,
318 						  name_size, ids[i] - id_base);
319 			if (rc != 0)
320 				return rc;
321 		}
322 	}
323 
324 	return 0;
325 }
326 
327 static uint64_t
sfc_sw_stat_get_val(struct sfc_adapter * sa,unsigned int sw_stat_idx,uint16_t qid)328 sfc_sw_stat_get_val(struct sfc_adapter *sa,
329 		    unsigned int sw_stat_idx, uint16_t qid)
330 {
331 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
332 	uint64_t *res = &sw_stats->supp[sw_stat_idx].cache[qid];
333 	uint64_t values[SFC_SW_STATS_GROUP_SIZE_MAX];
334 	unsigned int group_start_idx;
335 	unsigned int group_size;
336 	unsigned int i;
337 
338 	if (*res != SFC_SW_STAT_INVALID)
339 		return *res;
340 
341 	/*
342 	 * Search for the group start, i.e. the stat that implements
343 	 * get value callback.
344 	 */
345 	group_start_idx = sw_stat_idx;
346 	while (sw_stats->supp[group_start_idx].descr->get_val == NULL)
347 		group_start_idx--;
348 
349 	/*
350 	 * Calculate number of elements in the group with loop till the next
351 	 * group start or the list end.
352 	 */
353 	group_size = 1;
354 	for (i = sw_stat_idx + 1; i < sw_stats->supp_count; i++) {
355 		if (sw_stats->supp[i].descr->get_val != NULL)
356 			break;
357 		group_size++;
358 	}
359 	group_size += sw_stat_idx - group_start_idx;
360 
361 	SFC_ASSERT(group_size <= SFC_SW_STATS_GROUP_SIZE_MAX);
362 	sw_stats->supp[group_start_idx].descr->get_val(sa, qid, values,
363 						       group_size);
364 	for (i = group_start_idx; i < (group_start_idx + group_size); i++)
365 		sw_stats->supp[i].cache[qid] = values[i - group_start_idx];
366 
367 	return *res;
368 }
369 
370 static void
sfc_sw_xstat_get_values(struct sfc_adapter * sa,const struct sfc_sw_stat_descr * sw_stat,unsigned int sw_stat_idx,struct rte_eth_xstat * xstats,unsigned int xstats_size,unsigned int * nb_written,unsigned int * nb_supported)371 sfc_sw_xstat_get_values(struct sfc_adapter *sa,
372 			const struct sfc_sw_stat_descr *sw_stat,
373 			unsigned int sw_stat_idx,
374 			struct rte_eth_xstat *xstats,
375 			unsigned int xstats_size,
376 			unsigned int *nb_written,
377 			unsigned int *nb_supported)
378 {
379 	unsigned int qid;
380 	uint64_t value;
381 	struct rte_eth_xstat *total_xstat;
382 	bool count_total_value = false;
383 	unsigned int nb_queues;
384 
385 	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
386 	if (nb_queues == 0)
387 		return;
388 	*nb_supported += sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues);
389 
390 	/*
391 	 * The order of each software xstat type is the total xstat
392 	 * followed by per-queue xstats.
393 	 */
394 	if (*nb_written < xstats_size && sw_stat->provide_total) {
395 		count_total_value = true;
396 		total_xstat = &xstats[*nb_written];
397 		xstats[*nb_written].id = *nb_written;
398 		xstats[*nb_written].value = 0;
399 		(*nb_written)++;
400 	}
401 
402 	for (qid = 0; qid < nb_queues; ++qid) {
403 		value = sfc_sw_stat_get_val(sa, sw_stat_idx, qid);
404 
405 		if (*nb_written < xstats_size) {
406 			xstats[*nb_written].id = *nb_written;
407 			xstats[*nb_written].value = value;
408 			(*nb_written)++;
409 		}
410 
411 		if (count_total_value)
412 			total_xstat->value += value;
413 	}
414 }
415 
416 static void
sfc_sw_xstat_get_values_by_id(struct sfc_adapter * sa,const struct sfc_sw_stat_descr * sw_stat,unsigned int sw_stat_idx,const uint64_t * ids,uint64_t * values,unsigned int ids_size,unsigned int * nb_supported)417 sfc_sw_xstat_get_values_by_id(struct sfc_adapter *sa,
418 			      const struct sfc_sw_stat_descr *sw_stat,
419 			      unsigned int sw_stat_idx,
420 			      const uint64_t *ids,
421 			      uint64_t *values,
422 			      unsigned int ids_size,
423 			      unsigned int *nb_supported)
424 {
425 	rte_spinlock_t *bmp_lock = &sa->sw_stats.queues_bitmap_lock;
426 	struct rte_bitmap *bmp = sa->sw_stats.queues_bitmap;
427 	unsigned int id_base = *nb_supported;
428 	unsigned int id_base_q;
429 	unsigned int id_end;
430 	bool count_total_value = false;
431 	unsigned int total_value_idx;
432 	uint64_t total_value = 0;
433 	unsigned int i, qid;
434 	unsigned int nb_queues;
435 
436 
437 	rte_spinlock_lock(bmp_lock);
438 	rte_bitmap_reset(bmp);
439 
440 	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
441 	if (nb_queues == 0)
442 		goto unlock;
443 	*nb_supported += sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues);
444 
445 	/*
446 	 * The order of each software xstat type is the total xstat
447 	 * followed by per-queue xstats.
448 	 */
449 	id_end = id_base + sw_stat->provide_total + nb_queues;
450 	for (i = 0; i < ids_size; i++) {
451 		if (id_base <= ids[i] && ids[i] < id_end) {
452 			if (sw_stat->provide_total && ids[i] == id_base) {
453 				/* Accumulative value */
454 				count_total_value = true;
455 				total_value_idx = i;
456 				continue;
457 			}
458 			id_base_q = id_base + sw_stat->provide_total;
459 			qid = ids[i] - id_base_q;
460 			values[i] = sfc_sw_stat_get_val(sa, sw_stat_idx, qid);
461 			total_value += values[i];
462 
463 			rte_bitmap_set(bmp, qid);
464 		}
465 	}
466 
467 	if (count_total_value) {
468 		values[total_value_idx] = 0;
469 		for (qid = 0; qid < nb_queues; ++qid) {
470 			if (rte_bitmap_get(bmp, qid) != 0)
471 				continue;
472 			values[total_value_idx] += sfc_sw_stat_get_val(sa,
473 								    sw_stat_idx,
474 								    qid);
475 		}
476 		values[total_value_idx] += total_value;
477 	}
478 
479 unlock:
480 	rte_spinlock_unlock(bmp_lock);
481 }
482 
483 unsigned int
sfc_sw_xstats_get_nb_supported(struct sfc_adapter * sa)484 sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa)
485 {
486 	SFC_ASSERT(sfc_adapter_is_locked(sa));
487 	return sa->sw_stats.xstats_count;
488 }
489 
490 static void
sfc_sw_stats_clear_cache(struct sfc_adapter * sa)491 sfc_sw_stats_clear_cache(struct sfc_adapter *sa)
492 {
493 	unsigned int cache_count = sa->sw_stats.cache_count;
494 	uint64_t *cache = sa->sw_stats.cache;
495 
496 	RTE_BUILD_BUG_ON(UINT64_C(0xffffffffffffffff) != SFC_SW_STAT_INVALID);
497 	memset(cache, 0xff, cache_count * sizeof(*cache));
498 }
499 
500 void
sfc_sw_xstats_get_vals(struct sfc_adapter * sa,struct rte_eth_xstat * xstats,unsigned int xstats_count,unsigned int * nb_written,unsigned int * nb_supported)501 sfc_sw_xstats_get_vals(struct sfc_adapter *sa,
502 		       struct rte_eth_xstat *xstats,
503 		       unsigned int xstats_count,
504 		       unsigned int *nb_written,
505 		       unsigned int *nb_supported)
506 {
507 	uint64_t *reset_vals = sa->sw_stats.reset_vals;
508 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
509 	unsigned int sw_xstats_offset;
510 	unsigned int i;
511 
512 	sfc_adapter_lock(sa);
513 
514 	sfc_sw_stats_clear_cache(sa);
515 
516 	sw_xstats_offset = *nb_supported;
517 
518 	for (i = 0; i < sw_stats->supp_count; i++) {
519 		sfc_sw_xstat_get_values(sa, sw_stats->supp[i].descr, i,
520 				xstats, xstats_count, nb_written, nb_supported);
521 	}
522 
523 	for (i = sw_xstats_offset; i < *nb_written; i++)
524 		xstats[i].value -= reset_vals[i - sw_xstats_offset];
525 
526 	sfc_adapter_unlock(sa);
527 }
528 
529 int
sfc_sw_xstats_get_names(struct sfc_adapter * sa,struct rte_eth_xstat_name * xstats_names,unsigned int xstats_count,unsigned int * nb_written,unsigned int * nb_supported)530 sfc_sw_xstats_get_names(struct sfc_adapter *sa,
531 			struct rte_eth_xstat_name *xstats_names,
532 			unsigned int xstats_count,
533 			unsigned int *nb_written,
534 			unsigned int *nb_supported)
535 {
536 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
537 	unsigned int i;
538 	int ret;
539 
540 	sfc_adapter_lock(sa);
541 
542 	for (i = 0; i < sw_stats->supp_count; i++) {
543 		ret = sfc_sw_stat_get_names(sa, sw_stats->supp[i].descr,
544 					    xstats_names, xstats_count,
545 					    nb_written, nb_supported);
546 		if (ret != 0) {
547 			sfc_adapter_unlock(sa);
548 			return ret;
549 		}
550 	}
551 
552 	sfc_adapter_unlock(sa);
553 
554 	return 0;
555 }
556 
557 void
sfc_sw_xstats_get_vals_by_id(struct sfc_adapter * sa,const uint64_t * ids,uint64_t * values,unsigned int n,unsigned int * nb_supported)558 sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa,
559 			     const uint64_t *ids,
560 			     uint64_t *values,
561 			     unsigned int n,
562 			     unsigned int *nb_supported)
563 {
564 	uint64_t *reset_vals = sa->sw_stats.reset_vals;
565 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
566 	unsigned int sw_xstats_offset;
567 	unsigned int i;
568 
569 	sfc_adapter_lock(sa);
570 
571 	sfc_sw_stats_clear_cache(sa);
572 
573 	sw_xstats_offset = *nb_supported;
574 
575 	for (i = 0; i < sw_stats->supp_count; i++) {
576 		sfc_sw_xstat_get_values_by_id(sa, sw_stats->supp[i].descr, i,
577 					      ids, values, n, nb_supported);
578 	}
579 
580 	for (i = 0; i < n; i++) {
581 		if (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported)
582 			values[i] -= reset_vals[ids[i] - sw_xstats_offset];
583 	}
584 
585 	sfc_adapter_unlock(sa);
586 }
587 
588 int
sfc_sw_xstats_get_names_by_id(struct sfc_adapter * sa,const uint64_t * ids,struct rte_eth_xstat_name * xstats_names,unsigned int size,unsigned int * nb_supported)589 sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa,
590 			      const uint64_t *ids,
591 			      struct rte_eth_xstat_name *xstats_names,
592 			      unsigned int size,
593 			      unsigned int *nb_supported)
594 {
595 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
596 	unsigned int i;
597 	int ret;
598 
599 	sfc_adapter_lock(sa);
600 
601 	for (i = 0; i < sw_stats->supp_count; i++) {
602 		ret = sfc_sw_xstat_get_names_by_id(sa, sw_stats->supp[i].descr,
603 						   ids, xstats_names, size,
604 						   nb_supported);
605 		if (ret != 0) {
606 			sfc_adapter_unlock(sa);
607 			SFC_ASSERT(ret < 0);
608 			return ret;
609 		}
610 	}
611 
612 	sfc_adapter_unlock(sa);
613 
614 	return 0;
615 }
616 
617 static void
sfc_sw_xstat_reset(struct sfc_adapter * sa,const struct sfc_sw_stat_descr * sw_stat,unsigned int sw_stat_idx,uint64_t * reset_vals)618 sfc_sw_xstat_reset(struct sfc_adapter *sa,
619 		   const struct sfc_sw_stat_descr *sw_stat,
620 		   unsigned int sw_stat_idx,
621 		   uint64_t *reset_vals)
622 {
623 	unsigned int nb_queues;
624 	unsigned int qid;
625 	uint64_t *total_xstat_reset = NULL;
626 
627 	SFC_ASSERT(sfc_adapter_is_locked(sa));
628 
629 	nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat);
630 	if (nb_queues == 0)
631 		return;
632 
633 	/*
634 	 * The order of each software xstat type is the total xstat
635 	 * followed by per-queue xstats.
636 	 */
637 	if (sw_stat->provide_total) {
638 		total_xstat_reset = reset_vals;
639 		*total_xstat_reset = 0;
640 		reset_vals++;
641 	}
642 
643 	for (qid = 0; qid < nb_queues; ++qid) {
644 		reset_vals[qid] = sfc_sw_stat_get_val(sa, sw_stat_idx, qid);
645 		if (sw_stat->provide_total)
646 			*total_xstat_reset += reset_vals[qid];
647 	}
648 }
649 
650 void
sfc_sw_xstats_reset(struct sfc_adapter * sa)651 sfc_sw_xstats_reset(struct sfc_adapter *sa)
652 {
653 	uint64_t *reset_vals = sa->sw_stats.reset_vals;
654 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
655 	unsigned int i;
656 
657 	SFC_ASSERT(sfc_adapter_is_locked(sa));
658 
659 	sfc_sw_stats_clear_cache(sa);
660 
661 	for (i = 0; i < sw_stats->supp_count; i++) {
662 		sfc_sw_xstat_reset(sa, sw_stats->supp[i].descr, i, reset_vals);
663 		reset_vals += sfc_sw_xstat_get_nb_supported(sa,
664 						       sw_stats->supp[i].descr);
665 	}
666 }
667 
668 static bool
sfc_sw_stats_is_packets_or_bytes(const char * xstat_name)669 sfc_sw_stats_is_packets_or_bytes(const char *xstat_name)
670 {
671 	return strcmp(xstat_name, SFC_SW_STAT_GOOD_PACKETS) == 0 ||
672 	       strcmp(xstat_name, SFC_SW_STAT_GOOD_BYTES) == 0;
673 }
674 
675 static void
sfc_sw_stats_fill_available_descr(struct sfc_adapter * sa)676 sfc_sw_stats_fill_available_descr(struct sfc_adapter *sa)
677 {
678 	const struct sfc_adapter_priv *sap = &sa->priv;
679 	bool have_dp_rx_stats = sap->dp_rx->features & SFC_DP_RX_FEAT_STATS;
680 	bool have_dp_tx_stats = sap->dp_tx->features & SFC_DP_TX_FEAT_STATS;
681 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
682 	const struct sfc_sw_stat_descr *sw_stat_descr;
683 	unsigned int i;
684 
685 	sw_stats->supp_count = 0;
686 	for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
687 		sw_stat_descr = &sfc_sw_stats_descr[i];
688 		if (!have_dp_rx_stats &&
689 		    sw_stat_descr->type == SFC_SW_STATS_RX &&
690 		    sfc_sw_stats_is_packets_or_bytes(sw_stat_descr->name))
691 			continue;
692 		if (!have_dp_tx_stats &&
693 		    sw_stat_descr->type == SFC_SW_STATS_TX &&
694 		    sfc_sw_stats_is_packets_or_bytes(sw_stat_descr->name))
695 			continue;
696 		sw_stats->supp[sw_stats->supp_count].descr = sw_stat_descr;
697 		sw_stats->supp_count++;
698 	}
699 }
700 
701 static int
sfc_sw_stats_set_reset_basic_stats(struct sfc_adapter * sa)702 sfc_sw_stats_set_reset_basic_stats(struct sfc_adapter *sa)
703 {
704 	uint64_t *reset_vals = sa->sw_stats.reset_vals;
705 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
706 	const struct sfc_sw_stat_descr *sw_stat;
707 	unsigned int i;
708 
709 	for (i = 0; i < sw_stats->supp_count; i++) {
710 		sw_stat = sw_stats->supp[i].descr;
711 
712 		switch (sw_stat->type) {
713 		case SFC_SW_STATS_RX:
714 			if (strcmp(sw_stat->name,
715 				   SFC_SW_STAT_GOOD_PACKETS) == 0)
716 				sa->sw_stats.reset_rx_pkts = reset_vals;
717 			else if (strcmp(sw_stat->name,
718 					SFC_SW_STAT_GOOD_BYTES) == 0)
719 				sa->sw_stats.reset_rx_bytes = reset_vals;
720 			break;
721 		case SFC_SW_STATS_TX:
722 			if (strcmp(sw_stat->name,
723 				   SFC_SW_STAT_GOOD_PACKETS) == 0)
724 				sa->sw_stats.reset_tx_pkts = reset_vals;
725 			else if (strcmp(sw_stat->name,
726 					SFC_SW_STAT_GOOD_BYTES) == 0)
727 				sa->sw_stats.reset_tx_bytes = reset_vals;
728 			break;
729 		default:
730 			SFC_GENERIC_LOG(ERR, "Unknown SW stat type");
731 			return -EINVAL;
732 		}
733 
734 		reset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_stat);
735 	}
736 
737 	return 0;
738 }
739 
740 int
sfc_sw_xstats_configure(struct sfc_adapter * sa)741 sfc_sw_xstats_configure(struct sfc_adapter *sa)
742 {
743 	uint64_t **reset_vals = &sa->sw_stats.reset_vals;
744 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
745 	unsigned int cache_count = 0;
746 	uint64_t **cache =  &sa->sw_stats.cache;
747 	uint64_t *stat_cache;
748 	size_t nb_supported = 0;
749 	unsigned int i;
750 	int rc;
751 
752 	sw_stats->supp_count = RTE_DIM(sfc_sw_stats_descr);
753 	if (sw_stats->supp == NULL) {
754 		sw_stats->supp = rte_malloc(NULL, sw_stats->supp_count *
755 					    sizeof(*sw_stats->supp), 0);
756 		if (sw_stats->supp == NULL)
757 			return -ENOMEM;
758 	}
759 	for (i = 0; i < sw_stats->supp_count; i++)
760 		sw_stats->supp[i].descr = &sfc_sw_stats_descr[i];
761 	sfc_sw_stats_fill_available_descr(sa);
762 
763 	for (i = 0; i < sw_stats->supp_count; i++) {
764 		nb_supported += sfc_sw_xstat_get_nb_supported(sa,
765 						       sw_stats->supp[i].descr);
766 		cache_count += sfc_sw_stat_get_queue_count(sa,
767 						       sw_stats->supp[i].descr);
768 	}
769 	sa->sw_stats.xstats_count = nb_supported;
770 
771 	*reset_vals = rte_realloc(*reset_vals,
772 				  nb_supported * sizeof(**reset_vals), 0);
773 	if (*reset_vals == NULL) {
774 		rc = -ENOMEM;
775 		goto fail_reset_vals;
776 	}
777 
778 	memset(*reset_vals, 0, nb_supported * sizeof(**reset_vals));
779 
780 	*cache = rte_realloc(*cache, cache_count * sizeof(**cache), 0);
781 	if (*cache == NULL) {
782 		rc = ENOMEM;
783 		goto fail_cache;
784 	}
785 	sa->sw_stats.cache_count = cache_count;
786 	stat_cache = *cache;
787 	rc = sfc_sw_stats_set_reset_basic_stats(sa);
788 	if (rc != 0)
789 		goto fail_reset_basic_stats;
790 
791 	for (i = 0; i < sw_stats->supp_count; i++) {
792 		sw_stats->supp[i].cache = stat_cache;
793 		stat_cache += sfc_sw_stat_get_queue_count(sa,
794 						       sw_stats->supp[i].descr);
795 	}
796 
797 	return 0;
798 
799 fail_reset_basic_stats:
800 	rte_free(*cache);
801 	*cache = NULL;
802 	sa->sw_stats.cache_count = 0;
803 fail_cache:
804 	rte_free(*reset_vals);
805 	*reset_vals = NULL;
806 fail_reset_vals:
807 	sa->sw_stats.xstats_count = 0;
808 	rte_free(sw_stats->supp);
809 	sw_stats->supp = NULL;
810 	sw_stats->supp_count = 0;
811 
812 	return rc;
813 }
814 
815 static void
sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter * sa)816 sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa)
817 {
818 	rte_bitmap_free(sa->sw_stats.queues_bitmap);
819 	rte_free(sa->sw_stats.queues_bitmap_mem);
820 }
821 
822 static int
sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter * sa)823 sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa)
824 {
825 	struct rte_bitmap **queues_bitmap = &sa->sw_stats.queues_bitmap;
826 	void **queues_bitmap_mem = &sa->sw_stats.queues_bitmap_mem;
827 	uint32_t bmp_size;
828 	int rc;
829 
830 	bmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT);
831 	*queues_bitmap_mem = NULL;
832 	*queues_bitmap = NULL;
833 
834 	*queues_bitmap_mem = rte_calloc_socket("bitmap_mem", bmp_size, 1, 0,
835 					       sa->socket_id);
836 	if (*queues_bitmap_mem == NULL)
837 		return ENOMEM;
838 
839 	*queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT,
840 					 *queues_bitmap_mem, bmp_size);
841 	if (*queues_bitmap == NULL) {
842 		rc = EINVAL;
843 		goto fail;
844 	}
845 
846 	rte_spinlock_init(&sa->sw_stats.queues_bitmap_lock);
847 	return 0;
848 
849 fail:
850 	sfc_sw_xstats_free_queues_bitmap(sa);
851 	return rc;
852 }
853 
854 int
sfc_sw_xstats_init(struct sfc_adapter * sa)855 sfc_sw_xstats_init(struct sfc_adapter *sa)
856 {
857 	sa->sw_stats.xstats_count = 0;
858 	sa->sw_stats.supp = NULL;
859 	sa->sw_stats.supp_count = 0;
860 	sa->sw_stats.cache = NULL;
861 	sa->sw_stats.cache_count = 0;
862 	sa->sw_stats.reset_vals = NULL;
863 
864 	return sfc_sw_xstats_alloc_queues_bitmap(sa);
865 }
866 
867 void
sfc_sw_xstats_close(struct sfc_adapter * sa)868 sfc_sw_xstats_close(struct sfc_adapter *sa)
869 {
870 	sfc_sw_xstats_free_queues_bitmap(sa);
871 	sa->sw_stats.reset_vals = NULL;
872 	rte_free(sa->sw_stats.cache);
873 	sa->sw_stats.cache = NULL;
874 	sa->sw_stats.cache_count = 0;
875 	rte_free(sa->sw_stats.reset_vals);
876 	rte_free(sa->sw_stats.supp);
877 	sa->sw_stats.supp = NULL;
878 	sa->sw_stats.supp_count = 0;
879 	sa->sw_stats.xstats_count = 0;
880 }
881