xref: /dpdk/drivers/net/ena/ena_rss.c (revision 8d54b1ec4a8be40975ae6978535bcc1431caad02)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2020 Amazon.com, Inc. or its affiliates.
3  * All rights reserved.
4  */
5 
6 #include "ena_ethdev.h"
7 #include "ena_logs.h"
8 
9 #include <ena_admin_defs.h>
10 
11 #define TEST_BIT(val, bit_shift) ((val) & (1UL << (bit_shift)))
12 
13 #define ENA_HF_RSS_ALL_L2	(ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA)
14 #define ENA_HF_RSS_ALL_L3	(ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA)
15 #define ENA_HF_RSS_ALL_L4	(ENA_ADMIN_RSS_L4_SP | ENA_ADMIN_RSS_L4_DP)
16 #define ENA_HF_RSS_ALL_L3_L4	(ENA_HF_RSS_ALL_L3 | ENA_HF_RSS_ALL_L4)
17 #define ENA_HF_RSS_ALL_L2_L3_L4	(ENA_HF_RSS_ALL_L2 | ENA_HF_RSS_ALL_L3_L4)
18 
19 enum ena_rss_hash_fields {
20 	ENA_HF_RSS_TCP4		= ENA_HF_RSS_ALL_L3_L4,
21 	ENA_HF_RSS_UDP4		= ENA_HF_RSS_ALL_L3_L4,
22 	ENA_HF_RSS_TCP6		= ENA_HF_RSS_ALL_L3_L4,
23 	ENA_HF_RSS_UDP6		= ENA_HF_RSS_ALL_L3_L4,
24 	ENA_HF_RSS_IP4		= ENA_HF_RSS_ALL_L3,
25 	ENA_HF_RSS_IP6		= ENA_HF_RSS_ALL_L3,
26 	ENA_HF_RSS_IP4_FRAG	= ENA_HF_RSS_ALL_L3,
27 	ENA_HF_RSS_NOT_IP	= ENA_HF_RSS_ALL_L2,
28 	ENA_HF_RSS_TCP6_EX	= ENA_HF_RSS_ALL_L3_L4,
29 	ENA_HF_RSS_IP6_EX	= ENA_HF_RSS_ALL_L3,
30 };
31 
32 static int ena_fill_indirect_table_default(struct ena_com_dev *ena_dev,
33 					   size_t tbl_size,
34 					   size_t queue_num);
35 static uint64_t ena_admin_hf_to_eth_hf(enum ena_admin_flow_hash_proto proto,
36 				       uint16_t field);
37 static uint16_t ena_eth_hf_to_admin_hf(enum ena_admin_flow_hash_proto proto,
38 				       uint64_t rss_hf);
39 static int ena_set_hash_fields(struct ena_com_dev *ena_dev, uint64_t rss_hf);
40 static int ena_rss_hash_set(struct ena_com_dev *ena_dev,
41 			    struct rte_eth_rss_conf *rss_conf,
42 			    bool default_allowed);
43 static void ena_reorder_rss_hash_key(uint8_t *reordered_key,
44 				     uint8_t *key,
45 				     size_t key_size);
46 static int ena_get_rss_hash_key(struct ena_com_dev *ena_dev, uint8_t *rss_key);
47 
48 void ena_rss_key_fill(void *key, size_t size)
49 {
50 	static bool key_generated;
51 	static uint8_t default_key[ENA_HASH_KEY_SIZE];
52 	size_t i;
53 
54 	if (!key_generated) {
55 		for (i = 0; i < RTE_DIM(default_key); ++i)
56 			default_key[i] = rte_rand() & 0xff;
57 		key_generated = true;
58 	}
59 
60 	RTE_ASSERT(size <= sizeof(default_key));
61 	rte_memcpy(key, default_key, RTE_MIN(size, sizeof(default_key)));
62 }
63 
64 int ena_rss_reta_update(struct rte_eth_dev *dev,
65 			struct rte_eth_rss_reta_entry64 *reta_conf,
66 			uint16_t reta_size)
67 {
68 	struct ena_adapter *adapter = dev->data->dev_private;
69 	struct ena_com_dev *ena_dev = &adapter->ena_dev;
70 	int rc, i;
71 	u16 entry_value;
72 	int conf_idx;
73 	int idx;
74 
75 	if (reta_size == 0 || reta_conf == NULL)
76 		return -EINVAL;
77 
78 	if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) {
79 		PMD_DRV_LOG(ERR,
80 			"RSS was not configured for the PMD\n");
81 		return -ENOTSUP;
82 	}
83 
84 	if (reta_size > ENA_RX_RSS_TABLE_SIZE) {
85 		PMD_DRV_LOG(WARNING,
86 			"Requested indirection table size (%d) is bigger than supported: %d\n",
87 			reta_size, ENA_RX_RSS_TABLE_SIZE);
88 		return -EINVAL;
89 	}
90 
91 	/* Prevent RETA table structure update races */
92 	rte_spinlock_lock(&adapter->admin_lock);
93 	for (i = 0 ; i < reta_size ; i++) {
94 		/* Each reta_conf is for 64 entries.
95 		 * To support 128 we use 2 conf of 64.
96 		 */
97 		conf_idx = i / RTE_ETH_RETA_GROUP_SIZE;
98 		idx = i % RTE_ETH_RETA_GROUP_SIZE;
99 		if (TEST_BIT(reta_conf[conf_idx].mask, idx)) {
100 			entry_value =
101 				ENA_IO_RXQ_IDX(reta_conf[conf_idx].reta[idx]);
102 
103 			rc = ena_com_indirect_table_fill_entry(ena_dev, i,
104 				entry_value);
105 			if (unlikely(rc != 0)) {
106 				PMD_DRV_LOG(ERR,
107 					"Cannot fill indirection table\n");
108 				return rc;
109 			}
110 		}
111 	}
112 
113 	rc = ena_mp_indirect_table_set(adapter);
114 	rte_spinlock_unlock(&adapter->admin_lock);
115 	if (unlikely(rc != 0)) {
116 		PMD_DRV_LOG(ERR, "Cannot set the indirection table\n");
117 		return rc;
118 	}
119 
120 	PMD_DRV_LOG(DEBUG, "RSS configured %d entries for port %d\n",
121 		reta_size, dev->data->port_id);
122 
123 	return 0;
124 }
125 
126 /* Query redirection table. */
127 int ena_rss_reta_query(struct rte_eth_dev *dev,
128 		       struct rte_eth_rss_reta_entry64 *reta_conf,
129 		       uint16_t reta_size)
130 {
131 	uint32_t indirect_table[ENA_RX_RSS_TABLE_SIZE];
132 	struct ena_adapter *adapter = dev->data->dev_private;
133 	int rc;
134 	int i;
135 	int reta_conf_idx;
136 	int reta_idx;
137 
138 	if (reta_size == 0 || reta_conf == NULL)
139 		return -EINVAL;
140 
141 	if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) {
142 		PMD_DRV_LOG(ERR,
143 			"RSS was not configured for the PMD\n");
144 		return -ENOTSUP;
145 	}
146 
147 	rte_spinlock_lock(&adapter->admin_lock);
148 	rc = ena_mp_indirect_table_get(adapter, indirect_table);
149 	rte_spinlock_unlock(&adapter->admin_lock);
150 	if (unlikely(rc != 0)) {
151 		PMD_DRV_LOG(ERR, "Cannot get indirection table\n");
152 		return rc;
153 	}
154 
155 	for (i = 0 ; i < reta_size ; i++) {
156 		reta_conf_idx = i / RTE_ETH_RETA_GROUP_SIZE;
157 		reta_idx = i % RTE_ETH_RETA_GROUP_SIZE;
158 		if (TEST_BIT(reta_conf[reta_conf_idx].mask, reta_idx))
159 			reta_conf[reta_conf_idx].reta[reta_idx] =
160 				ENA_IO_RXQ_IDX_REV(indirect_table[i]);
161 	}
162 
163 	return 0;
164 }
165 
166 static int ena_fill_indirect_table_default(struct ena_com_dev *ena_dev,
167 					   size_t tbl_size,
168 					   size_t queue_num)
169 {
170 	size_t i;
171 	int rc;
172 	uint16_t val;
173 
174 	for (i = 0; i < tbl_size; ++i) {
175 		val = i % queue_num;
176 		rc = ena_com_indirect_table_fill_entry(ena_dev, i,
177 			ENA_IO_RXQ_IDX(val));
178 		if (unlikely(rc != 0)) {
179 			PMD_DRV_LOG(DEBUG,
180 				"Failed to set %zu indirection table entry with val %" PRIu16 "\n",
181 				i, val);
182 			return rc;
183 		}
184 	}
185 
186 	return 0;
187 }
188 
189 static uint64_t ena_admin_hf_to_eth_hf(enum ena_admin_flow_hash_proto proto,
190 				       uint16_t fields)
191 {
192 	uint64_t rss_hf = 0;
193 
194 	/* If no fields are activated, then RSS is disabled for this proto */
195 	if ((fields & ENA_HF_RSS_ALL_L2_L3_L4) == 0)
196 		return 0;
197 
198 	/* Convert proto to ETH flag */
199 	switch (proto) {
200 	case ENA_ADMIN_RSS_TCP4:
201 		rss_hf |= RTE_ETH_RSS_NONFRAG_IPV4_TCP;
202 		break;
203 	case ENA_ADMIN_RSS_UDP4:
204 		rss_hf |= RTE_ETH_RSS_NONFRAG_IPV4_UDP;
205 		break;
206 	case ENA_ADMIN_RSS_TCP6:
207 		rss_hf |= RTE_ETH_RSS_NONFRAG_IPV6_TCP;
208 		break;
209 	case ENA_ADMIN_RSS_UDP6:
210 		rss_hf |= RTE_ETH_RSS_NONFRAG_IPV6_UDP;
211 		break;
212 	case ENA_ADMIN_RSS_IP4:
213 		rss_hf |= RTE_ETH_RSS_IPV4;
214 		break;
215 	case ENA_ADMIN_RSS_IP6:
216 		rss_hf |= RTE_ETH_RSS_IPV6;
217 		break;
218 	case ENA_ADMIN_RSS_IP4_FRAG:
219 		rss_hf |= RTE_ETH_RSS_FRAG_IPV4;
220 		break;
221 	case ENA_ADMIN_RSS_NOT_IP:
222 		rss_hf |= RTE_ETH_RSS_L2_PAYLOAD;
223 		break;
224 	case ENA_ADMIN_RSS_TCP6_EX:
225 		rss_hf |= RTE_ETH_RSS_IPV6_TCP_EX;
226 		break;
227 	case ENA_ADMIN_RSS_IP6_EX:
228 		rss_hf |= RTE_ETH_RSS_IPV6_EX;
229 		break;
230 	default:
231 		break;
232 	};
233 
234 	/* Check if only DA or SA is being used for L3. */
235 	switch (fields & ENA_HF_RSS_ALL_L3) {
236 	case ENA_ADMIN_RSS_L3_SA:
237 		rss_hf |= RTE_ETH_RSS_L3_SRC_ONLY;
238 		break;
239 	case ENA_ADMIN_RSS_L3_DA:
240 		rss_hf |= RTE_ETH_RSS_L3_DST_ONLY;
241 		break;
242 	default:
243 		break;
244 	};
245 
246 	/* Check if only DA or SA is being used for L4. */
247 	switch (fields & ENA_HF_RSS_ALL_L4) {
248 	case ENA_ADMIN_RSS_L4_SP:
249 		rss_hf |= RTE_ETH_RSS_L4_SRC_ONLY;
250 		break;
251 	case ENA_ADMIN_RSS_L4_DP:
252 		rss_hf |= RTE_ETH_RSS_L4_DST_ONLY;
253 		break;
254 	default:
255 		break;
256 	};
257 
258 	return rss_hf;
259 }
260 
261 static uint16_t ena_eth_hf_to_admin_hf(enum ena_admin_flow_hash_proto proto,
262 				       uint64_t rss_hf)
263 {
264 	uint16_t fields_mask = 0;
265 
266 	/* L2 always uses source and destination addresses. */
267 	fields_mask = ENA_ADMIN_RSS_L2_DA | ENA_ADMIN_RSS_L2_SA;
268 
269 	/* Determine which fields of L3 should be used. */
270 	switch (rss_hf & (RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY)) {
271 	case RTE_ETH_RSS_L3_DST_ONLY:
272 		fields_mask |= ENA_ADMIN_RSS_L3_DA;
273 		break;
274 	case RTE_ETH_RSS_L3_SRC_ONLY:
275 		fields_mask |= ENA_ADMIN_RSS_L3_SA;
276 		break;
277 	default:
278 		/*
279 		 * If SRC nor DST aren't set, it means both of them should be
280 		 * used.
281 		 */
282 		fields_mask |= ENA_HF_RSS_ALL_L3;
283 	}
284 
285 	/* Determine which fields of L4 should be used. */
286 	switch (rss_hf & (RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY)) {
287 	case RTE_ETH_RSS_L4_DST_ONLY:
288 		fields_mask |= ENA_ADMIN_RSS_L4_DP;
289 		break;
290 	case RTE_ETH_RSS_L4_SRC_ONLY:
291 		fields_mask |= ENA_ADMIN_RSS_L4_SP;
292 		break;
293 	default:
294 		/*
295 		 * If SRC nor DST aren't set, it means both of them should be
296 		 * used.
297 		 */
298 		fields_mask |= ENA_HF_RSS_ALL_L4;
299 	}
300 
301 	/* Return appropriate hash fields. */
302 	switch (proto) {
303 	case ENA_ADMIN_RSS_TCP4:
304 		return ENA_HF_RSS_TCP4 & fields_mask;
305 	case ENA_ADMIN_RSS_UDP4:
306 		return ENA_HF_RSS_UDP4 & fields_mask;
307 	case ENA_ADMIN_RSS_TCP6:
308 		return ENA_HF_RSS_TCP6 & fields_mask;
309 	case ENA_ADMIN_RSS_UDP6:
310 		return ENA_HF_RSS_UDP6 & fields_mask;
311 	case ENA_ADMIN_RSS_IP4:
312 		return ENA_HF_RSS_IP4 & fields_mask;
313 	case ENA_ADMIN_RSS_IP6:
314 		return ENA_HF_RSS_IP6 & fields_mask;
315 	case ENA_ADMIN_RSS_IP4_FRAG:
316 		return ENA_HF_RSS_IP4_FRAG & fields_mask;
317 	case ENA_ADMIN_RSS_NOT_IP:
318 		return ENA_HF_RSS_NOT_IP & fields_mask;
319 	case ENA_ADMIN_RSS_TCP6_EX:
320 		return ENA_HF_RSS_TCP6_EX & fields_mask;
321 	case ENA_ADMIN_RSS_IP6_EX:
322 		return ENA_HF_RSS_IP6_EX & fields_mask;
323 	default:
324 		break;
325 	}
326 
327 	return 0;
328 }
329 
330 static int ena_set_hash_fields(struct ena_com_dev *ena_dev, uint64_t rss_hf)
331 {
332 	struct ena_admin_proto_input selected_fields[ENA_ADMIN_RSS_PROTO_NUM] = {};
333 	int rc, i;
334 
335 	/* Turn on appropriate fields for each requested packet type */
336 	if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP) != 0)
337 		selected_fields[ENA_ADMIN_RSS_TCP4].fields =
338 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP4, rss_hf);
339 
340 	if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP) != 0)
341 		selected_fields[ENA_ADMIN_RSS_UDP4].fields =
342 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_UDP4, rss_hf);
343 
344 	if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP) != 0)
345 		selected_fields[ENA_ADMIN_RSS_TCP6].fields =
346 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP6, rss_hf);
347 
348 	if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP) != 0)
349 		selected_fields[ENA_ADMIN_RSS_UDP6].fields =
350 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_UDP6, rss_hf);
351 
352 	if ((rss_hf & RTE_ETH_RSS_IPV4) != 0)
353 		selected_fields[ENA_ADMIN_RSS_IP4].fields =
354 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP4, rss_hf);
355 
356 	if ((rss_hf & RTE_ETH_RSS_IPV6) != 0)
357 		selected_fields[ENA_ADMIN_RSS_IP6].fields =
358 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP6, rss_hf);
359 
360 	if ((rss_hf & RTE_ETH_RSS_FRAG_IPV4) != 0)
361 		selected_fields[ENA_ADMIN_RSS_IP4_FRAG].fields =
362 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP4_FRAG, rss_hf);
363 
364 	if ((rss_hf & RTE_ETH_RSS_L2_PAYLOAD) != 0)
365 		selected_fields[ENA_ADMIN_RSS_NOT_IP].fields =
366 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_NOT_IP, rss_hf);
367 
368 	if ((rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) != 0)
369 		selected_fields[ENA_ADMIN_RSS_TCP6_EX].fields =
370 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP6_EX, rss_hf);
371 
372 	if ((rss_hf & RTE_ETH_RSS_IPV6_EX) != 0)
373 		selected_fields[ENA_ADMIN_RSS_IP6_EX].fields =
374 			ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP6_EX, rss_hf);
375 
376 	/* Try to write them to the device */
377 	for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; i++) {
378 		rc = ena_com_fill_hash_ctrl(ena_dev,
379 			(enum ena_admin_flow_hash_proto)i,
380 			selected_fields[i].fields);
381 		if (unlikely(rc != 0)) {
382 			PMD_DRV_LOG(DEBUG,
383 				"Failed to set ENA HF %d with fields %" PRIu16 "\n",
384 				i, selected_fields[i].fields);
385 			return rc;
386 		}
387 	}
388 
389 	return 0;
390 }
391 
392 static int ena_rss_hash_set(struct ena_com_dev *ena_dev,
393 			    struct rte_eth_rss_conf *rss_conf,
394 			    bool default_allowed)
395 {
396 	uint8_t hw_rss_key[ENA_HASH_KEY_SIZE];
397 	uint8_t *rss_key;
398 	int rc;
399 
400 	if (rss_conf->rss_key != NULL) {
401 		/* Reorder the RSS key bytes for the hardware requirements. */
402 		ena_reorder_rss_hash_key(hw_rss_key, rss_conf->rss_key,
403 			ENA_HASH_KEY_SIZE);
404 		rss_key = hw_rss_key;
405 	} else {
406 		rss_key = NULL;
407 	}
408 
409 	/* If the rss_key is NULL, then the randomized key will be used. */
410 	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ,
411 		rss_key, ENA_HASH_KEY_SIZE, 0);
412 	if (rc != 0 && !(default_allowed && rc == ENA_COM_UNSUPPORTED)) {
413 		PMD_DRV_LOG(ERR,
414 			"Failed to set RSS hash function in the device\n");
415 		return rc;
416 	}
417 
418 	rc = ena_set_hash_fields(ena_dev, rss_conf->rss_hf);
419 	if (rc == ENA_COM_UNSUPPORTED) {
420 		if (rss_conf->rss_key == NULL && !default_allowed) {
421 			PMD_DRV_LOG(ERR,
422 				"Setting RSS hash fields is not supported\n");
423 			return -ENOTSUP;
424 		}
425 		PMD_DRV_LOG(WARNING,
426 			"Setting RSS hash fields is not supported. Using default values: 0x%" PRIx64 "\n",
427 			(uint64_t)(ENA_ALL_RSS_HF));
428 	} else if (rc != 0)  {
429 		PMD_DRV_LOG(ERR, "Failed to set RSS hash fields\n");
430 		return rc;
431 	}
432 
433 	return 0;
434 }
435 
436 /* ENA HW interprets the RSS key in reverse bytes order. Because of that, the
437  * key must be processed upon interaction with ena_com layer.
438  */
439 static void ena_reorder_rss_hash_key(uint8_t *reordered_key,
440 				     uint8_t *key,
441 				     size_t key_size)
442 {
443 	size_t i, rev_i;
444 
445 	for (i = 0, rev_i = key_size - 1; i < key_size; ++i, --rev_i)
446 		reordered_key[i] = key[rev_i];
447 }
448 
449 static int ena_get_rss_hash_key(struct ena_com_dev *ena_dev, uint8_t *rss_key)
450 {
451 	uint8_t hw_rss_key[ENA_HASH_KEY_SIZE];
452 	int rc;
453 
454 	/* The default RSS hash key cannot be retrieved from the HW. Unless it's
455 	 * explicitly set, this operation shouldn't be supported.
456 	 */
457 	if (ena_dev->rss.hash_key == NULL) {
458 		PMD_DRV_LOG(WARNING,
459 			"Retrieving default RSS hash key is not supported\n");
460 		return -ENOTSUP;
461 	}
462 
463 	rc = ena_com_get_hash_key(ena_dev, hw_rss_key);
464 	if (rc != 0)
465 		return rc;
466 
467 	ena_reorder_rss_hash_key(rss_key, hw_rss_key, ENA_HASH_KEY_SIZE);
468 
469 	return 0;
470 }
471 
472 int ena_rss_configure(struct ena_adapter *adapter)
473 {
474 	struct rte_eth_rss_conf *rss_conf;
475 	struct ena_com_dev *ena_dev;
476 	int rc;
477 
478 	ena_dev = &adapter->ena_dev;
479 	rss_conf = &adapter->edev_data->dev_conf.rx_adv_conf.rss_conf;
480 
481 	if (adapter->edev_data->nb_rx_queues == 0)
482 		return 0;
483 
484 	/* Restart the indirection table. The number of queues could change
485 	 * between start/stop calls, so it must be reinitialized with default
486 	 * values.
487 	 */
488 	rc = ena_fill_indirect_table_default(ena_dev, ENA_RX_RSS_TABLE_SIZE,
489 		adapter->edev_data->nb_rx_queues);
490 	if (unlikely(rc != 0)) {
491 		PMD_DRV_LOG(ERR,
492 			"Failed to fill indirection table with default values\n");
493 		return rc;
494 	}
495 
496 	rc = ena_com_indirect_table_set(ena_dev);
497 	if (unlikely(rc != 0 && rc != ENA_COM_UNSUPPORTED)) {
498 		PMD_DRV_LOG(ERR,
499 			"Failed to set indirection table in the device\n");
500 		return rc;
501 	}
502 
503 	rc = ena_rss_hash_set(ena_dev, rss_conf, true);
504 	if (unlikely(rc != 0)) {
505 		PMD_DRV_LOG(ERR, "Failed to set RSS hash\n");
506 		return rc;
507 	}
508 
509 	PMD_DRV_LOG(DEBUG, "RSS configured for port %d\n",
510 		adapter->edev_data->port_id);
511 
512 	return 0;
513 }
514 
515 int ena_rss_hash_update(struct rte_eth_dev *dev,
516 			struct rte_eth_rss_conf *rss_conf)
517 {
518 	struct ena_adapter *adapter = dev->data->dev_private;
519 	int rc;
520 
521 	rte_spinlock_lock(&adapter->admin_lock);
522 	rc = ena_rss_hash_set(&adapter->ena_dev, rss_conf, false);
523 	rte_spinlock_unlock(&adapter->admin_lock);
524 	if (unlikely(rc != 0)) {
525 		PMD_DRV_LOG(ERR, "Failed to set RSS hash\n");
526 		return rc;
527 	}
528 
529 	return 0;
530 }
531 
532 int ena_rss_hash_conf_get(struct rte_eth_dev *dev,
533 			  struct rte_eth_rss_conf *rss_conf)
534 {
535 	struct ena_adapter *adapter = dev->data->dev_private;
536 	struct ena_com_dev *ena_dev = &adapter->ena_dev;
537 	enum ena_admin_flow_hash_proto proto;
538 	uint64_t rss_hf = 0;
539 	int rc, i;
540 	uint16_t admin_hf;
541 	static bool warn_once;
542 
543 	if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) {
544 		PMD_DRV_LOG(ERR, "RSS was not configured for the PMD\n");
545 		return -ENOTSUP;
546 	}
547 
548 	if (rss_conf->rss_key != NULL) {
549 		rc = ena_get_rss_hash_key(ena_dev, rss_conf->rss_key);
550 		if (unlikely(rc != 0)) {
551 			PMD_DRV_LOG(ERR,
552 				"Cannot retrieve RSS hash key, err: %d\n",
553 				rc);
554 			return rc;
555 		}
556 	}
557 
558 	for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; ++i) {
559 		proto = (enum ena_admin_flow_hash_proto)i;
560 		rte_spinlock_lock(&adapter->admin_lock);
561 		rc = ena_com_get_hash_ctrl(ena_dev, proto, &admin_hf);
562 		rte_spinlock_unlock(&adapter->admin_lock);
563 		if (rc == ENA_COM_UNSUPPORTED) {
564 			/* As some devices may support only reading rss hash
565 			 * key and not the hash ctrl, we want to notify the
566 			 * caller that this feature is only partially supported
567 			 * and do not return an error - the caller could be
568 			 * interested only in the key value.
569 			 */
570 			if (!warn_once) {
571 				PMD_DRV_LOG(WARNING,
572 					"Reading hash control from the device is not supported. .rss_hf will contain a default value.\n");
573 				warn_once = true;
574 			}
575 			rss_hf = ENA_ALL_RSS_HF;
576 			break;
577 		} else if (rc != 0) {
578 			PMD_DRV_LOG(ERR,
579 				"Failed to retrieve hash ctrl for proto: %d with err: %d\n",
580 				i, rc);
581 			return rc;
582 		}
583 
584 		rss_hf |= ena_admin_hf_to_eth_hf(proto, admin_hf);
585 	}
586 
587 	rss_conf->rss_hf = rss_hf;
588 	return 0;
589 }
590