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