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