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>
17 #include "mlx5_rxtx.h"
18 #include "mlx5_defs.h"
20 static const struct mlx5_counter_ctrl mlx5_counters_init
[] = {
22 .dpdk_name
= "rx_port_unicast_bytes",
23 .ctr_name
= "rx_vport_unicast_bytes",
26 .dpdk_name
= "rx_port_multicast_bytes",
27 .ctr_name
= "rx_vport_multicast_bytes",
30 .dpdk_name
= "rx_port_broadcast_bytes",
31 .ctr_name
= "rx_vport_broadcast_bytes",
34 .dpdk_name
= "rx_port_unicast_packets",
35 .ctr_name
= "rx_vport_unicast_packets",
38 .dpdk_name
= "rx_port_multicast_packets",
39 .ctr_name
= "rx_vport_multicast_packets",
42 .dpdk_name
= "rx_port_broadcast_packets",
43 .ctr_name
= "rx_vport_broadcast_packets",
46 .dpdk_name
= "tx_port_unicast_bytes",
47 .ctr_name
= "tx_vport_unicast_bytes",
50 .dpdk_name
= "tx_port_multicast_bytes",
51 .ctr_name
= "tx_vport_multicast_bytes",
54 .dpdk_name
= "tx_port_broadcast_bytes",
55 .ctr_name
= "tx_vport_broadcast_bytes",
58 .dpdk_name
= "tx_port_unicast_packets",
59 .ctr_name
= "tx_vport_unicast_packets",
62 .dpdk_name
= "tx_port_multicast_packets",
63 .ctr_name
= "tx_vport_multicast_packets",
66 .dpdk_name
= "tx_port_broadcast_packets",
67 .ctr_name
= "tx_vport_broadcast_packets",
70 .dpdk_name
= "rx_wqe_err",
71 .ctr_name
= "rx_wqe_err",
74 .dpdk_name
= "rx_crc_errors_phy",
75 .ctr_name
= "rx_crc_errors_phy",
78 .dpdk_name
= "rx_in_range_len_errors_phy",
79 .ctr_name
= "rx_in_range_len_errors_phy",
82 .dpdk_name
= "rx_symbol_err_phy",
83 .ctr_name
= "rx_symbol_err_phy",
86 .dpdk_name
= "tx_errors_phy",
87 .ctr_name
= "tx_errors_phy",
90 .dpdk_name
= "rx_out_of_buffer",
91 .ctr_name
= "out_of_buffer",
95 .dpdk_name
= "tx_packets_phy",
96 .ctr_name
= "tx_packets_phy",
99 .dpdk_name
= "rx_packets_phy",
100 .ctr_name
= "rx_packets_phy",
103 .dpdk_name
= "tx_discards_phy",
104 .ctr_name
= "tx_discards_phy",
107 .dpdk_name
= "rx_discards_phy",
108 .ctr_name
= "rx_discards_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",
118 /* Representor only */
120 .dpdk_name
= "rx_packets",
121 .ctr_name
= "vport_rx_packets",
124 .dpdk_name
= "rx_bytes",
125 .ctr_name
= "vport_rx_bytes",
128 .dpdk_name
= "tx_packets",
129 .ctr_name
= "vport_tx_packets",
132 .dpdk_name
= "tx_bytes",
133 .ctr_name
= "vport_tx_bytes",
137 static const unsigned int xstats_n
= RTE_DIM(mlx5_counters_init
);
140 mlx5_read_ib_stat(struct mlx5_priv
*priv
, const char *ctr_name
, uint64_t *stat
)
144 MKSTR(path
, "%s/ports/%d/hw_counters/%s",
145 priv
->sh
->ibdev_path
,
149 file
= fopen(path
, "rb");
151 int n
= fscanf(file
, "%" SCNu64
, stat
);
162 * Read device counters table.
165 * Pointer to Ethernet device.
167 * Counters table output buffer.
170 * 0 on success and stats is filled, negative errno value otherwise and
174 mlx5_read_dev_counters(struct rte_eth_dev
*dev
, uint64_t *stats
)
176 struct mlx5_priv
*priv
= dev
->data
->dev_private
;
177 struct mlx5_xstats_ctrl
*xstats_ctrl
= &priv
->xstats_ctrl
;
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
;
185 et_stats
->cmd
= ETHTOOL_GSTATS
;
186 et_stats
->n_stats
= xstats_ctrl
->stats_n
;
187 ifr
.ifr_data
= (caddr_t
)et_stats
;
188 ret
= mlx5_ifreq(dev
, SIOCETHTOOL
, &ifr
);
191 "port %u unable to read statistic values from device",
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
,
200 stats
[i
] = (uint64_t)
201 et_stats
->data
[xstats_ctrl
->dev_table_idx
[i
]];
208 * Query the number of statistics provided by ETHTOOL.
211 * Pointer to Ethernet device.
214 * Number of statistics on success, negative errno value otherwise and
218 mlx5_ethtool_get_stats_n(struct rte_eth_dev
*dev
) {
219 struct ethtool_drvinfo drvinfo
;
223 drvinfo
.cmd
= ETHTOOL_GDRVINFO
;
224 ifr
.ifr_data
= (caddr_t
)&drvinfo
;
225 ret
= mlx5_ifreq(dev
, SIOCETHTOOL
, &ifr
);
227 DRV_LOG(WARNING
, "port %u unable to query number of statistics",
231 return drvinfo
.n_stats
;
235 * Init the structures to read device counters.
238 * Pointer to Ethernet device.
241 mlx5_stats_init(struct rte_eth_dev
*dev
)
243 struct mlx5_priv
*priv
= dev
->data
->dev_private
;
244 struct mlx5_xstats_ctrl
*xstats_ctrl
= &priv
->xstats_ctrl
;
245 struct mlx5_stats_ctrl
*stats_ctrl
= &priv
->stats_ctrl
;
249 struct ethtool_gstrings
*strings
= NULL
;
250 unsigned int dev_stats_n
;
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
);
258 DRV_LOG(WARNING
, "port %u no extended statistics available",
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);
269 DRV_LOG(WARNING
, "port %u unable to allocate memory for xstats",
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
;
277 ret
= mlx5_ifreq(dev
, SIOCETHTOOL
, &ifr
);
279 DRV_LOG(WARNING
, "port %u unable to get statistic names",
283 for (i
= 0; i
!= dev_stats_n
; ++i
) {
284 const char *curr_string
= (const char *)
285 &strings
->data
[i
* ETH_GSTRING_LEN
];
287 for (j
= 0; j
!= xstats_n
; ++j
) {
288 if (!strcmp(mlx5_counters_init
[j
].ctr_name
,
290 unsigned int idx
= xstats_ctrl
->mlx5_stats_n
++;
292 xstats_ctrl
->dev_table_idx
[idx
] = i
;
293 xstats_ctrl
->info
[idx
] = mlx5_counters_init
[j
];
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
++;
303 xstats_ctrl
->info
[idx
] = mlx5_counters_init
[i
];
306 assert(xstats_ctrl
->mlx5_stats_n
<= MLX5_MAX_XSTATS
);
307 xstats_ctrl
->stats_n
= dev_stats_n
;
308 /* Copy to base at first time. */
309 ret
= mlx5_read_dev_counters(dev
, xstats_ctrl
->base
);
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
);
319 * DPDK callback to get extended device statistics.
322 * Pointer to Ethernet device.
324 * Pointer to rte extended stats table.
326 * The size of the stats table.
329 * Number of extended stats on success and stats is filled,
330 * negative on error and rte_errno is set.
333 mlx5_xstats_get(struct rte_eth_dev
*dev
, struct rte_eth_xstat
*stats
,
336 struct mlx5_priv
*priv
= dev
->data
->dev_private
;
338 uint64_t counters
[n
];
339 struct mlx5_xstats_ctrl
*xstats_ctrl
= &priv
->xstats_ctrl
;
340 uint16_t mlx5_stats_n
= xstats_ctrl
->mlx5_stats_n
;
342 if (n
>= mlx5_stats_n
&& stats
) {
346 stats_n
= mlx5_ethtool_get_stats_n(dev
);
349 if (xstats_ctrl
->stats_n
!= stats_n
)
350 mlx5_stats_init(dev
);
351 ret
= mlx5_read_dev_counters(dev
, counters
);
354 for (i
= 0; i
!= mlx5_stats_n
; ++i
) {
356 stats
[i
].value
= (counters
[i
] - xstats_ctrl
->base
[i
]);
363 * DPDK callback to get device statistics.
366 * Pointer to Ethernet device structure.
368 * Stats structure output buffer.
371 * 0 on success and stats is filled, negative errno value otherwise and
375 mlx5_stats_get(struct rte_eth_dev
*dev
, struct rte_eth_stats
*stats
)
377 struct mlx5_priv
*priv
= dev
->data
->dev_private
;
378 struct rte_eth_stats tmp
;
382 memset(&tmp
, 0, sizeof(tmp
));
383 /* Add software counters. */
384 for (i
= 0; (i
!= priv
->rxqs_n
); ++i
) {
385 struct mlx5_rxq_data
*rxq
= (*priv
->rxqs
)[i
];
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
;
395 tmp
.q_errors
[idx
] += (rxq
->stats
.idropped
+
396 rxq
->stats
.rx_nombuf
);
398 #ifdef MLX5_PMD_SOFT_COUNTERS
399 tmp
.ipackets
+= rxq
->stats
.ipackets
;
400 tmp
.ibytes
+= rxq
->stats
.ibytes
;
402 tmp
.ierrors
+= rxq
->stats
.idropped
;
403 tmp
.rx_nombuf
+= rxq
->stats
.rx_nombuf
;
405 for (i
= 0; (i
!= priv
->txqs_n
); ++i
) {
406 struct mlx5_txq_data
*txq
= (*priv
->txqs
)[i
];
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
;
416 tmp
.q_errors
[idx
] += txq
->stats
.oerrors
;
418 #ifdef MLX5_PMD_SOFT_COUNTERS
419 tmp
.opackets
+= txq
->stats
.opackets
;
420 tmp
.obytes
+= txq
->stats
.obytes
;
422 tmp
.oerrors
+= txq
->stats
.oerrors
;
424 mlx5_read_ib_stat(priv
, "out_of_buffer", &tmp
.imissed
);
425 tmp
.imissed
-= priv
->stats_ctrl
.imissed_base
;
426 #ifndef MLX5_PMD_SOFT_COUNTERS
427 /* FIXME: retrieve and add hardware counters. */
434 * DPDK callback to clear device statistics.
437 * Pointer to Ethernet device structure.
440 mlx5_stats_reset(struct rte_eth_dev
*dev
)
442 struct mlx5_priv
*priv
= dev
->data
->dev_private
;
443 struct mlx5_stats_ctrl
*stats_ctrl
= &priv
->stats_ctrl
;
446 for (i
= 0; (i
!= priv
->rxqs_n
); ++i
) {
447 if ((*priv
->rxqs
)[i
] == NULL
)
449 memset(&(*priv
->rxqs
)[i
]->stats
, 0,
450 sizeof(struct mlx5_rxq_stats
));
452 for (i
= 0; (i
!= priv
->txqs_n
); ++i
) {
453 if ((*priv
->txqs
)[i
] == NULL
)
455 memset(&(*priv
->txqs
)[i
]->stats
, 0,
456 sizeof(struct mlx5_txq_stats
));
458 mlx5_read_ib_stat(priv
, "out_of_buffer", &stats_ctrl
->imissed_base
);
459 #ifndef MLX5_PMD_SOFT_COUNTERS
460 /* FIXME: reset hardware counters. */
465 * DPDK callback to clear device extended statistics.
468 * Pointer to Ethernet device structure.
471 mlx5_xstats_reset(struct rte_eth_dev
*dev
)
473 struct mlx5_priv
*priv
= dev
->data
->dev_private
;
474 struct mlx5_xstats_ctrl
*xstats_ctrl
= &priv
->xstats_ctrl
;
477 unsigned int n
= xstats_ctrl
->mlx5_stats_n
;
478 uint64_t counters
[n
];
481 stats_n
= mlx5_ethtool_get_stats_n(dev
);
483 DRV_LOG(ERR
, "port %u cannot get stats: %s", dev
->data
->port_id
,
487 if (xstats_ctrl
->stats_n
!= stats_n
)
488 mlx5_stats_init(dev
);
489 ret
= mlx5_read_dev_counters(dev
, counters
);
491 DRV_LOG(ERR
, "port %u cannot read device counters: %s",
492 dev
->data
->port_id
, strerror(rte_errno
));
495 for (i
= 0; i
!= n
; ++i
)
496 xstats_ctrl
->base
[i
] = counters
[i
];
500 * DPDK callback to retrieve names of extended device statistics
503 * Pointer to Ethernet device structure.
504 * @param[out] xstats_names
505 * Buffer to insert names into.
510 * Number of xstats names.
513 mlx5_xstats_get_names(struct rte_eth_dev
*dev __rte_unused
,
514 struct rte_eth_xstat_name
*xstats_names
, unsigned int n
)
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
;
521 if (n
>= mlx5_xstats_n
&& xstats_names
) {
522 for (i
= 0; i
!= mlx5_xstats_n
; ++i
) {
523 strncpy(xstats_names
[i
].name
,
524 xstats_ctrl
->info
[i
].dpdk_name
,
525 RTE_ETH_XSTATS_NAME_SIZE
);
526 xstats_names
[i
].name
[RTE_ETH_XSTATS_NAME_SIZE
- 1] = 0;
529 return mlx5_xstats_n
;