net/sfc/base: add a new means to control RSS hash
[dpdk.git] / drivers / net / sfc / base / ef10_rx.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright (c) 2012-2018 Solarflare Communications Inc.
4  * All rights reserved.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10
11 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
12
13
14 static  __checkReturn   efx_rc_t
15 efx_mcdi_init_rxq(
16         __in            efx_nic_t *enp,
17         __in            uint32_t ndescs,
18         __in            uint32_t target_evq,
19         __in            uint32_t label,
20         __in            uint32_t instance,
21         __in            efsys_mem_t *esmp,
22         __in            boolean_t disable_scatter,
23         __in            boolean_t want_inner_classes,
24         __in            uint32_t ps_bufsize)
25 {
26         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
27         efx_mcdi_req_t req;
28         uint8_t payload[MAX(MC_CMD_INIT_RXQ_EXT_IN_LEN,
29                             MC_CMD_INIT_RXQ_EXT_OUT_LEN)];
30         int npages = EFX_RXQ_NBUFS(ndescs);
31         int i;
32         efx_qword_t *dma_addr;
33         uint64_t addr;
34         efx_rc_t rc;
35         uint32_t dma_mode;
36         boolean_t want_outer_classes;
37
38         EFSYS_ASSERT3U(ndescs, <=, EFX_RXQ_MAXNDESCS);
39
40         if ((esmp == NULL) || (EFSYS_MEM_SIZE(esmp) < EFX_RXQ_SIZE(ndescs))) {
41                 rc = EINVAL;
42                 goto fail1;
43         }
44
45         if (ps_bufsize > 0)
46                 dma_mode = MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM;
47         else
48                 dma_mode = MC_CMD_INIT_RXQ_EXT_IN_SINGLE_PACKET;
49
50         if (encp->enc_tunnel_encapsulations_supported != 0 &&
51             !want_inner_classes) {
52                 /*
53                  * WANT_OUTER_CLASSES can only be specified on hardware which
54                  * supports tunnel encapsulation offloads, even though it is
55                  * effectively the behaviour the hardware gives.
56                  *
57                  * Also, on hardware which does support such offloads, older
58                  * firmware rejects the flag if the offloads are not supported
59                  * by the current firmware variant, which means this may fail if
60                  * the capabilities are not updated when the firmware variant
61                  * changes. This is not an issue on newer firmware, as it was
62                  * changed in bug 69842 (v6.4.2.1007) to permit this flag to be
63                  * specified on all firmware variants.
64                  */
65                 want_outer_classes = B_TRUE;
66         } else {
67                 want_outer_classes = B_FALSE;
68         }
69
70         (void) memset(payload, 0, sizeof (payload));
71         req.emr_cmd = MC_CMD_INIT_RXQ;
72         req.emr_in_buf = payload;
73         req.emr_in_length = MC_CMD_INIT_RXQ_EXT_IN_LEN;
74         req.emr_out_buf = payload;
75         req.emr_out_length = MC_CMD_INIT_RXQ_EXT_OUT_LEN;
76
77         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_SIZE, ndescs);
78         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_TARGET_EVQ, target_evq);
79         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_LABEL, label);
80         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_INSTANCE, instance);
81         MCDI_IN_POPULATE_DWORD_9(req, INIT_RXQ_EXT_IN_FLAGS,
82             INIT_RXQ_EXT_IN_FLAG_BUFF_MODE, 0,
83             INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT, 0,
84             INIT_RXQ_EXT_IN_FLAG_TIMESTAMP, 0,
85             INIT_RXQ_EXT_IN_CRC_MODE, 0,
86             INIT_RXQ_EXT_IN_FLAG_PREFIX, 1,
87             INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER, disable_scatter,
88             INIT_RXQ_EXT_IN_DMA_MODE,
89             dma_mode,
90             INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE, ps_bufsize,
91             INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES, want_outer_classes);
92         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_OWNER_ID, 0);
93         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
94
95         dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
96         addr = EFSYS_MEM_ADDR(esmp);
97
98         for (i = 0; i < npages; i++) {
99                 EFX_POPULATE_QWORD_2(*dma_addr,
100                     EFX_DWORD_1, (uint32_t)(addr >> 32),
101                     EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
102
103                 dma_addr++;
104                 addr += EFX_BUF_SIZE;
105         }
106
107         efx_mcdi_execute(enp, &req);
108
109         if (req.emr_rc != 0) {
110                 rc = req.emr_rc;
111                 goto fail2;
112         }
113
114         return (0);
115
116 fail2:
117         EFSYS_PROBE(fail2);
118 fail1:
119         EFSYS_PROBE1(fail1, efx_rc_t, rc);
120
121         return (rc);
122 }
123
124 static  __checkReturn   efx_rc_t
125 efx_mcdi_fini_rxq(
126         __in            efx_nic_t *enp,
127         __in            uint32_t instance)
128 {
129         efx_mcdi_req_t req;
130         uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN,
131                             MC_CMD_FINI_RXQ_OUT_LEN)];
132         efx_rc_t rc;
133
134         (void) memset(payload, 0, sizeof (payload));
135         req.emr_cmd = MC_CMD_FINI_RXQ;
136         req.emr_in_buf = payload;
137         req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
138         req.emr_out_buf = payload;
139         req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
140
141         MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
142
143         efx_mcdi_execute_quiet(enp, &req);
144
145         if (req.emr_rc != 0) {
146                 rc = req.emr_rc;
147                 goto fail1;
148         }
149
150         return (0);
151
152 fail1:
153         /*
154          * EALREADY is not an error, but indicates that the MC has rebooted and
155          * that the RXQ has already been destroyed.
156          */
157         if (rc != EALREADY)
158                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
159
160         return (rc);
161 }
162
163 #if EFSYS_OPT_RX_SCALE
164 static  __checkReturn   efx_rc_t
165 efx_mcdi_rss_context_alloc(
166         __in            efx_nic_t *enp,
167         __in            efx_rx_scale_context_type_t type,
168         __in            uint32_t num_queues,
169         __out           uint32_t *rss_contextp)
170 {
171         efx_mcdi_req_t req;
172         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
173                             MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)];
174         uint32_t rss_context;
175         uint32_t context_type;
176         efx_rc_t rc;
177
178         if (num_queues > EFX_MAXRSS) {
179                 rc = EINVAL;
180                 goto fail1;
181         }
182
183         switch (type) {
184         case EFX_RX_SCALE_EXCLUSIVE:
185                 context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE;
186                 break;
187         case EFX_RX_SCALE_SHARED:
188                 context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED;
189                 break;
190         default:
191                 rc = EINVAL;
192                 goto fail2;
193         }
194
195         (void) memset(payload, 0, sizeof (payload));
196         req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
197         req.emr_in_buf = payload;
198         req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
199         req.emr_out_buf = payload;
200         req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
201
202         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
203             EVB_PORT_ID_ASSIGNED);
204         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE, context_type);
205
206         /*
207          * For exclusive contexts, NUM_QUEUES is only used to validate
208          * indirection table offsets.
209          * For shared contexts, the provided context will spread traffic over
210          * NUM_QUEUES many queues.
211          */
212         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues);
213
214         efx_mcdi_execute(enp, &req);
215
216         if (req.emr_rc != 0) {
217                 rc = req.emr_rc;
218                 goto fail3;
219         }
220
221         if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
222                 rc = EMSGSIZE;
223                 goto fail4;
224         }
225
226         rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
227         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
228                 rc = ENOENT;
229                 goto fail5;
230         }
231
232         *rss_contextp = rss_context;
233
234         return (0);
235
236 fail5:
237         EFSYS_PROBE(fail5);
238 fail4:
239         EFSYS_PROBE(fail4);
240 fail3:
241         EFSYS_PROBE(fail3);
242 fail2:
243         EFSYS_PROBE(fail2);
244 fail1:
245         EFSYS_PROBE1(fail1, efx_rc_t, rc);
246
247         return (rc);
248 }
249 #endif /* EFSYS_OPT_RX_SCALE */
250
251 #if EFSYS_OPT_RX_SCALE
252 static                  efx_rc_t
253 efx_mcdi_rss_context_free(
254         __in            efx_nic_t *enp,
255         __in            uint32_t rss_context)
256 {
257         efx_mcdi_req_t req;
258         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN,
259                             MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)];
260         efx_rc_t rc;
261
262         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
263                 rc = EINVAL;
264                 goto fail1;
265         }
266
267         (void) memset(payload, 0, sizeof (payload));
268         req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE;
269         req.emr_in_buf = payload;
270         req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN;
271         req.emr_out_buf = payload;
272         req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN;
273
274         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context);
275
276         efx_mcdi_execute_quiet(enp, &req);
277
278         if (req.emr_rc != 0) {
279                 rc = req.emr_rc;
280                 goto fail2;
281         }
282
283         return (0);
284
285 fail2:
286         EFSYS_PROBE(fail2);
287 fail1:
288         EFSYS_PROBE1(fail1, efx_rc_t, rc);
289
290         return (rc);
291 }
292 #endif /* EFSYS_OPT_RX_SCALE */
293
294 #if EFSYS_OPT_RX_SCALE
295 static                  efx_rc_t
296 efx_mcdi_rss_context_set_flags(
297         __in            efx_nic_t *enp,
298         __in            uint32_t rss_context,
299         __in            efx_rx_hash_type_t type)
300 {
301         efx_rx_hash_type_t type_ipv4;
302         efx_rx_hash_type_t type_ipv4_tcp;
303         efx_rx_hash_type_t type_ipv6;
304         efx_rx_hash_type_t type_ipv6_tcp;
305         efx_mcdi_req_t req;
306         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
307                             MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)];
308         efx_rc_t rc;
309
310         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_TCP_LBN ==
311                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_LBN);
312         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_TCP_WIDTH ==
313                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_WIDTH);
314         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_LBN ==
315                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_LBN);
316         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_WIDTH ==
317                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_WIDTH);
318         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_TCP_LBN ==
319                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_LBN);
320         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_TCP_WIDTH ==
321                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_WIDTH);
322         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_LBN ==
323                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_LBN);
324         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_WIDTH ==
325                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_WIDTH);
326
327         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
328                 rc = EINVAL;
329                 goto fail1;
330         }
331
332         (void) memset(payload, 0, sizeof (payload));
333         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS;
334         req.emr_in_buf = payload;
335         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN;
336         req.emr_out_buf = payload;
337         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN;
338
339         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
340             rss_context);
341
342         type_ipv4 = EFX_RX_HASH(IPV4, 2TUPLE) | EFX_RX_HASH(IPV4_TCP, 2TUPLE);
343         type_ipv4_tcp = EFX_RX_HASH(IPV4_TCP, 4TUPLE);
344         type_ipv6 = EFX_RX_HASH(IPV6, 2TUPLE) | EFX_RX_HASH(IPV6_TCP, 2TUPLE);
345         type_ipv6_tcp = EFX_RX_HASH(IPV6_TCP, 4TUPLE);
346
347         MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
348             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
349             ((type & type_ipv4) == type_ipv4) ? 1 : 0,
350             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
351             ((type & type_ipv4_tcp) == type_ipv4_tcp) ? 1 : 0,
352             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
353             ((type & type_ipv6) == type_ipv6) ? 1 : 0,
354             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
355             ((type & type_ipv6_tcp) == type_ipv6_tcp) ? 1 : 0);
356
357         efx_mcdi_execute(enp, &req);
358
359         if (req.emr_rc != 0) {
360                 rc = req.emr_rc;
361                 goto fail2;
362         }
363
364         return (0);
365
366 fail2:
367         EFSYS_PROBE(fail2);
368 fail1:
369         EFSYS_PROBE1(fail1, efx_rc_t, rc);
370
371         return (rc);
372 }
373 #endif /* EFSYS_OPT_RX_SCALE */
374
375 #if EFSYS_OPT_RX_SCALE
376 static                  efx_rc_t
377 efx_mcdi_rss_context_set_key(
378         __in            efx_nic_t *enp,
379         __in            uint32_t rss_context,
380         __in_ecount(n)  uint8_t *key,
381         __in            size_t n)
382 {
383         efx_mcdi_req_t req;
384         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN,
385                             MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)];
386         efx_rc_t rc;
387
388         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
389                 rc = EINVAL;
390                 goto fail1;
391         }
392
393         (void) memset(payload, 0, sizeof (payload));
394         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY;
395         req.emr_in_buf = payload;
396         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN;
397         req.emr_out_buf = payload;
398         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN;
399
400         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID,
401             rss_context);
402
403         EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
404         if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) {
405                 rc = EINVAL;
406                 goto fail2;
407         }
408
409         memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY),
410             key, n);
411
412         efx_mcdi_execute(enp, &req);
413
414         if (req.emr_rc != 0) {
415                 rc = req.emr_rc;
416                 goto fail3;
417         }
418
419         return (0);
420
421 fail3:
422         EFSYS_PROBE(fail3);
423 fail2:
424         EFSYS_PROBE(fail2);
425 fail1:
426         EFSYS_PROBE1(fail1, efx_rc_t, rc);
427
428         return (rc);
429 }
430 #endif /* EFSYS_OPT_RX_SCALE */
431
432 #if EFSYS_OPT_RX_SCALE
433 static                  efx_rc_t
434 efx_mcdi_rss_context_set_table(
435         __in            efx_nic_t *enp,
436         __in            uint32_t rss_context,
437         __in_ecount(n)  unsigned int *table,
438         __in            size_t n)
439 {
440         efx_mcdi_req_t req;
441         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN,
442                             MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)];
443         uint8_t *req_table;
444         int i, rc;
445
446         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
447                 rc = EINVAL;
448                 goto fail1;
449         }
450
451         (void) memset(payload, 0, sizeof (payload));
452         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE;
453         req.emr_in_buf = payload;
454         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN;
455         req.emr_out_buf = payload;
456         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN;
457
458         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID,
459             rss_context);
460
461         req_table =
462             MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE);
463
464         for (i = 0;
465             i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN;
466             i++) {
467                 req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0;
468         }
469
470         efx_mcdi_execute(enp, &req);
471
472         if (req.emr_rc != 0) {
473                 rc = req.emr_rc;
474                 goto fail2;
475         }
476
477         return (0);
478
479 fail2:
480         EFSYS_PROBE(fail2);
481 fail1:
482         EFSYS_PROBE1(fail1, efx_rc_t, rc);
483
484         return (rc);
485 }
486 #endif /* EFSYS_OPT_RX_SCALE */
487
488
489         __checkReturn   efx_rc_t
490 ef10_rx_init(
491         __in            efx_nic_t *enp)
492 {
493 #if EFSYS_OPT_RX_SCALE
494
495         if (efx_mcdi_rss_context_alloc(enp, EFX_RX_SCALE_EXCLUSIVE, EFX_MAXRSS,
496                 &enp->en_rss_context) == 0) {
497                 /*
498                  * Allocated an exclusive RSS context, which allows both the
499                  * indirection table and key to be modified.
500                  */
501                 enp->en_rss_context_type = EFX_RX_SCALE_EXCLUSIVE;
502                 enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
503         } else {
504                 /*
505                  * Failed to allocate an exclusive RSS context. Continue
506                  * operation without support for RSS. The pseudo-header in
507                  * received packets will not contain a Toeplitz hash value.
508                  */
509                 enp->en_rss_context_type = EFX_RX_SCALE_UNAVAILABLE;
510                 enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE;
511         }
512
513 #endif /* EFSYS_OPT_RX_SCALE */
514
515         return (0);
516 }
517
518 #if EFSYS_OPT_RX_SCATTER
519         __checkReturn   efx_rc_t
520 ef10_rx_scatter_enable(
521         __in            efx_nic_t *enp,
522         __in            unsigned int buf_size)
523 {
524         _NOTE(ARGUNUSED(enp, buf_size))
525         return (0);
526 }
527 #endif  /* EFSYS_OPT_RX_SCATTER */
528
529 #if EFSYS_OPT_RX_SCALE
530         __checkReturn   efx_rc_t
531 ef10_rx_scale_context_alloc(
532         __in            efx_nic_t *enp,
533         __in            efx_rx_scale_context_type_t type,
534         __in            uint32_t num_queues,
535         __out           uint32_t *rss_contextp)
536 {
537         efx_rc_t rc;
538
539         rc = efx_mcdi_rss_context_alloc(enp, type, num_queues, rss_contextp);
540         if (rc != 0)
541                 goto fail1;
542
543         return (0);
544
545 fail1:
546         EFSYS_PROBE1(fail1, efx_rc_t, rc);
547         return (rc);
548 }
549 #endif /* EFSYS_OPT_RX_SCALE */
550
551 #if EFSYS_OPT_RX_SCALE
552         __checkReturn   efx_rc_t
553 ef10_rx_scale_context_free(
554         __in            efx_nic_t *enp,
555         __in            uint32_t rss_context)
556 {
557         efx_rc_t rc;
558
559         rc = efx_mcdi_rss_context_free(enp, rss_context);
560         if (rc != 0)
561                 goto fail1;
562
563         return (0);
564
565 fail1:
566         EFSYS_PROBE1(fail1, efx_rc_t, rc);
567         return (rc);
568 }
569 #endif /* EFSYS_OPT_RX_SCALE */
570
571 #if EFSYS_OPT_RX_SCALE
572         __checkReturn   efx_rc_t
573 ef10_rx_scale_mode_set(
574         __in            efx_nic_t *enp,
575         __in            uint32_t rss_context,
576         __in            efx_rx_hash_alg_t alg,
577         __in            efx_rx_hash_type_t type,
578         __in            boolean_t insert)
579 {
580         efx_rc_t rc;
581
582         EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ);
583         EFSYS_ASSERT3U(insert, ==, B_TRUE);
584
585         if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) {
586                 rc = EINVAL;
587                 goto fail1;
588         }
589
590         if (rss_context == EFX_RSS_CONTEXT_DEFAULT) {
591                 if (enp->en_rss_context_type == EFX_RX_SCALE_UNAVAILABLE) {
592                         rc = ENOTSUP;
593                         goto fail2;
594                 }
595                 rss_context = enp->en_rss_context;
596         }
597
598         if ((rc = efx_mcdi_rss_context_set_flags(enp,
599                     rss_context, type)) != 0)
600                 goto fail3;
601
602         return (0);
603
604 fail3:
605         EFSYS_PROBE(fail3);
606 fail2:
607         EFSYS_PROBE(fail2);
608 fail1:
609         EFSYS_PROBE1(fail1, efx_rc_t, rc);
610
611         return (rc);
612 }
613 #endif /* EFSYS_OPT_RX_SCALE */
614
615 #if EFSYS_OPT_RX_SCALE
616         __checkReturn   efx_rc_t
617 ef10_rx_scale_key_set(
618         __in            efx_nic_t *enp,
619         __in            uint32_t rss_context,
620         __in_ecount(n)  uint8_t *key,
621         __in            size_t n)
622 {
623         efx_rc_t rc;
624
625         EFX_STATIC_ASSERT(EFX_RSS_KEY_SIZE ==
626             MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
627
628         if (rss_context == EFX_RSS_CONTEXT_DEFAULT) {
629                 if (enp->en_rss_context_type == EFX_RX_SCALE_UNAVAILABLE) {
630                         rc = ENOTSUP;
631                         goto fail1;
632                 }
633                 rss_context = enp->en_rss_context;
634         }
635
636         if ((rc = efx_mcdi_rss_context_set_key(enp, rss_context, key, n)) != 0)
637                 goto fail2;
638
639         return (0);
640
641 fail2:
642         EFSYS_PROBE(fail2);
643 fail1:
644         EFSYS_PROBE1(fail1, efx_rc_t, rc);
645
646         return (rc);
647 }
648 #endif /* EFSYS_OPT_RX_SCALE */
649
650 #if EFSYS_OPT_RX_SCALE
651         __checkReturn   efx_rc_t
652 ef10_rx_scale_tbl_set(
653         __in            efx_nic_t *enp,
654         __in            uint32_t rss_context,
655         __in_ecount(n)  unsigned int *table,
656         __in            size_t n)
657 {
658         efx_rc_t rc;
659
660
661         if (rss_context == EFX_RSS_CONTEXT_DEFAULT) {
662                 if (enp->en_rss_context_type == EFX_RX_SCALE_UNAVAILABLE) {
663                         rc = ENOTSUP;
664                         goto fail1;
665                 }
666                 rss_context = enp->en_rss_context;
667         }
668
669         if ((rc = efx_mcdi_rss_context_set_table(enp,
670                     rss_context, table, n)) != 0)
671                 goto fail2;
672
673         return (0);
674
675 fail2:
676         EFSYS_PROBE(fail2);
677 fail1:
678         EFSYS_PROBE1(fail1, efx_rc_t, rc);
679
680         return (rc);
681 }
682 #endif /* EFSYS_OPT_RX_SCALE */
683
684
685 /*
686  * EF10 RX pseudo-header
687  * ---------------------
688  *
689  * Receive packets are prefixed by an (optional) 14 byte pseudo-header:
690  *
691  *  +00: Toeplitz hash value.
692  *       (32bit little-endian)
693  *  +04: Outer VLAN tag. Zero if the packet did not have an outer VLAN tag.
694  *       (16bit big-endian)
695  *  +06: Inner VLAN tag. Zero if the packet did not have an inner VLAN tag.
696  *       (16bit big-endian)
697  *  +08: Packet Length. Zero if the RX datapath was in cut-through mode.
698  *       (16bit little-endian)
699  *  +10: MAC timestamp. Zero if timestamping is not enabled.
700  *       (32bit little-endian)
701  *
702  * See "The RX Pseudo-header" in SF-109306-TC.
703  */
704
705         __checkReturn   efx_rc_t
706 ef10_rx_prefix_pktlen(
707         __in            efx_nic_t *enp,
708         __in            uint8_t *buffer,
709         __out           uint16_t *lengthp)
710 {
711         _NOTE(ARGUNUSED(enp))
712
713         /*
714          * The RX pseudo-header contains the packet length, excluding the
715          * pseudo-header. If the hardware receive datapath was operating in
716          * cut-through mode then the length in the RX pseudo-header will be
717          * zero, and the packet length must be obtained from the DMA length
718          * reported in the RX event.
719          */
720         *lengthp = buffer[8] | (buffer[9] << 8);
721         return (0);
722 }
723
724 #if EFSYS_OPT_RX_SCALE
725         __checkReturn   uint32_t
726 ef10_rx_prefix_hash(
727         __in            efx_nic_t *enp,
728         __in            efx_rx_hash_alg_t func,
729         __in            uint8_t *buffer)
730 {
731         _NOTE(ARGUNUSED(enp))
732
733         switch (func) {
734         case EFX_RX_HASHALG_TOEPLITZ:
735                 return (buffer[0] |
736                     (buffer[1] << 8) |
737                     (buffer[2] << 16) |
738                     (buffer[3] << 24));
739
740         default:
741                 EFSYS_ASSERT(0);
742                 return (0);
743         }
744 }
745 #endif /* EFSYS_OPT_RX_SCALE */
746
747 #if EFSYS_OPT_RX_PACKED_STREAM
748 /*
749  * Fake length for RXQ descriptors in packed stream mode
750  * to make hardware happy
751  */
752 #define EFX_RXQ_PACKED_STREAM_FAKE_BUF_SIZE 32
753 #endif
754
755                                 void
756 ef10_rx_qpost(
757         __in                    efx_rxq_t *erp,
758         __in_ecount(ndescs)     efsys_dma_addr_t *addrp,
759         __in                    size_t size,
760         __in                    unsigned int ndescs,
761         __in                    unsigned int completed,
762         __in                    unsigned int added)
763 {
764         efx_qword_t qword;
765         unsigned int i;
766         unsigned int offset;
767         unsigned int id;
768
769         _NOTE(ARGUNUSED(completed))
770
771 #if EFSYS_OPT_RX_PACKED_STREAM
772         /*
773          * Real size of the buffer does not fit into ESF_DZ_RX_KER_BYTE_CNT
774          * and equal to 0 after applying mask. Hardware does not like it.
775          */
776         if (erp->er_ev_qstate->eers_rx_packed_stream)
777                 size = EFX_RXQ_PACKED_STREAM_FAKE_BUF_SIZE;
778 #endif
779
780         /* The client driver must not overfill the queue */
781         EFSYS_ASSERT3U(added - completed + ndescs, <=,
782             EFX_RXQ_LIMIT(erp->er_mask + 1));
783
784         id = added & (erp->er_mask);
785         for (i = 0; i < ndescs; i++) {
786                 EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
787                     unsigned int, id, efsys_dma_addr_t, addrp[i],
788                     size_t, size);
789
790                 EFX_POPULATE_QWORD_3(qword,
791                     ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size),
792                     ESF_DZ_RX_KER_BUF_ADDR_DW0,
793                     (uint32_t)(addrp[i] & 0xffffffff),
794                     ESF_DZ_RX_KER_BUF_ADDR_DW1,
795                     (uint32_t)(addrp[i] >> 32));
796
797                 offset = id * sizeof (efx_qword_t);
798                 EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
799
800                 id = (id + 1) & (erp->er_mask);
801         }
802 }
803
804                         void
805 ef10_rx_qpush(
806         __in    efx_rxq_t *erp,
807         __in    unsigned int added,
808         __inout unsigned int *pushedp)
809 {
810         efx_nic_t *enp = erp->er_enp;
811         unsigned int pushed = *pushedp;
812         uint32_t wptr;
813         efx_dword_t dword;
814
815         /* Hardware has alignment restriction for WPTR */
816         wptr = P2ALIGN(added, EF10_RX_WPTR_ALIGN);
817         if (pushed == wptr)
818                 return;
819
820         *pushedp = wptr;
821
822         /* Push the populated descriptors out */
823         wptr &= erp->er_mask;
824
825         EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr);
826
827         /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
828         EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
829             wptr, pushed & erp->er_mask);
830         EFSYS_PIO_WRITE_BARRIER();
831         EFX_BAR_VI_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
832             erp->er_index, &dword, B_FALSE);
833 }
834
835 #if EFSYS_OPT_RX_PACKED_STREAM
836
837                         void
838 ef10_rx_qpush_ps_credits(
839         __in            efx_rxq_t *erp)
840 {
841         efx_nic_t *enp = erp->er_enp;
842         efx_dword_t dword;
843         efx_evq_rxq_state_t *rxq_state = erp->er_ev_qstate;
844         uint32_t credits;
845
846         EFSYS_ASSERT(rxq_state->eers_rx_packed_stream);
847
848         if (rxq_state->eers_rx_packed_stream_credits == 0)
849                 return;
850
851         /*
852          * It is a bug if we think that FW has utilized more
853          * credits than it is allowed to have (maximum). However,
854          * make sure that we do not credit more than maximum anyway.
855          */
856         credits = MIN(rxq_state->eers_rx_packed_stream_credits,
857             EFX_RX_PACKED_STREAM_MAX_CREDITS);
858         EFX_POPULATE_DWORD_3(dword,
859             ERF_DZ_RX_DESC_MAGIC_DOORBELL, 1,
860             ERF_DZ_RX_DESC_MAGIC_CMD,
861             ERE_DZ_RX_DESC_MAGIC_CMD_PS_CREDITS,
862             ERF_DZ_RX_DESC_MAGIC_DATA, credits);
863         EFX_BAR_VI_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
864             erp->er_index, &dword, B_FALSE);
865
866         rxq_state->eers_rx_packed_stream_credits = 0;
867 }
868
869 /*
870  * In accordance with SF-112241-TC the received data has the following layout:
871  *  - 8 byte pseudo-header which consist of:
872  *    - 4 byte little-endian timestamp
873  *    - 2 byte little-endian captured length in bytes
874  *    - 2 byte little-endian original packet length in bytes
875  *  - captured packet bytes
876  *  - optional padding to align to 64 bytes boundary
877  *  - 64 bytes scratch space for the host software
878  */
879         __checkReturn   uint8_t *
880 ef10_rx_qps_packet_info(
881         __in            efx_rxq_t *erp,
882         __in            uint8_t *buffer,
883         __in            uint32_t buffer_length,
884         __in            uint32_t current_offset,
885         __out           uint16_t *lengthp,
886         __out           uint32_t *next_offsetp,
887         __out           uint32_t *timestamp)
888 {
889         uint16_t buf_len;
890         uint8_t *pkt_start;
891         efx_qword_t *qwordp;
892         efx_evq_rxq_state_t *rxq_state = erp->er_ev_qstate;
893
894         EFSYS_ASSERT(rxq_state->eers_rx_packed_stream);
895
896         buffer += current_offset;
897         pkt_start = buffer + EFX_RX_PACKED_STREAM_RX_PREFIX_SIZE;
898
899         qwordp = (efx_qword_t *)buffer;
900         *timestamp = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_TSTAMP);
901         *lengthp   = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_ORIG_LEN);
902         buf_len    = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_CAP_LEN);
903
904         buf_len = P2ROUNDUP(buf_len + EFX_RX_PACKED_STREAM_RX_PREFIX_SIZE,
905                             EFX_RX_PACKED_STREAM_ALIGNMENT);
906         *next_offsetp =
907             current_offset + buf_len + EFX_RX_PACKED_STREAM_ALIGNMENT;
908
909         EFSYS_ASSERT3U(*next_offsetp, <=, buffer_length);
910         EFSYS_ASSERT3U(current_offset + *lengthp, <, *next_offsetp);
911
912         if ((*next_offsetp ^ current_offset) &
913             EFX_RX_PACKED_STREAM_MEM_PER_CREDIT)
914                 rxq_state->eers_rx_packed_stream_credits++;
915
916         return (pkt_start);
917 }
918
919
920 #endif
921
922         __checkReturn   efx_rc_t
923 ef10_rx_qflush(
924         __in    efx_rxq_t *erp)
925 {
926         efx_nic_t *enp = erp->er_enp;
927         efx_rc_t rc;
928
929         if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0)
930                 goto fail1;
931
932         return (0);
933
934 fail1:
935         /*
936          * EALREADY is not an error, but indicates that the MC has rebooted and
937          * that the RXQ has already been destroyed. Callers need to know that
938          * the RXQ flush has completed to avoid waiting until timeout for a
939          * flush done event that will not be delivered.
940          */
941         if (rc != EALREADY)
942                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
943
944         return (rc);
945 }
946
947                 void
948 ef10_rx_qenable(
949         __in    efx_rxq_t *erp)
950 {
951         /* FIXME */
952         _NOTE(ARGUNUSED(erp))
953         /* FIXME */
954 }
955
956         __checkReturn   efx_rc_t
957 ef10_rx_qcreate(
958         __in            efx_nic_t *enp,
959         __in            unsigned int index,
960         __in            unsigned int label,
961         __in            efx_rxq_type_t type,
962         __in            uint32_t type_data,
963         __in            efsys_mem_t *esmp,
964         __in            size_t ndescs,
965         __in            uint32_t id,
966         __in            unsigned int flags,
967         __in            efx_evq_t *eep,
968         __in            efx_rxq_t *erp)
969 {
970         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
971         efx_rc_t rc;
972         boolean_t disable_scatter;
973         boolean_t want_inner_classes;
974         unsigned int ps_buf_size;
975
976         _NOTE(ARGUNUSED(id, erp, type_data))
977
978         EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH));
979         EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
980         EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
981
982         EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
983         EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
984
985         if (!ISP2(ndescs) ||
986             (ndescs < EFX_RXQ_MINNDESCS) || (ndescs > EFX_RXQ_MAXNDESCS)) {
987                 rc = EINVAL;
988                 goto fail1;
989         }
990         if (index >= encp->enc_rxq_limit) {
991                 rc = EINVAL;
992                 goto fail2;
993         }
994
995         switch (type) {
996         case EFX_RXQ_TYPE_DEFAULT:
997                 ps_buf_size = 0;
998                 break;
999 #if EFSYS_OPT_RX_PACKED_STREAM
1000         case EFX_RXQ_TYPE_PACKED_STREAM:
1001                 switch (type_data) {
1002                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_1M:
1003                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_1M;
1004                         break;
1005                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_512K:
1006                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_512K;
1007                         break;
1008                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_256K:
1009                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_256K;
1010                         break;
1011                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_128K:
1012                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_128K;
1013                         break;
1014                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_64K:
1015                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_64K;
1016                         break;
1017                 default:
1018                         rc = ENOTSUP;
1019                         goto fail3;
1020                 }
1021                 break;
1022 #endif /* EFSYS_OPT_RX_PACKED_STREAM */
1023         default:
1024                 rc = ENOTSUP;
1025                 goto fail4;
1026         }
1027
1028 #if EFSYS_OPT_RX_PACKED_STREAM
1029         if (ps_buf_size != 0) {
1030                 /* Check if datapath firmware supports packed stream mode */
1031                 if (encp->enc_rx_packed_stream_supported == B_FALSE) {
1032                         rc = ENOTSUP;
1033                         goto fail5;
1034                 }
1035                 /* Check if packed stream allows configurable buffer sizes */
1036                 if ((ps_buf_size != MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_1M) &&
1037                     (encp->enc_rx_var_packed_stream_supported == B_FALSE)) {
1038                         rc = ENOTSUP;
1039                         goto fail6;
1040                 }
1041         }
1042 #else /* EFSYS_OPT_RX_PACKED_STREAM */
1043         EFSYS_ASSERT(ps_buf_size == 0);
1044 #endif /* EFSYS_OPT_RX_PACKED_STREAM */
1045
1046         /* Scatter can only be disabled if the firmware supports doing so */
1047         if (flags & EFX_RXQ_FLAG_SCATTER)
1048                 disable_scatter = B_FALSE;
1049         else
1050                 disable_scatter = encp->enc_rx_disable_scatter_supported;
1051
1052         if (flags & EFX_RXQ_FLAG_INNER_CLASSES)
1053                 want_inner_classes = B_TRUE;
1054         else
1055                 want_inner_classes = B_FALSE;
1056
1057         if ((rc = efx_mcdi_init_rxq(enp, ndescs, eep->ee_index, label, index,
1058                     esmp, disable_scatter, want_inner_classes,
1059                     ps_buf_size)) != 0)
1060                 goto fail7;
1061
1062         erp->er_eep = eep;
1063         erp->er_label = label;
1064
1065         ef10_ev_rxlabel_init(eep, erp, label, type);
1066
1067         erp->er_ev_qstate = &erp->er_eep->ee_rxq_state[label];
1068
1069         return (0);
1070
1071 fail7:
1072         EFSYS_PROBE(fail7);
1073 #if EFSYS_OPT_RX_PACKED_STREAM
1074 fail6:
1075         EFSYS_PROBE(fail6);
1076 fail5:
1077         EFSYS_PROBE(fail5);
1078 #endif /* EFSYS_OPT_RX_PACKED_STREAM */
1079 fail4:
1080         EFSYS_PROBE(fail4);
1081 #if EFSYS_OPT_RX_PACKED_STREAM
1082 fail3:
1083         EFSYS_PROBE(fail3);
1084 #endif /* EFSYS_OPT_RX_PACKED_STREAM */
1085 fail2:
1086         EFSYS_PROBE(fail2);
1087 fail1:
1088         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1089
1090         return (rc);
1091 }
1092
1093                 void
1094 ef10_rx_qdestroy(
1095         __in    efx_rxq_t *erp)
1096 {
1097         efx_nic_t *enp = erp->er_enp;
1098         efx_evq_t *eep = erp->er_eep;
1099         unsigned int label = erp->er_label;
1100
1101         ef10_ev_rxlabel_fini(eep, label);
1102
1103         EFSYS_ASSERT(enp->en_rx_qcount != 0);
1104         --enp->en_rx_qcount;
1105
1106         EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
1107 }
1108
1109                 void
1110 ef10_rx_fini(
1111         __in    efx_nic_t *enp)
1112 {
1113 #if EFSYS_OPT_RX_SCALE
1114         if (enp->en_rss_context_type != EFX_RX_SCALE_UNAVAILABLE)
1115                 (void) efx_mcdi_rss_context_free(enp, enp->en_rss_context);
1116         enp->en_rss_context = 0;
1117         enp->en_rss_context_type = EFX_RX_SCALE_UNAVAILABLE;
1118 #else
1119         _NOTE(ARGUNUSED(enp))
1120 #endif /* EFSYS_OPT_RX_SCALE */
1121 }
1122
1123 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */