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 protocols for which RSS is enabled. */ 166 priv->rss_hf = rss_conf->rss_hf; 167 priv_unlock(priv); 168 assert(err >= 0); 169 return -err; 170 } 171 172 /** 173 * DPDK callback to get the RSS hash configuration. 174 * 175 * @param dev 176 * Pointer to Ethernet device structure. 177 * @param[in, out] rss_conf 178 * RSS configuration data. 179 * 180 * @return 181 * 0 on success, negative errno value on failure. 182 */ 183 int 184 mlx5_rss_hash_conf_get(struct rte_eth_dev *dev, 185 struct rte_eth_rss_conf *rss_conf) 186 { 187 struct priv *priv = dev->data->dev_private; 188 struct rte_eth_rss_conf *priv_rss_conf; 189 190 priv_lock(priv); 191 192 assert(priv->rss_conf != NULL); 193 194 priv_rss_conf = rss_hash_get(priv, rss_conf->rss_hf); 195 if (!priv_rss_conf) { 196 rss_conf->rss_hf = 0; 197 priv_unlock(priv); 198 return -EINVAL; 199 } 200 if (rss_conf->rss_key && 201 rss_conf->rss_key_len >= priv_rss_conf->rss_key_len) 202 memcpy(rss_conf->rss_key, 203 priv_rss_conf->rss_key, 204 priv_rss_conf->rss_key_len); 205 rss_conf->rss_key_len = priv_rss_conf->rss_key_len; 206 rss_conf->rss_hf = priv_rss_conf->rss_hf; 207 208 priv_unlock(priv); 209 return 0; 210 } 211 212 /** 213 * Allocate/reallocate RETA index table. 214 * 215 * @param priv 216 * Pointer to private structure. 217 * @praram reta_size 218 * The size of the array to allocate. 219 * 220 * @return 221 * 0 on success, errno value on failure. 222 */ 223 int 224 priv_rss_reta_index_resize(struct priv *priv, unsigned int reta_size) 225 { 226 void *mem; 227 unsigned int old_size = priv->reta_idx_n; 228 229 if (priv->reta_idx_n == reta_size) 230 return 0; 231 232 mem = rte_realloc(priv->reta_idx, 233 reta_size * sizeof((*priv->reta_idx)[0]), 0); 234 if (!mem) 235 return ENOMEM; 236 priv->reta_idx = mem; 237 priv->reta_idx_n = reta_size; 238 239 if (old_size < reta_size) 240 memset(&(*priv->reta_idx)[old_size], 0, 241 (reta_size - old_size) * 242 sizeof((*priv->reta_idx)[0])); 243 return 0; 244 } 245 246 /** 247 * Query RETA table. 248 * 249 * @param priv 250 * Pointer to private structure. 251 * @param[in, out] reta_conf 252 * Pointer to the first RETA configuration structure. 253 * @param reta_size 254 * Number of entries. 255 * 256 * @return 257 * 0 on success, errno value on failure. 258 */ 259 static int 260 priv_dev_rss_reta_query(struct priv *priv, 261 struct rte_eth_rss_reta_entry64 *reta_conf, 262 unsigned int reta_size) 263 { 264 unsigned int idx; 265 unsigned int i; 266 int ret; 267 268 /* See RETA comment in mlx5_dev_infos_get(). */ 269 ret = priv_rss_reta_index_resize(priv, priv->ind_table_max_size); 270 if (ret) 271 return ret; 272 273 /* Fill each entry of the table even if its bit is not set. */ 274 for (idx = 0, i = 0; (i != reta_size); ++i) { 275 idx = i / RTE_RETA_GROUP_SIZE; 276 reta_conf[idx].reta[i % RTE_RETA_GROUP_SIZE] = 277 (*priv->reta_idx)[i]; 278 } 279 return 0; 280 } 281 282 /** 283 * Update RETA table. 284 * 285 * @param priv 286 * Pointer to private structure. 287 * @param[in] reta_conf 288 * Pointer to the first RETA configuration structure. 289 * @param reta_size 290 * Number of entries. 291 * 292 * @return 293 * 0 on success, errno value on failure. 294 */ 295 static int 296 priv_dev_rss_reta_update(struct priv *priv, 297 struct rte_eth_rss_reta_entry64 *reta_conf, 298 unsigned int reta_size) 299 { 300 unsigned int idx; 301 unsigned int i; 302 unsigned int pos; 303 int ret; 304 305 /* See RETA comment in mlx5_dev_infos_get(). */ 306 ret = priv_rss_reta_index_resize(priv, priv->ind_table_max_size); 307 if (ret) 308 return ret; 309 310 for (idx = 0, i = 0; (i != reta_size); ++i) { 311 idx = i / RTE_RETA_GROUP_SIZE; 312 pos = i % RTE_RETA_GROUP_SIZE; 313 if (((reta_conf[idx].mask >> i) & 0x1) == 0) 314 continue; 315 assert(reta_conf[idx].reta[pos] < priv->rxqs_n); 316 (*priv->reta_idx)[i] = reta_conf[idx].reta[pos]; 317 } 318 return 0; 319 } 320 321 /** 322 * DPDK callback to get the RETA indirection table. 323 * 324 * @param dev 325 * Pointer to Ethernet device structure. 326 * @param reta_conf 327 * Pointer to RETA configuration structure array. 328 * @param reta_size 329 * Size of the RETA table. 330 * 331 * @return 332 * 0 on success, negative errno value on failure. 333 */ 334 int 335 mlx5_dev_rss_reta_query(struct rte_eth_dev *dev, 336 struct rte_eth_rss_reta_entry64 *reta_conf, 337 uint16_t reta_size) 338 { 339 int ret; 340 struct priv *priv = dev->data->dev_private; 341 342 priv_lock(priv); 343 ret = priv_dev_rss_reta_query(priv, reta_conf, reta_size); 344 priv_unlock(priv); 345 return -ret; 346 } 347 348 /** 349 * DPDK callback to update the RETA indirection table. 350 * 351 * @param dev 352 * Pointer to Ethernet device structure. 353 * @param reta_conf 354 * Pointer to RETA configuration structure array. 355 * @param reta_size 356 * Size of the RETA table. 357 * 358 * @return 359 * 0 on success, negative errno value on failure. 360 */ 361 int 362 mlx5_dev_rss_reta_update(struct rte_eth_dev *dev, 363 struct rte_eth_rss_reta_entry64 *reta_conf, 364 uint16_t reta_size) 365 { 366 int ret; 367 struct priv *priv = dev->data->dev_private; 368 369 priv_lock(priv); 370 ret = priv_dev_rss_reta_update(priv, reta_conf, reta_size); 371 priv_unlock(priv); 372 return -ret; 373 } 374