1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2015 6WIND S.A.
3 * Copyright 2015 Mellanox Technologies, Ltd
7 #include <linux/sockios.h>
8 #include <linux/ethtool.h>
12 #include <rte_ethdev_driver.h>
13 #include <rte_common.h>
14 #include <rte_malloc.h>
16 #include <mlx5_common.h>
18 #include "mlx5_defs.h"
20 #include "mlx5_rxtx.h"
23 static const struct mlx5_counter_ctrl mlx5_counters_init[] = {
25 .dpdk_name = "rx_port_unicast_bytes",
26 .ctr_name = "rx_vport_unicast_bytes",
29 .dpdk_name = "rx_port_multicast_bytes",
30 .ctr_name = "rx_vport_multicast_bytes",
33 .dpdk_name = "rx_port_broadcast_bytes",
34 .ctr_name = "rx_vport_broadcast_bytes",
37 .dpdk_name = "rx_port_unicast_packets",
38 .ctr_name = "rx_vport_unicast_packets",
41 .dpdk_name = "rx_port_multicast_packets",
42 .ctr_name = "rx_vport_multicast_packets",
45 .dpdk_name = "rx_port_broadcast_packets",
46 .ctr_name = "rx_vport_broadcast_packets",
49 .dpdk_name = "tx_port_unicast_bytes",
50 .ctr_name = "tx_vport_unicast_bytes",
53 .dpdk_name = "tx_port_multicast_bytes",
54 .ctr_name = "tx_vport_multicast_bytes",
57 .dpdk_name = "tx_port_broadcast_bytes",
58 .ctr_name = "tx_vport_broadcast_bytes",
61 .dpdk_name = "tx_port_unicast_packets",
62 .ctr_name = "tx_vport_unicast_packets",
65 .dpdk_name = "tx_port_multicast_packets",
66 .ctr_name = "tx_vport_multicast_packets",
69 .dpdk_name = "tx_port_broadcast_packets",
70 .ctr_name = "tx_vport_broadcast_packets",
73 .dpdk_name = "rx_wqe_err",
74 .ctr_name = "rx_wqe_err",
77 .dpdk_name = "rx_crc_errors_phy",
78 .ctr_name = "rx_crc_errors_phy",
81 .dpdk_name = "rx_in_range_len_errors_phy",
82 .ctr_name = "rx_in_range_len_errors_phy",
85 .dpdk_name = "rx_symbol_err_phy",
86 .ctr_name = "rx_symbol_err_phy",
89 .dpdk_name = "tx_errors_phy",
90 .ctr_name = "tx_errors_phy",
93 .dpdk_name = "rx_out_of_buffer",
94 .ctr_name = "out_of_buffer",
98 .dpdk_name = "tx_packets_phy",
99 .ctr_name = "tx_packets_phy",
102 .dpdk_name = "rx_packets_phy",
103 .ctr_name = "rx_packets_phy",
106 .dpdk_name = "tx_discards_phy",
107 .ctr_name = "tx_discards_phy",
110 .dpdk_name = "rx_discards_phy",
111 .ctr_name = "rx_discards_phy",
114 .dpdk_name = "tx_bytes_phy",
115 .ctr_name = "tx_bytes_phy",
118 .dpdk_name = "rx_bytes_phy",
119 .ctr_name = "rx_bytes_phy",
121 /* Representor only */
123 .dpdk_name = "rx_packets",
124 .ctr_name = "vport_rx_packets",
127 .dpdk_name = "rx_bytes",
128 .ctr_name = "vport_rx_bytes",
131 .dpdk_name = "tx_packets",
132 .ctr_name = "vport_tx_packets",
135 .dpdk_name = "tx_bytes",
136 .ctr_name = "vport_tx_bytes",
140 static const unsigned int xstats_n = RTE_DIM(mlx5_counters_init);
143 mlx5_read_ib_stat(struct mlx5_priv *priv, const char *ctr_name, uint64_t *stat)
147 MKSTR(path, "%s/ports/%d/hw_counters/%s",
148 priv->sh->ibdev_path,
152 file = fopen(path, "rb");
154 int n = fscanf(file, "%" SCNu64, stat);
166 * Read device counters table.
169 * Pointer to Ethernet device.
171 * Counters table output buffer.
174 * 0 on success and stats is filled, negative errno value otherwise and
178 mlx5_read_dev_counters(struct rte_eth_dev *dev, uint64_t *stats)
180 struct mlx5_priv *priv = dev->data->dev_private;
181 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
184 unsigned int stats_sz = xstats_ctrl->stats_n * sizeof(uint64_t);
185 unsigned char et_stat_buf[sizeof(struct ethtool_stats) + stats_sz];
186 struct ethtool_stats *et_stats = (struct ethtool_stats *)et_stat_buf;
189 et_stats->cmd = ETHTOOL_GSTATS;
190 et_stats->n_stats = xstats_ctrl->stats_n;
191 ifr.ifr_data = (caddr_t)et_stats;
192 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
195 "port %u unable to read statistic values from device",
199 for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) {
200 if (xstats_ctrl->info[i].ib) {
201 ret = mlx5_read_ib_stat(priv,
202 xstats_ctrl->info[i].ctr_name,
204 /* return last xstats counter if fail to read. */
206 xstats_ctrl->xstats[i] = stats[i];
208 stats[i] = xstats_ctrl->xstats[i];
210 stats[i] = (uint64_t)
211 et_stats->data[xstats_ctrl->dev_table_idx[i]];
218 * Query the number of statistics provided by ETHTOOL.
221 * Pointer to Ethernet device.
224 * Number of statistics on success, negative errno value otherwise and
228 mlx5_ethtool_get_stats_n(struct rte_eth_dev *dev) {
229 struct ethtool_drvinfo drvinfo;
233 drvinfo.cmd = ETHTOOL_GDRVINFO;
234 ifr.ifr_data = (caddr_t)&drvinfo;
235 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
237 DRV_LOG(WARNING, "port %u unable to query number of statistics",
241 return drvinfo.n_stats;
245 * Init the structures to read device counters.
248 * Pointer to Ethernet device.
251 mlx5_stats_init(struct rte_eth_dev *dev)
253 struct mlx5_priv *priv = dev->data->dev_private;
254 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
255 struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
259 struct ethtool_gstrings *strings = NULL;
260 unsigned int dev_stats_n;
264 /* So that it won't aggregate for each init. */
265 xstats_ctrl->mlx5_stats_n = 0;
266 ret = mlx5_ethtool_get_stats_n(dev);
268 DRV_LOG(WARNING, "port %u no extended statistics available",
273 /* Allocate memory to grab stat names and values. */
274 str_sz = dev_stats_n * ETH_GSTRING_LEN;
275 strings = (struct ethtool_gstrings *)
276 rte_malloc("xstats_strings",
277 str_sz + sizeof(struct ethtool_gstrings), 0);
279 DRV_LOG(WARNING, "port %u unable to allocate memory for xstats",
283 strings->cmd = ETHTOOL_GSTRINGS;
284 strings->string_set = ETH_SS_STATS;
285 strings->len = dev_stats_n;
286 ifr.ifr_data = (caddr_t)strings;
287 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
289 DRV_LOG(WARNING, "port %u unable to get statistic names",
293 for (i = 0; i != dev_stats_n; ++i) {
294 const char *curr_string = (const char *)
295 &strings->data[i * ETH_GSTRING_LEN];
297 for (j = 0; j != xstats_n; ++j) {
298 if (!strcmp(mlx5_counters_init[j].ctr_name,
300 unsigned int idx = xstats_ctrl->mlx5_stats_n++;
302 xstats_ctrl->dev_table_idx[idx] = i;
303 xstats_ctrl->info[idx] = mlx5_counters_init[j];
308 /* Add IB counters. */
309 for (i = 0; i != xstats_n; ++i) {
310 if (mlx5_counters_init[i].ib) {
311 unsigned int idx = xstats_ctrl->mlx5_stats_n++;
313 xstats_ctrl->info[idx] = mlx5_counters_init[i];
314 xstats_ctrl->hw_stats[idx] = 0;
317 MLX5_ASSERT(xstats_ctrl->mlx5_stats_n <= MLX5_MAX_XSTATS);
318 xstats_ctrl->stats_n = dev_stats_n;
319 /* Copy to base at first time. */
320 ret = mlx5_read_dev_counters(dev, xstats_ctrl->base);
322 DRV_LOG(ERR, "port %u cannot read device counters: %s",
323 dev->data->port_id, strerror(rte_errno));
324 mlx5_read_ib_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
325 stats_ctrl->imissed = 0;
331 * DPDK callback to get extended device statistics.
334 * Pointer to Ethernet device.
336 * Pointer to rte extended stats table.
338 * The size of the stats table.
341 * Number of extended stats on success and stats is filled,
342 * negative on error and rte_errno is set.
345 mlx5_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
348 struct mlx5_priv *priv = dev->data->dev_private;
350 uint64_t counters[n];
351 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
352 uint16_t mlx5_stats_n = xstats_ctrl->mlx5_stats_n;
354 if (n >= mlx5_stats_n && stats) {
358 stats_n = mlx5_ethtool_get_stats_n(dev);
361 if (xstats_ctrl->stats_n != stats_n)
362 mlx5_stats_init(dev);
363 ret = mlx5_read_dev_counters(dev, counters);
366 for (i = 0; i != mlx5_stats_n; ++i) {
368 if (xstats_ctrl->info[i].ib) {
370 uint64_t hw_stat = xstats_ctrl->hw_stats[i];
372 stats[i].value = (counters[i] -
373 xstats_ctrl->base[i]) &
374 (uint64_t)UINT32_MAX;
375 wrap_n = hw_stat >> 32;
377 (hw_stat & (uint64_t)UINT32_MAX))
379 stats[i].value |= (wrap_n) << 32;
380 xstats_ctrl->hw_stats[i] = stats[i].value;
383 (counters[i] - xstats_ctrl->base[i]);
391 * DPDK callback to get device statistics.
394 * Pointer to Ethernet device structure.
396 * Stats structure output buffer.
399 * 0 on success and stats is filled, negative errno value otherwise and
403 mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
405 struct mlx5_priv *priv = dev->data->dev_private;
406 struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
407 struct rte_eth_stats tmp;
413 memset(&tmp, 0, sizeof(tmp));
414 /* Add software counters. */
415 for (i = 0; (i != priv->rxqs_n); ++i) {
416 struct mlx5_rxq_data *rxq = (*priv->rxqs)[i];
421 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
422 #ifdef MLX5_PMD_SOFT_COUNTERS
423 tmp.q_ipackets[idx] += rxq->stats.ipackets;
424 tmp.q_ibytes[idx] += rxq->stats.ibytes;
426 tmp.q_errors[idx] += (rxq->stats.idropped +
427 rxq->stats.rx_nombuf);
429 #ifdef MLX5_PMD_SOFT_COUNTERS
430 tmp.ipackets += rxq->stats.ipackets;
431 tmp.ibytes += rxq->stats.ibytes;
433 tmp.ierrors += rxq->stats.idropped;
434 tmp.rx_nombuf += rxq->stats.rx_nombuf;
436 for (i = 0; (i != priv->txqs_n); ++i) {
437 struct mlx5_txq_data *txq = (*priv->txqs)[i];
442 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
443 #ifdef MLX5_PMD_SOFT_COUNTERS
444 tmp.q_opackets[idx] += txq->stats.opackets;
445 tmp.q_obytes[idx] += txq->stats.obytes;
448 #ifdef MLX5_PMD_SOFT_COUNTERS
449 tmp.opackets += txq->stats.opackets;
450 tmp.obytes += txq->stats.obytes;
452 tmp.oerrors += txq->stats.oerrors;
454 ret = mlx5_read_ib_stat(priv, "out_of_buffer", &tmp.imissed);
456 tmp.imissed = (tmp.imissed - stats_ctrl->imissed_base) &
457 (uint64_t)UINT32_MAX;
458 wrap_n = stats_ctrl->imissed >> 32;
459 if (tmp.imissed < (stats_ctrl->imissed & (uint64_t)UINT32_MAX))
461 tmp.imissed |= (wrap_n) << 32;
462 stats_ctrl->imissed = tmp.imissed;
464 tmp.imissed = stats_ctrl->imissed;
466 #ifndef MLX5_PMD_SOFT_COUNTERS
467 /* FIXME: retrieve and add hardware counters. */
474 * DPDK callback to clear device statistics.
477 * Pointer to Ethernet device structure.
480 * always 0 on success and stats is reset
483 mlx5_stats_reset(struct rte_eth_dev *dev)
485 struct mlx5_priv *priv = dev->data->dev_private;
486 struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
489 for (i = 0; (i != priv->rxqs_n); ++i) {
490 if ((*priv->rxqs)[i] == NULL)
492 memset(&(*priv->rxqs)[i]->stats, 0,
493 sizeof(struct mlx5_rxq_stats));
495 for (i = 0; (i != priv->txqs_n); ++i) {
496 if ((*priv->txqs)[i] == NULL)
498 memset(&(*priv->txqs)[i]->stats, 0,
499 sizeof(struct mlx5_txq_stats));
501 mlx5_read_ib_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
502 stats_ctrl->imissed = 0;
503 #ifndef MLX5_PMD_SOFT_COUNTERS
504 /* FIXME: reset hardware counters. */
511 * DPDK callback to clear device extended statistics.
514 * Pointer to Ethernet device structure.
517 * 0 on success and stats is reset, negative errno value otherwise and
521 mlx5_xstats_reset(struct rte_eth_dev *dev)
523 struct mlx5_priv *priv = dev->data->dev_private;
524 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
527 unsigned int n = xstats_ctrl->mlx5_stats_n;
528 uint64_t counters[n];
531 stats_n = mlx5_ethtool_get_stats_n(dev);
533 DRV_LOG(ERR, "port %u cannot get stats: %s", dev->data->port_id,
537 if (xstats_ctrl->stats_n != stats_n)
538 mlx5_stats_init(dev);
539 ret = mlx5_read_dev_counters(dev, counters);
541 DRV_LOG(ERR, "port %u cannot read device counters: %s",
542 dev->data->port_id, strerror(rte_errno));
545 for (i = 0; i != n; ++i) {
546 xstats_ctrl->base[i] = counters[i];
547 xstats_ctrl->hw_stats[i] = 0;
554 * DPDK callback to retrieve names of extended device statistics
557 * Pointer to Ethernet device structure.
558 * @param[out] xstats_names
559 * Buffer to insert names into.
564 * Number of xstats names.
567 mlx5_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
568 struct rte_eth_xstat_name *xstats_names, unsigned int n)
571 struct mlx5_priv *priv = dev->data->dev_private;
572 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
573 unsigned int mlx5_xstats_n = xstats_ctrl->mlx5_stats_n;
575 if (n >= mlx5_xstats_n && xstats_names) {
576 for (i = 0; i != mlx5_xstats_n; ++i) {
577 strncpy(xstats_names[i].name,
578 xstats_ctrl->info[i].dpdk_name,
579 RTE_ETH_XSTATS_NAME_SIZE);
580 xstats_names[i].name[RTE_ETH_XSTATS_NAME_SIZE - 1] = 0;
583 return mlx5_xstats_n;