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