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 = (*priv->rxqs)[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 if ((*priv->rxqs)[i] == NULL) 185 continue; 186 memset(&(*priv->rxqs)[i]->stats, 0, 187 sizeof(struct mlx5_rxq_stats)); 188 } 189 for (i = 0; (i != priv->txqs_n); ++i) { 190 if ((*priv->txqs)[i] == NULL) 191 continue; 192 memset(&(*priv->txqs)[i]->stats, 0, 193 sizeof(struct mlx5_txq_stats)); 194 } 195 mlx5_os_read_dev_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base); 196 stats_ctrl->imissed = 0; 197 #ifndef MLX5_PMD_SOFT_COUNTERS 198 /* FIXME: reset hardware counters. */ 199 #endif 200 201 return 0; 202 } 203 204 /** 205 * DPDK callback to clear device extended statistics. 206 * 207 * @param dev 208 * Pointer to Ethernet device structure. 209 * 210 * @return 211 * 0 on success and stats is reset, negative errno value otherwise and 212 * rte_errno is set. 213 */ 214 int 215 mlx5_xstats_reset(struct rte_eth_dev *dev) 216 { 217 struct mlx5_priv *priv = dev->data->dev_private; 218 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl; 219 int stats_n; 220 unsigned int i; 221 uint64_t *counters; 222 int ret; 223 224 stats_n = mlx5_os_get_stats_n(dev); 225 if (stats_n < 0) { 226 DRV_LOG(ERR, "port %u cannot get stats: %s", dev->data->port_id, 227 strerror(-stats_n)); 228 return stats_n; 229 } 230 if (xstats_ctrl->stats_n != stats_n) 231 mlx5_os_stats_init(dev); 232 counters = mlx5_malloc(MLX5_MEM_SYS, sizeof(*counters) * 233 xstats_ctrl->mlx5_stats_n, 0, 234 SOCKET_ID_ANY); 235 if (!counters) { 236 DRV_LOG(WARNING, "port %u unable to allocate memory for xstats " 237 "counters", 238 dev->data->port_id); 239 rte_errno = ENOMEM; 240 return -rte_errno; 241 } 242 ret = mlx5_os_read_dev_counters(dev, counters); 243 if (ret) { 244 DRV_LOG(ERR, "port %u cannot read device counters: %s", 245 dev->data->port_id, strerror(rte_errno)); 246 mlx5_free(counters); 247 return ret; 248 } 249 for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) { 250 xstats_ctrl->base[i] = counters[i]; 251 xstats_ctrl->hw_stats[i] = 0; 252 } 253 mlx5_txpp_xstats_reset(dev); 254 mlx5_free(counters); 255 return 0; 256 } 257 258 /** 259 * DPDK callback to retrieve names of extended device statistics 260 * 261 * @param dev 262 * Pointer to Ethernet device structure. 263 * @param[out] xstats_names 264 * Buffer to insert names into. 265 * @param n 266 * Number of names. 267 * 268 * @return 269 * Number of xstats names. 270 */ 271 int 272 mlx5_xstats_get_names(struct rte_eth_dev *dev, 273 struct rte_eth_xstat_name *xstats_names, unsigned int n) 274 { 275 unsigned int i; 276 struct mlx5_priv *priv = dev->data->dev_private; 277 struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl; 278 unsigned int mlx5_xstats_n = xstats_ctrl->mlx5_stats_n; 279 280 if (n >= mlx5_xstats_n && xstats_names) { 281 for (i = 0; i != mlx5_xstats_n; ++i) { 282 strncpy(xstats_names[i].name, 283 xstats_ctrl->info[i].dpdk_name, 284 RTE_ETH_XSTATS_NAME_SIZE); 285 xstats_names[i].name[RTE_ETH_XSTATS_NAME_SIZE - 1] = 0; 286 } 287 } 288 mlx5_xstats_n = mlx5_txpp_xstats_get_names(dev, xstats_names, 289 n, mlx5_xstats_n); 290 return mlx5_xstats_n; 291 } 292