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