]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/dpdk/drivers/net/mlx5/mlx5_stats.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / seastar / dpdk / drivers / net / mlx5 / mlx5_stats.c
CommitLineData
9f95a23c
TL
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2015 6WIND S.A.
3 * Copyright 2015 Mellanox Technologies, Ltd
11fdf7f2
TL
4 */
5
9f95a23c 6#include <inttypes.h>
11fdf7f2
TL
7#include <linux/sockios.h>
8#include <linux/ethtool.h>
9f95a23c
TL
9#include <stdint.h>
10#include <stdio.h>
11fdf7f2 11
9f95a23c 12#include <rte_ethdev_driver.h>
11fdf7f2
TL
13#include <rte_common.h>
14#include <rte_malloc.h>
11fdf7f2
TL
15
16#include "mlx5.h"
17#include "mlx5_rxtx.h"
18#include "mlx5_defs.h"
19
11fdf7f2
TL
20static const struct mlx5_counter_ctrl mlx5_counters_init[] = {
21 {
22 .dpdk_name = "rx_port_unicast_bytes",
23 .ctr_name = "rx_vport_unicast_bytes",
24 },
25 {
26 .dpdk_name = "rx_port_multicast_bytes",
27 .ctr_name = "rx_vport_multicast_bytes",
28 },
29 {
30 .dpdk_name = "rx_port_broadcast_bytes",
31 .ctr_name = "rx_vport_broadcast_bytes",
32 },
33 {
34 .dpdk_name = "rx_port_unicast_packets",
35 .ctr_name = "rx_vport_unicast_packets",
36 },
37 {
38 .dpdk_name = "rx_port_multicast_packets",
39 .ctr_name = "rx_vport_multicast_packets",
40 },
41 {
42 .dpdk_name = "rx_port_broadcast_packets",
43 .ctr_name = "rx_vport_broadcast_packets",
44 },
45 {
46 .dpdk_name = "tx_port_unicast_bytes",
47 .ctr_name = "tx_vport_unicast_bytes",
48 },
49 {
50 .dpdk_name = "tx_port_multicast_bytes",
51 .ctr_name = "tx_vport_multicast_bytes",
52 },
53 {
54 .dpdk_name = "tx_port_broadcast_bytes",
55 .ctr_name = "tx_vport_broadcast_bytes",
56 },
57 {
58 .dpdk_name = "tx_port_unicast_packets",
59 .ctr_name = "tx_vport_unicast_packets",
60 },
61 {
62 .dpdk_name = "tx_port_multicast_packets",
63 .ctr_name = "tx_vport_multicast_packets",
64 },
65 {
66 .dpdk_name = "tx_port_broadcast_packets",
67 .ctr_name = "tx_vport_broadcast_packets",
68 },
69 {
70 .dpdk_name = "rx_wqe_err",
71 .ctr_name = "rx_wqe_err",
72 },
73 {
74 .dpdk_name = "rx_crc_errors_phy",
75 .ctr_name = "rx_crc_errors_phy",
76 },
77 {
78 .dpdk_name = "rx_in_range_len_errors_phy",
79 .ctr_name = "rx_in_range_len_errors_phy",
80 },
81 {
82 .dpdk_name = "rx_symbol_err_phy",
83 .ctr_name = "rx_symbol_err_phy",
84 },
85 {
86 .dpdk_name = "tx_errors_phy",
87 .ctr_name = "tx_errors_phy",
88 },
89 {
90 .dpdk_name = "rx_out_of_buffer",
91 .ctr_name = "out_of_buffer",
9f95a23c
TL
92 .ib = 1,
93 },
94 {
95 .dpdk_name = "tx_packets_phy",
96 .ctr_name = "tx_packets_phy",
97 },
98 {
99 .dpdk_name = "rx_packets_phy",
100 .ctr_name = "rx_packets_phy",
101 },
102 {
103 .dpdk_name = "tx_discards_phy",
104 .ctr_name = "tx_discards_phy",
105 },
106 {
107 .dpdk_name = "rx_discards_phy",
108 .ctr_name = "rx_discards_phy",
109 },
110 {
111 .dpdk_name = "tx_bytes_phy",
112 .ctr_name = "tx_bytes_phy",
113 },
114 {
115 .dpdk_name = "rx_bytes_phy",
116 .ctr_name = "rx_bytes_phy",
117 },
118 /* Representor only */
119 {
120 .dpdk_name = "rx_packets",
121 .ctr_name = "vport_rx_packets",
122 },
123 {
124 .dpdk_name = "rx_bytes",
125 .ctr_name = "vport_rx_bytes",
126 },
127 {
128 .dpdk_name = "tx_packets",
129 .ctr_name = "vport_tx_packets",
130 },
131 {
132 .dpdk_name = "tx_bytes",
133 .ctr_name = "vport_tx_bytes",
11fdf7f2
TL
134 },
135};
136
137static const unsigned int xstats_n = RTE_DIM(mlx5_counters_init);
138
9f95a23c
TL
139static inline void
140mlx5_read_ib_stat(struct mlx5_priv *priv, const char *ctr_name, uint64_t *stat)
141{
142 FILE *file;
143 if (priv->sh) {
144 MKSTR(path, "%s/ports/%d/hw_counters/%s",
145 priv->sh->ibdev_path,
146 priv->ibv_port,
147 ctr_name);
148
149 file = fopen(path, "rb");
150 if (file) {
151 int n = fscanf(file, "%" SCNu64, stat);
152
153 fclose(file);
154 if (n == 1)
155 return;
156 }
157 }
158 *stat = 0;
159}
160
11fdf7f2
TL
161/**
162 * Read device counters table.
163 *
9f95a23c
TL
164 * @param dev
165 * Pointer to Ethernet device.
11fdf7f2
TL
166 * @param[out] stats
167 * Counters table output buffer.
168 *
169 * @return
9f95a23c
TL
170 * 0 on success and stats is filled, negative errno value otherwise and
171 * rte_errno is set.
11fdf7f2
TL
172 */
173static int
9f95a23c 174mlx5_read_dev_counters(struct rte_eth_dev *dev, uint64_t *stats)
11fdf7f2 175{
9f95a23c 176 struct mlx5_priv *priv = dev->data->dev_private;
11fdf7f2
TL
177 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
178 unsigned int i;
179 struct ifreq ifr;
9f95a23c
TL
180 unsigned int stats_sz = xstats_ctrl->stats_n * sizeof(uint64_t);
181 unsigned char et_stat_buf[sizeof(struct ethtool_stats) + stats_sz];
182 struct ethtool_stats *et_stats = (struct ethtool_stats *)et_stat_buf;
183 int ret;
11fdf7f2
TL
184
185 et_stats->cmd = ETHTOOL_GSTATS;
186 et_stats->n_stats = xstats_ctrl->stats_n;
187 ifr.ifr_data = (caddr_t)et_stats;
9f95a23c
TL
188 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
189 if (ret) {
190 DRV_LOG(WARNING,
191 "port %u unable to read statistic values from device",
192 dev->data->port_id);
193 return ret;
11fdf7f2 194 }
9f95a23c
TL
195 for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) {
196 if (xstats_ctrl->info[i].ib) {
197 mlx5_read_ib_stat(priv, xstats_ctrl->info[i].ctr_name,
198 &stats[i]);
199 } else {
11fdf7f2
TL
200 stats[i] = (uint64_t)
201 et_stats->data[xstats_ctrl->dev_table_idx[i]];
9f95a23c 202 }
11fdf7f2
TL
203 }
204 return 0;
205}
206
207/**
208 * Query the number of statistics provided by ETHTOOL.
209 *
9f95a23c
TL
210 * @param dev
211 * Pointer to Ethernet device.
11fdf7f2
TL
212 *
213 * @return
9f95a23c
TL
214 * Number of statistics on success, negative errno value otherwise and
215 * rte_errno is set.
11fdf7f2
TL
216 */
217static int
9f95a23c 218mlx5_ethtool_get_stats_n(struct rte_eth_dev *dev) {
11fdf7f2
TL
219 struct ethtool_drvinfo drvinfo;
220 struct ifreq ifr;
9f95a23c 221 int ret;
11fdf7f2
TL
222
223 drvinfo.cmd = ETHTOOL_GDRVINFO;
224 ifr.ifr_data = (caddr_t)&drvinfo;
9f95a23c
TL
225 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
226 if (ret) {
227 DRV_LOG(WARNING, "port %u unable to query number of statistics",
228 dev->data->port_id);
229 return ret;
11fdf7f2
TL
230 }
231 return drvinfo.n_stats;
232}
233
234/**
235 * Init the structures to read device counters.
236 *
9f95a23c
TL
237 * @param dev
238 * Pointer to Ethernet device.
11fdf7f2
TL
239 */
240void
9f95a23c 241mlx5_stats_init(struct rte_eth_dev *dev)
11fdf7f2 242{
9f95a23c 243 struct mlx5_priv *priv = dev->data->dev_private;
11fdf7f2 244 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
9f95a23c 245 struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
11fdf7f2
TL
246 unsigned int i;
247 unsigned int j;
248 struct ifreq ifr;
249 struct ethtool_gstrings *strings = NULL;
250 unsigned int dev_stats_n;
251 unsigned int str_sz;
9f95a23c 252 int ret;
11fdf7f2 253
9f95a23c
TL
254 /* So that it won't aggregate for each init. */
255 xstats_ctrl->mlx5_stats_n = 0;
256 ret = mlx5_ethtool_get_stats_n(dev);
257 if (ret < 0) {
258 DRV_LOG(WARNING, "port %u no extended statistics available",
259 dev->data->port_id);
11fdf7f2
TL
260 return;
261 }
9f95a23c 262 dev_stats_n = ret;
11fdf7f2
TL
263 /* Allocate memory to grab stat names and values. */
264 str_sz = dev_stats_n * ETH_GSTRING_LEN;
265 strings = (struct ethtool_gstrings *)
266 rte_malloc("xstats_strings",
267 str_sz + sizeof(struct ethtool_gstrings), 0);
268 if (!strings) {
9f95a23c
TL
269 DRV_LOG(WARNING, "port %u unable to allocate memory for xstats",
270 dev->data->port_id);
11fdf7f2
TL
271 return;
272 }
273 strings->cmd = ETHTOOL_GSTRINGS;
274 strings->string_set = ETH_SS_STATS;
275 strings->len = dev_stats_n;
276 ifr.ifr_data = (caddr_t)strings;
9f95a23c
TL
277 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
278 if (ret) {
279 DRV_LOG(WARNING, "port %u unable to get statistic names",
280 dev->data->port_id);
11fdf7f2
TL
281 goto free;
282 }
11fdf7f2
TL
283 for (i = 0; i != dev_stats_n; ++i) {
284 const char *curr_string = (const char *)
285 &strings->data[i * ETH_GSTRING_LEN];
286
287 for (j = 0; j != xstats_n; ++j) {
288 if (!strcmp(mlx5_counters_init[j].ctr_name,
289 curr_string)) {
9f95a23c
TL
290 unsigned int idx = xstats_ctrl->mlx5_stats_n++;
291
292 xstats_ctrl->dev_table_idx[idx] = i;
293 xstats_ctrl->info[idx] = mlx5_counters_init[j];
11fdf7f2
TL
294 break;
295 }
296 }
297 }
9f95a23c
TL
298 /* Add IB counters. */
299 for (i = 0; i != xstats_n; ++i) {
300 if (mlx5_counters_init[i].ib) {
301 unsigned int idx = xstats_ctrl->mlx5_stats_n++;
302
303 xstats_ctrl->info[idx] = mlx5_counters_init[i];
11fdf7f2
TL
304 }
305 }
9f95a23c
TL
306 assert(xstats_ctrl->mlx5_stats_n <= MLX5_MAX_XSTATS);
307 xstats_ctrl->stats_n = dev_stats_n;
11fdf7f2 308 /* Copy to base at first time. */
9f95a23c
TL
309 ret = mlx5_read_dev_counters(dev, xstats_ctrl->base);
310 if (ret)
311 DRV_LOG(ERR, "port %u cannot read device counters: %s",
312 dev->data->port_id, strerror(rte_errno));
313 mlx5_read_ib_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
11fdf7f2
TL
314free:
315 rte_free(strings);
316}
317
318/**
9f95a23c 319 * DPDK callback to get extended device statistics.
11fdf7f2 320 *
9f95a23c
TL
321 * @param dev
322 * Pointer to Ethernet device.
11fdf7f2
TL
323 * @param[out] stats
324 * Pointer to rte extended stats table.
9f95a23c
TL
325 * @param n
326 * The size of the stats table.
11fdf7f2
TL
327 *
328 * @return
329 * Number of extended stats on success and stats is filled,
9f95a23c 330 * negative on error and rte_errno is set.
11fdf7f2 331 */
9f95a23c
TL
332int
333mlx5_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
334 unsigned int n)
11fdf7f2 335{
9f95a23c 336 struct mlx5_priv *priv = dev->data->dev_private;
11fdf7f2 337 unsigned int i;
11fdf7f2 338 uint64_t counters[n];
11fdf7f2 339 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
9f95a23c 340 uint16_t mlx5_stats_n = xstats_ctrl->mlx5_stats_n;
11fdf7f2 341
9f95a23c
TL
342 if (n >= mlx5_stats_n && stats) {
343 int stats_n;
344 int ret;
345
346 stats_n = mlx5_ethtool_get_stats_n(dev);
347 if (stats_n < 0)
348 return stats_n;
349 if (xstats_ctrl->stats_n != stats_n)
350 mlx5_stats_init(dev);
351 ret = mlx5_read_dev_counters(dev, counters);
352 if (ret)
353 return ret;
354 for (i = 0; i != mlx5_stats_n; ++i) {
355 stats[i].id = i;
356 stats[i].value = (counters[i] - xstats_ctrl->base[i]);
357 }
358 }
359 return mlx5_stats_n;
11fdf7f2
TL
360}
361
362/**
363 * DPDK callback to get device statistics.
364 *
365 * @param dev
366 * Pointer to Ethernet device structure.
367 * @param[out] stats
368 * Stats structure output buffer.
9f95a23c
TL
369 *
370 * @return
371 * 0 on success and stats is filled, negative errno value otherwise and
372 * rte_errno is set.
11fdf7f2 373 */
9f95a23c 374int
11fdf7f2
TL
375mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
376{
9f95a23c
TL
377 struct mlx5_priv *priv = dev->data->dev_private;
378 struct rte_eth_stats tmp;
11fdf7f2
TL
379 unsigned int i;
380 unsigned int idx;
381
9f95a23c 382 memset(&tmp, 0, sizeof(tmp));
11fdf7f2
TL
383 /* Add software counters. */
384 for (i = 0; (i != priv->rxqs_n); ++i) {
9f95a23c 385 struct mlx5_rxq_data *rxq = (*priv->rxqs)[i];
11fdf7f2
TL
386
387 if (rxq == NULL)
388 continue;
9f95a23c 389 idx = rxq->idx;
11fdf7f2
TL
390 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
391#ifdef MLX5_PMD_SOFT_COUNTERS
392 tmp.q_ipackets[idx] += rxq->stats.ipackets;
393 tmp.q_ibytes[idx] += rxq->stats.ibytes;
394#endif
395 tmp.q_errors[idx] += (rxq->stats.idropped +
396 rxq->stats.rx_nombuf);
397 }
398#ifdef MLX5_PMD_SOFT_COUNTERS
399 tmp.ipackets += rxq->stats.ipackets;
400 tmp.ibytes += rxq->stats.ibytes;
401#endif
402 tmp.ierrors += rxq->stats.idropped;
403 tmp.rx_nombuf += rxq->stats.rx_nombuf;
404 }
405 for (i = 0; (i != priv->txqs_n); ++i) {
9f95a23c 406 struct mlx5_txq_data *txq = (*priv->txqs)[i];
11fdf7f2
TL
407
408 if (txq == NULL)
409 continue;
9f95a23c 410 idx = txq->idx;
11fdf7f2
TL
411 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
412#ifdef MLX5_PMD_SOFT_COUNTERS
413 tmp.q_opackets[idx] += txq->stats.opackets;
414 tmp.q_obytes[idx] += txq->stats.obytes;
415#endif
9f95a23c 416 tmp.q_errors[idx] += txq->stats.oerrors;
11fdf7f2
TL
417 }
418#ifdef MLX5_PMD_SOFT_COUNTERS
419 tmp.opackets += txq->stats.opackets;
420 tmp.obytes += txq->stats.obytes;
421#endif
9f95a23c 422 tmp.oerrors += txq->stats.oerrors;
11fdf7f2 423 }
9f95a23c
TL
424 mlx5_read_ib_stat(priv, "out_of_buffer", &tmp.imissed);
425 tmp.imissed -= priv->stats_ctrl.imissed_base;
11fdf7f2
TL
426#ifndef MLX5_PMD_SOFT_COUNTERS
427 /* FIXME: retrieve and add hardware counters. */
428#endif
429 *stats = tmp;
9f95a23c 430 return 0;
11fdf7f2
TL
431}
432
433/**
434 * DPDK callback to clear device statistics.
435 *
436 * @param dev
437 * Pointer to Ethernet device structure.
438 */
439void
440mlx5_stats_reset(struct rte_eth_dev *dev)
441{
9f95a23c
TL
442 struct mlx5_priv *priv = dev->data->dev_private;
443 struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
11fdf7f2 444 unsigned int i;
11fdf7f2 445
11fdf7f2
TL
446 for (i = 0; (i != priv->rxqs_n); ++i) {
447 if ((*priv->rxqs)[i] == NULL)
448 continue;
9f95a23c
TL
449 memset(&(*priv->rxqs)[i]->stats, 0,
450 sizeof(struct mlx5_rxq_stats));
11fdf7f2
TL
451 }
452 for (i = 0; (i != priv->txqs_n); ++i) {
453 if ((*priv->txqs)[i] == NULL)
454 continue;
9f95a23c
TL
455 memset(&(*priv->txqs)[i]->stats, 0,
456 sizeof(struct mlx5_txq_stats));
11fdf7f2 457 }
9f95a23c 458 mlx5_read_ib_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
11fdf7f2
TL
459#ifndef MLX5_PMD_SOFT_COUNTERS
460 /* FIXME: reset hardware counters. */
461#endif
11fdf7f2
TL
462}
463
464/**
465 * DPDK callback to clear device extended statistics.
466 *
467 * @param dev
468 * Pointer to Ethernet device structure.
469 */
470void
471mlx5_xstats_reset(struct rte_eth_dev *dev)
472{
9f95a23c 473 struct mlx5_priv *priv = dev->data->dev_private;
11fdf7f2
TL
474 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
475 int stats_n;
9f95a23c
TL
476 unsigned int i;
477 unsigned int n = xstats_ctrl->mlx5_stats_n;
478 uint64_t counters[n];
479 int ret;
11fdf7f2 480
9f95a23c
TL
481 stats_n = mlx5_ethtool_get_stats_n(dev);
482 if (stats_n < 0) {
483 DRV_LOG(ERR, "port %u cannot get stats: %s", dev->data->port_id,
484 strerror(-stats_n));
11fdf7f2 485 return;
9f95a23c 486 }
11fdf7f2 487 if (xstats_ctrl->stats_n != stats_n)
9f95a23c
TL
488 mlx5_stats_init(dev);
489 ret = mlx5_read_dev_counters(dev, counters);
490 if (ret) {
491 DRV_LOG(ERR, "port %u cannot read device counters: %s",
492 dev->data->port_id, strerror(rte_errno));
493 return;
494 }
495 for (i = 0; i != n; ++i)
496 xstats_ctrl->base[i] = counters[i];
11fdf7f2
TL
497}
498
499/**
500 * DPDK callback to retrieve names of extended device statistics
501 *
502 * @param dev
503 * Pointer to Ethernet device structure.
504 * @param[out] xstats_names
505 * Buffer to insert names into.
506 * @param n
507 * Number of names.
508 *
509 * @return
510 * Number of xstats names.
511 */
512int
9f95a23c
TL
513mlx5_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
514 struct rte_eth_xstat_name *xstats_names, unsigned int n)
11fdf7f2 515{
11fdf7f2 516 unsigned int i;
9f95a23c
TL
517 struct mlx5_priv *priv = dev->data->dev_private;
518 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
519 unsigned int mlx5_xstats_n = xstats_ctrl->mlx5_stats_n;
11fdf7f2 520
9f95a23c
TL
521 if (n >= mlx5_xstats_n && xstats_names) {
522 for (i = 0; i != mlx5_xstats_n; ++i) {
11fdf7f2 523 strncpy(xstats_names[i].name,
9f95a23c 524 xstats_ctrl->info[i].dpdk_name,
11fdf7f2
TL
525 RTE_ETH_XSTATS_NAME_SIZE);
526 xstats_names[i].name[RTE_ETH_XSTATS_NAME_SIZE - 1] = 0;
527 }
11fdf7f2 528 }
9f95a23c 529 return mlx5_xstats_n;
11fdf7f2 530}