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 tmp.q_ibytes[idx] += rxq->stats.ibytes; 119 #endif 120 tmp.q_errors[idx] += (rxq->stats.idropped + 121 rxq->stats.rx_nombuf); 122 } 123 #ifdef MLX5_PMD_SOFT_COUNTERS 124 tmp.ipackets += rxq->stats.ipackets; 125 tmp.ibytes += rxq->stats.ibytes; 126 #endif 127 tmp.ierrors += rxq->stats.idropped; 128 tmp.rx_nombuf += rxq->stats.rx_nombuf; 129 } 130 for (i = 0; (i != priv->txqs_n); ++i) { 131 struct mlx5_txq_data *txq = (*priv->txqs)[i]; 132 133 if (txq == NULL) 134 continue; 135 idx = txq->idx; 136 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 137 #ifdef MLX5_PMD_SOFT_COUNTERS 138 tmp.q_opackets[idx] += txq->stats.opackets; 139 tmp.q_obytes[idx] += txq->stats.obytes; 140 #endif 141 } 142 #ifdef MLX5_PMD_SOFT_COUNTERS 143 tmp.opackets += txq->stats.opackets; 144 tmp.obytes += txq->stats.obytes; 145 #endif 146 tmp.oerrors += txq->stats.oerrors; 147 } 148 ret = mlx5_os_read_dev_stat(priv, "out_of_buffer", &tmp.imissed); 149 if (ret == 0) { 150 tmp.imissed = (tmp.imissed - stats_ctrl->imissed_base) & 151 (uint64_t)UINT32_MAX; 152 wrap_n = stats_ctrl->imissed >> 32; 153 if (tmp.imissed < (stats_ctrl->imissed & (uint64_t)UINT32_MAX)) 154 wrap_n++; 155 tmp.imissed |= (wrap_n) << 32; 156 stats_ctrl->imissed = tmp.imissed; 157 } else { 158 tmp.imissed = stats_ctrl->imissed; 159 } 160 #ifndef MLX5_PMD_SOFT_COUNTERS 161 /* FIXME: retrieve and add hardware counters. */ 162 #endif 163 *stats = tmp; 164 return 0; 165 } 166 167 /** 168 * DPDK callback to clear device statistics. 169 * 170 * @param dev 171 * Pointer to Ethernet device structure. 172 * 173 * @return 174 * always 0 on success and stats is reset 175 */ 176 int 177 mlx5_stats_reset(struct rte_eth_dev *dev) 178 { 179 struct mlx5_priv *priv = dev->data->dev_private; 180 struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl; 181 unsigned int i; 182 183 for (i = 0; (i != priv->rxqs_n); ++i) { 184 struct mlx5_rxq_data *rxq_data = mlx5_rxq_data_get(dev, i); 185 186 if (rxq_data == NULL) 187 continue; 188 memset(&rxq_data->stats, 0, sizeof(struct mlx5_rxq_stats)); 189 } 190 for (i = 0; (i != priv->txqs_n); ++i) { 191 if ((*priv->txqs)[i] == NULL) 192 continue; 193 memset(&(*priv->txqs)[i]->stats, 0, 194 sizeof(struct mlx5_txq_stats)); 195 } 196 mlx5_os_read_dev_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base); 197 stats_ctrl->imissed = 0; 198 #ifndef MLX5_PMD_SOFT_COUNTERS 199 /* FIXME: reset hardware counters. */ 200 #endif 201 202 return 0; 203 } 204 205 /** 206 * DPDK callback to clear device extended statistics. 207 * 208 * @param dev 209 * Pointer to Ethernet device structure. 210 * 211 * @return 212 * 0 on success and stats is reset, negative errno value otherwise and 213 * rte_errno is set. 214 */ 215 int 216 mlx5_xstats_reset(struct rte_eth_dev *dev) 217 { 218 struct mlx5_priv *priv = dev->data->dev_private; 219 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl; 220 int stats_n; 221 unsigned int i; 222 uint64_t *counters; 223 int ret; 224 225 stats_n = mlx5_os_get_stats_n(dev); 226 if (stats_n < 0) { 227 DRV_LOG(ERR, "port %u cannot get stats: %s", dev->data->port_id, 228 strerror(-stats_n)); 229 return stats_n; 230 } 231 if (xstats_ctrl->stats_n != stats_n) 232 mlx5_os_stats_init(dev); 233 counters = mlx5_malloc(MLX5_MEM_SYS, sizeof(*counters) * 234 xstats_ctrl->mlx5_stats_n, 0, 235 SOCKET_ID_ANY); 236 if (!counters) { 237 DRV_LOG(WARNING, "port %u unable to allocate memory for xstats " 238 "counters", 239 dev->data->port_id); 240 rte_errno = ENOMEM; 241 return -rte_errno; 242 } 243 ret = mlx5_os_read_dev_counters(dev, counters); 244 if (ret) { 245 DRV_LOG(ERR, "port %u cannot read device counters: %s", 246 dev->data->port_id, strerror(rte_errno)); 247 mlx5_free(counters); 248 return ret; 249 } 250 for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) { 251 xstats_ctrl->base[i] = counters[i]; 252 xstats_ctrl->hw_stats[i] = 0; 253 } 254 mlx5_txpp_xstats_reset(dev); 255 mlx5_free(counters); 256 return 0; 257 } 258 259 /** 260 * DPDK callback to retrieve names of extended device statistics 261 * 262 * @param dev 263 * Pointer to Ethernet device structure. 264 * @param[out] xstats_names 265 * Buffer to insert names into. 266 * @param n 267 * Number of names. 268 * 269 * @return 270 * Number of xstats names. 271 */ 272 int 273 mlx5_xstats_get_names(struct rte_eth_dev *dev, 274 struct rte_eth_xstat_name *xstats_names, unsigned int n) 275 { 276 unsigned int i; 277 struct mlx5_priv *priv = dev->data->dev_private; 278 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl; 279 unsigned int mlx5_xstats_n = xstats_ctrl->mlx5_stats_n; 280 281 if (n >= mlx5_xstats_n && xstats_names) { 282 for (i = 0; i != mlx5_xstats_n; ++i) { 283 strncpy(xstats_names[i].name, 284 xstats_ctrl->info[i].dpdk_name, 285 RTE_ETH_XSTATS_NAME_SIZE); 286 xstats_names[i].name[RTE_ETH_XSTATS_NAME_SIZE - 1] = 0; 287 } 288 } 289 mlx5_xstats_n = mlx5_txpp_xstats_get_names(dev, xstats_names, 290 n, mlx5_xstats_n); 291 return mlx5_xstats_n; 292 } 293