ef10_rx.c revision 283514
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 283514 2015-05-25 08:34:55Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efsys.h"
35283514Sarybchik#include "efx.h"
36283514Sarybchik#include "efx_impl.h"
37283514Sarybchik
38283514Sarybchik
39283514Sarybchik#if EFSYS_OPT_HUNTINGTON
40283514Sarybchik
41283514Sarybchik
42283514Sarybchikstatic	__checkReturn	int
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,
49283514Sarybchik	__in		efsys_mem_t *esmp)
50283514Sarybchik{
51283514Sarybchik	efx_mcdi_req_t req;
52283514Sarybchik	uint8_t payload[
53283514Sarybchik	    MAX(MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS)),
54283514Sarybchik		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;
59283514Sarybchik	int rc;
60283514Sarybchik
61283514Sarybchik	EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS);
62283514Sarybchik
63283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
64283514Sarybchik	req.emr_cmd = MC_CMD_INIT_RXQ;
65283514Sarybchik	req.emr_in_buf = payload;
66283514Sarybchik	req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages);
67283514Sarybchik	req.emr_out_buf = payload;
68283514Sarybchik	req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN;
69283514Sarybchik
70283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size);
71283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq);
72283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label);
73283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance);
74283514Sarybchik	MCDI_IN_POPULATE_DWORD_5(req, INIT_RXQ_IN_FLAGS,
75283514Sarybchik				    INIT_RXQ_IN_FLAG_BUFF_MODE, 0,
76283514Sarybchik				    INIT_RXQ_IN_FLAG_HDR_SPLIT, 0,
77283514Sarybchik				    INIT_RXQ_IN_FLAG_TIMESTAMP, 0,
78283514Sarybchik				    INIT_RXQ_IN_CRC_MODE, 0,
79283514Sarybchik				    INIT_RXQ_IN_FLAG_PREFIX, 1);
80283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0);
81283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
82283514Sarybchik
83283514Sarybchik	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
84283514Sarybchik	addr = EFSYS_MEM_ADDR(esmp);
85283514Sarybchik
86283514Sarybchik	for (i = 0; i < npages; i++) {
87283514Sarybchik		EFX_POPULATE_QWORD_2(*dma_addr,
88283514Sarybchik		    EFX_DWORD_1, (uint32_t)(addr >> 32),
89283514Sarybchik		    EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
90283514Sarybchik
91283514Sarybchik		dma_addr++;
92283514Sarybchik		addr += EFX_BUF_SIZE;
93283514Sarybchik	}
94283514Sarybchik
95283514Sarybchik	efx_mcdi_execute(enp, &req);
96283514Sarybchik
97283514Sarybchik	if (req.emr_rc != 0) {
98283514Sarybchik		rc = req.emr_rc;
99283514Sarybchik		goto fail1;
100283514Sarybchik	}
101283514Sarybchik
102283514Sarybchik	return (0);
103283514Sarybchik
104283514Sarybchikfail1:
105283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
106283514Sarybchik
107283514Sarybchik	return (rc);
108283514Sarybchik}
109283514Sarybchik
110283514Sarybchikstatic	__checkReturn	int
111283514Sarybchikefx_mcdi_fini_rxq(
112283514Sarybchik	__in		efx_nic_t *enp,
113283514Sarybchik	__in		uint32_t instance)
114283514Sarybchik{
115283514Sarybchik	efx_mcdi_req_t req;
116283514Sarybchik	uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN,
117283514Sarybchik			    MC_CMD_FINI_RXQ_OUT_LEN)];
118283514Sarybchik	int rc;
119283514Sarybchik
120283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
121283514Sarybchik	req.emr_cmd = MC_CMD_FINI_RXQ;
122283514Sarybchik	req.emr_in_buf = payload;
123283514Sarybchik	req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
124283514Sarybchik	req.emr_out_buf = payload;
125283514Sarybchik	req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
126283514Sarybchik
127283514Sarybchik	MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
128283514Sarybchik
129283514Sarybchik	efx_mcdi_execute(enp, &req);
130283514Sarybchik
131283514Sarybchik	if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) {
132283514Sarybchik		rc = req.emr_rc;
133283514Sarybchik		goto fail1;
134283514Sarybchik	}
135283514Sarybchik
136283514Sarybchik	return (0);
137283514Sarybchik
138283514Sarybchikfail1:
139283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
140283514Sarybchik
141283514Sarybchik	return (rc);
142283514Sarybchik}
143283514Sarybchik
144283514Sarybchik#if EFSYS_OPT_RX_SCALE
145283514Sarybchikstatic	__checkReturn	int
146283514Sarybchikefx_mcdi_rss_context_alloc(
147283514Sarybchik	__in		efx_nic_t *enp,
148283514Sarybchik	__out		uint32_t *rss_contextp)
149283514Sarybchik{
150283514Sarybchik	efx_mcdi_req_t req;
151283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
152283514Sarybchik			    MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)];
153283514Sarybchik	uint32_t rss_context;
154283514Sarybchik	int rc;
155283514Sarybchik
156283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
157283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
158283514Sarybchik	req.emr_in_buf = payload;
159283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
160283514Sarybchik	req.emr_out_buf = payload;
161283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
162283514Sarybchik
163283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
164283514Sarybchik	    EVB_PORT_ID_ASSIGNED);
165283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE,
166283514Sarybchik	    MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE);
167283514Sarybchik	/* NUM_QUEUES is only used to validate indirection table offsets */
168283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, 64);
169283514Sarybchik
170283514Sarybchik	efx_mcdi_execute(enp, &req);
171283514Sarybchik
172283514Sarybchik	if (req.emr_rc != 0) {
173283514Sarybchik		rc = req.emr_rc;
174283514Sarybchik		goto fail1;
175283514Sarybchik	}
176283514Sarybchik
177283514Sarybchik	if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
178283514Sarybchik		rc = EMSGSIZE;
179283514Sarybchik		goto fail2;
180283514Sarybchik	}
181283514Sarybchik
182283514Sarybchik	rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
183283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
184283514Sarybchik		rc = ENOENT;
185283514Sarybchik		goto fail3;
186283514Sarybchik	}
187283514Sarybchik
188283514Sarybchik	*rss_contextp = rss_context;
189283514Sarybchik
190283514Sarybchik	return (0);
191283514Sarybchik
192283514Sarybchikfail3:
193283514Sarybchik	EFSYS_PROBE(fail3);
194283514Sarybchikfail2:
195283514Sarybchik	EFSYS_PROBE(fail2);
196283514Sarybchikfail1:
197283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
198283514Sarybchik
199283514Sarybchik	return (rc);
200283514Sarybchik}
201283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
202283514Sarybchik
203283514Sarybchik#if EFSYS_OPT_RX_SCALE
204283514Sarybchikstatic	int
205283514Sarybchikefx_mcdi_rss_context_free(
206283514Sarybchik	__in		efx_nic_t *enp,
207283514Sarybchik	__in		uint32_t rss_context)
208283514Sarybchik{
209283514Sarybchik	efx_mcdi_req_t req;
210283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN,
211283514Sarybchik			    MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)];
212283514Sarybchik	int rc;
213283514Sarybchik
214283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
215283514Sarybchik		rc = EINVAL;
216283514Sarybchik		goto fail1;
217283514Sarybchik	}
218283514Sarybchik
219283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
220283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE;
221283514Sarybchik	req.emr_in_buf = payload;
222283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN;
223283514Sarybchik	req.emr_out_buf = payload;
224283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN;
225283514Sarybchik
226283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context);
227283514Sarybchik
228283514Sarybchik	efx_mcdi_execute(enp, &req);
229283514Sarybchik
230283514Sarybchik	if (req.emr_rc != 0) {
231283514Sarybchik		rc = req.emr_rc;
232283514Sarybchik		goto fail2;
233283514Sarybchik	}
234283514Sarybchik
235283514Sarybchik	return (0);
236283514Sarybchik
237283514Sarybchikfail2:
238283514Sarybchik	EFSYS_PROBE(fail2);
239283514Sarybchikfail1:
240283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
241283514Sarybchik
242283514Sarybchik	return (rc);
243283514Sarybchik}
244283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
245283514Sarybchik
246283514Sarybchik#if EFSYS_OPT_RX_SCALE
247283514Sarybchikstatic	int
248283514Sarybchikefx_mcdi_rss_context_set_flags(
249283514Sarybchik	__in		efx_nic_t *enp,
250283514Sarybchik	__in		uint32_t rss_context,
251283514Sarybchik	__in		efx_rx_hash_type_t type)
252283514Sarybchik{
253283514Sarybchik	efx_mcdi_req_t req;
254283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
255283514Sarybchik			    MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)];
256283514Sarybchik	int rc;
257283514Sarybchik
258283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
259283514Sarybchik		rc = EINVAL;
260283514Sarybchik		goto fail1;
261283514Sarybchik	}
262283514Sarybchik
263283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
264283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS;
265283514Sarybchik	req.emr_in_buf = payload;
266283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN;
267283514Sarybchik	req.emr_out_buf = payload;
268283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN;
269283514Sarybchik
270283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
271283514Sarybchik	    rss_context);
272283514Sarybchik
273283514Sarybchik	MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
274283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
275283514Sarybchik	    (type & (1U << EFX_RX_HASH_IPV4)) ? 1 : 0,
276283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
277283514Sarybchik	    (type & (1U << EFX_RX_HASH_TCPIPV4)) ? 1 : 0,
278283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
279283514Sarybchik	    (type & (1U << EFX_RX_HASH_IPV6)) ? 1 : 0,
280283514Sarybchik	    RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
281283514Sarybchik	    (type & (1U << EFX_RX_HASH_TCPIPV6)) ? 1 : 0);
282283514Sarybchik
283283514Sarybchik	efx_mcdi_execute(enp, &req);
284283514Sarybchik
285283514Sarybchik	if (req.emr_rc != 0) {
286283514Sarybchik		rc = req.emr_rc;
287283514Sarybchik		goto fail2;
288283514Sarybchik	}
289283514Sarybchik
290283514Sarybchik	return (0);
291283514Sarybchik
292283514Sarybchikfail2:
293283514Sarybchik	EFSYS_PROBE(fail2);
294283514Sarybchikfail1:
295283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
296283514Sarybchik
297283514Sarybchik	return (rc);
298283514Sarybchik}
299283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
300283514Sarybchik
301283514Sarybchik#if EFSYS_OPT_RX_SCALE
302283514Sarybchikstatic	int
303283514Sarybchikefx_mcdi_rss_context_set_key(
304283514Sarybchik	__in		efx_nic_t *enp,
305283514Sarybchik	__in		uint32_t rss_context,
306283514Sarybchik	__in_ecount(n)	uint8_t *key,
307283514Sarybchik	__in		size_t n)
308283514Sarybchik{
309283514Sarybchik	efx_mcdi_req_t req;
310283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN,
311283514Sarybchik			    MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)];
312283514Sarybchik	int rc;
313283514Sarybchik
314283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
315283514Sarybchik		rc = EINVAL;
316283514Sarybchik		goto fail1;
317283514Sarybchik	}
318283514Sarybchik
319283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
320283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY;
321283514Sarybchik	req.emr_in_buf = payload;
322283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN;
323283514Sarybchik	req.emr_out_buf = payload;
324283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN;
325283514Sarybchik
326283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID,
327283514Sarybchik	    rss_context);
328283514Sarybchik
329283514Sarybchik	EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
330283514Sarybchik	if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) {
331283514Sarybchik		rc = EINVAL;
332283514Sarybchik		goto fail2;
333283514Sarybchik	}
334283514Sarybchik
335283514Sarybchik	memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY),
336283514Sarybchik	    key, n);
337283514Sarybchik
338283514Sarybchik	efx_mcdi_execute(enp, &req);
339283514Sarybchik
340283514Sarybchik	if (req.emr_rc != 0) {
341283514Sarybchik		rc = req.emr_rc;
342283514Sarybchik		goto fail3;
343283514Sarybchik	}
344283514Sarybchik
345283514Sarybchik	return (0);
346283514Sarybchik
347283514Sarybchikfail3:
348283514Sarybchik	EFSYS_PROBE(fail3);
349283514Sarybchikfail2:
350283514Sarybchik	EFSYS_PROBE(fail2);
351283514Sarybchikfail1:
352283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
353283514Sarybchik
354283514Sarybchik	return (rc);
355283514Sarybchik}
356283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
357283514Sarybchik
358283514Sarybchik#if EFSYS_OPT_RX_SCALE
359283514Sarybchikstatic	int
360283514Sarybchikefx_mcdi_rss_context_set_table(
361283514Sarybchik	__in		efx_nic_t *enp,
362283514Sarybchik	__in		uint32_t rss_context,
363283514Sarybchik	__in_ecount(n)	unsigned int *table,
364283514Sarybchik	__in		size_t n)
365283514Sarybchik{
366283514Sarybchik	efx_mcdi_req_t req;
367283514Sarybchik	uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN,
368283514Sarybchik			    MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)];
369283514Sarybchik	uint8_t *req_table;
370283514Sarybchik	int i, rc;
371283514Sarybchik
372283514Sarybchik	if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
373283514Sarybchik		rc = EINVAL;
374283514Sarybchik		goto fail1;
375283514Sarybchik	}
376283514Sarybchik
377283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
378283514Sarybchik	req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE;
379283514Sarybchik	req.emr_in_buf = payload;
380283514Sarybchik	req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN;
381283514Sarybchik	req.emr_out_buf = payload;
382283514Sarybchik	req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN;
383283514Sarybchik
384283514Sarybchik	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID,
385283514Sarybchik	    rss_context);
386283514Sarybchik
387283514Sarybchik	req_table =
388283514Sarybchik	    MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE);
389283514Sarybchik
390283514Sarybchik	for (i = 0;
391283514Sarybchik	    i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN;
392283514Sarybchik	    i++) {
393283514Sarybchik		req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0;
394283514Sarybchik	}
395283514Sarybchik
396283514Sarybchik	efx_mcdi_execute(enp, &req);
397283514Sarybchik
398283514Sarybchik	if (req.emr_rc != 0) {
399283514Sarybchik		rc = req.emr_rc;
400283514Sarybchik		goto fail2;
401283514Sarybchik	}
402283514Sarybchik
403283514Sarybchik	return (0);
404283514Sarybchik
405283514Sarybchikfail2:
406283514Sarybchik	EFSYS_PROBE(fail2);
407283514Sarybchikfail1:
408283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
409283514Sarybchik
410283514Sarybchik	return (rc);
411283514Sarybchik}
412283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
413283514Sarybchik
414283514Sarybchik
415283514Sarybchik	__checkReturn	int
416283514Sarybchikhunt_rx_init(
417283514Sarybchik	__in		efx_nic_t *enp)
418283514Sarybchik{
419283514Sarybchik#if EFSYS_OPT_RX_SCALE
420283514Sarybchik
421283514Sarybchik	if (efx_mcdi_rss_context_alloc(enp, &enp->en_rss_context) == 0) {
422283514Sarybchik		/*
423283514Sarybchik		 * Allocated an exclusive RSS context, which allows both the
424283514Sarybchik		 * indirection table and key to be modified.
425283514Sarybchik		 */
426283514Sarybchik		enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE;
427283514Sarybchik		enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
428283514Sarybchik	} else {
429283514Sarybchik		/*
430283514Sarybchik		 * Failed to allocate an exclusive RSS context. Continue
431283514Sarybchik		 * operation without support for RSS. The pseudo-header in
432283514Sarybchik		 * received packets will not contain a Toeplitz hash value.
433283514Sarybchik		 */
434283514Sarybchik		enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
435283514Sarybchik		enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE;
436283514Sarybchik	}
437283514Sarybchik
438283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
439283514Sarybchik
440283514Sarybchik	return (0);
441283514Sarybchik}
442283514Sarybchik
443283514Sarybchik#if EFSYS_OPT_RX_HDR_SPLIT
444283514Sarybchik	__checkReturn	int
445283514Sarybchikhunt_rx_hdr_split_enable(
446283514Sarybchik	__in		efx_nic_t *enp,
447283514Sarybchik	__in		unsigned int hdr_buf_size,
448283514Sarybchik	__in		unsigned int pld_buf_size)
449283514Sarybchik{
450283514Sarybchik	int rc;
451283514Sarybchik
452283514Sarybchik	/* FIXME */
453283514Sarybchik	_NOTE(ARGUNUSED(enp, hdr_buf_size, pld_buf_size))
454283514Sarybchik	if (B_FALSE) {
455283514Sarybchik		rc = ENOTSUP;
456283514Sarybchik		goto fail1;
457283514Sarybchik	}
458283514Sarybchik	/* FIXME */
459283514Sarybchik
460283514Sarybchik	return (0);
461283514Sarybchik
462283514Sarybchikfail1:
463283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
464283514Sarybchik
465283514Sarybchik	return (rc);
466283514Sarybchik}
467283514Sarybchik#endif	/* EFSYS_OPT_RX_HDR_SPLIT */
468283514Sarybchik
469283514Sarybchik#if EFSYS_OPT_RX_SCATTER
470283514Sarybchik	__checkReturn	int
471283514Sarybchikhunt_rx_scatter_enable(
472283514Sarybchik	__in		efx_nic_t *enp,
473283514Sarybchik	__in		unsigned int buf_size)
474283514Sarybchik{
475283514Sarybchik	_NOTE(ARGUNUSED(enp, buf_size))
476283514Sarybchik	return (0);
477283514Sarybchik}
478283514Sarybchik#endif	/* EFSYS_OPT_RX_SCATTER */
479283514Sarybchik
480283514Sarybchik#if EFSYS_OPT_RX_SCALE
481283514Sarybchik	__checkReturn	int
482283514Sarybchikhunt_rx_scale_mode_set(
483283514Sarybchik	__in		efx_nic_t *enp,
484283514Sarybchik	__in		efx_rx_hash_alg_t alg,
485283514Sarybchik	__in		efx_rx_hash_type_t type,
486283514Sarybchik	__in		boolean_t insert)
487283514Sarybchik{
488283514Sarybchik	int rc;
489283514Sarybchik
490283514Sarybchik	EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ);
491283514Sarybchik	EFSYS_ASSERT3U(insert, ==, B_TRUE);
492283514Sarybchik
493283514Sarybchik	if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) {
494283514Sarybchik		rc = EINVAL;
495283514Sarybchik		goto fail1;
496283514Sarybchik	}
497283514Sarybchik
498283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
499283514Sarybchik		rc = ENOTSUP;
500283514Sarybchik		goto fail2;
501283514Sarybchik	}
502283514Sarybchik
503283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_flags(enp,
504283514Sarybchik		    enp->en_rss_context, type)) != 0)
505283514Sarybchik		goto fail3;
506283514Sarybchik
507283514Sarybchik	return (0);
508283514Sarybchik
509283514Sarybchikfail3:
510283514Sarybchik	EFSYS_PROBE(fail3);
511283514Sarybchikfail2:
512283514Sarybchik	EFSYS_PROBE(fail2);
513283514Sarybchikfail1:
514283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
515283514Sarybchik
516283514Sarybchik	return (rc);
517283514Sarybchik}
518283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
519283514Sarybchik
520283514Sarybchik#if EFSYS_OPT_RX_SCALE
521283514Sarybchik	__checkReturn	int
522283514Sarybchikhunt_rx_scale_key_set(
523283514Sarybchik	__in		efx_nic_t *enp,
524283514Sarybchik	__in_ecount(n)	uint8_t *key,
525283514Sarybchik	__in		size_t n)
526283514Sarybchik{
527283514Sarybchik	int rc;
528283514Sarybchik
529283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
530283514Sarybchik		rc = ENOTSUP;
531283514Sarybchik		goto fail1;
532283514Sarybchik	}
533283514Sarybchik
534283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_key(enp,
535283514Sarybchik	    enp->en_rss_context, key, n)) != 0)
536283514Sarybchik		goto fail2;
537283514Sarybchik
538283514Sarybchik	return (0);
539283514Sarybchik
540283514Sarybchikfail2:
541283514Sarybchik	EFSYS_PROBE(fail2);
542283514Sarybchikfail1:
543283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
544283514Sarybchik
545283514Sarybchik	return (rc);
546283514Sarybchik}
547283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
548283514Sarybchik
549283514Sarybchik#if EFSYS_OPT_RX_SCALE
550283514Sarybchik	__checkReturn	int
551283514Sarybchikhunt_rx_scale_tbl_set(
552283514Sarybchik	__in		efx_nic_t *enp,
553283514Sarybchik	__in_ecount(n)	unsigned int *table,
554283514Sarybchik	__in		size_t n)
555283514Sarybchik{
556283514Sarybchik	int rc;
557283514Sarybchik
558283514Sarybchik	if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
559283514Sarybchik		rc = ENOTSUP;
560283514Sarybchik		goto fail1;
561283514Sarybchik	}
562283514Sarybchik
563283514Sarybchik	if ((rc = efx_mcdi_rss_context_set_table(enp,
564283514Sarybchik	    enp->en_rss_context, table, n)) != 0)
565283514Sarybchik		goto fail2;
566283514Sarybchik
567283514Sarybchik	return (0);
568283514Sarybchik
569283514Sarybchikfail2:
570283514Sarybchik	EFSYS_PROBE(fail2);
571283514Sarybchikfail1:
572283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
573283514Sarybchik
574283514Sarybchik	return (rc);
575283514Sarybchik}
576283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
577283514Sarybchik
578283514Sarybchik			void
579283514Sarybchikhunt_rx_qpost(
580283514Sarybchik	__in		efx_rxq_t *erp,
581283514Sarybchik	__in_ecount(n)	efsys_dma_addr_t *addrp,
582283514Sarybchik	__in		size_t size,
583283514Sarybchik	__in		unsigned int n,
584283514Sarybchik	__in		unsigned int completed,
585283514Sarybchik	__in		unsigned int added)
586283514Sarybchik{
587283514Sarybchik	efx_qword_t qword;
588283514Sarybchik	unsigned int i;
589283514Sarybchik	unsigned int offset;
590283514Sarybchik	unsigned int id;
591283514Sarybchik
592283514Sarybchik	/* The client driver must not overfill the queue */
593283514Sarybchik	EFSYS_ASSERT3U(added - completed + n, <=,
594283514Sarybchik	    EFX_RXQ_LIMIT(erp->er_mask + 1));
595283514Sarybchik
596283514Sarybchik	id = added & (erp->er_mask);
597283514Sarybchik	for (i = 0; i < n; i++) {
598283514Sarybchik		EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
599283514Sarybchik		    unsigned int, id, efsys_dma_addr_t, addrp[i],
600283514Sarybchik		    size_t, size);
601283514Sarybchik
602283514Sarybchik		EFX_POPULATE_QWORD_3(qword,
603283514Sarybchik		    ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size),
604283514Sarybchik		    ESF_DZ_RX_KER_BUF_ADDR_DW0,
605283514Sarybchik		    (uint32_t)(addrp[i] & 0xffffffff),
606283514Sarybchik		    ESF_DZ_RX_KER_BUF_ADDR_DW1,
607283514Sarybchik		    (uint32_t)(addrp[i] >> 32));
608283514Sarybchik
609283514Sarybchik		offset = id * sizeof (efx_qword_t);
610283514Sarybchik		EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
611283514Sarybchik
612283514Sarybchik		id = (id + 1) & (erp->er_mask);
613283514Sarybchik	}
614283514Sarybchik}
615283514Sarybchik
616283514Sarybchik			void
617283514Sarybchikhunt_rx_qpush(
618283514Sarybchik	__in	efx_rxq_t *erp,
619283514Sarybchik	__in	unsigned int added,
620283514Sarybchik	__inout	unsigned int *pushedp)
621283514Sarybchik{
622283514Sarybchik	efx_nic_t *enp = erp->er_enp;
623283514Sarybchik	unsigned int pushed = *pushedp;
624283514Sarybchik	uint32_t wptr;
625283514Sarybchik	efx_dword_t dword;
626283514Sarybchik
627283514Sarybchik	/* Hardware has alignment restriction for WPTR */
628283514Sarybchik	wptr = P2ALIGN(added, HUNTINGTON_RX_WPTR_ALIGN);
629283514Sarybchik	if (pushed == wptr)
630283514Sarybchik		return;
631283514Sarybchik
632283514Sarybchik	*pushedp = wptr;
633283514Sarybchik
634283514Sarybchik	/* Push the populated descriptors out */
635283514Sarybchik	wptr &= erp->er_mask;
636283514Sarybchik
637283514Sarybchik	EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr);
638283514Sarybchik
639283514Sarybchik	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
640283514Sarybchik	EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
641283514Sarybchik	    wptr, pushed & erp->er_mask);
642283514Sarybchik	EFSYS_PIO_WRITE_BARRIER();
643283514Sarybchik	EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
644283514Sarybchik			    erp->er_index, &dword, B_FALSE);
645283514Sarybchik}
646283514Sarybchik
647283514Sarybchik	__checkReturn	int
648283514Sarybchikhunt_rx_qflush(
649283514Sarybchik	__in	efx_rxq_t *erp)
650283514Sarybchik{
651283514Sarybchik	efx_nic_t *enp = erp->er_enp;
652283514Sarybchik	int rc;
653283514Sarybchik
654283514Sarybchik	if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0)
655283514Sarybchik		goto fail1;
656283514Sarybchik
657283514Sarybchik	return (0);
658283514Sarybchik
659283514Sarybchikfail1:
660283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
661283514Sarybchik
662283514Sarybchik	return (rc);
663283514Sarybchik}
664283514Sarybchik
665283514Sarybchik		void
666283514Sarybchikhunt_rx_qenable(
667283514Sarybchik	__in	efx_rxq_t *erp)
668283514Sarybchik{
669283514Sarybchik	/* FIXME */
670283514Sarybchik	_NOTE(ARGUNUSED(erp))
671283514Sarybchik	/* FIXME */
672283514Sarybchik}
673283514Sarybchik
674283514Sarybchik	__checkReturn	int
675283514Sarybchikhunt_rx_qcreate(
676283514Sarybchik	__in		efx_nic_t *enp,
677283514Sarybchik	__in		unsigned int index,
678283514Sarybchik	__in		unsigned int label,
679283514Sarybchik	__in		efx_rxq_type_t type,
680283514Sarybchik	__in		efsys_mem_t *esmp,
681283514Sarybchik	__in		size_t n,
682283514Sarybchik	__in		uint32_t id,
683283514Sarybchik	__in		efx_evq_t *eep,
684283514Sarybchik	__in		efx_rxq_t *erp)
685283514Sarybchik{
686283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
687283514Sarybchik	int rc;
688283514Sarybchik
689283514Sarybchik	_NOTE(ARGUNUSED(erp))
690283514Sarybchik
691283514Sarybchik	EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH));
692283514Sarybchik	EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
693283514Sarybchik	EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
694283514Sarybchik
695283514Sarybchik	EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
696283514Sarybchik	EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
697283514Sarybchik
698283514Sarybchik	if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) {
699283514Sarybchik		rc = EINVAL;
700283514Sarybchik		goto fail1;
701283514Sarybchik	}
702283514Sarybchik	if (index >= encp->enc_rxq_limit) {
703283514Sarybchik		rc = EINVAL;
704283514Sarybchik		goto fail2;
705283514Sarybchik	}
706283514Sarybchik
707283514Sarybchik	/*
708283514Sarybchik	 * FIXME: Siena code handles different queue types (default, header
709283514Sarybchik	 * split, scatter); we'll need to do something more here later, but
710283514Sarybchik	 * all that stuff is TBD for now.
711283514Sarybchik	 */
712283514Sarybchik
713283514Sarybchik	if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index,
714283514Sarybchik	    esmp)) != 0)
715283514Sarybchik		goto fail3;
716283514Sarybchik
717283514Sarybchik	erp->er_eep = eep;
718283514Sarybchik	erp->er_label = label;
719283514Sarybchik
720283514Sarybchik	hunt_ev_rxlabel_init(eep, erp, label);
721283514Sarybchik
722283514Sarybchik	return (0);
723283514Sarybchik
724283514Sarybchikfail3:
725283514Sarybchik	EFSYS_PROBE(fail3);
726283514Sarybchikfail2:
727283514Sarybchik	EFSYS_PROBE(fail2);
728283514Sarybchikfail1:
729283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
730283514Sarybchik
731283514Sarybchik	return (rc);
732283514Sarybchik}
733283514Sarybchik
734283514Sarybchik		void
735283514Sarybchikhunt_rx_qdestroy(
736283514Sarybchik	__in	efx_rxq_t *erp)
737283514Sarybchik{
738283514Sarybchik	efx_nic_t *enp = erp->er_enp;
739283514Sarybchik	efx_evq_t *eep = erp->er_eep;
740283514Sarybchik	unsigned int label = erp->er_label;
741283514Sarybchik
742283514Sarybchik	hunt_ev_rxlabel_fini(eep, label);
743283514Sarybchik
744283514Sarybchik	EFSYS_ASSERT(enp->en_rx_qcount != 0);
745283514Sarybchik	--enp->en_rx_qcount;
746283514Sarybchik
747283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
748283514Sarybchik}
749283514Sarybchik
750283514Sarybchik		void
751283514Sarybchikhunt_rx_fini(
752283514Sarybchik	__in	efx_nic_t *enp)
753283514Sarybchik{
754283514Sarybchik#if EFSYS_OPT_RX_SCALE
755283514Sarybchik	if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) {
756283514Sarybchik		(void) efx_mcdi_rss_context_free(enp, enp->en_rss_context);
757283514Sarybchik	}
758283514Sarybchik	enp->en_rss_context = 0;
759283514Sarybchik	enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
760283514Sarybchik#else
761283514Sarybchik	_NOTE(ARGUNUSED(enp))
762283514Sarybchik#endif /* EFSYS_OPT_RX_SCALE */
763283514Sarybchik}
764283514Sarybchik
765283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */
766