net/mlx5: fix xstats reset reinitialization
[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 <stdint.h>
8 #include <stdio.h>
9 #include <unistd.h>
10
11 #include <rte_ethdev_driver.h>
12 #include <rte_common.h>
13 #include <rte_malloc.h>
14
15 #include <mlx5_common.h>
16
17 #include "mlx5_defs.h"
18 #include "mlx5.h"
19 #include "mlx5_rxtx.h"
20 #include "mlx5_malloc.h"
21
22 /**
23  * DPDK callback to get extended device statistics.
24  *
25  * @param dev
26  *   Pointer to Ethernet device.
27  * @param[out] stats
28  *   Pointer to rte extended stats table.
29  * @param n
30  *   The size of the stats table.
31  *
32  * @return
33  *   Number of extended stats on success and stats is filled,
34  *   negative on error and rte_errno is set.
35  */
36 int
37 mlx5_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
38                 unsigned int n)
39 {
40         struct mlx5_priv *priv = dev->data->dev_private;
41         unsigned int i;
42         uint64_t counters[n];
43         struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
44         uint16_t mlx5_stats_n = xstats_ctrl->mlx5_stats_n;
45
46         if (n >= mlx5_stats_n && stats) {
47                 int stats_n;
48                 int ret;
49
50                 stats_n = mlx5_os_get_stats_n(dev);
51                 if (stats_n < 0)
52                         return stats_n;
53                 if (xstats_ctrl->stats_n != stats_n)
54                         mlx5_os_stats_init(dev);
55                 ret = mlx5_os_read_dev_counters(dev, counters);
56                 if (ret)
57                         return ret;
58                 for (i = 0; i != mlx5_stats_n; ++i) {
59                         stats[i].id = i;
60                         if (xstats_ctrl->info[i].dev) {
61                                 uint64_t wrap_n;
62                                 uint64_t hw_stat = xstats_ctrl->hw_stats[i];
63
64                                 stats[i].value = (counters[i] -
65                                                   xstats_ctrl->base[i]) &
66                                                   (uint64_t)UINT32_MAX;
67                                 wrap_n = hw_stat >> 32;
68                                 if (stats[i].value <
69                                             (hw_stat & (uint64_t)UINT32_MAX))
70                                         wrap_n++;
71                                 stats[i].value |= (wrap_n) << 32;
72                                 xstats_ctrl->hw_stats[i] = stats[i].value;
73                         } else {
74                                 stats[i].value =
75                                         (counters[i] - xstats_ctrl->base[i]);
76                         }
77                 }
78         }
79         mlx5_stats_n = mlx5_txpp_xstats_get(dev, stats, n, mlx5_stats_n);
80         return mlx5_stats_n;
81 }
82
83 /**
84  * DPDK callback to get device statistics.
85  *
86  * @param dev
87  *   Pointer to Ethernet device structure.
88  * @param[out] stats
89  *   Stats structure output buffer.
90  *
91  * @return
92  *   0 on success and stats is filled, negative errno value otherwise and
93  *   rte_errno is set.
94  */
95 int
96 mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
97 {
98         struct mlx5_priv *priv = dev->data->dev_private;
99         struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
100         struct rte_eth_stats tmp;
101         unsigned int i;
102         unsigned int idx;
103         uint64_t wrap_n;
104         int ret;
105
106         memset(&tmp, 0, sizeof(tmp));
107         /* Add software counters. */
108         for (i = 0; (i != priv->rxqs_n); ++i) {
109                 struct mlx5_rxq_data *rxq = (*priv->rxqs)[i];
110
111                 if (rxq == NULL)
112                         continue;
113                 idx = rxq->idx;
114                 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
115 #ifdef MLX5_PMD_SOFT_COUNTERS
116                         tmp.q_ipackets[idx] += rxq->stats.ipackets;
117                         tmp.q_ibytes[idx] += rxq->stats.ibytes;
118 #endif
119                         tmp.q_errors[idx] += (rxq->stats.idropped +
120                                               rxq->stats.rx_nombuf);
121                 }
122 #ifdef MLX5_PMD_SOFT_COUNTERS
123                 tmp.ipackets += rxq->stats.ipackets;
124                 tmp.ibytes += rxq->stats.ibytes;
125 #endif
126                 tmp.ierrors += rxq->stats.idropped;
127                 tmp.rx_nombuf += rxq->stats.rx_nombuf;
128         }
129         for (i = 0; (i != priv->txqs_n); ++i) {
130                 struct mlx5_txq_data *txq = (*priv->txqs)[i];
131
132                 if (txq == NULL)
133                         continue;
134                 idx = txq->idx;
135                 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
136 #ifdef MLX5_PMD_SOFT_COUNTERS
137                         tmp.q_opackets[idx] += txq->stats.opackets;
138                         tmp.q_obytes[idx] += txq->stats.obytes;
139 #endif
140                 }
141 #ifdef MLX5_PMD_SOFT_COUNTERS
142                 tmp.opackets += txq->stats.opackets;
143                 tmp.obytes += txq->stats.obytes;
144 #endif
145                 tmp.oerrors += txq->stats.oerrors;
146         }
147         ret = mlx5_os_read_dev_stat(priv, "out_of_buffer", &tmp.imissed);
148         if (ret == 0) {
149                 tmp.imissed = (tmp.imissed - stats_ctrl->imissed_base) &
150                                  (uint64_t)UINT32_MAX;
151                 wrap_n = stats_ctrl->imissed >> 32;
152                 if (tmp.imissed < (stats_ctrl->imissed & (uint64_t)UINT32_MAX))
153                         wrap_n++;
154                 tmp.imissed |= (wrap_n) << 32;
155                 stats_ctrl->imissed = tmp.imissed;
156         } else {
157                 tmp.imissed = stats_ctrl->imissed;
158         }
159 #ifndef MLX5_PMD_SOFT_COUNTERS
160         /* FIXME: retrieve and add hardware counters. */
161 #endif
162         *stats = tmp;
163         return 0;
164 }
165
166 /**
167  * DPDK callback to clear device statistics.
168  *
169  * @param dev
170  *   Pointer to Ethernet device structure.
171  *
172  * @return
173  *   always 0 on success and stats is reset
174  */
175 int
176 mlx5_stats_reset(struct rte_eth_dev *dev)
177 {
178         struct mlx5_priv *priv = dev->data->dev_private;
179         struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
180         unsigned int i;
181
182         for (i = 0; (i != priv->rxqs_n); ++i) {
183                 if ((*priv->rxqs)[i] == NULL)
184                         continue;
185                 memset(&(*priv->rxqs)[i]->stats, 0,
186                        sizeof(struct mlx5_rxq_stats));
187         }
188         for (i = 0; (i != priv->txqs_n); ++i) {
189                 if ((*priv->txqs)[i] == NULL)
190                         continue;
191                 memset(&(*priv->txqs)[i]->stats, 0,
192                        sizeof(struct mlx5_txq_stats));
193         }
194         mlx5_os_read_dev_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
195         stats_ctrl->imissed = 0;
196 #ifndef MLX5_PMD_SOFT_COUNTERS
197         /* FIXME: reset hardware counters. */
198 #endif
199
200         return 0;
201 }
202
203 /**
204  * DPDK callback to clear device extended statistics.
205  *
206  * @param dev
207  *   Pointer to Ethernet device structure.
208  *
209  * @return
210  *   0 on success and stats is reset, negative errno value otherwise and
211  *   rte_errno is set.
212  */
213 int
214 mlx5_xstats_reset(struct rte_eth_dev *dev)
215 {
216         struct mlx5_priv *priv = dev->data->dev_private;
217         struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
218         int stats_n;
219         unsigned int i;
220         uint64_t *counters;
221         int ret;
222
223         stats_n = mlx5_os_get_stats_n(dev);
224         if (stats_n < 0) {
225                 DRV_LOG(ERR, "port %u cannot get stats: %s", dev->data->port_id,
226                         strerror(-stats_n));
227                 return stats_n;
228         }
229         if (xstats_ctrl->stats_n != stats_n)
230                 mlx5_os_stats_init(dev);
231         counters =  mlx5_malloc(MLX5_MEM_SYS, sizeof(*counters) *
232                         xstats_ctrl->mlx5_stats_n, 0,
233                         SOCKET_ID_ANY);
234         if (!counters) {
235                 DRV_LOG(WARNING, "port %u unable to allocate memory for xstats "
236                                 "counters",
237                      dev->data->port_id);
238                 rte_errno = ENOMEM;
239                 return -rte_errno;
240         }
241         ret = mlx5_os_read_dev_counters(dev, counters);
242         if (ret) {
243                 DRV_LOG(ERR, "port %u cannot read device counters: %s",
244                         dev->data->port_id, strerror(rte_errno));
245                 mlx5_free(counters);
246                 return ret;
247         }
248         for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) {
249                 xstats_ctrl->base[i] = counters[i];
250                 xstats_ctrl->hw_stats[i] = 0;
251         }
252         mlx5_txpp_xstats_reset(dev);
253         mlx5_free(counters);
254         return 0;
255 }
256
257 /**
258  * DPDK callback to retrieve names of extended device statistics
259  *
260  * @param dev
261  *   Pointer to Ethernet device structure.
262  * @param[out] xstats_names
263  *   Buffer to insert names into.
264  * @param n
265  *   Number of names.
266  *
267  * @return
268  *   Number of xstats names.
269  */
270 int
271 mlx5_xstats_get_names(struct rte_eth_dev *dev,
272                       struct rte_eth_xstat_name *xstats_names, unsigned int n)
273 {
274         unsigned int i;
275         struct mlx5_priv *priv = dev->data->dev_private;
276         struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
277         unsigned int mlx5_xstats_n = xstats_ctrl->mlx5_stats_n;
278
279         if (n >= mlx5_xstats_n && xstats_names) {
280                 for (i = 0; i != mlx5_xstats_n; ++i) {
281                         strncpy(xstats_names[i].name,
282                                 xstats_ctrl->info[i].dpdk_name,
283                                 RTE_ETH_XSTATS_NAME_SIZE);
284                         xstats_names[i].name[RTE_ETH_XSTATS_NAME_SIZE - 1] = 0;
285                 }
286         }
287         mlx5_xstats_n = mlx5_txpp_xstats_get_names(dev, xstats_names,
288                                                    n, mlx5_xstats_n);
289         return mlx5_xstats_n;
290 }