1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2015 6WIND S.A.
3 * Copyright 2015 Mellanox.
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>
17 #include "mlx5_rxtx.h"
18 #include "mlx5_defs.h"
20 struct mlx5_counter_ctrl {
21 /* Name of the counter. */
22 char dpdk_name[RTE_ETH_XSTATS_NAME_SIZE];
23 /* Name of the counter on the device table. */
24 char ctr_name[RTE_ETH_XSTATS_NAME_SIZE];
25 uint32_t ib:1; /**< Nonzero for IB counters. */
28 static const struct mlx5_counter_ctrl mlx5_counters_init[] = {
30 .dpdk_name = "rx_port_unicast_bytes",
31 .ctr_name = "rx_vport_unicast_bytes",
34 .dpdk_name = "rx_port_multicast_bytes",
35 .ctr_name = "rx_vport_multicast_bytes",
38 .dpdk_name = "rx_port_broadcast_bytes",
39 .ctr_name = "rx_vport_broadcast_bytes",
42 .dpdk_name = "rx_port_unicast_packets",
43 .ctr_name = "rx_vport_unicast_packets",
46 .dpdk_name = "rx_port_multicast_packets",
47 .ctr_name = "rx_vport_multicast_packets",
50 .dpdk_name = "rx_port_broadcast_packets",
51 .ctr_name = "rx_vport_broadcast_packets",
54 .dpdk_name = "tx_port_unicast_bytes",
55 .ctr_name = "tx_vport_unicast_bytes",
58 .dpdk_name = "tx_port_multicast_bytes",
59 .ctr_name = "tx_vport_multicast_bytes",
62 .dpdk_name = "tx_port_broadcast_bytes",
63 .ctr_name = "tx_vport_broadcast_bytes",
66 .dpdk_name = "tx_port_unicast_packets",
67 .ctr_name = "tx_vport_unicast_packets",
70 .dpdk_name = "tx_port_multicast_packets",
71 .ctr_name = "tx_vport_multicast_packets",
74 .dpdk_name = "tx_port_broadcast_packets",
75 .ctr_name = "tx_vport_broadcast_packets",
78 .dpdk_name = "rx_wqe_err",
79 .ctr_name = "rx_wqe_err",
82 .dpdk_name = "rx_crc_errors_phy",
83 .ctr_name = "rx_crc_errors_phy",
86 .dpdk_name = "rx_in_range_len_errors_phy",
87 .ctr_name = "rx_in_range_len_errors_phy",
90 .dpdk_name = "rx_symbol_err_phy",
91 .ctr_name = "rx_symbol_err_phy",
94 .dpdk_name = "tx_errors_phy",
95 .ctr_name = "tx_errors_phy",
98 .dpdk_name = "rx_out_of_buffer",
99 .ctr_name = "out_of_buffer",
103 .dpdk_name = "tx_packets_phy",
104 .ctr_name = "tx_packets_phy",
107 .dpdk_name = "rx_packets_phy",
108 .ctr_name = "rx_packets_phy",
111 .dpdk_name = "tx_bytes_phy",
112 .ctr_name = "tx_bytes_phy",
115 .dpdk_name = "rx_bytes_phy",
116 .ctr_name = "rx_bytes_phy",
120 static const unsigned int xstats_n = RTE_DIM(mlx5_counters_init);
123 * Read device counters table.
126 * Pointer to Ethernet device.
128 * Counters table output buffer.
131 * 0 on success and stats is filled, negative errno value otherwise and
135 mlx5_read_dev_counters(struct rte_eth_dev *dev, uint64_t *stats)
137 struct priv *priv = dev->data->dev_private;
138 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
141 unsigned int stats_sz = xstats_ctrl->stats_n * sizeof(uint64_t);
142 unsigned char et_stat_buf[sizeof(struct ethtool_stats) + stats_sz];
143 struct ethtool_stats *et_stats = (struct ethtool_stats *)et_stat_buf;
146 et_stats->cmd = ETHTOOL_GSTATS;
147 et_stats->n_stats = xstats_ctrl->stats_n;
148 ifr.ifr_data = (caddr_t)et_stats;
149 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
151 WARN("port %u unable to read statistic values from device",
155 for (i = 0; i != xstats_n; ++i) {
156 if (mlx5_counters_init[i].ib) {
158 MKSTR(path, "%s/ports/1/hw_counters/%s",
160 mlx5_counters_init[i].ctr_name);
162 file = fopen(path, "rb");
164 int n = fscanf(file, "%" SCNu64, &stats[i]);
171 stats[i] = (uint64_t)
172 et_stats->data[xstats_ctrl->dev_table_idx[i]];
179 * Query the number of statistics provided by ETHTOOL.
182 * Pointer to Ethernet device.
185 * Number of statistics on success, negative errno value otherwise and
189 mlx5_ethtool_get_stats_n(struct rte_eth_dev *dev) {
190 struct ethtool_drvinfo drvinfo;
194 drvinfo.cmd = ETHTOOL_GDRVINFO;
195 ifr.ifr_data = (caddr_t)&drvinfo;
196 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
198 WARN("port %u unable to query number of statistics",
202 return drvinfo.n_stats;
206 * Init the structures to read device counters.
209 * Pointer to Ethernet device.
212 mlx5_xstats_init(struct rte_eth_dev *dev)
214 struct priv *priv = dev->data->dev_private;
215 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
219 struct ethtool_gstrings *strings = NULL;
220 unsigned int dev_stats_n;
224 ret = mlx5_ethtool_get_stats_n(dev);
226 WARN("port %u no extended statistics available",
231 xstats_ctrl->stats_n = dev_stats_n;
232 /* Allocate memory to grab stat names and values. */
233 str_sz = dev_stats_n * ETH_GSTRING_LEN;
234 strings = (struct ethtool_gstrings *)
235 rte_malloc("xstats_strings",
236 str_sz + sizeof(struct ethtool_gstrings), 0);
238 WARN("port %u unable to allocate memory for xstats",
242 strings->cmd = ETHTOOL_GSTRINGS;
243 strings->string_set = ETH_SS_STATS;
244 strings->len = dev_stats_n;
245 ifr.ifr_data = (caddr_t)strings;
246 ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
248 WARN("port %u unable to get statistic names",
252 for (j = 0; j != xstats_n; ++j)
253 xstats_ctrl->dev_table_idx[j] = dev_stats_n;
254 for (i = 0; i != dev_stats_n; ++i) {
255 const char *curr_string = (const char *)
256 &strings->data[i * ETH_GSTRING_LEN];
258 for (j = 0; j != xstats_n; ++j) {
259 if (!strcmp(mlx5_counters_init[j].ctr_name,
261 xstats_ctrl->dev_table_idx[j] = i;
266 for (j = 0; j != xstats_n; ++j) {
267 if (mlx5_counters_init[j].ib)
269 if (xstats_ctrl->dev_table_idx[j] >= dev_stats_n) {
270 WARN("port %u counter \"%s\" is not recognized",
272 mlx5_counters_init[j].dpdk_name);
276 /* Copy to base at first time. */
277 assert(xstats_n <= MLX5_MAX_XSTATS);
278 ret = mlx5_read_dev_counters(dev, xstats_ctrl->base);
280 ERROR("port %u cannot read device counters: %s",
281 dev->data->port_id, strerror(rte_errno));
287 * DPDK callback to get extended device statistics.
290 * Pointer to Ethernet device.
292 * Pointer to rte extended stats table.
294 * The size of the stats table.
297 * Number of extended stats on success and stats is filled,
298 * negative on error and rte_errno is set.
301 mlx5_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
304 struct priv *priv = dev->data->dev_private;
306 uint64_t counters[n];
308 if (n >= xstats_n && stats) {
309 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
313 stats_n = mlx5_ethtool_get_stats_n(dev);
316 if (xstats_ctrl->stats_n != stats_n)
317 mlx5_xstats_init(dev);
318 ret = mlx5_read_dev_counters(dev, counters);
321 for (i = 0; i != xstats_n; ++i) {
323 stats[i].value = (counters[i] - xstats_ctrl->base[i]);
330 * DPDK callback to get device statistics.
333 * Pointer to Ethernet device structure.
335 * Stats structure output buffer.
338 * 0 on success and stats is filled, negative errno value otherwise and
342 mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
344 struct priv *priv = dev->data->dev_private;
345 struct rte_eth_stats tmp = {0};
349 /* Add software counters. */
350 for (i = 0; (i != priv->rxqs_n); ++i) {
351 struct mlx5_rxq_data *rxq = (*priv->rxqs)[i];
355 idx = rxq->stats.idx;
356 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
357 #ifdef MLX5_PMD_SOFT_COUNTERS
358 tmp.q_ipackets[idx] += rxq->stats.ipackets;
359 tmp.q_ibytes[idx] += rxq->stats.ibytes;
361 tmp.q_errors[idx] += (rxq->stats.idropped +
362 rxq->stats.rx_nombuf);
364 #ifdef MLX5_PMD_SOFT_COUNTERS
365 tmp.ipackets += rxq->stats.ipackets;
366 tmp.ibytes += rxq->stats.ibytes;
368 tmp.ierrors += rxq->stats.idropped;
369 tmp.rx_nombuf += rxq->stats.rx_nombuf;
371 for (i = 0; (i != priv->txqs_n); ++i) {
372 struct mlx5_txq_data *txq = (*priv->txqs)[i];
376 idx = txq->stats.idx;
377 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
378 #ifdef MLX5_PMD_SOFT_COUNTERS
379 tmp.q_opackets[idx] += txq->stats.opackets;
380 tmp.q_obytes[idx] += txq->stats.obytes;
382 tmp.q_errors[idx] += txq->stats.oerrors;
384 #ifdef MLX5_PMD_SOFT_COUNTERS
385 tmp.opackets += txq->stats.opackets;
386 tmp.obytes += txq->stats.obytes;
388 tmp.oerrors += txq->stats.oerrors;
390 #ifndef MLX5_PMD_SOFT_COUNTERS
391 /* FIXME: retrieve and add hardware counters. */
398 * DPDK callback to clear device statistics.
401 * Pointer to Ethernet device structure.
404 mlx5_stats_reset(struct rte_eth_dev *dev)
406 struct priv *priv = dev->data->dev_private;
410 for (i = 0; (i != priv->rxqs_n); ++i) {
411 if ((*priv->rxqs)[i] == NULL)
413 idx = (*priv->rxqs)[i]->stats.idx;
414 (*priv->rxqs)[i]->stats =
415 (struct mlx5_rxq_stats){ .idx = idx };
417 for (i = 0; (i != priv->txqs_n); ++i) {
418 if ((*priv->txqs)[i] == NULL)
420 idx = (*priv->txqs)[i]->stats.idx;
421 (*priv->txqs)[i]->stats =
422 (struct mlx5_txq_stats){ .idx = idx };
424 #ifndef MLX5_PMD_SOFT_COUNTERS
425 /* FIXME: reset hardware counters. */
430 * DPDK callback to clear device extended statistics.
433 * Pointer to Ethernet device structure.
436 mlx5_xstats_reset(struct rte_eth_dev *dev)
438 struct priv *priv = dev->data->dev_private;
439 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
442 unsigned int n = xstats_n;
443 uint64_t counters[n];
446 stats_n = mlx5_ethtool_get_stats_n(dev);
448 ERROR("port %u cannot get stats: %s", dev->data->port_id,
452 if (xstats_ctrl->stats_n != stats_n)
453 mlx5_xstats_init(dev);
454 ret = mlx5_read_dev_counters(dev, counters);
456 ERROR("port %u cannot read device counters: %s",
457 dev->data->port_id, strerror(rte_errno));
460 for (i = 0; i != n; ++i)
461 xstats_ctrl->base[i] = counters[i];
465 * DPDK callback to retrieve names of extended device statistics
468 * Pointer to Ethernet device structure.
469 * @param[out] xstats_names
470 * Buffer to insert names into.
475 * Number of xstats names.
478 mlx5_xstats_get_names(struct rte_eth_dev *dev __rte_unused,
479 struct rte_eth_xstat_name *xstats_names, unsigned int n)
483 if (n >= xstats_n && xstats_names) {
484 for (i = 0; i != xstats_n; ++i) {
485 strncpy(xstats_names[i].name,
486 mlx5_counters_init[i].dpdk_name,
487 RTE_ETH_XSTATS_NAME_SIZE);
488 xstats_names[i].name[RTE_ETH_XSTATS_NAME_SIZE - 1] = 0;