1283514Sarybchik/*-
2300607Sarybchik * Copyright (c) 2012-2016 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7283514Sarybchik *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29283514Sarybchik */
30283514Sarybchik
31283514Sarybchik#include <sys/cdefs.h>
32283514Sarybchik__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/ef10_rx.c 350411 2019-07-29 10:42:21Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efx.h"
35283514Sarybchik#include "efx_impl.h"
36283514Sarybchik
37283514Sarybchik
38299604Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
39283514Sarybchik
40283514Sarybchik
41291436Sarybchikstatic	__checkReturn	efx_rc_t
42283514Sarybchikefx_mcdi_init_rxq(
43283514Sarybchik	__in		efx_nic_t *enp,
44283514Sarybchik	__in		uint32_t size,
45283514Sarybchik	__in		uint32_t target_evq,
46283514Sarybchik	__in		uint32_t label,
47283514Sarybchik	__in		uint32_t instance,
48291747Sarybchik	__in		efsys_mem_t *esmp,
49291747Sarybchik	__in		boolean_t disable_scatter)
50283514Sarybchik{
51283514Sarybchik	efx_mcdi_req_t req;
52342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload,
53342445Sarybchik		MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS)),
54342445Sarybchik		MC_CMD_INIT_RXQ_OUT_LEN);
55283514Sarybchik	int npages = EFX_RXQ_NBUFS(size);
56283514Sarybchik	int i;
57283514Sarybchik	efx_qword_t *dma_addr;
58283514Sarybchik	uint64_t addr;
59291436Sarybchik	efx_rc_t rc;
60283514Sarybchik
61300847Sarybchik	/* If this changes, then the payload size might need to change. */
62300847Sarybchik	EFSYS_ASSERT3U(MC_CMD_INIT_RXQ_OUT_LEN, ==, 0);
63283514Sarybchik	EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS);
64283514Sarybchik
65283514Sarybchik	req.emr_cmd = MC_CMD_INIT_RXQ;
66283514Sarybchik	req.emr_in_buf = payload;
67283514Sarybchik	req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages);
68283514Sarybchik	req.emr_out_buf = payload;
69283514Sarybchik	req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN;
70283514Sarybchik
71283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size);
72283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq);
73283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label);
74283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance);
75291747Sarybchik	MCDI_IN_POPULATE_DWORD_6(req, INIT_RXQ_IN_FLAGS,
76291747Sarybchik			    INIT_RXQ_IN_FLAG_BUFF_MODE, 0,
77291747Sarybchik			    INIT_RXQ_IN_FLAG_HDR_SPLIT, 0,
78291747Sarybchik			    INIT_RXQ_IN_FLAG_TIMESTAMP, 0,
79291747Sarybchik			    INIT_RXQ_IN_CRC_MODE, 0,
80291747Sarybchik			    INIT_RXQ_IN_FLAG_PREFIX, 1,
81291747Sarybchik			    INIT_RXQ_IN_FLAG_DISABLE_SCATTER, disable_scatter);
82283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0);
83283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
84283514Sarybchik
85283514Sarybchik	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
86283514Sarybchik	addr = EFSYS_MEM_ADDR(esmp);
87283514Sarybchik
88283514Sarybchik	for (i = 0; i < npages; i++) {
89283514Sarybchik		EFX_POPULATE_QWORD_2(*dma_addr,
90283514Sarybchik		    EFX_DWORD_1, (uint32_t)(addr >> 32),
91283514Sarybchik		    EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
92283514Sarybchik
93283514Sarybchik		dma_addr++;
94283514Sarybchik		addr += EFX_BUF_SIZE;
95283514Sarybchik	}
96283514Sarybchik
97283514Sarybchik	efx_mcdi_execute(enp, &req);
98283514Sarybchik
99283514Sarybchik	if (req.emr_rc != 0) {
100283514Sarybchik		rc = req.emr_rc;
101283514Sarybchik		goto fail1;
102283514Sarybchik	}
103283514Sarybchik
104283514Sarybchik	return (0);
105283514Sarybchik
106283514Sarybchikfail1:
107291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
108283514Sarybchik
109283514Sarybchik	return (rc);
110283514Sarybchik}
111283514Sarybchik
112291436Sarybchikstatic	__checkReturn	efx_rc_t
113283514Sarybchikefx_mcdi_fini_rxq(
114283514Sarybchik	__in		efx_nic_t *enp,
115283514Sarybchik	__in		uint32_t instance)
116283514Sarybchik{
117283514Sarybchik	efx_mcdi_req_t req;
118342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_RXQ_IN_LEN,
119342445Sarybchik		MC_CMD_FINI_RXQ_OUT_LEN);
120291436Sarybchik	efx_rc_t rc;
121283514Sarybchik
122283514Sarybchik	req.emr_cmd = MC_CMD_FINI_RXQ;
123283514Sarybchik	req.emr_in_buf = payload;
124283514Sarybchik	req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
125283514Sarybchik	req.emr_out_buf = payload;
126283514Sarybchik	req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
127283514Sarybchik
128283514Sarybchik	MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
129283514Sarybchik
130299925Sarybchik	efx_mcdi_execute_quiet(enp, &req);
131283514Sarybchik
132342412Sarybchik	if (req.emr_rc != 0) {
133283514Sarybchik		rc = req.emr_rc;
134283514Sarybchik		goto fail1;
135283514Sarybchik	}
136283514Sarybchik
137283514Sarybchik	return (0);
138283514Sarybchik
139283514Sarybchikfail1:
140342412Sarybchik	/*
141342412Sarybchik	 * EALREADY is not an error, but indicates that the MC has rebooted and
142342412Sarybchik	 * that the RXQ has already been destroyed.
143342412Sarybchik	 */
144342412Sarybchik	if (rc != EALREADY)
145342412Sarybchik		EFSYS_PROBE1(fail1, efx_rc_t, rc);
146283514Sarybchik
147283514Sarybchik	return (rc);
148283514Sarybchik}
149283514Sarybchik
150283514Sarybchik#if EFSYS_OPT_RX_SCALE
151291436Sarybchikstatic	__checkReturn	efx_rc_t
152283514Sarybchikefx_mcdi_rss_context_alloc(
153283514Sarybchik	__in		efx_nic_t *enp,
154293772Sarybchik	__in		efx_rx_scale_support_t scale_support,
155293772Sarybchik	__in		uint32_t num_queues,
156283514Sarybchik	__out		uint32_t *rss_contextp)
157283514Sarybchik{
158283514Sarybchik	efx_mcdi_req_t req;
159342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
160342445Sarybchik		MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN);
161283514Sarybchik	uint32_t rss_context;
162293772Sarybchik	uint32_t context_type;
163291436Sarybchik	efx_rc_t rc;
164283514Sarybchik
165293772Sarybchik	if (num_queues > EFX_MAXRSS) {
166293772Sarybchik		rc = EINVAL;
167293772Sarybchik		goto fail1;
168293772Sarybchik	}
169293772Sarybchik
170293772Sarybchik	switch (scale_support) {
171293772Sarybchik	case EFX_RX_SCALE_EXCLUSIVE:
172293772Sarybchik		context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE;
173293772Sarybchik		break;
174293772Sarybchik	case EFX_RX_SCALE_SHARED:
175293772Sarybchik		context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED;
176293772Sarybchik		break;
177293772Sarybchik	default:
178293772Sarybchik		rc = EINVAL;
179293772Sarybchik		goto fail2;
180293772Sarybchik	}
181293772Sarybchik
182283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
183283514Sarybchik	req.emr_in_buf = payload;
184283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
185283514Sarybchik	req.emr_out_buf = payload;
186283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
187283514Sarybchik
188283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
189283514Sarybchik	    EVB_PORT_ID_ASSIGNED);
190293772Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE, context_type);
191283514Sarybchik	/* NUM_QUEUES is only used to validate indirection table offsets */
192293772Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues);
193283514Sarybchik
194283514Sarybchik	efx_mcdi_execute(enp, &req);
195283514Sarybchik
196283514Sarybchik	if (req.emr_rc != 0) {
197283514Sarybchik		rc = req.emr_rc;
198293772Sarybchik		goto fail3;
199283514Sarybchik	}
200283514Sarybchik
201283514Sarybchik	if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
202283514Sarybchik		rc = EMSGSIZE;
203293772Sarybchik		goto fail4;
204283514Sarybchik	}
205283514Sarybchik
206283514Sarybchik	rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
207293754Sarybchik	if (rss_context == EF10_RSS_CONTEXT_INVALID) {
208283514Sarybchik		rc = ENOENT;
209293772Sarybchik		goto fail5;
210283514Sarybchik	}
211283514Sarybchik
212283514Sarybchik	*rss_contextp = rss_context;
213283514Sarybchik
214283514Sarybchik	return (0);
215283514Sarybchik
216293772Sarybchikfail5:
217293772Sarybchik	EFSYS_PROBE(fail5);
218293772Sarybchikfail4:
219293772Sarybchik	EFSYS_PROBE(fail4);
220283514Sarybchikfail3:
221283514Sarybchik	EFSYS_PROBE(fail3);
222283514Sarybchikfail2:
223283514Sarybchik	EFSYS_PROBE(fail2);
224283514Sarybchikfail1:
225291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
226283514Sarybchik
227283514Sarybchik	return (rc);
228283514Sarybchik}
229283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
230283514Sarybchik
231283514Sarybchik#if EFSYS_OPT_RX_SCALE
232291436Sarybchikstatic			efx_rc_t
233283514Sarybchikefx_mcdi_rss_context_free(
234283514Sarybchik	__in		efx_nic_t *enp,
235283514Sarybchik	__in		uint32_t rss_context)
236283514Sarybchik{
237283514Sarybchik	efx_mcdi_req_t req;
238342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_FREE_IN_LEN,
239342445Sarybchik		MC_CMD_RSS_CONTEXT_FREE_OUT_LEN);
240291436Sarybchik	efx_rc_t rc;
241283514Sarybchik
242293754Sarybchik	if (rss_context == EF10_RSS_CONTEXT_INVALID) {
243283514Sarybchik		rc = EINVAL;
244283514Sarybchik		goto fail1;
245283514Sarybchik	}
246283514Sarybchik
247283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE;
248283514Sarybchik	req.emr_in_buf = payload;
249283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN;
250283514Sarybchik	req.emr_out_buf = payload;
251283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN;
252283514Sarybchik
253283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context);
254283514Sarybchik
255299925Sarybchik	efx_mcdi_execute_quiet(enp, &req);
256283514Sarybchik
257283514Sarybchik	if (req.emr_rc != 0) {
258283514Sarybchik		rc = req.emr_rc;
259283514Sarybchik		goto fail2;
260283514Sarybchik	}
261283514Sarybchik
262283514Sarybchik	return (0);
263283514Sarybchik
264283514Sarybchikfail2:
265283514Sarybchik	EFSYS_PROBE(fail2);
266283514Sarybchikfail1:
267291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
268283514Sarybchik
269283514Sarybchik	return (rc);
270283514Sarybchik}
271283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
272283514Sarybchik
273283514Sarybchik#if EFSYS_OPT_RX_SCALE
274291436Sarybchikstatic			efx_rc_t
275283514Sarybchikefx_mcdi_rss_context_set_flags(
276283514Sarybchik	__in		efx_nic_t *enp,
277283514Sarybchik	__in		uint32_t rss_context,
278283514Sarybchik	__in		efx_rx_hash_type_t type)
279283514Sarybchik{
280283514Sarybchik	efx_mcdi_req_t req;
281342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
282342445Sarybchik		MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN);
283291436Sarybchik	efx_rc_t rc;
284283514Sarybchik
285293754Sarybchik	if (rss_context == EF10_RSS_CONTEXT_INVALID) {
286283514Sarybchik		rc = EINVAL;
287283514Sarybchik		goto fail1;
288283514Sarybchik	}
289283514Sarybchik
290283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS;
291283514Sarybchik	req.emr_in_buf = payload;
292283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN;
293283514Sarybchik	req.emr_out_buf = payload;
294283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN;
295283514Sarybchik
296283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
297283514Sarybchik	    rss_context);
298283514Sarybchik
299283514Sarybchik	MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
300283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
301311023Sarybchik	    (type & EFX_RX_HASH_IPV4) ? 1 : 0,
302283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
303311023Sarybchik	    (type & EFX_RX_HASH_TCPIPV4) ? 1 : 0,
304283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
305311023Sarybchik	    (type & EFX_RX_HASH_IPV6) ? 1 : 0,
306283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
307311023Sarybchik	    (type & EFX_RX_HASH_TCPIPV6) ? 1 : 0);
308283514Sarybchik
309283514Sarybchik	efx_mcdi_execute(enp, &req);
310283514Sarybchik
311283514Sarybchik	if (req.emr_rc != 0) {
312283514Sarybchik		rc = req.emr_rc;
313283514Sarybchik		goto fail2;
314283514Sarybchik	}
315283514Sarybchik
316283514Sarybchik	return (0);
317283514Sarybchik
318283514Sarybchikfail2:
319283514Sarybchik	EFSYS_PROBE(fail2);
320283514Sarybchikfail1:
321291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
322283514Sarybchik
323283514Sarybchik	return (rc);
324283514Sarybchik}
325283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
326283514Sarybchik
327283514Sarybchik#if EFSYS_OPT_RX_SCALE
328291436Sarybchikstatic			efx_rc_t
329283514Sarybchikefx_mcdi_rss_context_set_key(
330283514Sarybchik	__in		efx_nic_t *enp,
331283514Sarybchik	__in		uint32_t rss_context,
332283514Sarybchik	__in_ecount(n)	uint8_t *key,
333283514Sarybchik	__in		size_t n)
334283514Sarybchik{
335283514Sarybchik	efx_mcdi_req_t req;
336342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN,
337342445Sarybchik		MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN);
338291436Sarybchik	efx_rc_t rc;
339283514Sarybchik
340293754Sarybchik	if (rss_context == EF10_RSS_CONTEXT_INVALID) {
341283514Sarybchik		rc = EINVAL;
342283514Sarybchik		goto fail1;
343283514Sarybchik	}
344283514Sarybchik
345283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY;
346283514Sarybchik	req.emr_in_buf = payload;
347283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN;
348283514Sarybchik	req.emr_out_buf = payload;
349283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN;
350283514Sarybchik
351283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID,
352283514Sarybchik	    rss_context);
353283514Sarybchik
354283514Sarybchik	EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
355283514Sarybchik	if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) {
356283514Sarybchik		rc = EINVAL;
357283514Sarybchik		goto fail2;
358283514Sarybchik	}
359283514Sarybchik
360283514Sarybchik	memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY),
361283514Sarybchik	    key, n);
362283514Sarybchik
363283514Sarybchik	efx_mcdi_execute(enp, &req);
364283514Sarybchik
365283514Sarybchik	if (req.emr_rc != 0) {
366283514Sarybchik		rc = req.emr_rc;
367283514Sarybchik		goto fail3;
368283514Sarybchik	}
369283514Sarybchik
370283514Sarybchik	return (0);
371283514Sarybchik
372283514Sarybchikfail3:
373283514Sarybchik	EFSYS_PROBE(fail3);
374283514Sarybchikfail2:
375283514Sarybchik	EFSYS_PROBE(fail2);
376283514Sarybchikfail1:
377291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
378283514Sarybchik
379283514Sarybchik	return (rc);
380283514Sarybchik}
381283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
382283514Sarybchik
383283514Sarybchik#if EFSYS_OPT_RX_SCALE
384291436Sarybchikstatic			efx_rc_t
385283514Sarybchikefx_mcdi_rss_context_set_table(
386283514Sarybchik	__in		efx_nic_t *enp,
387283514Sarybchik	__in		uint32_t rss_context,
388283514Sarybchik	__in_ecount(n)	unsigned int *table,
389283514Sarybchik	__in		size_t n)
390283514Sarybchik{
391283514Sarybchik	efx_mcdi_req_t req;
392342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN,
393342445Sarybchik		MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN);
394283514Sarybchik	uint8_t *req_table;
395283514Sarybchik	int i, rc;
396283514Sarybchik
397293754Sarybchik	if (rss_context == EF10_RSS_CONTEXT_INVALID) {
398283514Sarybchik		rc = EINVAL;
399283514Sarybchik		goto fail1;
400283514Sarybchik	}
401283514Sarybchik
402283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE;
403283514Sarybchik	req.emr_in_buf = payload;
404283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN;
405283514Sarybchik	req.emr_out_buf = payload;
406283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN;
407283514Sarybchik
408283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID,
409283514Sarybchik	    rss_context);
410283514Sarybchik
411283514Sarybchik	req_table =
412283514Sarybchik	    MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE);
413283514Sarybchik
414283514Sarybchik	for (i = 0;
415283514Sarybchik	    i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN;
416283514Sarybchik	    i++) {
417283514Sarybchik		req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0;
418283514Sarybchik	}
419283514Sarybchik
420283514Sarybchik	efx_mcdi_execute(enp, &req);
421283514Sarybchik
422283514Sarybchik	if (req.emr_rc != 0) {
423283514Sarybchik		rc = req.emr_rc;
424283514Sarybchik		goto fail2;
425283514Sarybchik	}
426283514Sarybchik
427283514Sarybchik	return (0);
428283514Sarybchik
429283514Sarybchikfail2:
430283514Sarybchik	EFSYS_PROBE(fail2);
431283514Sarybchikfail1:
432291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
433283514Sarybchik
434283514Sarybchik	return (rc);
435283514Sarybchik}
436283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
437283514Sarybchik
438283514Sarybchik
439291436Sarybchik	__checkReturn	efx_rc_t
440293754Sarybchikef10_rx_init(
441283514Sarybchik	__in		efx_nic_t *enp)
442283514Sarybchik{
443283514Sarybchik#if EFSYS_OPT_RX_SCALE
444283514Sarybchik
445293772Sarybchik	if (efx_mcdi_rss_context_alloc(enp, EFX_RX_SCALE_EXCLUSIVE, EFX_MAXRSS,
446293772Sarybchik		&enp->en_rss_context) == 0) {
447283514Sarybchik		/*
448283514Sarybchik		 * Allocated an exclusive RSS context, which allows both the
449283514Sarybchik		 * indirection table and key to be modified.
450283514Sarybchik		 */
451283514Sarybchik		enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE;
452283514Sarybchik		enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
453283514Sarybchik	} else {
454283514Sarybchik		/*
455283514Sarybchik		 * Failed to allocate an exclusive RSS context. Continue
456283514Sarybchik		 * operation without support for RSS. The pseudo-header in
457283514Sarybchik		 * received packets will not contain a Toeplitz hash value.
458283514Sarybchik		 */
459283514Sarybchik		enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
460283514Sarybchik		enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE;
461283514Sarybchik	}
462283514Sarybchik
463283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
464283514Sarybchik
465283514Sarybchik	return (0);
466283514Sarybchik}
467283514Sarybchik
468283514Sarybchik#if EFSYS_OPT_RX_SCATTER
469291436Sarybchik	__checkReturn	efx_rc_t
470293754Sarybchikef10_rx_scatter_enable(
471283514Sarybchik	__in		efx_nic_t *enp,
472283514Sarybchik	__in		unsigned int buf_size)
473283514Sarybchik{
474283514Sarybchik	_NOTE(ARGUNUSED(enp, buf_size))
475283514Sarybchik	return (0);
476283514Sarybchik}
477283514Sarybchik#endif	/* EFSYS_OPT_RX_SCATTER */
478283514Sarybchik
479283514Sarybchik#if EFSYS_OPT_RX_SCALE
480291436Sarybchik	__checkReturn	efx_rc_t
481293754Sarybchikef10_rx_scale_mode_set(
482283514Sarybchik	__in		efx_nic_t *enp,
483283514Sarybchik	__in		efx_rx_hash_alg_t alg,
484283514Sarybchik	__in		efx_rx_hash_type_t type,
485283514Sarybchik	__in		boolean_t insert)
486283514Sarybchik{
487291436Sarybchik	efx_rc_t rc;
488283514Sarybchik
489283514Sarybchik	EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ);
490283514Sarybchik	EFSYS_ASSERT3U(insert, ==, B_TRUE);
491283514Sarybchik
492283514Sarybchik	if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) {
493283514Sarybchik		rc = EINVAL;
494283514Sarybchik		goto fail1;
495283514Sarybchik	}
496283514Sarybchik
497283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
498283514Sarybchik		rc = ENOTSUP;
499283514Sarybchik		goto fail2;
500283514Sarybchik	}
501283514Sarybchik
502283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_flags(enp,
503283514Sarybchik		    enp->en_rss_context, type)) != 0)
504283514Sarybchik		goto fail3;
505283514Sarybchik
506283514Sarybchik	return (0);
507283514Sarybchik
508283514Sarybchikfail3:
509283514Sarybchik	EFSYS_PROBE(fail3);
510283514Sarybchikfail2:
511283514Sarybchik	EFSYS_PROBE(fail2);
512283514Sarybchikfail1:
513291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
514283514Sarybchik
515283514Sarybchik	return (rc);
516283514Sarybchik}
517283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
518283514Sarybchik
519283514Sarybchik#if EFSYS_OPT_RX_SCALE
520291436Sarybchik	__checkReturn	efx_rc_t
521293754Sarybchikef10_rx_scale_key_set(
522283514Sarybchik	__in		efx_nic_t *enp,
523283514Sarybchik	__in_ecount(n)	uint8_t *key,
524283514Sarybchik	__in		size_t n)
525283514Sarybchik{
526291436Sarybchik	efx_rc_t rc;
527283514Sarybchik
528283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
529283514Sarybchik		rc = ENOTSUP;
530283514Sarybchik		goto fail1;
531283514Sarybchik	}
532283514Sarybchik
533283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_key(enp,
534283514Sarybchik	    enp->en_rss_context, key, n)) != 0)
535283514Sarybchik		goto fail2;
536283514Sarybchik
537283514Sarybchik	return (0);
538283514Sarybchik
539283514Sarybchikfail2:
540283514Sarybchik	EFSYS_PROBE(fail2);
541283514Sarybchikfail1:
542291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
543283514Sarybchik
544283514Sarybchik	return (rc);
545283514Sarybchik}
546283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
547283514Sarybchik
548283514Sarybchik#if EFSYS_OPT_RX_SCALE
549291436Sarybchik	__checkReturn	efx_rc_t
550293754Sarybchikef10_rx_scale_tbl_set(
551283514Sarybchik	__in		efx_nic_t *enp,
552283514Sarybchik	__in_ecount(n)	unsigned int *table,
553283514Sarybchik	__in		size_t n)
554283514Sarybchik{
555291436Sarybchik	efx_rc_t rc;
556283514Sarybchik
557283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
558283514Sarybchik		rc = ENOTSUP;
559283514Sarybchik		goto fail1;
560283514Sarybchik	}
561283514Sarybchik
562283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_table(enp,
563283514Sarybchik	    enp->en_rss_context, table, n)) != 0)
564283514Sarybchik		goto fail2;
565283514Sarybchik
566283514Sarybchik	return (0);
567283514Sarybchik
568283514Sarybchikfail2:
569283514Sarybchik	EFSYS_PROBE(fail2);
570283514Sarybchikfail1:
571291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
572283514Sarybchik
573283514Sarybchik	return (rc);
574283514Sarybchik}
575283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
576283514Sarybchik
577293807Sarybchik
578293807Sarybchik/*
579293807Sarybchik * EF10 RX pseudo-header
580293807Sarybchik * ---------------------
581293807Sarybchik *
582293807Sarybchik * Receive packets are prefixed by an (optional) 14 byte pseudo-header:
583293807Sarybchik *
584293807Sarybchik *  +00: Toeplitz hash value.
585293807Sarybchik *       (32bit little-endian)
586293807Sarybchik *  +04: Outer VLAN tag. Zero if the packet did not have an outer VLAN tag.
587293807Sarybchik *       (16bit big-endian)
588293807Sarybchik *  +06: Inner VLAN tag. Zero if the packet did not have an inner VLAN tag.
589293807Sarybchik *       (16bit big-endian)
590293807Sarybchik *  +08: Packet Length. Zero if the RX datapath was in cut-through mode.
591293807Sarybchik *       (16bit little-endian)
592293807Sarybchik *  +10: MAC timestamp. Zero if timestamping is not enabled.
593293807Sarybchik *       (32bit little-endian)
594293807Sarybchik *
595293807Sarybchik * See "The RX Pseudo-header" in SF-109306-TC.
596293807Sarybchik */
597293807Sarybchik
598293807Sarybchik	__checkReturn	efx_rc_t
599293807Sarybchikef10_rx_prefix_pktlen(
600293807Sarybchik	__in		efx_nic_t *enp,
601293807Sarybchik	__in		uint8_t *buffer,
602293807Sarybchik	__out		uint16_t *lengthp)
603293807Sarybchik{
604300840Sarybchik	_NOTE(ARGUNUSED(enp))
605300840Sarybchik
606293807Sarybchik	/*
607293807Sarybchik	 * The RX pseudo-header contains the packet length, excluding the
608293807Sarybchik	 * pseudo-header. If the hardware receive datapath was operating in
609293807Sarybchik	 * cut-through mode then the length in the RX pseudo-header will be
610293807Sarybchik	 * zero, and the packet length must be obtained from the DMA length
611293807Sarybchik	 * reported in the RX event.
612293807Sarybchik	 */
613293807Sarybchik	*lengthp = buffer[8] | (buffer[9] << 8);
614293807Sarybchik	return (0);
615293807Sarybchik}
616293807Sarybchik
617293807Sarybchik#if EFSYS_OPT_RX_SCALE
618293807Sarybchik	__checkReturn	uint32_t
619293807Sarybchikef10_rx_prefix_hash(
620293807Sarybchik	__in		efx_nic_t *enp,
621293807Sarybchik	__in		efx_rx_hash_alg_t func,
622293807Sarybchik	__in		uint8_t *buffer)
623293807Sarybchik{
624300840Sarybchik	_NOTE(ARGUNUSED(enp))
625300840Sarybchik
626293807Sarybchik	switch (func) {
627293807Sarybchik	case EFX_RX_HASHALG_TOEPLITZ:
628293807Sarybchik		return (buffer[0] |
629293807Sarybchik		    (buffer[1] << 8) |
630293807Sarybchik		    (buffer[2] << 16) |
631293807Sarybchik		    (buffer[3] << 24));
632293807Sarybchik
633293807Sarybchik	default:
634293807Sarybchik		EFSYS_ASSERT(0);
635293807Sarybchik		return (0);
636293807Sarybchik	}
637293807Sarybchik}
638293807Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
639293807Sarybchik
640283514Sarybchik			void
641293754Sarybchikef10_rx_qpost(
642283514Sarybchik	__in		efx_rxq_t *erp,
643283514Sarybchik	__in_ecount(n)	efsys_dma_addr_t *addrp,
644283514Sarybchik	__in		size_t size,
645283514Sarybchik	__in		unsigned int n,
646283514Sarybchik	__in		unsigned int completed,
647283514Sarybchik	__in		unsigned int added)
648283514Sarybchik{
649283514Sarybchik	efx_qword_t qword;
650283514Sarybchik	unsigned int i;
651283514Sarybchik	unsigned int offset;
652283514Sarybchik	unsigned int id;
653283514Sarybchik
654342430Sarybchik	_NOTE(ARGUNUSED(completed))
655342430Sarybchik
656283514Sarybchik	/* The client driver must not overfill the queue */
657283514Sarybchik	EFSYS_ASSERT3U(added - completed + n, <=,
658283514Sarybchik	    EFX_RXQ_LIMIT(erp->er_mask + 1));
659283514Sarybchik
660283514Sarybchik	id = added & (erp->er_mask);
661283514Sarybchik	for (i = 0; i < n; i++) {
662283514Sarybchik		EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
663283514Sarybchik		    unsigned int, id, efsys_dma_addr_t, addrp[i],
664283514Sarybchik		    size_t, size);
665283514Sarybchik
666283514Sarybchik		EFX_POPULATE_QWORD_3(qword,
667283514Sarybchik		    ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size),
668283514Sarybchik		    ESF_DZ_RX_KER_BUF_ADDR_DW0,
669283514Sarybchik		    (uint32_t)(addrp[i] & 0xffffffff),
670283514Sarybchik		    ESF_DZ_RX_KER_BUF_ADDR_DW1,
671283514Sarybchik		    (uint32_t)(addrp[i] >> 32));
672283514Sarybchik
673283514Sarybchik		offset = id * sizeof (efx_qword_t);
674283514Sarybchik		EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
675283514Sarybchik
676283514Sarybchik		id = (id + 1) & (erp->er_mask);
677283514Sarybchik	}
678283514Sarybchik}
679283514Sarybchik
680283514Sarybchik			void
681293754Sarybchikef10_rx_qpush(
682283514Sarybchik	__in	efx_rxq_t *erp,
683283514Sarybchik	__in	unsigned int added,
684283514Sarybchik	__inout	unsigned int *pushedp)
685283514Sarybchik{
686283514Sarybchik	efx_nic_t *enp = erp->er_enp;
687283514Sarybchik	unsigned int pushed = *pushedp;
688283514Sarybchik	uint32_t wptr;
689283514Sarybchik	efx_dword_t dword;
690283514Sarybchik
691283514Sarybchik	/* Hardware has alignment restriction for WPTR */
692350411Sarybchik	wptr = EFX_P2ALIGN(unsigned int, added, EF10_RX_WPTR_ALIGN);
693283514Sarybchik	if (pushed == wptr)
694283514Sarybchik		return;
695283514Sarybchik
696283514Sarybchik	*pushedp = wptr;
697283514Sarybchik
698283514Sarybchik	/* Push the populated descriptors out */
699283514Sarybchik	wptr &= erp->er_mask;
700283514Sarybchik
701283514Sarybchik	EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr);
702283514Sarybchik
703283514Sarybchik	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
704283514Sarybchik	EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
705283514Sarybchik	    wptr, pushed & erp->er_mask);
706283514Sarybchik	EFSYS_PIO_WRITE_BARRIER();
707283514Sarybchik	EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
708283514Sarybchik			    erp->er_index, &dword, B_FALSE);
709283514Sarybchik}
710283514Sarybchik
711291436Sarybchik	__checkReturn	efx_rc_t
712293754Sarybchikef10_rx_qflush(
713283514Sarybchik	__in	efx_rxq_t *erp)
714283514Sarybchik{
715283514Sarybchik	efx_nic_t *enp = erp->er_enp;
716291436Sarybchik	efx_rc_t rc;
717283514Sarybchik
718283514Sarybchik	if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0)
719283514Sarybchik		goto fail1;
720283514Sarybchik
721283514Sarybchik	return (0);
722283514Sarybchik
723283514Sarybchikfail1:
724342412Sarybchik	/*
725342412Sarybchik	 * EALREADY is not an error, but indicates that the MC has rebooted and
726342412Sarybchik	 * that the RXQ has already been destroyed. Callers need to know that
727342412Sarybchik	 * the RXQ flush has completed to avoid waiting until timeout for a
728342412Sarybchik	 * flush done event that will not be delivered.
729342412Sarybchik	 */
730342412Sarybchik	if (rc != EALREADY)
731342412Sarybchik		EFSYS_PROBE1(fail1, efx_rc_t, rc);
732283514Sarybchik
733283514Sarybchik	return (rc);
734283514Sarybchik}
735283514Sarybchik
736283514Sarybchik		void
737293754Sarybchikef10_rx_qenable(
738283514Sarybchik	__in	efx_rxq_t *erp)
739283514Sarybchik{
740283514Sarybchik	/* FIXME */
741283514Sarybchik	_NOTE(ARGUNUSED(erp))
742283514Sarybchik	/* FIXME */
743283514Sarybchik}
744283514Sarybchik
745291436Sarybchik	__checkReturn	efx_rc_t
746293754Sarybchikef10_rx_qcreate(
747283514Sarybchik	__in		efx_nic_t *enp,
748283514Sarybchik	__in		unsigned int index,
749283514Sarybchik	__in		unsigned int label,
750283514Sarybchik	__in		efx_rxq_type_t type,
751283514Sarybchik	__in		efsys_mem_t *esmp,
752283514Sarybchik	__in		size_t n,
753283514Sarybchik	__in		uint32_t id,
754283514Sarybchik	__in		efx_evq_t *eep,
755283514Sarybchik	__in		efx_rxq_t *erp)
756283514Sarybchik{
757283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
758291436Sarybchik	efx_rc_t rc;
759291747Sarybchik	boolean_t disable_scatter;
760283514Sarybchik
761300840Sarybchik	_NOTE(ARGUNUSED(id, erp))
762283514Sarybchik
763283514Sarybchik	EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH));
764283514Sarybchik	EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
765283514Sarybchik	EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
766283514Sarybchik
767283514Sarybchik	EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
768283514Sarybchik	EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
769283514Sarybchik
770283514Sarybchik	if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) {
771283514Sarybchik		rc = EINVAL;
772283514Sarybchik		goto fail1;
773283514Sarybchik	}
774283514Sarybchik	if (index >= encp->enc_rxq_limit) {
775283514Sarybchik		rc = EINVAL;
776283514Sarybchik		goto fail2;
777283514Sarybchik	}
778283514Sarybchik
779291747Sarybchik	/* Scatter can only be disabled if the firmware supports doing so */
780311018Sarybchik	if (type == EFX_RXQ_TYPE_SCATTER)
781291747Sarybchik		disable_scatter = B_FALSE;
782311018Sarybchik	else
783311018Sarybchik		disable_scatter = encp->enc_rx_disable_scatter_supported;
784291747Sarybchik
785283514Sarybchik	if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index,
786291747Sarybchik	    esmp, disable_scatter)) != 0)
787283514Sarybchik		goto fail3;
788283514Sarybchik
789283514Sarybchik	erp->er_eep = eep;
790283514Sarybchik	erp->er_label = label;
791283514Sarybchik
792293752Sarybchik	ef10_ev_rxlabel_init(eep, erp, label);
793283514Sarybchik
794283514Sarybchik	return (0);
795283514Sarybchik
796283514Sarybchikfail3:
797283514Sarybchik	EFSYS_PROBE(fail3);
798283514Sarybchikfail2:
799283514Sarybchik	EFSYS_PROBE(fail2);
800283514Sarybchikfail1:
801291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
802283514Sarybchik
803283514Sarybchik	return (rc);
804283514Sarybchik}
805283514Sarybchik
806283514Sarybchik		void
807293754Sarybchikef10_rx_qdestroy(
808283514Sarybchik	__in	efx_rxq_t *erp)
809283514Sarybchik{
810283514Sarybchik	efx_nic_t *enp = erp->er_enp;
811283514Sarybchik	efx_evq_t *eep = erp->er_eep;
812283514Sarybchik	unsigned int label = erp->er_label;
813283514Sarybchik
814293752Sarybchik	ef10_ev_rxlabel_fini(eep, label);
815283514Sarybchik
816283514Sarybchik	EFSYS_ASSERT(enp->en_rx_qcount != 0);
817283514Sarybchik	--enp->en_rx_qcount;
818283514Sarybchik
819283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
820283514Sarybchik}
821283514Sarybchik
822283514Sarybchik		void
823293754Sarybchikef10_rx_fini(
824283514Sarybchik	__in	efx_nic_t *enp)
825283514Sarybchik{
826283514Sarybchik#if EFSYS_OPT_RX_SCALE
827283514Sarybchik	if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) {
828283514Sarybchik		(void) efx_mcdi_rss_context_free(enp, enp->en_rss_context);
829283514Sarybchik	}
830283514Sarybchik	enp->en_rss_context = 0;
831283514Sarybchik	enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
832283514Sarybchik#else
833283514Sarybchik	_NOTE(ARGUNUSED(enp))
834283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
835283514Sarybchik}
836283514Sarybchik
837299604Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
838