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