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