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