1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2015 6WIND S.A. 3 * Copyright 2015 Mellanox Technologies, Ltd 4 */ 5 6 #include <stddef.h> 7 #include <stdint.h> 8 #include <errno.h> 9 #include <string.h> 10 11 #include <rte_malloc.h> 12 #include <rte_ethdev_driver.h> 13 14 #include <mlx5_malloc.h> 15 16 #include "mlx5_defs.h" 17 #include "mlx5.h" 18 #include "mlx5_rxtx.h" 19 20 /** 21 * DPDK callback to update the RSS hash configuration. 22 * 23 * @param dev 24 * Pointer to Ethernet device structure. 25 * @param[in] rss_conf 26 * RSS configuration data. 27 * 28 * @return 29 * 0 on success, a negative errno value otherwise and rte_errno is set. 30 */ 31 int 32 mlx5_rss_hash_update(struct rte_eth_dev *dev, 33 struct rte_eth_rss_conf *rss_conf) 34 { 35 struct mlx5_priv *priv = dev->data->dev_private; 36 unsigned int i; 37 unsigned int idx; 38 39 if (rss_conf->rss_hf & MLX5_RSS_HF_MASK) { 40 rte_errno = EINVAL; 41 return -rte_errno; 42 } 43 if (rss_conf->rss_key && rss_conf->rss_key_len) { 44 if (rss_conf->rss_key_len != MLX5_RSS_HASH_KEY_LEN) { 45 DRV_LOG(ERR, 46 "port %u RSS key len must be %s Bytes long", 47 dev->data->port_id, 48 RTE_STR(MLX5_RSS_HASH_KEY_LEN)); 49 rte_errno = EINVAL; 50 return -rte_errno; 51 } 52 priv->rss_conf.rss_key = mlx5_realloc(priv->rss_conf.rss_key, 53 MLX5_MEM_RTE, 54 rss_conf->rss_key_len, 55 0, SOCKET_ID_ANY); 56 if (!priv->rss_conf.rss_key) { 57 rte_errno = ENOMEM; 58 return -rte_errno; 59 } 60 memcpy(priv->rss_conf.rss_key, rss_conf->rss_key, 61 rss_conf->rss_key_len); 62 priv->rss_conf.rss_key_len = rss_conf->rss_key_len; 63 } 64 priv->rss_conf.rss_hf = rss_conf->rss_hf; 65 /* Enable the RSS hash in all Rx queues. */ 66 for (i = 0, idx = 0; idx != priv->rxqs_n; ++i) { 67 if (!(*priv->rxqs)[i]) 68 continue; 69 (*priv->rxqs)[i]->rss_hash = !!rss_conf->rss_hf && 70 !!(dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS); 71 ++idx; 72 } 73 return 0; 74 } 75 76 /** 77 * DPDK callback to get the RSS hash configuration. 78 * 79 * @param dev 80 * Pointer to Ethernet device structure. 81 * @param[in, out] rss_conf 82 * RSS configuration data. 83 * 84 * @return 85 * 0 on success, a negative errno value otherwise and rte_errno is set. 86 */ 87 int 88 mlx5_rss_hash_conf_get(struct rte_eth_dev *dev, 89 struct rte_eth_rss_conf *rss_conf) 90 { 91 struct mlx5_priv *priv = dev->data->dev_private; 92 93 if (!rss_conf) { 94 rte_errno = EINVAL; 95 return -rte_errno; 96 } 97 if (rss_conf->rss_key && 98 (rss_conf->rss_key_len >= priv->rss_conf.rss_key_len)) { 99 memcpy(rss_conf->rss_key, priv->rss_conf.rss_key, 100 priv->rss_conf.rss_key_len); 101 } 102 rss_conf->rss_key_len = priv->rss_conf.rss_key_len; 103 rss_conf->rss_hf = priv->rss_conf.rss_hf; 104 return 0; 105 } 106 107 /** 108 * Allocate/reallocate RETA index table. 109 * 110 * @param dev 111 * Pointer to Ethernet device. 112 * @praram reta_size 113 * The size of the array to allocate. 114 * 115 * @return 116 * 0 on success, a negative errno value otherwise and rte_errno is set. 117 */ 118 int 119 mlx5_rss_reta_index_resize(struct rte_eth_dev *dev, unsigned int reta_size) 120 { 121 struct mlx5_priv *priv = dev->data->dev_private; 122 void *mem; 123 unsigned int old_size = priv->reta_idx_n; 124 125 if (priv->reta_idx_n == reta_size) 126 return 0; 127 128 mem = mlx5_realloc(priv->reta_idx, MLX5_MEM_RTE, 129 reta_size * sizeof((*priv->reta_idx)[0]), 0, 130 SOCKET_ID_ANY); 131 if (!mem) { 132 rte_errno = ENOMEM; 133 return -rte_errno; 134 } 135 priv->reta_idx = mem; 136 priv->reta_idx_n = reta_size; 137 if (old_size < reta_size) 138 memset(&(*priv->reta_idx)[old_size], 0, 139 (reta_size - old_size) * 140 sizeof((*priv->reta_idx)[0])); 141 return 0; 142 } 143 144 /** 145 * DPDK callback to get the RETA indirection table. 146 * 147 * @param dev 148 * Pointer to Ethernet device structure. 149 * @param reta_conf 150 * Pointer to RETA configuration structure array. 151 * @param reta_size 152 * Size of the RETA table. 153 * 154 * @return 155 * 0 on success, a negative errno value otherwise and rte_errno is set. 156 */ 157 int 158 mlx5_dev_rss_reta_query(struct rte_eth_dev *dev, 159 struct rte_eth_rss_reta_entry64 *reta_conf, 160 uint16_t reta_size) 161 { 162 struct mlx5_priv *priv = dev->data->dev_private; 163 unsigned int idx; 164 unsigned int i; 165 166 if (!reta_size || reta_size > priv->reta_idx_n) { 167 rte_errno = EINVAL; 168 return -rte_errno; 169 } 170 /* Fill each entry of the table even if its bit is not set. */ 171 for (idx = 0, i = 0; (i != reta_size); ++i) { 172 idx = i / RTE_RETA_GROUP_SIZE; 173 reta_conf[idx].reta[i % RTE_RETA_GROUP_SIZE] = 174 (*priv->reta_idx)[i]; 175 } 176 return 0; 177 } 178 179 /** 180 * DPDK callback to update the RETA indirection table. 181 * 182 * @param dev 183 * Pointer to Ethernet device structure. 184 * @param reta_conf 185 * Pointer to RETA configuration structure array. 186 * @param reta_size 187 * Size of the RETA table. 188 * 189 * @return 190 * 0 on success, a negative errno value otherwise and rte_errno is set. 191 */ 192 int 193 mlx5_dev_rss_reta_update(struct rte_eth_dev *dev, 194 struct rte_eth_rss_reta_entry64 *reta_conf, 195 uint16_t reta_size) 196 { 197 int ret; 198 struct mlx5_priv *priv = dev->data->dev_private; 199 unsigned int idx; 200 unsigned int i; 201 unsigned int pos; 202 203 if (!reta_size) { 204 rte_errno = EINVAL; 205 return -rte_errno; 206 } 207 ret = mlx5_rss_reta_index_resize(dev, reta_size); 208 if (ret) 209 return ret; 210 for (idx = 0, i = 0; (i != reta_size); ++i) { 211 idx = i / RTE_RETA_GROUP_SIZE; 212 pos = i % RTE_RETA_GROUP_SIZE; 213 if (((reta_conf[idx].mask >> i) & 0x1) == 0) 214 continue; 215 MLX5_ASSERT(reta_conf[idx].reta[pos] < priv->rxqs_n); 216 (*priv->reta_idx)[i] = reta_conf[idx].reta[pos]; 217 } 218 if (dev->data->dev_started) { 219 mlx5_dev_stop(dev); 220 priv->skip_default_rss_reta = 1; 221 return mlx5_dev_start(dev); 222 } 223 return 0; 224 } 225