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