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 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 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 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 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 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