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