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