ef10_rx.c revision 293752
1283514Sarybchik/*-
2283514Sarybchik * Copyright (c) 2012-2015 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: head/sys/dev/sfxge/common/hunt_rx.c 293752 2016-01-12 13:32:04Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efsys.h"
35283514Sarybchik#include "efx.h"
36283514Sarybchik#include "efx_impl.h"
37283514Sarybchik
38283514Sarybchik
39283514Sarybchik#if EFSYS_OPT_HUNTINGTON
40283514Sarybchik
41283514Sarybchik
42291436Sarybchikstatic	__checkReturn	efx_rc_t
43283514Sarybchikefx_mcdi_init_rxq(
44283514Sarybchik	__in		efx_nic_t *enp,
45283514Sarybchik	__in		uint32_t size,
46283514Sarybchik	__in		uint32_t target_evq,
47283514Sarybchik	__in		uint32_t label,
48283514Sarybchik	__in		uint32_t instance,
49291747Sarybchik	__in		efsys_mem_t *esmp,
50291747Sarybchik	__in		boolean_t disable_scatter)
51283514Sarybchik{
52283514Sarybchik	efx_mcdi_req_t req;
53283514Sarybchik	uint8_t payload[
54283514Sarybchik	    MAX(MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS)),
55283514Sarybchik		MC_CMD_INIT_RXQ_OUT_LEN)];
56283514Sarybchik	int npages = EFX_RXQ_NBUFS(size);
57283514Sarybchik	int i;
58283514Sarybchik	efx_qword_t *dma_addr;
59283514Sarybchik	uint64_t addr;
60291436Sarybchik	efx_rc_t rc;
61283514Sarybchik
62283514Sarybchik	EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS);
63283514Sarybchik
64283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
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;
118283514Sarybchik	uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN,
119283514Sarybchik			    MC_CMD_FINI_RXQ_OUT_LEN)];
120291436Sarybchik	efx_rc_t rc;
121283514Sarybchik
122283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
123283514Sarybchik	req.emr_cmd = MC_CMD_FINI_RXQ;
124283514Sarybchik	req.emr_in_buf = payload;
125283514Sarybchik	req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
126283514Sarybchik	req.emr_out_buf = payload;
127283514Sarybchik	req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
128283514Sarybchik
129283514Sarybchik	MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
130283514Sarybchik
131283514Sarybchik	efx_mcdi_execute(enp, &req);
132283514Sarybchik
133283514Sarybchik	if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) {
134283514Sarybchik		rc = req.emr_rc;
135283514Sarybchik		goto fail1;
136283514Sarybchik	}
137283514Sarybchik
138283514Sarybchik	return (0);
139283514Sarybchik
140283514Sarybchikfail1:
141291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
142283514Sarybchik
143283514Sarybchik	return (rc);
144283514Sarybchik}
145283514Sarybchik
146283514Sarybchik#if EFSYS_OPT_RX_SCALE
147291436Sarybchikstatic	__checkReturn	efx_rc_t
148283514Sarybchikefx_mcdi_rss_context_alloc(
149283514Sarybchik	__in		efx_nic_t *enp,
150283514Sarybchik	__out		uint32_t *rss_contextp)
151283514Sarybchik{
152283514Sarybchik	efx_mcdi_req_t req;
153283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
154283514Sarybchik			    MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)];
155283514Sarybchik	uint32_t rss_context;
156291436Sarybchik	efx_rc_t rc;
157283514Sarybchik
158283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
159283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
160283514Sarybchik	req.emr_in_buf = payload;
161283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
162283514Sarybchik	req.emr_out_buf = payload;
163283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
164283514Sarybchik
165283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
166283514Sarybchik	    EVB_PORT_ID_ASSIGNED);
167283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE,
168283514Sarybchik	    MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE);
169283514Sarybchik	/* NUM_QUEUES is only used to validate indirection table offsets */
170283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, 64);
171283514Sarybchik
172283514Sarybchik	efx_mcdi_execute(enp, &req);
173283514Sarybchik
174283514Sarybchik	if (req.emr_rc != 0) {
175283514Sarybchik		rc = req.emr_rc;
176283514Sarybchik		goto fail1;
177283514Sarybchik	}
178283514Sarybchik
179283514Sarybchik	if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
180283514Sarybchik		rc = EMSGSIZE;
181283514Sarybchik		goto fail2;
182283514Sarybchik	}
183283514Sarybchik
184283514Sarybchik	rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
185283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
186283514Sarybchik		rc = ENOENT;
187283514Sarybchik		goto fail3;
188283514Sarybchik	}
189283514Sarybchik
190283514Sarybchik	*rss_contextp = rss_context;
191283514Sarybchik
192283514Sarybchik	return (0);
193283514Sarybchik
194283514Sarybchikfail3:
195283514Sarybchik	EFSYS_PROBE(fail3);
196283514Sarybchikfail2:
197283514Sarybchik	EFSYS_PROBE(fail2);
198283514Sarybchikfail1:
199291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
200283514Sarybchik
201283514Sarybchik	return (rc);
202283514Sarybchik}
203283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
204283514Sarybchik
205283514Sarybchik#if EFSYS_OPT_RX_SCALE
206291436Sarybchikstatic			efx_rc_t
207283514Sarybchikefx_mcdi_rss_context_free(
208283514Sarybchik	__in		efx_nic_t *enp,
209283514Sarybchik	__in		uint32_t rss_context)
210283514Sarybchik{
211283514Sarybchik	efx_mcdi_req_t req;
212283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN,
213283514Sarybchik			    MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)];
214291436Sarybchik	efx_rc_t rc;
215283514Sarybchik
216283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
217283514Sarybchik		rc = EINVAL;
218283514Sarybchik		goto fail1;
219283514Sarybchik	}
220283514Sarybchik
221283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
222283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE;
223283514Sarybchik	req.emr_in_buf = payload;
224283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN;
225283514Sarybchik	req.emr_out_buf = payload;
226283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN;
227283514Sarybchik
228283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context);
229283514Sarybchik
230283514Sarybchik	efx_mcdi_execute(enp, &req);
231283514Sarybchik
232283514Sarybchik	if (req.emr_rc != 0) {
233283514Sarybchik		rc = req.emr_rc;
234283514Sarybchik		goto fail2;
235283514Sarybchik	}
236283514Sarybchik
237283514Sarybchik	return (0);
238283514Sarybchik
239283514Sarybchikfail2:
240283514Sarybchik	EFSYS_PROBE(fail2);
241283514Sarybchikfail1:
242291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
243283514Sarybchik
244283514Sarybchik	return (rc);
245283514Sarybchik}
246283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
247283514Sarybchik
248283514Sarybchik#if EFSYS_OPT_RX_SCALE
249291436Sarybchikstatic			efx_rc_t
250283514Sarybchikefx_mcdi_rss_context_set_flags(
251283514Sarybchik	__in		efx_nic_t *enp,
252283514Sarybchik	__in		uint32_t rss_context,
253283514Sarybchik	__in		efx_rx_hash_type_t type)
254283514Sarybchik{
255283514Sarybchik	efx_mcdi_req_t req;
256283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
257283514Sarybchik			    MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)];
258291436Sarybchik	efx_rc_t rc;
259283514Sarybchik
260283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
261283514Sarybchik		rc = EINVAL;
262283514Sarybchik		goto fail1;
263283514Sarybchik	}
264283514Sarybchik
265283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
266283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS;
267283514Sarybchik	req.emr_in_buf = payload;
268283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN;
269283514Sarybchik	req.emr_out_buf = payload;
270283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN;
271283514Sarybchik
272283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
273283514Sarybchik	    rss_context);
274283514Sarybchik
275283514Sarybchik	MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
276283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
277283514Sarybchik	    (type & (1U << EFX_RX_HASH_IPV4)) ? 1 : 0,
278283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
279283514Sarybchik	    (type & (1U << EFX_RX_HASH_TCPIPV4)) ? 1 : 0,
280283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
281283514Sarybchik	    (type & (1U << EFX_RX_HASH_IPV6)) ? 1 : 0,
282283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
283283514Sarybchik	    (type & (1U << EFX_RX_HASH_TCPIPV6)) ? 1 : 0);
284283514Sarybchik
285283514Sarybchik	efx_mcdi_execute(enp, &req);
286283514Sarybchik
287283514Sarybchik	if (req.emr_rc != 0) {
288283514Sarybchik		rc = req.emr_rc;
289283514Sarybchik		goto fail2;
290283514Sarybchik	}
291283514Sarybchik
292283514Sarybchik	return (0);
293283514Sarybchik
294283514Sarybchikfail2:
295283514Sarybchik	EFSYS_PROBE(fail2);
296283514Sarybchikfail1:
297291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
298283514Sarybchik
299283514Sarybchik	return (rc);
300283514Sarybchik}
301283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
302283514Sarybchik
303283514Sarybchik#if EFSYS_OPT_RX_SCALE
304291436Sarybchikstatic			efx_rc_t
305283514Sarybchikefx_mcdi_rss_context_set_key(
306283514Sarybchik	__in		efx_nic_t *enp,
307283514Sarybchik	__in		uint32_t rss_context,
308283514Sarybchik	__in_ecount(n)	uint8_t *key,
309283514Sarybchik	__in		size_t n)
310283514Sarybchik{
311283514Sarybchik	efx_mcdi_req_t req;
312283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN,
313283514Sarybchik			    MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)];
314291436Sarybchik	efx_rc_t rc;
315283514Sarybchik
316283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
317283514Sarybchik		rc = EINVAL;
318283514Sarybchik		goto fail1;
319283514Sarybchik	}
320283514Sarybchik
321283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
322283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY;
323283514Sarybchik	req.emr_in_buf = payload;
324283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN;
325283514Sarybchik	req.emr_out_buf = payload;
326283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN;
327283514Sarybchik
328283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID,
329283514Sarybchik	    rss_context);
330283514Sarybchik
331283514Sarybchik	EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
332283514Sarybchik	if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) {
333283514Sarybchik		rc = EINVAL;
334283514Sarybchik		goto fail2;
335283514Sarybchik	}
336283514Sarybchik
337283514Sarybchik	memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY),
338283514Sarybchik	    key, n);
339283514Sarybchik
340283514Sarybchik	efx_mcdi_execute(enp, &req);
341283514Sarybchik
342283514Sarybchik	if (req.emr_rc != 0) {
343283514Sarybchik		rc = req.emr_rc;
344283514Sarybchik		goto fail3;
345283514Sarybchik	}
346283514Sarybchik
347283514Sarybchik	return (0);
348283514Sarybchik
349283514Sarybchikfail3:
350283514Sarybchik	EFSYS_PROBE(fail3);
351283514Sarybchikfail2:
352283514Sarybchik	EFSYS_PROBE(fail2);
353283514Sarybchikfail1:
354291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
355283514Sarybchik
356283514Sarybchik	return (rc);
357283514Sarybchik}
358283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
359283514Sarybchik
360283514Sarybchik#if EFSYS_OPT_RX_SCALE
361291436Sarybchikstatic			efx_rc_t
362283514Sarybchikefx_mcdi_rss_context_set_table(
363283514Sarybchik	__in		efx_nic_t *enp,
364283514Sarybchik	__in		uint32_t rss_context,
365283514Sarybchik	__in_ecount(n)	unsigned int *table,
366283514Sarybchik	__in		size_t n)
367283514Sarybchik{
368283514Sarybchik	efx_mcdi_req_t req;
369283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN,
370283514Sarybchik			    MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)];
371283514Sarybchik	uint8_t *req_table;
372283514Sarybchik	int i, rc;
373283514Sarybchik
374283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
375283514Sarybchik		rc = EINVAL;
376283514Sarybchik		goto fail1;
377283514Sarybchik	}
378283514Sarybchik
379283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
380283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE;
381283514Sarybchik	req.emr_in_buf = payload;
382283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN;
383283514Sarybchik	req.emr_out_buf = payload;
384283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN;
385283514Sarybchik
386283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID,
387283514Sarybchik	    rss_context);
388283514Sarybchik
389283514Sarybchik	req_table =
390283514Sarybchik	    MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE);
391283514Sarybchik
392283514Sarybchik	for (i = 0;
393283514Sarybchik	    i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN;
394283514Sarybchik	    i++) {
395283514Sarybchik		req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0;
396283514Sarybchik	}
397283514Sarybchik
398283514Sarybchik	efx_mcdi_execute(enp, &req);
399283514Sarybchik
400283514Sarybchik	if (req.emr_rc != 0) {
401283514Sarybchik		rc = req.emr_rc;
402283514Sarybchik		goto fail2;
403283514Sarybchik	}
404283514Sarybchik
405283514Sarybchik	return (0);
406283514Sarybchik
407283514Sarybchikfail2:
408283514Sarybchik	EFSYS_PROBE(fail2);
409283514Sarybchikfail1:
410291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
411283514Sarybchik
412283514Sarybchik	return (rc);
413283514Sarybchik}
414283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
415283514Sarybchik
416283514Sarybchik
417291436Sarybchik	__checkReturn	efx_rc_t
418283514Sarybchikhunt_rx_init(
419283514Sarybchik	__in		efx_nic_t *enp)
420283514Sarybchik{
421283514Sarybchik#if EFSYS_OPT_RX_SCALE
422283514Sarybchik
423283514Sarybchik	if (efx_mcdi_rss_context_alloc(enp, &enp->en_rss_context) == 0) {
424283514Sarybchik		/*
425283514Sarybchik		 * Allocated an exclusive RSS context, which allows both the
426283514Sarybchik		 * indirection table and key to be modified.
427283514Sarybchik		 */
428283514Sarybchik		enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE;
429283514Sarybchik		enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
430283514Sarybchik	} else {
431283514Sarybchik		/*
432283514Sarybchik		 * Failed to allocate an exclusive RSS context. Continue
433283514Sarybchik		 * operation without support for RSS. The pseudo-header in
434283514Sarybchik		 * received packets will not contain a Toeplitz hash value.
435283514Sarybchik		 */
436283514Sarybchik		enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
437283514Sarybchik		enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE;
438283514Sarybchik	}
439283514Sarybchik
440283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
441283514Sarybchik
442283514Sarybchik	return (0);
443283514Sarybchik}
444283514Sarybchik
445283514Sarybchik#if EFSYS_OPT_RX_HDR_SPLIT
446291436Sarybchik	__checkReturn	efx_rc_t
447283514Sarybchikhunt_rx_hdr_split_enable(
448283514Sarybchik	__in		efx_nic_t *enp,
449283514Sarybchik	__in		unsigned int hdr_buf_size,
450283514Sarybchik	__in		unsigned int pld_buf_size)
451283514Sarybchik{
452291436Sarybchik	efx_rc_t rc;
453283514Sarybchik
454283514Sarybchik	/* FIXME */
455283514Sarybchik	_NOTE(ARGUNUSED(enp, hdr_buf_size, pld_buf_size))
456283514Sarybchik	if (B_FALSE) {
457283514Sarybchik		rc = ENOTSUP;
458283514Sarybchik		goto fail1;
459283514Sarybchik	}
460283514Sarybchik	/* FIXME */
461283514Sarybchik
462283514Sarybchik	return (0);
463283514Sarybchik
464283514Sarybchikfail1:
465291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
466283514Sarybchik
467283514Sarybchik	return (rc);
468283514Sarybchik}
469283514Sarybchik#endif	/* EFSYS_OPT_RX_HDR_SPLIT */
470283514Sarybchik
471283514Sarybchik#if EFSYS_OPT_RX_SCATTER
472291436Sarybchik	__checkReturn	efx_rc_t
473283514Sarybchikhunt_rx_scatter_enable(
474283514Sarybchik	__in		efx_nic_t *enp,
475283514Sarybchik	__in		unsigned int buf_size)
476283514Sarybchik{
477283514Sarybchik	_NOTE(ARGUNUSED(enp, buf_size))
478283514Sarybchik	return (0);
479283514Sarybchik}
480283514Sarybchik#endif	/* EFSYS_OPT_RX_SCATTER */
481283514Sarybchik
482283514Sarybchik#if EFSYS_OPT_RX_SCALE
483291436Sarybchik	__checkReturn	efx_rc_t
484283514Sarybchikhunt_rx_scale_mode_set(
485283514Sarybchik	__in		efx_nic_t *enp,
486283514Sarybchik	__in		efx_rx_hash_alg_t alg,
487283514Sarybchik	__in		efx_rx_hash_type_t type,
488283514Sarybchik	__in		boolean_t insert)
489283514Sarybchik{
490291436Sarybchik	efx_rc_t rc;
491283514Sarybchik
492283514Sarybchik	EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ);
493283514Sarybchik	EFSYS_ASSERT3U(insert, ==, B_TRUE);
494283514Sarybchik
495283514Sarybchik	if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) {
496283514Sarybchik		rc = EINVAL;
497283514Sarybchik		goto fail1;
498283514Sarybchik	}
499283514Sarybchik
500283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
501283514Sarybchik		rc = ENOTSUP;
502283514Sarybchik		goto fail2;
503283514Sarybchik	}
504283514Sarybchik
505283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_flags(enp,
506283514Sarybchik		    enp->en_rss_context, type)) != 0)
507283514Sarybchik		goto fail3;
508283514Sarybchik
509283514Sarybchik	return (0);
510283514Sarybchik
511283514Sarybchikfail3:
512283514Sarybchik	EFSYS_PROBE(fail3);
513283514Sarybchikfail2:
514283514Sarybchik	EFSYS_PROBE(fail2);
515283514Sarybchikfail1:
516291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
517283514Sarybchik
518283514Sarybchik	return (rc);
519283514Sarybchik}
520283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
521283514Sarybchik
522283514Sarybchik#if EFSYS_OPT_RX_SCALE
523291436Sarybchik	__checkReturn	efx_rc_t
524283514Sarybchikhunt_rx_scale_key_set(
525283514Sarybchik	__in		efx_nic_t *enp,
526283514Sarybchik	__in_ecount(n)	uint8_t *key,
527283514Sarybchik	__in		size_t n)
528283514Sarybchik{
529291436Sarybchik	efx_rc_t rc;
530283514Sarybchik
531283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
532283514Sarybchik		rc = ENOTSUP;
533283514Sarybchik		goto fail1;
534283514Sarybchik	}
535283514Sarybchik
536283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_key(enp,
537283514Sarybchik	    enp->en_rss_context, key, n)) != 0)
538283514Sarybchik		goto fail2;
539283514Sarybchik
540283514Sarybchik	return (0);
541283514Sarybchik
542283514Sarybchikfail2:
543283514Sarybchik	EFSYS_PROBE(fail2);
544283514Sarybchikfail1:
545291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
546283514Sarybchik
547283514Sarybchik	return (rc);
548283514Sarybchik}
549283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
550283514Sarybchik
551283514Sarybchik#if EFSYS_OPT_RX_SCALE
552291436Sarybchik	__checkReturn	efx_rc_t
553283514Sarybchikhunt_rx_scale_tbl_set(
554283514Sarybchik	__in		efx_nic_t *enp,
555283514Sarybchik	__in_ecount(n)	unsigned int *table,
556283514Sarybchik	__in		size_t n)
557283514Sarybchik{
558291436Sarybchik	efx_rc_t rc;
559283514Sarybchik
560283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
561283514Sarybchik		rc = ENOTSUP;
562283514Sarybchik		goto fail1;
563283514Sarybchik	}
564283514Sarybchik
565283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_table(enp,
566283514Sarybchik	    enp->en_rss_context, table, n)) != 0)
567283514Sarybchik		goto fail2;
568283514Sarybchik
569283514Sarybchik	return (0);
570283514Sarybchik
571283514Sarybchikfail2:
572283514Sarybchik	EFSYS_PROBE(fail2);
573283514Sarybchikfail1:
574291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
575283514Sarybchik
576283514Sarybchik	return (rc);
577283514Sarybchik}
578283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
579283514Sarybchik
580283514Sarybchik			void
581283514Sarybchikhunt_rx_qpost(
582283514Sarybchik	__in		efx_rxq_t *erp,
583283514Sarybchik	__in_ecount(n)	efsys_dma_addr_t *addrp,
584283514Sarybchik	__in		size_t size,
585283514Sarybchik	__in		unsigned int n,
586283514Sarybchik	__in		unsigned int completed,
587283514Sarybchik	__in		unsigned int added)
588283514Sarybchik{
589283514Sarybchik	efx_qword_t qword;
590283514Sarybchik	unsigned int i;
591283514Sarybchik	unsigned int offset;
592283514Sarybchik	unsigned int id;
593283514Sarybchik
594283514Sarybchik	/* The client driver must not overfill the queue */
595283514Sarybchik	EFSYS_ASSERT3U(added - completed + n, <=,
596283514Sarybchik	    EFX_RXQ_LIMIT(erp->er_mask + 1));
597283514Sarybchik
598283514Sarybchik	id = added & (erp->er_mask);
599283514Sarybchik	for (i = 0; i < n; i++) {
600283514Sarybchik		EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
601283514Sarybchik		    unsigned int, id, efsys_dma_addr_t, addrp[i],
602283514Sarybchik		    size_t, size);
603283514Sarybchik
604283514Sarybchik		EFX_POPULATE_QWORD_3(qword,
605283514Sarybchik		    ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size),
606283514Sarybchik		    ESF_DZ_RX_KER_BUF_ADDR_DW0,
607283514Sarybchik		    (uint32_t)(addrp[i] & 0xffffffff),
608283514Sarybchik		    ESF_DZ_RX_KER_BUF_ADDR_DW1,
609283514Sarybchik		    (uint32_t)(addrp[i] >> 32));
610283514Sarybchik
611283514Sarybchik		offset = id * sizeof (efx_qword_t);
612283514Sarybchik		EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
613283514Sarybchik
614283514Sarybchik		id = (id + 1) & (erp->er_mask);
615283514Sarybchik	}
616283514Sarybchik}
617283514Sarybchik
618283514Sarybchik			void
619283514Sarybchikhunt_rx_qpush(
620283514Sarybchik	__in	efx_rxq_t *erp,
621283514Sarybchik	__in	unsigned int added,
622283514Sarybchik	__inout	unsigned int *pushedp)
623283514Sarybchik{
624283514Sarybchik	efx_nic_t *enp = erp->er_enp;
625283514Sarybchik	unsigned int pushed = *pushedp;
626283514Sarybchik	uint32_t wptr;
627283514Sarybchik	efx_dword_t dword;
628283514Sarybchik
629283514Sarybchik	/* Hardware has alignment restriction for WPTR */
630283514Sarybchik	wptr = P2ALIGN(added, HUNTINGTON_RX_WPTR_ALIGN);
631283514Sarybchik	if (pushed == wptr)
632283514Sarybchik		return;
633283514Sarybchik
634283514Sarybchik	*pushedp = wptr;
635283514Sarybchik
636283514Sarybchik	/* Push the populated descriptors out */
637283514Sarybchik	wptr &= erp->er_mask;
638283514Sarybchik
639283514Sarybchik	EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr);
640283514Sarybchik
641283514Sarybchik	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
642283514Sarybchik	EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
643283514Sarybchik	    wptr, pushed & erp->er_mask);
644283514Sarybchik	EFSYS_PIO_WRITE_BARRIER();
645283514Sarybchik	EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
646283514Sarybchik			    erp->er_index, &dword, B_FALSE);
647283514Sarybchik}
648283514Sarybchik
649291436Sarybchik	__checkReturn	efx_rc_t
650283514Sarybchikhunt_rx_qflush(
651283514Sarybchik	__in	efx_rxq_t *erp)
652283514Sarybchik{
653283514Sarybchik	efx_nic_t *enp = erp->er_enp;
654291436Sarybchik	efx_rc_t rc;
655283514Sarybchik
656283514Sarybchik	if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0)
657283514Sarybchik		goto fail1;
658283514Sarybchik
659283514Sarybchik	return (0);
660283514Sarybchik
661283514Sarybchikfail1:
662291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
663283514Sarybchik
664283514Sarybchik	return (rc);
665283514Sarybchik}
666283514Sarybchik
667283514Sarybchik		void
668283514Sarybchikhunt_rx_qenable(
669283514Sarybchik	__in	efx_rxq_t *erp)
670283514Sarybchik{
671283514Sarybchik	/* FIXME */
672283514Sarybchik	_NOTE(ARGUNUSED(erp))
673283514Sarybchik	/* FIXME */
674283514Sarybchik}
675283514Sarybchik
676291436Sarybchik	__checkReturn	efx_rc_t
677283514Sarybchikhunt_rx_qcreate(
678283514Sarybchik	__in		efx_nic_t *enp,
679283514Sarybchik	__in		unsigned int index,
680283514Sarybchik	__in		unsigned int label,
681283514Sarybchik	__in		efx_rxq_type_t type,
682283514Sarybchik	__in		efsys_mem_t *esmp,
683283514Sarybchik	__in		size_t n,
684283514Sarybchik	__in		uint32_t id,
685283514Sarybchik	__in		efx_evq_t *eep,
686283514Sarybchik	__in		efx_rxq_t *erp)
687283514Sarybchik{
688283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
689291436Sarybchik	efx_rc_t rc;
690291747Sarybchik	boolean_t disable_scatter;
691283514Sarybchik
692283514Sarybchik	_NOTE(ARGUNUSED(erp))
693283514Sarybchik
694283514Sarybchik	EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH));
695283514Sarybchik	EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
696283514Sarybchik	EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
697283514Sarybchik
698283514Sarybchik	EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
699283514Sarybchik	EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
700283514Sarybchik
701283514Sarybchik	if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) {
702283514Sarybchik		rc = EINVAL;
703283514Sarybchik		goto fail1;
704283514Sarybchik	}
705283514Sarybchik	if (index >= encp->enc_rxq_limit) {
706283514Sarybchik		rc = EINVAL;
707283514Sarybchik		goto fail2;
708283514Sarybchik	}
709283514Sarybchik
710291747Sarybchik	/* Scatter can only be disabled if the firmware supports doing so */
711291747Sarybchik	if ((type != EFX_RXQ_TYPE_SCATTER) &&
712291747Sarybchik	    enp->en_nic_cfg.enc_rx_disable_scatter_supported) {
713291747Sarybchik		disable_scatter = B_TRUE;
714291747Sarybchik	} else {
715291747Sarybchik		disable_scatter = B_FALSE;
716291747Sarybchik	}
717291747Sarybchik
718283514Sarybchik	/*
719291747Sarybchik	 * Note: EFX_RXQ_TYPE_SPLIT_HEADER and EFX_RXQ_TYPE_SPLIT_PAYLOAD are
720291747Sarybchik	 * not supported here.
721283514Sarybchik	 */
722283514Sarybchik
723283514Sarybchik	if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index,
724291747Sarybchik	    esmp, disable_scatter)) != 0)
725283514Sarybchik		goto fail3;
726283514Sarybchik
727283514Sarybchik	erp->er_eep = eep;
728283514Sarybchik	erp->er_label = label;
729283514Sarybchik
730293752Sarybchik	ef10_ev_rxlabel_init(eep, erp, label);
731283514Sarybchik
732283514Sarybchik	return (0);
733283514Sarybchik
734283514Sarybchikfail3:
735283514Sarybchik	EFSYS_PROBE(fail3);
736283514Sarybchikfail2:
737283514Sarybchik	EFSYS_PROBE(fail2);
738283514Sarybchikfail1:
739291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
740283514Sarybchik
741283514Sarybchik	return (rc);
742283514Sarybchik}
743283514Sarybchik
744283514Sarybchik		void
745283514Sarybchikhunt_rx_qdestroy(
746283514Sarybchik	__in	efx_rxq_t *erp)
747283514Sarybchik{
748283514Sarybchik	efx_nic_t *enp = erp->er_enp;
749283514Sarybchik	efx_evq_t *eep = erp->er_eep;
750283514Sarybchik	unsigned int label = erp->er_label;
751283514Sarybchik
752293752Sarybchik	ef10_ev_rxlabel_fini(eep, label);
753283514Sarybchik
754283514Sarybchik	EFSYS_ASSERT(enp->en_rx_qcount != 0);
755283514Sarybchik	--enp->en_rx_qcount;
756283514Sarybchik
757283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
758283514Sarybchik}
759283514Sarybchik
760283514Sarybchik		void
761283514Sarybchikhunt_rx_fini(
762283514Sarybchik	__in	efx_nic_t *enp)
763283514Sarybchik{
764283514Sarybchik#if EFSYS_OPT_RX_SCALE
765283514Sarybchik	if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) {
766283514Sarybchik		(void) efx_mcdi_rss_context_free(enp, enp->en_rss_context);
767283514Sarybchik	}
768283514Sarybchik	enp->en_rss_context = 0;
769283514Sarybchik	enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
770283514Sarybchik#else
771283514Sarybchik	_NOTE(ARGUNUSED(enp))
772283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
773283514Sarybchik}
774283514Sarybchik
775283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */
776