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 "-Wpedantic" 44 #endif 45 #include <infiniband/verbs.h> 46 #ifdef PEDANTIC 47 #pragma GCC diagnostic error "-Wpedantic" 48 #endif 49 50 #include <rte_malloc.h> 51 #include <rte_ethdev.h> 52 53 #include "mlx5.h" 54 #include "mlx5_rxtx.h" 55 56 /** 57 * Get a RSS configuration hash key. 58 * 59 * @param priv 60 * Pointer to private structure. 61 * @param rss_hf 62 * RSS hash functions configuration must be retrieved for. 63 * 64 * @return 65 * Pointer to a RSS configuration structure or NULL if rss_hf cannot 66 * be matched. 67 */ 68 static struct rte_eth_rss_conf * 69 rss_hash_get(struct priv *priv, uint64_t rss_hf) 70 { 71 unsigned int i; 72 73 for (i = 0; (i != hash_rxq_init_n); ++i) { 74 uint64_t dpdk_rss_hf = hash_rxq_init[i].dpdk_rss_hf; 75 76 if (!(dpdk_rss_hf & rss_hf)) 77 continue; 78 return (*priv->rss_conf)[i]; 79 } 80 return NULL; 81 } 82 83 /** 84 * Register a RSS key. 85 * 86 * @param priv 87 * Pointer to private structure. 88 * @param key 89 * Hash key to register. 90 * @param key_len 91 * Hash key length in bytes. 92 * @param rss_hf 93 * RSS hash functions the provided key applies to. 94 * 95 * @return 96 * 0 on success, errno value on failure. 97 */ 98 int 99 rss_hash_rss_conf_new_key(struct priv *priv, const uint8_t *key, 100 unsigned int key_len, uint64_t rss_hf) 101 { 102 unsigned int i; 103 104 for (i = 0; (i != hash_rxq_init_n); ++i) { 105 struct rte_eth_rss_conf *rss_conf; 106 uint64_t dpdk_rss_hf = hash_rxq_init[i].dpdk_rss_hf; 107 108 if (!(dpdk_rss_hf & rss_hf)) 109 continue; 110 rss_conf = rte_realloc((*priv->rss_conf)[i], 111 (sizeof(*rss_conf) + key_len), 112 0); 113 if (!rss_conf) 114 return ENOMEM; 115 rss_conf->rss_key = (void *)(rss_conf + 1); 116 rss_conf->rss_key_len = key_len; 117 rss_conf->rss_hf = dpdk_rss_hf; 118 memcpy(rss_conf->rss_key, key, key_len); 119 (*priv->rss_conf)[i] = rss_conf; 120 } 121 return 0; 122 } 123 124 /** 125 * DPDK callback to update the RSS hash configuration. 126 * 127 * @param dev 128 * Pointer to Ethernet device structure. 129 * @param[in] rss_conf 130 * RSS configuration data. 131 * 132 * @return 133 * 0 on success, negative errno value on failure. 134 */ 135 int 136 mlx5_rss_hash_update(struct rte_eth_dev *dev, 137 struct rte_eth_rss_conf *rss_conf) 138 { 139 struct priv *priv = dev->data->dev_private; 140 int err = 0; 141 142 priv_lock(priv); 143 144 assert(priv->rss_conf != NULL); 145 146 /* Apply configuration. */ 147 if (rss_conf->rss_key) 148 err = rss_hash_rss_conf_new_key(priv, 149 rss_conf->rss_key, 150 rss_conf->rss_key_len, 151 rss_conf->rss_hf); 152 /* Store protocols for which RSS is enabled. */ 153 priv->rss_hf = rss_conf->rss_hf; 154 priv_unlock(priv); 155 assert(err >= 0); 156 return -err; 157 } 158 159 /** 160 * DPDK callback to get the RSS hash configuration. 161 * 162 * @param dev 163 * Pointer to Ethernet device structure. 164 * @param[in, out] rss_conf 165 * RSS configuration data. 166 * 167 * @return 168 * 0 on success, negative errno value on failure. 169 */ 170 int 171 mlx5_rss_hash_conf_get(struct rte_eth_dev *dev, 172 struct rte_eth_rss_conf *rss_conf) 173 { 174 struct priv *priv = dev->data->dev_private; 175 struct rte_eth_rss_conf *priv_rss_conf; 176 177 priv_lock(priv); 178 179 assert(priv->rss_conf != NULL); 180 181 priv_rss_conf = rss_hash_get(priv, rss_conf->rss_hf); 182 if (!priv_rss_conf) { 183 rss_conf->rss_hf = 0; 184 priv_unlock(priv); 185 return -EINVAL; 186 } 187 if (rss_conf->rss_key && 188 rss_conf->rss_key_len >= priv_rss_conf->rss_key_len) 189 memcpy(rss_conf->rss_key, 190 priv_rss_conf->rss_key, 191 priv_rss_conf->rss_key_len); 192 rss_conf->rss_key_len = priv_rss_conf->rss_key_len; 193 rss_conf->rss_hf = priv_rss_conf->rss_hf; 194 195 priv_unlock(priv); 196 return 0; 197 } 198 199 /** 200 * Allocate/reallocate RETA index table. 201 * 202 * @param priv 203 * Pointer to private structure. 204 * @praram reta_size 205 * The size of the array to allocate. 206 * 207 * @return 208 * 0 on success, errno value on failure. 209 */ 210 int 211 priv_rss_reta_index_resize(struct priv *priv, unsigned int reta_size) 212 { 213 void *mem; 214 unsigned int old_size = priv->reta_idx_n; 215 216 if (priv->reta_idx_n == reta_size) 217 return 0; 218 219 mem = rte_realloc(priv->reta_idx, 220 reta_size * sizeof((*priv->reta_idx)[0]), 0); 221 if (!mem) 222 return ENOMEM; 223 priv->reta_idx = mem; 224 priv->reta_idx_n = reta_size; 225 226 if (old_size < reta_size) 227 memset(&(*priv->reta_idx)[old_size], 0, 228 (reta_size - old_size) * 229 sizeof((*priv->reta_idx)[0])); 230 return 0; 231 } 232 233 /** 234 * Query RETA table. 235 * 236 * @param priv 237 * Pointer to private structure. 238 * @param[in, out] reta_conf 239 * Pointer to the first RETA configuration structure. 240 * @param reta_size 241 * Number of entries. 242 * 243 * @return 244 * 0 on success, errno value on failure. 245 */ 246 static int 247 priv_dev_rss_reta_query(struct priv *priv, 248 struct rte_eth_rss_reta_entry64 *reta_conf, 249 unsigned int reta_size) 250 { 251 unsigned int idx; 252 unsigned int i; 253 254 if (!reta_size || reta_size > priv->reta_idx_n) 255 return EINVAL; 256 /* Fill each entry of the table even if its bit is not set. */ 257 for (idx = 0, i = 0; (i != reta_size); ++i) { 258 idx = i / RTE_RETA_GROUP_SIZE; 259 reta_conf[idx].reta[i % RTE_RETA_GROUP_SIZE] = 260 (*priv->reta_idx)[i]; 261 } 262 return 0; 263 } 264 265 /** 266 * Update RETA table. 267 * 268 * @param priv 269 * Pointer to private structure. 270 * @param[in] reta_conf 271 * Pointer to the first RETA configuration structure. 272 * @param reta_size 273 * Number of entries. 274 * 275 * @return 276 * 0 on success, errno value on failure. 277 */ 278 static int 279 priv_dev_rss_reta_update(struct priv *priv, 280 struct rte_eth_rss_reta_entry64 *reta_conf, 281 unsigned int reta_size) 282 { 283 unsigned int idx; 284 unsigned int i; 285 unsigned int pos; 286 int ret; 287 288 if (!reta_size) 289 return EINVAL; 290 ret = priv_rss_reta_index_resize(priv, reta_size); 291 if (ret) 292 return ret; 293 294 for (idx = 0, i = 0; (i != reta_size); ++i) { 295 idx = i / RTE_RETA_GROUP_SIZE; 296 pos = i % RTE_RETA_GROUP_SIZE; 297 if (((reta_conf[idx].mask >> i) & 0x1) == 0) 298 continue; 299 assert(reta_conf[idx].reta[pos] < priv->rxqs_n); 300 (*priv->reta_idx)[i] = reta_conf[idx].reta[pos]; 301 } 302 return 0; 303 } 304 305 /** 306 * DPDK callback to get the RETA indirection table. 307 * 308 * @param dev 309 * Pointer to Ethernet device structure. 310 * @param reta_conf 311 * Pointer to RETA configuration structure array. 312 * @param reta_size 313 * Size of the RETA table. 314 * 315 * @return 316 * 0 on success, negative errno value on failure. 317 */ 318 int 319 mlx5_dev_rss_reta_query(struct rte_eth_dev *dev, 320 struct rte_eth_rss_reta_entry64 *reta_conf, 321 uint16_t reta_size) 322 { 323 int ret; 324 struct priv *priv = dev->data->dev_private; 325 326 priv_lock(priv); 327 ret = priv_dev_rss_reta_query(priv, reta_conf, reta_size); 328 priv_unlock(priv); 329 return -ret; 330 } 331 332 /** 333 * DPDK callback to update the RETA indirection table. 334 * 335 * @param dev 336 * Pointer to Ethernet device structure. 337 * @param reta_conf 338 * Pointer to RETA configuration structure array. 339 * @param reta_size 340 * Size of the RETA table. 341 * 342 * @return 343 * 0 on success, negative errno value on failure. 344 */ 345 int 346 mlx5_dev_rss_reta_update(struct rte_eth_dev *dev, 347 struct rte_eth_rss_reta_entry64 *reta_conf, 348 uint16_t reta_size) 349 { 350 int ret; 351 struct priv *priv = dev->data->dev_private; 352 353 assert(!mlx5_is_secondary()); 354 mlx5_dev_stop(dev); 355 priv_lock(priv); 356 ret = priv_dev_rss_reta_update(priv, reta_conf, reta_size); 357 priv_unlock(priv); 358 if (ret) 359 return -ret; 360 return mlx5_dev_start(dev); 361 } 362