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 <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_rx.h"
20 #include "mlx5_tx.h"
21 #include "mlx5_malloc.h"
22
23 /**
24 * DPDK callback to get extended device statistics.
25 *
26 * @param dev
27 * Pointer to Ethernet device.
28 * @param[out] stats
29 * Pointer to rte extended stats table.
30 * @param n
31 * The size of the stats table.
32 *
33 * @return
34 * Number of extended stats on success and stats is filled,
35 * negative on error and rte_errno is set.
36 */
37 int
mlx5_xstats_get(struct rte_eth_dev * dev,struct rte_eth_xstat * stats,unsigned int n)38 mlx5_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats,
39 unsigned int n)
40 {
41 struct mlx5_priv *priv = dev->data->dev_private;
42 uint64_t counters[MLX5_MAX_XSTATS];
43 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
44 unsigned int i;
45 uint16_t stats_n = 0;
46 uint16_t stats_n_2nd = 0;
47 uint16_t mlx5_stats_n = xstats_ctrl->mlx5_stats_n;
48 bool bond_master = (priv->master && priv->pf_bond >= 0);
49
50 if (n >= mlx5_stats_n && stats) {
51 int ret;
52
53 ret = mlx5_os_get_stats_n(dev, bond_master, &stats_n, &stats_n_2nd);
54 if (ret < 0)
55 return ret;
56 /*
57 * The number of statistics fetched via "ETH_SS_STATS" may vary because
58 * of the port configuration each time. This is also true between 2
59 * ports. There might be a case that the numbers are the same even if
60 * configurations are different.
61 * It is not recommended to change the configuration without using
62 * RTE API. The port(traffic) restart may trigger another initialization
63 * to make sure the map are correct.
64 */
65 if (xstats_ctrl->stats_n != stats_n ||
66 (bond_master && xstats_ctrl->stats_n_2nd != stats_n_2nd))
67 mlx5_os_stats_init(dev);
68 ret = mlx5_os_read_dev_counters(dev, bond_master, counters);
69 if (ret < 0)
70 return ret;
71 for (i = 0; i != mlx5_stats_n; i++) {
72 stats[i].id = i;
73 if (xstats_ctrl->info[i].dev) {
74 uint64_t wrap_n;
75 uint64_t hw_stat = xstats_ctrl->hw_stats[i];
76
77 stats[i].value = (counters[i] -
78 xstats_ctrl->base[i]) &
79 (uint64_t)UINT32_MAX;
80 wrap_n = hw_stat >> 32;
81 if (stats[i].value <
82 (hw_stat & (uint64_t)UINT32_MAX))
83 wrap_n++;
84 stats[i].value |= (wrap_n) << 32;
85 xstats_ctrl->hw_stats[i] = stats[i].value;
86 } else {
87 stats[i].value =
88 (counters[i] - xstats_ctrl->base[i]);
89 }
90 }
91 }
92 mlx5_stats_n = mlx5_txpp_xstats_get(dev, stats, n, mlx5_stats_n);
93 return mlx5_stats_n;
94 }
95
96 /**
97 * DPDK callback to get device statistics.
98 *
99 * @param dev
100 * Pointer to Ethernet device structure.
101 * @param[out] stats
102 * Stats structure output buffer.
103 *
104 * @return
105 * 0 on success and stats is filled, negative errno value otherwise and
106 * rte_errno is set.
107 */
108 int
mlx5_stats_get(struct rte_eth_dev * dev,struct rte_eth_stats * stats)109 mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
110 {
111 struct mlx5_priv *priv = dev->data->dev_private;
112 struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
113 struct rte_eth_stats tmp;
114 unsigned int i;
115 unsigned int idx;
116 uint64_t wrap_n;
117 int ret;
118
119 memset(&tmp, 0, sizeof(tmp));
120 /* Add software counters. */
121 for (i = 0; (i != priv->rxqs_n); ++i) {
122 struct mlx5_rxq_data *rxq = mlx5_rxq_data_get(dev, i);
123
124 if (rxq == NULL)
125 continue;
126 idx = rxq->idx;
127 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
128 #ifdef MLX5_PMD_SOFT_COUNTERS
129 tmp.q_ipackets[idx] += rxq->stats.ipackets -
130 rxq->stats_reset.ipackets;
131 tmp.q_ibytes[idx] += rxq->stats.ibytes -
132 rxq->stats_reset.ibytes;
133 #endif
134 tmp.q_errors[idx] += (rxq->stats.idropped +
135 rxq->stats.rx_nombuf) -
136 (rxq->stats_reset.idropped +
137 rxq->stats_reset.rx_nombuf);
138 }
139 #ifdef MLX5_PMD_SOFT_COUNTERS
140 tmp.ipackets += rxq->stats.ipackets - rxq->stats_reset.ipackets;
141 tmp.ibytes += rxq->stats.ibytes - rxq->stats_reset.ibytes;
142 #endif
143 tmp.ierrors += rxq->stats.idropped - rxq->stats_reset.idropped;
144 tmp.rx_nombuf += rxq->stats.rx_nombuf -
145 rxq->stats_reset.rx_nombuf;
146 }
147 for (i = 0; (i != priv->txqs_n); ++i) {
148 struct mlx5_txq_data *txq = (*priv->txqs)[i];
149
150 if (txq == NULL)
151 continue;
152 idx = txq->idx;
153 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
154 #ifdef MLX5_PMD_SOFT_COUNTERS
155 tmp.q_opackets[idx] += txq->stats.opackets -
156 txq->stats_reset.opackets;
157 tmp.q_obytes[idx] += txq->stats.obytes -
158 txq->stats_reset.obytes;
159 #endif
160 }
161 #ifdef MLX5_PMD_SOFT_COUNTERS
162 tmp.opackets += txq->stats.opackets - txq->stats_reset.opackets;
163 tmp.obytes += txq->stats.obytes - txq->stats_reset.obytes;
164 #endif
165 tmp.oerrors += txq->stats.oerrors - txq->stats_reset.oerrors;
166 }
167 ret = mlx5_os_read_dev_stat(priv, "out_of_buffer", &tmp.imissed);
168 if (ret == 0) {
169 tmp.imissed = (tmp.imissed - stats_ctrl->imissed_base) &
170 (uint64_t)UINT32_MAX;
171 wrap_n = stats_ctrl->imissed >> 32;
172 if (tmp.imissed < (stats_ctrl->imissed & (uint64_t)UINT32_MAX))
173 wrap_n++;
174 tmp.imissed |= (wrap_n) << 32;
175 stats_ctrl->imissed = tmp.imissed;
176 } else {
177 tmp.imissed = stats_ctrl->imissed;
178 }
179 #ifndef MLX5_PMD_SOFT_COUNTERS
180 /* FIXME: retrieve and add hardware counters. */
181 #endif
182 *stats = tmp;
183 return 0;
184 }
185
186 /**
187 * DPDK callback to clear device statistics.
188 *
189 * @param dev
190 * Pointer to Ethernet device structure.
191 *
192 * @return
193 * always 0 on success and stats is reset
194 */
195 int
mlx5_stats_reset(struct rte_eth_dev * dev)196 mlx5_stats_reset(struct rte_eth_dev *dev)
197 {
198 struct mlx5_priv *priv = dev->data->dev_private;
199 struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
200 unsigned int i;
201
202 for (i = 0; (i != priv->rxqs_n); ++i) {
203 struct mlx5_rxq_data *rxq_data = mlx5_rxq_data_get(dev, i);
204
205 if (rxq_data == NULL)
206 continue;
207 rxq_data->stats_reset = rxq_data->stats;
208 }
209 for (i = 0; (i != priv->txqs_n); ++i) {
210 struct mlx5_txq_data *txq_data = (*priv->txqs)[i];
211
212 if (txq_data == NULL)
213 continue;
214 txq_data->stats_reset = txq_data->stats;
215 }
216 mlx5_os_read_dev_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
217 stats_ctrl->imissed = 0;
218 #ifndef MLX5_PMD_SOFT_COUNTERS
219 /* FIXME: reset hardware counters. */
220 #endif
221
222 return 0;
223 }
224
225 /**
226 * DPDK callback to clear device extended statistics.
227 *
228 * @param dev
229 * Pointer to Ethernet device structure.
230 *
231 * @return
232 * 0 on success and stats is reset, negative errno value otherwise and
233 * rte_errno is set.
234 */
235 int
mlx5_xstats_reset(struct rte_eth_dev * dev)236 mlx5_xstats_reset(struct rte_eth_dev *dev)
237 {
238 struct mlx5_priv *priv = dev->data->dev_private;
239 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
240 unsigned int i;
241 uint64_t *counters;
242 int ret;
243 uint16_t stats_n = 0;
244 uint16_t stats_n_2nd = 0;
245 bool bond_master = (priv->master && priv->pf_bond >= 0);
246
247 ret = mlx5_os_get_stats_n(dev, bond_master, &stats_n, &stats_n_2nd);
248 if (ret < 0) {
249 DRV_LOG(ERR, "port %u cannot get stats: %s", dev->data->port_id,
250 strerror(-ret));
251 return ret;
252 }
253 if (xstats_ctrl->stats_n != stats_n ||
254 (bond_master && xstats_ctrl->stats_n_2nd != stats_n_2nd))
255 mlx5_os_stats_init(dev);
256 /* Considering to use stack directly. */
257 counters = mlx5_malloc(MLX5_MEM_SYS, sizeof(*counters) * xstats_ctrl->mlx5_stats_n,
258 0, SOCKET_ID_ANY);
259 if (!counters) {
260 DRV_LOG(WARNING, "port %u unable to allocate memory for xstats counters",
261 dev->data->port_id);
262 rte_errno = ENOMEM;
263 return -rte_errno;
264 }
265 ret = mlx5_os_read_dev_counters(dev, bond_master, counters);
266 if (ret) {
267 DRV_LOG(ERR, "port %u cannot read device counters: %s",
268 dev->data->port_id, strerror(rte_errno));
269 mlx5_free(counters);
270 return ret;
271 }
272 for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) {
273 xstats_ctrl->base[i] = counters[i];
274 xstats_ctrl->hw_stats[i] = 0;
275 }
276 mlx5_txpp_xstats_reset(dev);
277 mlx5_free(counters);
278 return 0;
279 }
280
281 /**
282 * DPDK callback to retrieve names of extended device statistics
283 *
284 * @param dev
285 * Pointer to Ethernet device structure.
286 * @param[out] xstats_names
287 * Buffer to insert names into.
288 * @param n
289 * Number of names.
290 *
291 * @return
292 * Number of xstats names.
293 */
294 int
mlx5_xstats_get_names(struct rte_eth_dev * dev,struct rte_eth_xstat_name * xstats_names,unsigned int n)295 mlx5_xstats_get_names(struct rte_eth_dev *dev,
296 struct rte_eth_xstat_name *xstats_names, unsigned int n)
297 {
298 unsigned int i;
299 struct mlx5_priv *priv = dev->data->dev_private;
300 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
301 unsigned int mlx5_xstats_n = xstats_ctrl->mlx5_stats_n;
302
303 if (n >= mlx5_xstats_n && xstats_names) {
304 for (i = 0; i != mlx5_xstats_n; ++i) {
305 strlcpy(xstats_names[i].name,
306 xstats_ctrl->info[i].dpdk_name,
307 RTE_ETH_XSTATS_NAME_SIZE);
308 }
309 }
310 mlx5_xstats_n = mlx5_txpp_xstats_get_names(dev, xstats_names,
311 n, mlx5_xstats_n);
312 return mlx5_xstats_n;
313 }
314