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