]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/ef10_rx.c
MFC r340800
[FreeBSD/stable/10.git] / sys / dev / sfxge / common / 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 <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efx.h"
35 #include "efx_impl.h"
36
37
38 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
39
40
41 static  __checkReturn   efx_rc_t
42 efx_mcdi_init_rxq(
43         __in            efx_nic_t *enp,
44         __in            uint32_t size,
45         __in            uint32_t target_evq,
46         __in            uint32_t label,
47         __in            uint32_t instance,
48         __in            efsys_mem_t *esmp,
49         __in            boolean_t disable_scatter)
50 {
51         efx_mcdi_req_t req;
52         uint8_t payload[
53             MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS))];
54         int npages = EFX_RXQ_NBUFS(size);
55         int i;
56         efx_qword_t *dma_addr;
57         uint64_t addr;
58         efx_rc_t rc;
59
60         /* If this changes, then the payload size might need to change. */
61         EFSYS_ASSERT3U(MC_CMD_INIT_RXQ_OUT_LEN, ==, 0);
62         EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS);
63
64         (void) memset(payload, 0, sizeof (payload));
65         req.emr_cmd = MC_CMD_INIT_RXQ;
66         req.emr_in_buf = payload;
67         req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages);
68         req.emr_out_buf = payload;
69         req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN;
70
71         MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size);
72         MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq);
73         MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label);
74         MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance);
75         MCDI_IN_POPULATE_DWORD_6(req, INIT_RXQ_IN_FLAGS,
76                             INIT_RXQ_IN_FLAG_BUFF_MODE, 0,
77                             INIT_RXQ_IN_FLAG_HDR_SPLIT, 0,
78                             INIT_RXQ_IN_FLAG_TIMESTAMP, 0,
79                             INIT_RXQ_IN_CRC_MODE, 0,
80                             INIT_RXQ_IN_FLAG_PREFIX, 1,
81                             INIT_RXQ_IN_FLAG_DISABLE_SCATTER, disable_scatter);
82         MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0);
83         MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
84
85         dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
86         addr = EFSYS_MEM_ADDR(esmp);
87
88         for (i = 0; i < npages; i++) {
89                 EFX_POPULATE_QWORD_2(*dma_addr,
90                     EFX_DWORD_1, (uint32_t)(addr >> 32),
91                     EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
92
93                 dma_addr++;
94                 addr += EFX_BUF_SIZE;
95         }
96
97         efx_mcdi_execute(enp, &req);
98
99         if (req.emr_rc != 0) {
100                 rc = req.emr_rc;
101                 goto fail1;
102         }
103
104         return (0);
105
106 fail1:
107         EFSYS_PROBE1(fail1, efx_rc_t, rc);
108
109         return (rc);
110 }
111
112 static  __checkReturn   efx_rc_t
113 efx_mcdi_fini_rxq(
114         __in            efx_nic_t *enp,
115         __in            uint32_t instance)
116 {
117         efx_mcdi_req_t req;
118         uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN,
119                             MC_CMD_FINI_RXQ_OUT_LEN)];
120         efx_rc_t rc;
121
122         (void) memset(payload, 0, sizeof (payload));
123         req.emr_cmd = MC_CMD_FINI_RXQ;
124         req.emr_in_buf = payload;
125         req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
126         req.emr_out_buf = payload;
127         req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
128
129         MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
130
131         efx_mcdi_execute_quiet(enp, &req);
132
133         if (req.emr_rc != 0) {
134                 rc = req.emr_rc;
135                 goto fail1;
136         }
137
138         return (0);
139
140 fail1:
141         /*
142          * EALREADY is not an error, but indicates that the MC has rebooted and
143          * that the RXQ has already been destroyed.
144          */
145         if (rc != EALREADY)
146                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
147
148         return (rc);
149 }
150
151 #if EFSYS_OPT_RX_SCALE
152 static  __checkReturn   efx_rc_t
153 efx_mcdi_rss_context_alloc(
154         __in            efx_nic_t *enp,
155         __in            efx_rx_scale_support_t scale_support,
156         __in            uint32_t num_queues,
157         __out           uint32_t *rss_contextp)
158 {
159         efx_mcdi_req_t req;
160         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
161                             MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)];
162         uint32_t rss_context;
163         uint32_t context_type;
164         efx_rc_t rc;
165
166         if (num_queues > EFX_MAXRSS) {
167                 rc = EINVAL;
168                 goto fail1;
169         }
170
171         switch (scale_support) {
172         case EFX_RX_SCALE_EXCLUSIVE:
173                 context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE;
174                 break;
175         case EFX_RX_SCALE_SHARED:
176                 context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED;
177                 break;
178         default:
179                 rc = EINVAL;
180                 goto fail2;
181         }
182
183         (void) memset(payload, 0, sizeof (payload));
184         req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
185         req.emr_in_buf = payload;
186         req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
187         req.emr_out_buf = payload;
188         req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
189
190         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
191             EVB_PORT_ID_ASSIGNED);
192         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE, context_type);
193         /* NUM_QUEUES is only used to validate indirection table offsets */
194         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues);
195
196         efx_mcdi_execute(enp, &req);
197
198         if (req.emr_rc != 0) {
199                 rc = req.emr_rc;
200                 goto fail3;
201         }
202
203         if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
204                 rc = EMSGSIZE;
205                 goto fail4;
206         }
207
208         rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
209         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
210                 rc = ENOENT;
211                 goto fail5;
212         }
213
214         *rss_contextp = rss_context;
215
216         return (0);
217
218 fail5:
219         EFSYS_PROBE(fail5);
220 fail4:
221         EFSYS_PROBE(fail4);
222 fail3:
223         EFSYS_PROBE(fail3);
224 fail2:
225         EFSYS_PROBE(fail2);
226 fail1:
227         EFSYS_PROBE1(fail1, efx_rc_t, rc);
228
229         return (rc);
230 }
231 #endif /* EFSYS_OPT_RX_SCALE */
232
233 #if EFSYS_OPT_RX_SCALE
234 static                  efx_rc_t
235 efx_mcdi_rss_context_free(
236         __in            efx_nic_t *enp,
237         __in            uint32_t rss_context)
238 {
239         efx_mcdi_req_t req;
240         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN,
241                             MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)];
242         efx_rc_t rc;
243
244         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
245                 rc = EINVAL;
246                 goto fail1;
247         }
248
249         (void) memset(payload, 0, sizeof (payload));
250         req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE;
251         req.emr_in_buf = payload;
252         req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN;
253         req.emr_out_buf = payload;
254         req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN;
255
256         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context);
257
258         efx_mcdi_execute_quiet(enp, &req);
259
260         if (req.emr_rc != 0) {
261                 rc = req.emr_rc;
262                 goto fail2;
263         }
264
265         return (0);
266
267 fail2:
268         EFSYS_PROBE(fail2);
269 fail1:
270         EFSYS_PROBE1(fail1, efx_rc_t, rc);
271
272         return (rc);
273 }
274 #endif /* EFSYS_OPT_RX_SCALE */
275
276 #if EFSYS_OPT_RX_SCALE
277 static                  efx_rc_t
278 efx_mcdi_rss_context_set_flags(
279         __in            efx_nic_t *enp,
280         __in            uint32_t rss_context,
281         __in            efx_rx_hash_type_t type)
282 {
283         efx_mcdi_req_t req;
284         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
285                             MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)];
286         efx_rc_t rc;
287
288         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
289                 rc = EINVAL;
290                 goto fail1;
291         }
292
293         (void) memset(payload, 0, sizeof (payload));
294         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS;
295         req.emr_in_buf = payload;
296         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN;
297         req.emr_out_buf = payload;
298         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN;
299
300         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
301             rss_context);
302
303         MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
304             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
305             (type & EFX_RX_HASH_IPV4) ? 1 : 0,
306             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
307             (type & EFX_RX_HASH_TCPIPV4) ? 1 : 0,
308             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
309             (type & EFX_RX_HASH_IPV6) ? 1 : 0,
310             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
311             (type & EFX_RX_HASH_TCPIPV6) ? 1 : 0);
312
313         efx_mcdi_execute(enp, &req);
314
315         if (req.emr_rc != 0) {
316                 rc = req.emr_rc;
317                 goto fail2;
318         }
319
320         return (0);
321
322 fail2:
323         EFSYS_PROBE(fail2);
324 fail1:
325         EFSYS_PROBE1(fail1, efx_rc_t, rc);
326
327         return (rc);
328 }
329 #endif /* EFSYS_OPT_RX_SCALE */
330
331 #if EFSYS_OPT_RX_SCALE
332 static                  efx_rc_t
333 efx_mcdi_rss_context_set_key(
334         __in            efx_nic_t *enp,
335         __in            uint32_t rss_context,
336         __in_ecount(n)  uint8_t *key,
337         __in            size_t n)
338 {
339         efx_mcdi_req_t req;
340         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN,
341                             MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)];
342         efx_rc_t rc;
343
344         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
345                 rc = EINVAL;
346                 goto fail1;
347         }
348
349         (void) memset(payload, 0, sizeof (payload));
350         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY;
351         req.emr_in_buf = payload;
352         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN;
353         req.emr_out_buf = payload;
354         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN;
355
356         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID,
357             rss_context);
358
359         EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
360         if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) {
361                 rc = EINVAL;
362                 goto fail2;
363         }
364
365         memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY),
366             key, n);
367
368         efx_mcdi_execute(enp, &req);
369
370         if (req.emr_rc != 0) {
371                 rc = req.emr_rc;
372                 goto fail3;
373         }
374
375         return (0);
376
377 fail3:
378         EFSYS_PROBE(fail3);
379 fail2:
380         EFSYS_PROBE(fail2);
381 fail1:
382         EFSYS_PROBE1(fail1, efx_rc_t, rc);
383
384         return (rc);
385 }
386 #endif /* EFSYS_OPT_RX_SCALE */
387
388 #if EFSYS_OPT_RX_SCALE
389 static                  efx_rc_t
390 efx_mcdi_rss_context_set_table(
391         __in            efx_nic_t *enp,
392         __in            uint32_t rss_context,
393         __in_ecount(n)  unsigned int *table,
394         __in            size_t n)
395 {
396         efx_mcdi_req_t req;
397         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN,
398                             MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)];
399         uint8_t *req_table;
400         int i, rc;
401
402         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
403                 rc = EINVAL;
404                 goto fail1;
405         }
406
407         (void) memset(payload, 0, sizeof (payload));
408         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE;
409         req.emr_in_buf = payload;
410         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN;
411         req.emr_out_buf = payload;
412         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN;
413
414         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID,
415             rss_context);
416
417         req_table =
418             MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE);
419
420         for (i = 0;
421             i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN;
422             i++) {
423                 req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0;
424         }
425
426         efx_mcdi_execute(enp, &req);
427
428         if (req.emr_rc != 0) {
429                 rc = req.emr_rc;
430                 goto fail2;
431         }
432
433         return (0);
434
435 fail2:
436         EFSYS_PROBE(fail2);
437 fail1:
438         EFSYS_PROBE1(fail1, efx_rc_t, rc);
439
440         return (rc);
441 }
442 #endif /* EFSYS_OPT_RX_SCALE */
443
444
445         __checkReturn   efx_rc_t
446 ef10_rx_init(
447         __in            efx_nic_t *enp)
448 {
449 #if EFSYS_OPT_RX_SCALE
450
451         if (efx_mcdi_rss_context_alloc(enp, EFX_RX_SCALE_EXCLUSIVE, EFX_MAXRSS,
452                 &enp->en_rss_context) == 0) {
453                 /*
454                  * Allocated an exclusive RSS context, which allows both the
455                  * indirection table and key to be modified.
456                  */
457                 enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE;
458                 enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
459         } else {
460                 /*
461                  * Failed to allocate an exclusive RSS context. Continue
462                  * operation without support for RSS. The pseudo-header in
463                  * received packets will not contain a Toeplitz hash value.
464                  */
465                 enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
466                 enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE;
467         }
468
469 #endif /* EFSYS_OPT_RX_SCALE */
470
471         return (0);
472 }
473
474 #if EFSYS_OPT_RX_SCATTER
475         __checkReturn   efx_rc_t
476 ef10_rx_scatter_enable(
477         __in            efx_nic_t *enp,
478         __in            unsigned int buf_size)
479 {
480         _NOTE(ARGUNUSED(enp, buf_size))
481         return (0);
482 }
483 #endif  /* EFSYS_OPT_RX_SCATTER */
484
485 #if EFSYS_OPT_RX_SCALE
486         __checkReturn   efx_rc_t
487 ef10_rx_scale_mode_set(
488         __in            efx_nic_t *enp,
489         __in            efx_rx_hash_alg_t alg,
490         __in            efx_rx_hash_type_t type,
491         __in            boolean_t insert)
492 {
493         efx_rc_t rc;
494
495         EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ);
496         EFSYS_ASSERT3U(insert, ==, B_TRUE);
497
498         if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) {
499                 rc = EINVAL;
500                 goto fail1;
501         }
502
503         if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
504                 rc = ENOTSUP;
505                 goto fail2;
506         }
507
508         if ((rc = efx_mcdi_rss_context_set_flags(enp,
509                     enp->en_rss_context, type)) != 0)
510                 goto fail3;
511
512         return (0);
513
514 fail3:
515         EFSYS_PROBE(fail3);
516 fail2:
517         EFSYS_PROBE(fail2);
518 fail1:
519         EFSYS_PROBE1(fail1, efx_rc_t, rc);
520
521         return (rc);
522 }
523 #endif /* EFSYS_OPT_RX_SCALE */
524
525 #if EFSYS_OPT_RX_SCALE
526         __checkReturn   efx_rc_t
527 ef10_rx_scale_key_set(
528         __in            efx_nic_t *enp,
529         __in_ecount(n)  uint8_t *key,
530         __in            size_t n)
531 {
532         efx_rc_t rc;
533
534         if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
535                 rc = ENOTSUP;
536                 goto fail1;
537         }
538
539         if ((rc = efx_mcdi_rss_context_set_key(enp,
540             enp->en_rss_context, key, n)) != 0)
541                 goto fail2;
542
543         return (0);
544
545 fail2:
546         EFSYS_PROBE(fail2);
547 fail1:
548         EFSYS_PROBE1(fail1, efx_rc_t, rc);
549
550         return (rc);
551 }
552 #endif /* EFSYS_OPT_RX_SCALE */
553
554 #if EFSYS_OPT_RX_SCALE
555         __checkReturn   efx_rc_t
556 ef10_rx_scale_tbl_set(
557         __in            efx_nic_t *enp,
558         __in_ecount(n)  unsigned int *table,
559         __in            size_t n)
560 {
561         efx_rc_t rc;
562
563         if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
564                 rc = ENOTSUP;
565                 goto fail1;
566         }
567
568         if ((rc = efx_mcdi_rss_context_set_table(enp,
569             enp->en_rss_context, table, n)) != 0)
570                 goto fail2;
571
572         return (0);
573
574 fail2:
575         EFSYS_PROBE(fail2);
576 fail1:
577         EFSYS_PROBE1(fail1, efx_rc_t, rc);
578
579         return (rc);
580 }
581 #endif /* EFSYS_OPT_RX_SCALE */
582
583
584 /*
585  * EF10 RX pseudo-header
586  * ---------------------
587  *
588  * Receive packets are prefixed by an (optional) 14 byte pseudo-header:
589  *
590  *  +00: Toeplitz hash value.
591  *       (32bit little-endian)
592  *  +04: Outer VLAN tag. Zero if the packet did not have an outer VLAN tag.
593  *       (16bit big-endian)
594  *  +06: Inner VLAN tag. Zero if the packet did not have an inner VLAN tag.
595  *       (16bit big-endian)
596  *  +08: Packet Length. Zero if the RX datapath was in cut-through mode.
597  *       (16bit little-endian)
598  *  +10: MAC timestamp. Zero if timestamping is not enabled.
599  *       (32bit little-endian)
600  *
601  * See "The RX Pseudo-header" in SF-109306-TC.
602  */
603
604         __checkReturn   efx_rc_t
605 ef10_rx_prefix_pktlen(
606         __in            efx_nic_t *enp,
607         __in            uint8_t *buffer,
608         __out           uint16_t *lengthp)
609 {
610         _NOTE(ARGUNUSED(enp))
611
612         /*
613          * The RX pseudo-header contains the packet length, excluding the
614          * pseudo-header. If the hardware receive datapath was operating in
615          * cut-through mode then the length in the RX pseudo-header will be
616          * zero, and the packet length must be obtained from the DMA length
617          * reported in the RX event.
618          */
619         *lengthp = buffer[8] | (buffer[9] << 8);
620         return (0);
621 }
622
623 #if EFSYS_OPT_RX_SCALE
624         __checkReturn   uint32_t
625 ef10_rx_prefix_hash(
626         __in            efx_nic_t *enp,
627         __in            efx_rx_hash_alg_t func,
628         __in            uint8_t *buffer)
629 {
630         _NOTE(ARGUNUSED(enp))
631
632         switch (func) {
633         case EFX_RX_HASHALG_TOEPLITZ:
634                 return (buffer[0] |
635                     (buffer[1] << 8) |
636                     (buffer[2] << 16) |
637                     (buffer[3] << 24));
638
639         default:
640                 EFSYS_ASSERT(0);
641                 return (0);
642         }
643 }
644 #endif /* EFSYS_OPT_RX_SCALE */
645
646                         void
647 ef10_rx_qpost(
648         __in            efx_rxq_t *erp,
649         __in_ecount(n)  efsys_dma_addr_t *addrp,
650         __in            size_t size,
651         __in            unsigned int n,
652         __in            unsigned int completed,
653         __in            unsigned int added)
654 {
655         efx_qword_t qword;
656         unsigned int i;
657         unsigned int offset;
658         unsigned int id;
659
660         /* The client driver must not overfill the queue */
661         EFSYS_ASSERT3U(added - completed + n, <=,
662             EFX_RXQ_LIMIT(erp->er_mask + 1));
663
664         id = added & (erp->er_mask);
665         for (i = 0; i < n; i++) {
666                 EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
667                     unsigned int, id, efsys_dma_addr_t, addrp[i],
668                     size_t, size);
669
670                 EFX_POPULATE_QWORD_3(qword,
671                     ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size),
672                     ESF_DZ_RX_KER_BUF_ADDR_DW0,
673                     (uint32_t)(addrp[i] & 0xffffffff),
674                     ESF_DZ_RX_KER_BUF_ADDR_DW1,
675                     (uint32_t)(addrp[i] >> 32));
676
677                 offset = id * sizeof (efx_qword_t);
678                 EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
679
680                 id = (id + 1) & (erp->er_mask);
681         }
682 }
683
684                         void
685 ef10_rx_qpush(
686         __in    efx_rxq_t *erp,
687         __in    unsigned int added,
688         __inout unsigned int *pushedp)
689 {
690         efx_nic_t *enp = erp->er_enp;
691         unsigned int pushed = *pushedp;
692         uint32_t wptr;
693         efx_dword_t dword;
694
695         /* Hardware has alignment restriction for WPTR */
696         wptr = P2ALIGN(added, EF10_RX_WPTR_ALIGN);
697         if (pushed == wptr)
698                 return;
699
700         *pushedp = wptr;
701
702         /* Push the populated descriptors out */
703         wptr &= erp->er_mask;
704
705         EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr);
706
707         /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
708         EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
709             wptr, pushed & erp->er_mask);
710         EFSYS_PIO_WRITE_BARRIER();
711         EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
712                             erp->er_index, &dword, B_FALSE);
713 }
714
715         __checkReturn   efx_rc_t
716 ef10_rx_qflush(
717         __in    efx_rxq_t *erp)
718 {
719         efx_nic_t *enp = erp->er_enp;
720         efx_rc_t rc;
721
722         if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0)
723                 goto fail1;
724
725         return (0);
726
727 fail1:
728         /*
729          * EALREADY is not an error, but indicates that the MC has rebooted and
730          * that the RXQ has already been destroyed. Callers need to know that
731          * the RXQ flush has completed to avoid waiting until timeout for a
732          * flush done event that will not be delivered.
733          */
734         if (rc != EALREADY)
735                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
736
737         return (rc);
738 }
739
740                 void
741 ef10_rx_qenable(
742         __in    efx_rxq_t *erp)
743 {
744         /* FIXME */
745         _NOTE(ARGUNUSED(erp))
746         /* FIXME */
747 }
748
749         __checkReturn   efx_rc_t
750 ef10_rx_qcreate(
751         __in            efx_nic_t *enp,
752         __in            unsigned int index,
753         __in            unsigned int label,
754         __in            efx_rxq_type_t type,
755         __in            efsys_mem_t *esmp,
756         __in            size_t n,
757         __in            uint32_t id,
758         __in            efx_evq_t *eep,
759         __in            efx_rxq_t *erp)
760 {
761         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
762         efx_rc_t rc;
763         boolean_t disable_scatter;
764
765         _NOTE(ARGUNUSED(id, erp))
766
767         EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH));
768         EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
769         EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
770
771         EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
772         EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
773
774         if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) {
775                 rc = EINVAL;
776                 goto fail1;
777         }
778         if (index >= encp->enc_rxq_limit) {
779                 rc = EINVAL;
780                 goto fail2;
781         }
782
783         /* Scatter can only be disabled if the firmware supports doing so */
784         if (type == EFX_RXQ_TYPE_SCATTER)
785                 disable_scatter = B_FALSE;
786         else
787                 disable_scatter = encp->enc_rx_disable_scatter_supported;
788
789         if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index,
790             esmp, disable_scatter)) != 0)
791                 goto fail3;
792
793         erp->er_eep = eep;
794         erp->er_label = label;
795
796         ef10_ev_rxlabel_init(eep, erp, label);
797
798         return (0);
799
800 fail3:
801         EFSYS_PROBE(fail3);
802 fail2:
803         EFSYS_PROBE(fail2);
804 fail1:
805         EFSYS_PROBE1(fail1, efx_rc_t, rc);
806
807         return (rc);
808 }
809
810                 void
811 ef10_rx_qdestroy(
812         __in    efx_rxq_t *erp)
813 {
814         efx_nic_t *enp = erp->er_enp;
815         efx_evq_t *eep = erp->er_eep;
816         unsigned int label = erp->er_label;
817
818         ef10_ev_rxlabel_fini(eep, label);
819
820         EFSYS_ASSERT(enp->en_rx_qcount != 0);
821         --enp->en_rx_qcount;
822
823         EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
824 }
825
826                 void
827 ef10_rx_fini(
828         __in    efx_nic_t *enp)
829 {
830 #if EFSYS_OPT_RX_SCALE
831         if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) {
832                 (void) efx_mcdi_rss_context_free(enp, enp->en_rss_context);
833         }
834         enp->en_rss_context = 0;
835         enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
836 #else
837         _NOTE(ARGUNUSED(enp))
838 #endif /* EFSYS_OPT_RX_SCALE */
839 }
840
841 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */