1 /*- 2 * BSD LICENSE 3 * 4 * Copyright 2015 6WIND S.A. 5 * Copyright 2015 Mellanox. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of 6WIND S.A. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stddef.h> 35 #include <stdint.h> 36 #include <errno.h> 37 #include <string.h> 38 #include <assert.h> 39 40 /* Verbs header. */ 41 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */ 42 #ifdef PEDANTIC 43 #pragma GCC diagnostic ignored "-pedantic" 44 #endif 45 #include <infiniband/verbs.h> 46 #ifdef PEDANTIC 47 #pragma GCC diagnostic error "-pedantic" 48 #endif 49 50 /* DPDK headers don't like -pedantic. */ 51 #ifdef PEDANTIC 52 #pragma GCC diagnostic ignored "-pedantic" 53 #endif 54 #include <rte_malloc.h> 55 #include <rte_ethdev.h> 56 #ifdef PEDANTIC 57 #pragma GCC diagnostic error "-pedantic" 58 #endif 59 60 #include "mlx5.h" 61 #include "mlx5_rxtx.h" 62 63 /** 64 * Get a RSS configuration hash key. 65 * 66 * @param priv 67 * Pointer to private structure. 68 * @param rss_hf 69 * RSS hash functions configuration must be retrieved for. 70 * 71 * @return 72 * Pointer to a RSS configuration structure or NULL if rss_hf cannot 73 * be matched. 74 */ 75 static struct rte_eth_rss_conf * 76 rss_hash_get(struct priv *priv, uint64_t rss_hf) 77 { 78 unsigned int i; 79 80 for (i = 0; (i != hash_rxq_init_n); ++i) { 81 uint64_t dpdk_rss_hf = hash_rxq_init[i].dpdk_rss_hf; 82 83 if (!(dpdk_rss_hf & rss_hf)) 84 continue; 85 return (*priv->rss_conf)[i]; 86 } 87 return NULL; 88 } 89 90 /** 91 * Register a RSS key. 92 * 93 * @param priv 94 * Pointer to private structure. 95 * @param key 96 * Hash key to register. 97 * @param key_len 98 * Hash key length in bytes. 99 * @param rss_hf 100 * RSS hash functions the provided key applies to. 101 * 102 * @return 103 * 0 on success, errno value on failure. 104 */ 105 int 106 rss_hash_rss_conf_new_key(struct priv *priv, const uint8_t *key, 107 unsigned int key_len, uint64_t rss_hf) 108 { 109 unsigned int i; 110 111 for (i = 0; (i != hash_rxq_init_n); ++i) { 112 struct rte_eth_rss_conf *rss_conf; 113 uint64_t dpdk_rss_hf = hash_rxq_init[i].dpdk_rss_hf; 114 115 if (!(dpdk_rss_hf & rss_hf)) 116 continue; 117 rss_conf = rte_realloc((*priv->rss_conf)[i], 118 (sizeof(*rss_conf) + key_len), 119 0); 120 if (!rss_conf) 121 return ENOMEM; 122 rss_conf->rss_key = (void *)(rss_conf + 1); 123 rss_conf->rss_key_len = key_len; 124 rss_conf->rss_hf = dpdk_rss_hf; 125 memcpy(rss_conf->rss_key, key, key_len); 126 (*priv->rss_conf)[i] = rss_conf; 127 } 128 return 0; 129 } 130 131 /** 132 * DPDK callback to update the RSS hash configuration. 133 * 134 * @param dev 135 * Pointer to Ethernet device structure. 136 * @param[in] rss_conf 137 * RSS configuration data. 138 * 139 * @return 140 * 0 on success, negative errno value on failure. 141 */ 142 int 143 mlx5_rss_hash_update(struct rte_eth_dev *dev, 144 struct rte_eth_rss_conf *rss_conf) 145 { 146 struct priv *priv = dev->data->dev_private; 147 int err = 0; 148 149 priv_lock(priv); 150 151 assert(priv->rss_conf != NULL); 152 153 /* Apply configuration. */ 154 if (rss_conf->rss_key) 155 err = rss_hash_rss_conf_new_key(priv, 156 rss_conf->rss_key, 157 rss_conf->rss_key_len, 158 rss_conf->rss_hf); 159 else 160 err = rss_hash_rss_conf_new_key(priv, 161 rss_hash_default_key, 162 rss_hash_default_key_len, 163 ETH_RSS_PROTO_MASK); 164 165 /* Store the configuration set into port configure. 166 * This will enable/disable hash RX queues associated to the protocols 167 * enabled/disabled by this update. */ 168 priv->dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf = 169 rss_conf->rss_hf; 170 priv_unlock(priv); 171 assert(err >= 0); 172 return -err; 173 } 174 175 /** 176 * DPDK callback to get the RSS hash configuration. 177 * 178 * @param dev 179 * Pointer to Ethernet device structure. 180 * @param[in, out] rss_conf 181 * RSS configuration data. 182 * 183 * @return 184 * 0 on success, negative errno value on failure. 185 */ 186 int 187 mlx5_rss_hash_conf_get(struct rte_eth_dev *dev, 188 struct rte_eth_rss_conf *rss_conf) 189 { 190 struct priv *priv = dev->data->dev_private; 191 struct rte_eth_rss_conf *priv_rss_conf; 192 193 priv_lock(priv); 194 195 assert(priv->rss_conf != NULL); 196 197 priv_rss_conf = rss_hash_get(priv, rss_conf->rss_hf); 198 if (!priv_rss_conf) { 199 rss_conf->rss_hf = 0; 200 priv_unlock(priv); 201 return -EINVAL; 202 } 203 if (rss_conf->rss_key && 204 rss_conf->rss_key_len >= priv_rss_conf->rss_key_len) 205 memcpy(rss_conf->rss_key, 206 priv_rss_conf->rss_key, 207 priv_rss_conf->rss_key_len); 208 rss_conf->rss_key_len = priv_rss_conf->rss_key_len; 209 rss_conf->rss_hf = priv_rss_conf->rss_hf; 210 211 priv_unlock(priv); 212 return 0; 213 } 214 215 /** 216 * Allocate/reallocate RETA index table. 217 * 218 * @param priv 219 * Pointer to private structure. 220 * @praram reta_size 221 * The size of the array to allocate. 222 * 223 * @return 224 * 0 on success, errno value on failure. 225 */ 226 int 227 priv_rss_reta_index_resize(struct priv *priv, unsigned int reta_size) 228 { 229 void *mem; 230 unsigned int old_size = priv->reta_idx_n; 231 232 if (priv->reta_idx_n == reta_size) 233 return 0; 234 235 mem = rte_realloc(priv->reta_idx, 236 reta_size * sizeof((*priv->reta_idx)[0]), 0); 237 if (!mem) 238 return ENOMEM; 239 priv->reta_idx = mem; 240 priv->reta_idx_n = reta_size; 241 242 if (old_size < reta_size) 243 memset(&(*priv->reta_idx)[old_size], 0, 244 (reta_size - old_size) * 245 sizeof((*priv->reta_idx)[0])); 246 return 0; 247 } 248 249 /** 250 * Query RETA table. 251 * 252 * @param priv 253 * Pointer to private structure. 254 * @param[in, out] reta_conf 255 * Pointer to the first RETA configuration structure. 256 * @param reta_size 257 * Number of entries. 258 * 259 * @return 260 * 0 on success, errno value on failure. 261 */ 262 static int 263 priv_dev_rss_reta_query(struct priv *priv, 264 struct rte_eth_rss_reta_entry64 *reta_conf, 265 unsigned int reta_size) 266 { 267 unsigned int idx; 268 unsigned int i; 269 int ret; 270 271 /* See RETA comment in mlx5_dev_infos_get(). */ 272 ret = priv_rss_reta_index_resize(priv, priv->ind_table_max_size); 273 if (ret) 274 return ret; 275 276 /* Fill each entry of the table even if its bit is not set. */ 277 for (idx = 0, i = 0; (i != reta_size); ++i) { 278 idx = i / RTE_RETA_GROUP_SIZE; 279 reta_conf[idx].reta[i % RTE_RETA_GROUP_SIZE] = 280 (*priv->reta_idx)[i]; 281 } 282 return 0; 283 } 284 285 /** 286 * Update RETA table. 287 * 288 * @param priv 289 * Pointer to private structure. 290 * @param[in] reta_conf 291 * Pointer to the first RETA configuration structure. 292 * @param reta_size 293 * Number of entries. 294 * 295 * @return 296 * 0 on success, errno value on failure. 297 */ 298 static int 299 priv_dev_rss_reta_update(struct priv *priv, 300 struct rte_eth_rss_reta_entry64 *reta_conf, 301 unsigned int reta_size) 302 { 303 unsigned int idx; 304 unsigned int i; 305 unsigned int pos; 306 int ret; 307 308 /* See RETA comment in mlx5_dev_infos_get(). */ 309 ret = priv_rss_reta_index_resize(priv, priv->ind_table_max_size); 310 if (ret) 311 return ret; 312 313 for (idx = 0, i = 0; (i != reta_size); ++i) { 314 idx = i / RTE_RETA_GROUP_SIZE; 315 pos = i % RTE_RETA_GROUP_SIZE; 316 if (((reta_conf[idx].mask >> i) & 0x1) == 0) 317 continue; 318 assert(reta_conf[idx].reta[pos] < priv->rxqs_n); 319 (*priv->reta_idx)[i] = reta_conf[idx].reta[pos]; 320 } 321 return 0; 322 } 323 324 /** 325 * DPDK callback to get the RETA indirection table. 326 * 327 * @param dev 328 * Pointer to Ethernet device structure. 329 * @param reta_conf 330 * Pointer to RETA configuration structure array. 331 * @param reta_size 332 * Size of the RETA table. 333 * 334 * @return 335 * 0 on success, negative errno value on failure. 336 */ 337 int 338 mlx5_dev_rss_reta_query(struct rte_eth_dev *dev, 339 struct rte_eth_rss_reta_entry64 *reta_conf, 340 uint16_t reta_size) 341 { 342 int ret; 343 struct priv *priv = dev->data->dev_private; 344 345 priv_lock(priv); 346 ret = priv_dev_rss_reta_query(priv, reta_conf, reta_size); 347 priv_unlock(priv); 348 return -ret; 349 } 350 351 /** 352 * DPDK callback to update the RETA indirection table. 353 * 354 * @param dev 355 * Pointer to Ethernet device structure. 356 * @param reta_conf 357 * Pointer to RETA configuration structure array. 358 * @param reta_size 359 * Size of the RETA table. 360 * 361 * @return 362 * 0 on success, negative errno value on failure. 363 */ 364 int 365 mlx5_dev_rss_reta_update(struct rte_eth_dev *dev, 366 struct rte_eth_rss_reta_entry64 *reta_conf, 367 uint16_t reta_size) 368 { 369 int ret; 370 struct priv *priv = dev->data->dev_private; 371 372 priv_lock(priv); 373 ret = priv_dev_rss_reta_update(priv, reta_conf, reta_size); 374 priv_unlock(priv); 375 return -ret; 376 } 377