Branch data Line data Source code
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 : 0 : 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 [ # # ]: 0 : if (!key_generated) {
55 [ # # ]: 0 : for (i = 0; i < RTE_DIM(default_key); ++i)
56 : 0 : default_key[i] = rte_rand() & 0xff;
57 : 0 : key_generated = true;
58 : : }
59 : :
60 : : RTE_ASSERT(size <= sizeof(default_key));
61 [ # # ]: 0 : rte_memcpy(key, default_key, RTE_MIN(size, sizeof(default_key)));
62 : 0 : }
63 : :
64 : 0 : 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 : 0 : struct ena_adapter *adapter = dev->data->dev_private;
69 : 0 : 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 [ # # ]: 0 : if (reta_size == 0 || reta_conf == NULL)
76 : : return -EINVAL;
77 : :
78 [ # # ]: 0 : if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) {
79 : 0 : PMD_DRV_LOG_LINE(ERR,
80 : : "RSS was not configured for the PMD");
81 : 0 : return -ENOTSUP;
82 : : }
83 : :
84 [ # # ]: 0 : if (reta_size > ENA_RX_RSS_TABLE_SIZE) {
85 : 0 : 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 : 0 : return -EINVAL;
89 : : }
90 : :
91 : : /* Prevent RETA table structure update races */
92 : 0 : rte_spinlock_lock(&adapter->admin_lock);
93 [ # # ]: 0 : 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 : 0 : conf_idx = i / RTE_ETH_RETA_GROUP_SIZE;
98 : 0 : idx = i % RTE_ETH_RETA_GROUP_SIZE;
99 [ # # ]: 0 : if (TEST_BIT(reta_conf[conf_idx].mask, idx)) {
100 : 0 : entry_value =
101 : 0 : ENA_IO_RXQ_IDX(reta_conf[conf_idx].reta[idx]);
102 : :
103 : 0 : rc = ena_com_indirect_table_fill_entry(ena_dev, i,
104 : : entry_value);
105 [ # # ]: 0 : if (unlikely(rc != 0)) {
106 : 0 : PMD_DRV_LOG_LINE(ERR,
107 : : "Cannot fill indirection table");
108 : : rte_spinlock_unlock(&adapter->admin_lock);
109 : 0 : return rc;
110 : : }
111 : : }
112 : : }
113 : :
114 : 0 : rc = ena_mp_indirect_table_set(adapter);
115 : : rte_spinlock_unlock(&adapter->admin_lock);
116 [ # # ]: 0 : if (unlikely(rc != 0)) {
117 : 0 : PMD_DRV_LOG_LINE(ERR, "Cannot set the indirection table");
118 : 0 : return rc;
119 : : }
120 : :
121 : 0 : PMD_DRV_LOG_LINE(DEBUG, "RSS configured %d entries for port %d",
122 : : reta_size, dev->data->port_id);
123 : :
124 : 0 : return 0;
125 : : }
126 : :
127 : : /* Query redirection table. */
128 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (reta_size == 0 || reta_conf == NULL)
140 : : return -EINVAL;
141 : :
142 [ # # ]: 0 : if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) {
143 : 0 : PMD_DRV_LOG_LINE(ERR,
144 : : "RSS was not configured for the PMD");
145 : 0 : return -ENOTSUP;
146 : : }
147 : :
148 : 0 : rte_spinlock_lock(&adapter->admin_lock);
149 : 0 : rc = ena_mp_indirect_table_get(adapter, indirect_table);
150 : : rte_spinlock_unlock(&adapter->admin_lock);
151 [ # # ]: 0 : if (unlikely(rc != 0)) {
152 : 0 : PMD_DRV_LOG_LINE(ERR, "Cannot get indirection table");
153 : 0 : return rc;
154 : : }
155 : :
156 [ # # ]: 0 : for (i = 0 ; i < reta_size ; i++) {
157 : 0 : reta_conf_idx = i / RTE_ETH_RETA_GROUP_SIZE;
158 : 0 : reta_idx = i % RTE_ETH_RETA_GROUP_SIZE;
159 [ # # ]: 0 : if (TEST_BIT(reta_conf[reta_conf_idx].mask, reta_idx))
160 : 0 : reta_conf[reta_conf_idx].reta[reta_idx] =
161 : 0 : ENA_IO_RXQ_IDX_REV(indirect_table[i]);
162 : : }
163 : :
164 : : return 0;
165 : : }
166 : :
167 : 0 : 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 [ # # ]: 0 : for (i = 0; i < tbl_size; ++i) {
176 : 0 : val = i % queue_num;
177 : 0 : rc = ena_com_indirect_table_fill_entry(ena_dev, i,
178 : 0 : ENA_IO_RXQ_IDX(val));
179 [ # # ]: 0 : if (unlikely(rc != 0)) {
180 : 0 : PMD_DRV_LOG_LINE(DEBUG,
181 : : "Failed to set %zu indirection table entry with val %" PRIu16 "",
182 : : i, val);
183 : 0 : return rc;
184 : : }
185 : : }
186 : :
187 : : return 0;
188 : : }
189 : :
190 : 0 : 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 [ # # ]: 0 : 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 [ # # # ]: 0 : switch (fields & ENA_HF_RSS_ALL_L3) {
237 : 0 : case ENA_ADMIN_RSS_L3_SA:
238 : 0 : rss_hf |= RTE_ETH_RSS_L3_SRC_ONLY;
239 : 0 : break;
240 : 0 : case ENA_ADMIN_RSS_L3_DA:
241 : 0 : rss_hf |= RTE_ETH_RSS_L3_DST_ONLY;
242 : 0 : break;
243 : : default:
244 : : break;
245 : : };
246 : :
247 : : /* Check if only DA or SA is being used for L4. */
248 [ # # # ]: 0 : switch (fields & ENA_HF_RSS_ALL_L4) {
249 : 0 : case ENA_ADMIN_RSS_L4_SP:
250 : 0 : rss_hf |= RTE_ETH_RSS_L4_SRC_ONLY;
251 : 0 : break;
252 : 0 : case ENA_ADMIN_RSS_L4_DP:
253 : 0 : rss_hf |= RTE_ETH_RSS_L4_DST_ONLY;
254 : 0 : 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 [ # # # # : 0 : 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 : 0 : case RTE_ETH_RSS_L3_SRC_ONLY:
276 : : fields_mask |= ENA_ADMIN_RSS_L3_SA;
277 : 0 : break;
278 : 0 : 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 [ # # # # : 0 : switch (rss_hf & (RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY)) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
288 : 0 : case RTE_ETH_RSS_L4_DST_ONLY:
289 : 0 : fields_mask |= ENA_ADMIN_RSS_L4_DP;
290 : 0 : break;
291 : 0 : case RTE_ETH_RSS_L4_SRC_ONLY:
292 : 0 : fields_mask |= ENA_ADMIN_RSS_L4_SP;
293 : 0 : break;
294 : 0 : default:
295 : : /*
296 : : * If SRC nor DST aren't set, it means both of them should be
297 : : * used.
298 : : */
299 : 0 : fields_mask |= ENA_HF_RSS_ALL_L4;
300 : : }
301 : :
302 : : /* Return appropriate hash fields. */
303 : : switch (proto) {
304 : : case ENA_ADMIN_RSS_TCP4:
305 : 0 : return ENA_HF_RSS_TCP4 & fields_mask;
306 : : case ENA_ADMIN_RSS_UDP4:
307 : 0 : return ENA_HF_RSS_UDP4 & fields_mask;
308 : : case ENA_ADMIN_RSS_TCP6:
309 : 0 : return ENA_HF_RSS_TCP6 & fields_mask;
310 : : case ENA_ADMIN_RSS_UDP6:
311 : 0 : return ENA_HF_RSS_UDP6 & fields_mask;
312 : : case ENA_ADMIN_RSS_IP4:
313 : 0 : return ENA_HF_RSS_IP4 & fields_mask;
314 : : case ENA_ADMIN_RSS_IP6:
315 : 0 : return ENA_HF_RSS_IP6 & fields_mask;
316 : : case ENA_ADMIN_RSS_IP4_FRAG:
317 : 0 : return ENA_HF_RSS_IP4_FRAG & fields_mask;
318 : : case ENA_ADMIN_RSS_NOT_IP:
319 : 0 : return ENA_HF_RSS_NOT_IP & fields_mask;
320 : : case ENA_ADMIN_RSS_TCP6_EX:
321 : 0 : return ENA_HF_RSS_TCP6_EX & fields_mask;
322 : : case ENA_ADMIN_RSS_IP6_EX:
323 : 0 : return ENA_HF_RSS_IP6_EX & fields_mask;
324 : : default:
325 : : break;
326 : : }
327 : :
328 : : return 0;
329 : : }
330 : :
331 : 0 : static int ena_set_hash_fields(struct ena_com_dev *ena_dev, uint64_t rss_hf)
332 : : {
333 : 0 : 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 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP) != 0)
338 : 0 : selected_fields[ENA_ADMIN_RSS_TCP4].fields =
339 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP4, rss_hf);
340 : :
341 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP) != 0)
342 : 0 : selected_fields[ENA_ADMIN_RSS_UDP4].fields =
343 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_UDP4, rss_hf);
344 : :
345 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP) != 0)
346 : 0 : selected_fields[ENA_ADMIN_RSS_TCP6].fields =
347 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP6, rss_hf);
348 : :
349 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP) != 0)
350 : 0 : selected_fields[ENA_ADMIN_RSS_UDP6].fields =
351 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_UDP6, rss_hf);
352 : :
353 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_IPV4) != 0)
354 : 0 : selected_fields[ENA_ADMIN_RSS_IP4].fields =
355 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP4, rss_hf);
356 : :
357 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_IPV6) != 0)
358 : 0 : selected_fields[ENA_ADMIN_RSS_IP6].fields =
359 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP6, rss_hf);
360 : :
361 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_FRAG_IPV4) != 0)
362 : 0 : selected_fields[ENA_ADMIN_RSS_IP4_FRAG].fields =
363 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP4_FRAG, rss_hf);
364 : :
365 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_L2_PAYLOAD) != 0)
366 : 0 : selected_fields[ENA_ADMIN_RSS_NOT_IP].fields =
367 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_NOT_IP, rss_hf);
368 : :
369 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) != 0)
370 : 0 : selected_fields[ENA_ADMIN_RSS_TCP6_EX].fields =
371 : : ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP6_EX, rss_hf);
372 : :
373 [ # # ]: 0 : if ((rss_hf & RTE_ETH_RSS_IPV6_EX) != 0)
374 : 0 : 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 [ # # ]: 0 : for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; i++) {
379 : 0 : rc = ena_com_fill_hash_ctrl(ena_dev,
380 : : (enum ena_admin_flow_hash_proto)i,
381 : 0 : selected_fields[i].fields);
382 [ # # ]: 0 : if (unlikely(rc != 0)) {
383 : 0 : PMD_DRV_LOG_LINE(DEBUG,
384 : : "Failed to set ENA HF %d with fields %" PRIu16 "",
385 : : i, selected_fields[i].fields);
386 : 0 : return rc;
387 : : }
388 : : }
389 : :
390 : : return 0;
391 : : }
392 : :
393 : 0 : 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 [ # # ]: 0 : 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 : 0 : rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ,
412 : : rss_key, ENA_HASH_KEY_SIZE, 0);
413 [ # # # # ]: 0 : if (rc != 0 && !(default_allowed && rc == ENA_COM_UNSUPPORTED)) {
414 : 0 : PMD_DRV_LOG_LINE(ERR,
415 : : "Failed to set RSS hash function in the device");
416 : 0 : return rc;
417 : : }
418 : :
419 : 0 : rc = ena_set_hash_fields(ena_dev, rss_conf->rss_hf);
420 [ # # ]: 0 : if (rc == ENA_COM_UNSUPPORTED) {
421 [ # # # # ]: 0 : if (rss_conf->rss_key == NULL && !default_allowed) {
422 : 0 : PMD_DRV_LOG_LINE(ERR,
423 : : "Setting RSS hash fields is not supported");
424 : 0 : return -ENOTSUP;
425 : : }
426 : 0 : 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 [ # # ]: 0 : } else if (rc != 0) {
430 : 0 : PMD_DRV_LOG_LINE(ERR, "Failed to set RSS hash fields");
431 : 0 : 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 [ # # # # ]: 0 : for (i = 0, rev_i = key_size - 1; i < key_size; ++i, --rev_i)
447 : 0 : reordered_key[i] = key[rev_i];
448 : : }
449 : :
450 : 0 : 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 [ # # ]: 0 : if (ena_dev->rss.hash_key == NULL) {
459 : 0 : PMD_DRV_LOG_LINE(WARNING,
460 : : "Retrieving default RSS hash key is not supported");
461 : 0 : return -ENOTSUP;
462 : : }
463 : :
464 : 0 : rc = ena_com_get_hash_key(ena_dev, hw_rss_key);
465 [ # # ]: 0 : 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 : 0 : 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 : 0 : ena_dev = &adapter->ena_dev;
480 : 0 : rss_conf = &adapter->edev_data->dev_conf.rx_adv_conf.rss_conf;
481 : :
482 [ # # ]: 0 : 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 : 0 : rc = ena_fill_indirect_table_default(ena_dev, ENA_RX_RSS_TABLE_SIZE,
490 : : adapter->edev_data->nb_rx_queues);
491 [ # # ]: 0 : if (unlikely(rc != 0)) {
492 : 0 : PMD_DRV_LOG_LINE(ERR,
493 : : "Failed to fill indirection table with default values");
494 : 0 : return rc;
495 : : }
496 : :
497 : 0 : rc = ena_com_indirect_table_set(ena_dev);
498 [ # # ]: 0 : if (unlikely(rc != 0 && rc != ENA_COM_UNSUPPORTED)) {
499 : 0 : PMD_DRV_LOG_LINE(ERR,
500 : : "Failed to set indirection table in the device");
501 : 0 : return rc;
502 : : }
503 : :
504 : 0 : rc = ena_rss_hash_set(ena_dev, rss_conf, true);
505 [ # # ]: 0 : if (unlikely(rc != 0)) {
506 : 0 : PMD_DRV_LOG_LINE(ERR, "Failed to set RSS hash");
507 : 0 : return rc;
508 : : }
509 : :
510 : 0 : PMD_DRV_LOG_LINE(DEBUG, "RSS configured for port %d",
511 : : adapter->edev_data->port_id);
512 : :
513 : 0 : return 0;
514 : : }
515 : :
516 : 0 : int ena_rss_hash_update(struct rte_eth_dev *dev,
517 : : struct rte_eth_rss_conf *rss_conf)
518 : : {
519 : 0 : struct ena_adapter *adapter = dev->data->dev_private;
520 : : int rc;
521 : :
522 : 0 : rte_spinlock_lock(&adapter->admin_lock);
523 : 0 : rc = ena_rss_hash_set(&adapter->ena_dev, rss_conf, false);
524 : : rte_spinlock_unlock(&adapter->admin_lock);
525 [ # # ]: 0 : if (unlikely(rc != 0)) {
526 : 0 : PMD_DRV_LOG_LINE(ERR, "Failed to set RSS hash");
527 : 0 : return rc;
528 : : }
529 : :
530 : : return 0;
531 : : }
532 : :
533 : 0 : int ena_rss_hash_conf_get(struct rte_eth_dev *dev,
534 : : struct rte_eth_rss_conf *rss_conf)
535 : : {
536 : 0 : struct ena_adapter *adapter = dev->data->dev_private;
537 : 0 : 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 [ # # ]: 0 : if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) {
545 : 0 : PMD_DRV_LOG_LINE(ERR, "RSS was not configured for the PMD");
546 : 0 : return -ENOTSUP;
547 : : }
548 : :
549 [ # # ]: 0 : if (rss_conf->rss_key != NULL) {
550 : 0 : rc = ena_get_rss_hash_key(ena_dev, rss_conf->rss_key);
551 [ # # ]: 0 : if (unlikely(rc != 0)) {
552 : 0 : PMD_DRV_LOG_LINE(ERR,
553 : : "Cannot retrieve RSS hash key, err: %d",
554 : : rc);
555 : 0 : return rc;
556 : : }
557 : : }
558 : :
559 [ # # ]: 0 : for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; ++i) {
560 : 0 : proto = (enum ena_admin_flow_hash_proto)i;
561 : 0 : rte_spinlock_lock(&adapter->admin_lock);
562 : 0 : rc = ena_com_get_hash_ctrl(ena_dev, proto, &admin_hf);
563 : : rte_spinlock_unlock(&adapter->admin_lock);
564 [ # # ]: 0 : 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 [ # # ]: 0 : if (!warn_once) {
572 : 0 : PMD_DRV_LOG_LINE(WARNING,
573 : : "Reading hash control from the device is not supported. .rss_hf will contain a default value.");
574 : 0 : warn_once = true;
575 : : }
576 : : rss_hf = ENA_ALL_RSS_HF;
577 : : break;
578 [ # # ]: 0 : } else if (rc != 0) {
579 : 0 : PMD_DRV_LOG_LINE(ERR,
580 : : "Failed to retrieve hash ctrl for proto: %d with err: %d",
581 : : i, rc);
582 : 0 : return rc;
583 : : }
584 : :
585 : 0 : rss_hf |= ena_admin_hf_to_eth_hf(proto, admin_hf);
586 : : }
587 : :
588 : 0 : rss_conf->rss_hf = rss_hf;
589 : 0 : return 0;
590 : : }
|