ef10_nic.c revision 291747
1220137Strasz/*-
2220137Strasz * Copyright (c) 2012-2015 Solarflare Communications Inc.
3220137Strasz * All rights reserved.
4220137Strasz *
5220137Strasz * Redistribution and use in source and binary forms, with or without
6220137Strasz * modification, are permitted provided that the following conditions are met:
7220137Strasz *
8220137Strasz * 1. Redistributions of source code must retain the above copyright notice,
9220137Strasz *    this list of conditions and the following disclaimer.
10220137Strasz * 2. Redistributions in binary form must reproduce the above copyright notice,
11220137Strasz *    this list of conditions and the following disclaimer in the documentation
12220137Strasz *    and/or other materials provided with the distribution.
13220137Strasz *
14220137Strasz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15220137Strasz * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16220137Strasz * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17220137Strasz * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18220137Strasz * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19220137Strasz * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20220137Strasz * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21220137Strasz * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22220137Strasz * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23220137Strasz * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24220137Strasz * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25220137Strasz *
26220137Strasz * The views and conclusions contained in the software and documentation are
27220137Strasz * those of the authors and should not be interpreted as representing official
28220137Strasz * policies, either expressed or implied, of the FreeBSD Project.
29220137Strasz */
30220137Strasz
31220137Strasz#include <sys/cdefs.h>
32220137Strasz__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_nic.c 291747 2015-12-04 06:54:46Z arybchik $");
33220137Strasz
34220137Strasz#include "efsys.h"
35242139Strasz#include "efx.h"
36220137Strasz#include "efx_impl.h"
37220137Strasz#include "mcdi_mon.h"
38228430Savg
39220137Strasz#if EFSYS_OPT_HUNTINGTON
40220137Strasz
41220137Strasz#include "ef10_tlv_layout.h"
42220137Strasz
43220137Straszstatic	__checkReturn	efx_rc_t
44220137Straszefx_mcdi_get_port_assignment(
45220137Strasz	__in		efx_nic_t *enp,
46220137Strasz	__out		uint32_t *portp)
47220137Strasz{
48220137Strasz	efx_mcdi_req_t req;
49220137Strasz	uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN,
50220137Strasz			    MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)];
51220137Strasz	efx_rc_t rc;
52220137Strasz
53242139Strasz	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
54220137Strasz
55242139Strasz	(void) memset(payload, 0, sizeof (payload));
56220137Strasz	req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT;
57220137Strasz	req.emr_in_buf = payload;
58220137Strasz	req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN;
59242139Strasz	req.emr_out_buf = payload;
60220137Strasz	req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN;
61220137Strasz
62220137Strasz	efx_mcdi_execute(enp, &req);
63220137Strasz
64220137Strasz	if (req.emr_rc != 0) {
65220137Strasz		rc = req.emr_rc;
66220137Strasz		goto fail1;
67220137Strasz	}
68220137Strasz
69242139Strasz	if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) {
70242139Strasz		rc = EMSGSIZE;
71242139Strasz		goto fail2;
72242139Strasz	}
73242139Strasz
74242139Strasz	*portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT);
75242139Strasz
76242139Strasz	return (0);
77242139Strasz
78242139Straszfail2:
79242139Strasz	EFSYS_PROBE(fail2);
80242139Straszfail1:
81242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
82242139Strasz
83242139Strasz	return (rc);
84242139Strasz}
85242139Strasz
86220137Straszstatic	__checkReturn	efx_rc_t
87220137Straszefx_mcdi_get_port_modes(
88220137Strasz	__in		efx_nic_t *enp,
89220137Strasz	__out		uint32_t *modesp)
90220137Strasz{
91220137Strasz	efx_mcdi_req_t req;
92220137Strasz	uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN,
93220137Strasz			    MC_CMD_GET_PORT_MODES_OUT_LEN)];
94220137Strasz	efx_rc_t rc;
95220137Strasz
96220137Strasz	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
97220137Strasz
98258622Savg	(void) memset(payload, 0, sizeof (payload));
99220137Strasz	req.emr_cmd = MC_CMD_GET_PORT_MODES;
100258622Savg	req.emr_in_buf = payload;
101220137Strasz	req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN;
102258622Savg	req.emr_out_buf = payload;
103220137Strasz	req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN;
104258622Savg
105220137Strasz	efx_mcdi_execute(enp, &req);
106258622Savg
107220137Strasz	if (req.emr_rc != 0) {
108258622Savg		rc = req.emr_rc;
109220137Strasz		goto fail1;
110258622Savg	}
111220137Strasz
112258622Savg	/* Accept pre-Medford size (8 bytes - no CurrentMode field) */
113220137Strasz	if (req.emr_out_length_used <
114258622Savg	    MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) {
115258622Savg		rc = EMSGSIZE;
116258622Savg		goto fail2;
117220137Strasz	}
118258622Savg
119220137Strasz	*modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES);
120258622Savg
121220137Strasz	return (0);
122220137Strasz
123220137Straszfail2:
124220137Strasz	EFSYS_PROBE(fail2);
125224036Straszfail1:
126220137Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
127220137Strasz
128220137Strasz	return (rc);
129220137Strasz}
130220137Strasz
131220137Strasz
132220137Straszstatic	__checkReturn		efx_rc_t
133220137Straszefx_mcdi_vadaptor_alloc(
134220137Strasz	__in			efx_nic_t *enp,
135220137Strasz	__in			uint32_t port_id)
136220137Strasz{
137220137Strasz	efx_mcdi_req_t req;
138220137Strasz	uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN,
139220137Strasz			    MC_CMD_VADAPTOR_ALLOC_OUT_LEN)];
140220137Strasz	efx_rc_t rc;
141220137Strasz
142220137Strasz	EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL);
143220137Strasz
144220137Strasz	(void) memset(payload, 0, sizeof (payload));
145220137Strasz	req.emr_cmd = MC_CMD_VADAPTOR_ALLOC;
146220137Strasz	req.emr_in_buf = payload;
147220137Strasz	req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN;
148220137Strasz	req.emr_out_buf = payload;
149220137Strasz	req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN;
150220137Strasz
151220137Strasz	MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
152220137Strasz
153220137Strasz	efx_mcdi_execute(enp, &req);
154220137Strasz
155220137Strasz	if (req.emr_rc != 0) {
156220137Strasz		rc = req.emr_rc;
157220137Strasz		goto fail1;
158220137Strasz	}
159220137Strasz
160220137Strasz	return (0);
161220137Strasz
162220137Straszfail1:
163242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
164242139Strasz
165242139Strasz	return (rc);
166220137Strasz}
167242139Strasz
168242139Straszstatic	__checkReturn		efx_rc_t
169242139Straszefx_mcdi_vadaptor_free(
170242139Strasz	__in			efx_nic_t *enp,
171242139Strasz	__in			uint32_t port_id)
172242139Strasz{
173242139Strasz	efx_mcdi_req_t req;
174242139Strasz	uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN,
175242139Strasz			    MC_CMD_VADAPTOR_FREE_OUT_LEN)];
176242139Strasz	efx_rc_t rc;
177242139Strasz
178242139Strasz	(void) memset(payload, 0, sizeof (payload));
179242139Strasz	req.emr_cmd = MC_CMD_VADAPTOR_FREE;
180242139Strasz	req.emr_in_buf = payload;
181242139Strasz	req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN;
182242139Strasz	req.emr_out_buf = payload;
183242139Strasz	req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN;
184242139Strasz
185242139Strasz	MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
186242139Strasz
187242139Strasz	efx_mcdi_execute(enp, &req);
188242139Strasz
189242139Strasz	if (req.emr_rc != 0) {
190242139Strasz		rc = req.emr_rc;
191242139Strasz		goto fail1;
192242139Strasz	}
193242139Strasz
194242139Strasz	return (0);
195242139Strasz
196242139Straszfail1:
197242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
198242139Strasz
199242139Strasz	return (rc);
200242139Strasz}
201242139Strasz
202242139Straszstatic	__checkReturn	efx_rc_t
203242139Straszefx_mcdi_get_mac_address_pf(
204242139Strasz	__in			efx_nic_t *enp,
205242139Strasz	__out_ecount_opt(6)	uint8_t mac_addrp[6])
206242139Strasz{
207242139Strasz	efx_mcdi_req_t req;
208242139Strasz	uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN,
209242139Strasz			    MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)];
210242139Strasz	efx_rc_t rc;
211242139Strasz
212242139Strasz	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
213242139Strasz
214242139Strasz	(void) memset(payload, 0, sizeof (payload));
215242139Strasz	req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES;
216242139Strasz	req.emr_in_buf = payload;
217242139Strasz	req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN;
218242139Strasz	req.emr_out_buf = payload;
219242139Strasz	req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN;
220242139Strasz
221242139Strasz	efx_mcdi_execute(enp, &req);
222242139Strasz
223242139Strasz	if (req.emr_rc != 0) {
224242139Strasz		rc = req.emr_rc;
225242139Strasz		goto fail1;
226242139Strasz	}
227242139Strasz
228242139Strasz	if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) {
229242139Strasz		rc = EMSGSIZE;
230242139Strasz		goto fail2;
231242139Strasz	}
232242139Strasz
233242139Strasz	if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) {
234242139Strasz		rc = ENOENT;
235242139Strasz		goto fail3;
236242139Strasz	}
237242139Strasz
238242139Strasz	if (mac_addrp != NULL) {
239242139Strasz		uint8_t *addrp;
240242139Strasz
241242139Strasz		addrp = MCDI_OUT2(req, uint8_t,
242242139Strasz		    GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE);
243242139Strasz
244242139Strasz		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
245242139Strasz	}
246242139Strasz
247242139Strasz	return (0);
248242139Strasz
249242139Straszfail3:
250242139Strasz	EFSYS_PROBE(fail3);
251242139Straszfail2:
252242139Strasz	EFSYS_PROBE(fail2);
253242139Straszfail1:
254242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
255242139Strasz
256242139Strasz	return (rc);
257242139Strasz}
258242139Strasz
259242139Straszstatic	__checkReturn	efx_rc_t
260242139Straszefx_mcdi_get_mac_address_vf(
261242139Strasz	__in			efx_nic_t *enp,
262242139Strasz	__out_ecount_opt(6)	uint8_t mac_addrp[6])
263242139Strasz{
264242139Strasz	efx_mcdi_req_t req;
265242139Strasz	uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN,
266242139Strasz			    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)];
267242139Strasz	efx_rc_t rc;
268242139Strasz
269242139Strasz	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
270242139Strasz
271242139Strasz	(void) memset(payload, 0, sizeof (payload));
272242139Strasz	req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES;
273242139Strasz	req.emr_in_buf = payload;
274242139Strasz	req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN;
275242139Strasz	req.emr_out_buf = payload;
276242139Strasz	req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX;
277242139Strasz
278242139Strasz	MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID,
279242139Strasz	    EVB_PORT_ID_ASSIGNED);
280242139Strasz
281242139Strasz	efx_mcdi_execute(enp, &req);
282242139Strasz
283242139Strasz	if (req.emr_rc != 0) {
284242139Strasz		rc = req.emr_rc;
285242139Strasz		goto fail1;
286242139Strasz	}
287242139Strasz
288242139Strasz	if (req.emr_out_length_used <
289242139Strasz	    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) {
290242139Strasz		rc = EMSGSIZE;
291242139Strasz		goto fail2;
292242139Strasz	}
293242139Strasz
294242139Strasz	if (MCDI_OUT_DWORD(req,
295242139Strasz		VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) {
296242139Strasz		rc = ENOENT;
297242139Strasz		goto fail3;
298242139Strasz	}
299242139Strasz
300242139Strasz	if (mac_addrp != NULL) {
301242139Strasz		uint8_t *addrp;
302242139Strasz
303242139Strasz		addrp = MCDI_OUT2(req, uint8_t,
304242139Strasz		    VPORT_GET_MAC_ADDRESSES_OUT_MACADDR);
305242139Strasz
306242139Strasz		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
307242139Strasz	}
308242139Strasz
309242139Strasz	return (0);
310242139Strasz
311242139Straszfail3:
312242139Strasz	EFSYS_PROBE(fail3);
313242139Straszfail2:
314242139Strasz	EFSYS_PROBE(fail2);
315242139Straszfail1:
316242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
317242139Strasz
318242139Strasz	return (rc);
319242139Strasz}
320242139Strasz
321242139Straszstatic	__checkReturn	efx_rc_t
322242139Straszefx_mcdi_get_clock(
323242139Strasz	__in		efx_nic_t *enp,
324242139Strasz	__out		uint32_t *sys_freqp)
325242139Strasz{
326242139Strasz	efx_mcdi_req_t req;
327242139Strasz	uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN,
328242139Strasz			    MC_CMD_GET_CLOCK_OUT_LEN)];
329242139Strasz	efx_rc_t rc;
330242139Strasz
331242139Strasz	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
332242139Strasz
333242139Strasz	(void) memset(payload, 0, sizeof (payload));
334242139Strasz	req.emr_cmd = MC_CMD_GET_CLOCK;
335242139Strasz	req.emr_in_buf = payload;
336242139Strasz	req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN;
337242139Strasz	req.emr_out_buf = payload;
338242139Strasz	req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN;
339242139Strasz
340242139Strasz	efx_mcdi_execute(enp, &req);
341242139Strasz
342242139Strasz	if (req.emr_rc != 0) {
343242139Strasz		rc = req.emr_rc;
344242139Strasz		goto fail1;
345242139Strasz	}
346242139Strasz
347242139Strasz	if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) {
348242139Strasz		rc = EMSGSIZE;
349242139Strasz		goto fail2;
350242139Strasz	}
351242139Strasz
352242139Strasz	*sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ);
353242139Strasz	if (*sys_freqp == 0) {
354242139Strasz		rc = EINVAL;
355242139Strasz		goto fail3;
356242139Strasz	}
357242139Strasz
358242139Strasz	return (0);
359242139Strasz
360242139Straszfail3:
361242139Strasz	EFSYS_PROBE(fail3);
362242139Straszfail2:
363242139Strasz	EFSYS_PROBE(fail2);
364242139Straszfail1:
365242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
366242139Strasz
367242139Strasz	return (rc);
368242139Strasz}
369242139Strasz
370242139Straszstatic 	__checkReturn	efx_rc_t
371242139Straszefx_mcdi_get_vector_cfg(
372242139Strasz	__in		efx_nic_t *enp,
373242139Strasz	__out_opt	uint32_t *vec_basep,
374242139Strasz	__out_opt	uint32_t *pf_nvecp,
375220137Strasz	__out_opt	uint32_t *vf_nvecp)
376220137Strasz{
377220137Strasz	efx_mcdi_req_t req;
378220137Strasz	uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN,
379220137Strasz			    MC_CMD_GET_VECTOR_CFG_OUT_LEN)];
380220137Strasz	efx_rc_t rc;
381220137Strasz
382220137Strasz	(void) memset(payload, 0, sizeof (payload));
383220137Strasz	req.emr_cmd = MC_CMD_GET_VECTOR_CFG;
384220137Strasz	req.emr_in_buf = payload;
385220137Strasz	req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN;
386220137Strasz	req.emr_out_buf = payload;
387243088Strasz	req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN;
388243088Strasz
389220137Strasz	efx_mcdi_execute(enp, &req);
390243088Strasz
391243088Strasz	if (req.emr_rc != 0) {
392220137Strasz		rc = req.emr_rc;
393220137Strasz		goto fail1;
394220137Strasz	}
395220137Strasz
396220137Strasz	if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) {
397220137Strasz		rc = EMSGSIZE;
398220137Strasz		goto fail2;
399220137Strasz	}
400220137Strasz
401220137Strasz	if (vec_basep != NULL)
402220137Strasz		*vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE);
403220137Strasz	if (pf_nvecp != NULL)
404220137Strasz		*pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF);
405220137Strasz	if (vf_nvecp != NULL)
406220137Strasz		*vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF);
407243070Strasz
408220137Strasz	return (0);
409243088Strasz
410243088Straszfail2:
411220137Strasz	EFSYS_PROBE(fail2);
412243088Straszfail1:
413243088Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
414220137Strasz
415243088Strasz	return (rc);
416243088Strasz}
417220137Strasz
418242139Straszstatic	__checkReturn	efx_rc_t
419220137Straszefx_mcdi_get_capabilities(
420220137Strasz	__in		efx_nic_t *enp,
421243070Strasz	__out		efx_dword_t *flagsp)
422243070Strasz{
423243088Strasz	efx_mcdi_req_t req;
424220137Strasz	uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN,
425220137Strasz			    MC_CMD_GET_CAPABILITIES_OUT_LEN)];
426220137Strasz	efx_rc_t rc;
427220137Strasz
428220137Strasz	(void) memset(payload, 0, sizeof (payload));
429220137Strasz	req.emr_cmd = MC_CMD_GET_CAPABILITIES;
430220137Strasz	req.emr_in_buf = payload;
431220137Strasz	req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
432220137Strasz	req.emr_out_buf = payload;
433220137Strasz	req.emr_out_length = MC_CMD_GET_CAPABILITIES_OUT_LEN;
434220137Strasz
435220137Strasz	efx_mcdi_execute(enp, &req);
436220137Strasz
437220137Strasz	if (req.emr_rc != 0) {
438220137Strasz		rc = req.emr_rc;
439220137Strasz		goto fail1;
440220137Strasz	}
441220137Strasz
442220137Strasz	if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
443220137Strasz		rc = EMSGSIZE;
444220137Strasz		goto fail2;
445220137Strasz	}
446220137Strasz
447220137Strasz	*flagsp = *MCDI_OUT2(req, efx_dword_t, GET_CAPABILITIES_OUT_FLAGS1);
448220137Strasz
449220137Strasz	return (0);
450220137Strasz
451220137Straszfail2:
452220137Strasz	EFSYS_PROBE(fail2);
453220137Straszfail1:
454220137Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
455220137Strasz
456223844Strasz	return (rc);
457220137Strasz}
458223844Strasz
459220137Strasz
460220137Straszstatic	__checkReturn	efx_rc_t
461220137Straszefx_mcdi_alloc_vis(
462220137Strasz	__in		efx_nic_t *enp,
463220137Strasz	__in		uint32_t min_vi_count,
464220137Strasz	__in		uint32_t max_vi_count,
465220137Strasz	__out_opt	uint32_t *vi_basep,
466220137Strasz	__out		uint32_t *vi_countp)
467220137Strasz
468220137Strasz{
469220137Strasz	efx_mcdi_req_t req;
470220137Strasz	uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN,
471220137Strasz			    MC_CMD_ALLOC_VIS_OUT_LEN)];
472220137Strasz	efx_rc_t rc;
473220137Strasz
474220137Strasz	if (vi_countp == NULL) {
475220137Strasz		rc = EINVAL;
476220137Strasz		goto fail1;
477220137Strasz	}
478220137Strasz
479220137Strasz	(void) memset(payload, 0, sizeof (payload));
480220137Strasz	req.emr_cmd = MC_CMD_ALLOC_VIS;
481220137Strasz	req.emr_in_buf = payload;
482220137Strasz	req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN;
483220137Strasz	req.emr_out_buf = payload;
484220137Strasz	req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN;
485220137Strasz
486220137Strasz	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count);
487220137Strasz	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count);
488220137Strasz
489220137Strasz	efx_mcdi_execute(enp, &req);
490220137Strasz
491220137Strasz	if (req.emr_rc != 0) {
492220137Strasz		rc = req.emr_rc;
493242139Strasz		goto fail2;
494243088Strasz	}
495220137Strasz
496220137Strasz	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) {
497242139Strasz		rc = EMSGSIZE;
498242139Strasz		goto fail3;
499242139Strasz	}
500242139Strasz
501242139Strasz	if (vi_basep != NULL)
502242139Strasz		*vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE);
503242139Strasz
504242139Strasz	if (vi_countp != NULL)
505242139Strasz		*vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT);
506242139Strasz
507242139Strasz	return (0);
508242139Strasz
509242139Straszfail3:
510220137Strasz	EFSYS_PROBE(fail3);
511220137Straszfail2:
512225944Strasz	EFSYS_PROBE(fail2);
513225944Straszfail1:
514220137Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
515220137Strasz
516220137Strasz	return (rc);
517220137Strasz}
518220137Strasz
519220137Strasz
520220137Straszstatic	__checkReturn	efx_rc_t
521220137Straszefx_mcdi_free_vis(
522220137Strasz	__in		efx_nic_t *enp)
523220137Strasz{
524220137Strasz	efx_mcdi_req_t req;
525220137Strasz	efx_rc_t rc;
526220137Strasz
527220137Strasz	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0);
528223844Strasz	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0);
529258622Savg
530220137Strasz	req.emr_cmd = MC_CMD_FREE_VIS;
531220137Strasz	req.emr_in_buf = NULL;
532220137Strasz	req.emr_in_length = 0;
533220137Strasz	req.emr_out_buf = NULL;
534220137Strasz	req.emr_out_length = 0;
535220137Strasz
536220137Strasz	efx_mcdi_execute_quiet(enp, &req);
537220137Strasz
538220137Strasz	/* Ignore ELREADY (no allocated VIs, so nothing to free) */
539220137Strasz	if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) {
540225944Strasz		rc = req.emr_rc;
541225944Strasz		goto fail1;
542225944Strasz	}
543225944Strasz
544225944Strasz	return (0);
545225944Strasz
546225944Straszfail1:
547225944Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
548225944Strasz
549225944Strasz	return (rc);
550225944Strasz}
551225944Strasz
552225944Strasz
553225944Straszstatic	__checkReturn	efx_rc_t
554225944Straszefx_mcdi_alloc_piobuf(
555220137Strasz	__in		efx_nic_t *enp,
556220137Strasz	__out		efx_piobuf_handle_t *handlep)
557220137Strasz{
558220137Strasz	efx_mcdi_req_t req;
559220137Strasz	uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN,
560258622Savg			    MC_CMD_ALLOC_PIOBUF_OUT_LEN)];
561220137Strasz	efx_rc_t rc;
562220137Strasz
563220137Strasz	if (handlep == NULL) {
564220137Strasz		rc = EINVAL;
565221362Strasz		goto fail1;
566221362Strasz	}
567220137Strasz
568220137Strasz	(void) memset(payload, 0, sizeof (payload));
569220137Strasz	req.emr_cmd = MC_CMD_ALLOC_PIOBUF;
570220137Strasz	req.emr_in_buf = payload;
571220137Strasz	req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN;
572220137Strasz	req.emr_out_buf = payload;
573220137Strasz	req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN;
574220137Strasz
575220137Strasz	efx_mcdi_execute_quiet(enp, &req);
576220137Strasz
577220137Strasz	if (req.emr_rc != 0) {
578220137Strasz		rc = req.emr_rc;
579220137Strasz		goto fail2;
580220137Strasz	}
581220137Strasz
582220137Strasz	if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) {
583220137Strasz		rc = EMSGSIZE;
584220137Strasz		goto fail3;
585220137Strasz	}
586220137Strasz
587220137Strasz	*handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE);
588220137Strasz
589220137Strasz	return (0);
590220137Strasz
591220137Straszfail3:
592220137Strasz	EFSYS_PROBE(fail3);
593258622Savgfail2:
594220137Strasz	EFSYS_PROBE(fail2);
595220137Straszfail1:
596220137Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
597220137Strasz
598220137Strasz	return (rc);
599220137Strasz}
600220137Strasz
601220137Straszstatic	__checkReturn	efx_rc_t
602220137Straszefx_mcdi_free_piobuf(
603220137Strasz	__in		efx_nic_t *enp,
604220137Strasz	__in		efx_piobuf_handle_t handle)
605220137Strasz{
606220137Strasz	efx_mcdi_req_t req;
607220137Strasz	uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN,
608220137Strasz			    MC_CMD_FREE_PIOBUF_OUT_LEN)];
609242139Strasz	efx_rc_t rc;
610242139Strasz
611220137Strasz	(void) memset(payload, 0, sizeof (payload));
612220137Strasz	req.emr_cmd = MC_CMD_FREE_PIOBUF;
613220137Strasz	req.emr_in_buf = payload;
614220137Strasz	req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN;
615220137Strasz	req.emr_out_buf = payload;
616220137Strasz	req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN;
617220137Strasz
618220137Strasz	MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle);
619220137Strasz
620220137Strasz	efx_mcdi_execute_quiet(enp, &req);
621220137Strasz
622242139Strasz	if (req.emr_rc != 0) {
623242139Strasz		rc = req.emr_rc;
624242139Strasz		goto fail1;
625242139Strasz	}
626242139Strasz
627242139Strasz	return (0);
628242139Strasz
629242139Straszfail1:
630242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
631242139Strasz
632242139Strasz	return (rc);
633242139Strasz}
634242139Strasz
635242139Straszstatic	__checkReturn	efx_rc_t
636242139Straszefx_mcdi_link_piobuf(
637242139Strasz	__in		efx_nic_t *enp,
638220137Strasz	__in		uint32_t vi_index,
639242139Strasz	__in		efx_piobuf_handle_t handle)
640243088Strasz{
641220137Strasz	efx_mcdi_req_t req;
642220137Strasz	uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN,
643220137Strasz			    MC_CMD_LINK_PIOBUF_OUT_LEN)];
644242139Strasz	efx_rc_t rc;
645242139Strasz
646223844Strasz	(void) memset(payload, 0, sizeof (payload));
647258622Savg	req.emr_cmd = MC_CMD_LINK_PIOBUF;
648220137Strasz	req.emr_in_buf = payload;
649220137Strasz	req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN;
650220137Strasz	req.emr_out_buf = payload;
651220137Strasz	req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN;
652220137Strasz
653242139Strasz	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle);
654242139Strasz	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
655242139Strasz
656242139Strasz	efx_mcdi_execute(enp, &req);
657242139Strasz
658220137Strasz	if (req.emr_rc != 0) {
659220137Strasz		rc = req.emr_rc;
660220137Strasz		goto fail1;
661220137Strasz	}
662220137Strasz
663220137Strasz	return (0);
664220137Strasz
665220137Straszfail1:
666220137Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
667220137Strasz
668220137Strasz	return (rc);
669220137Strasz}
670220137Strasz
671220137Straszstatic	__checkReturn	efx_rc_t
672220137Straszefx_mcdi_unlink_piobuf(
673220137Strasz	__in		efx_nic_t *enp,
674220137Strasz	__in		uint32_t vi_index)
675220137Strasz{
676220137Strasz	efx_mcdi_req_t req;
677220137Strasz	uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN,
678220137Strasz			    MC_CMD_UNLINK_PIOBUF_OUT_LEN)];
679220137Strasz	efx_rc_t rc;
680242139Strasz
681242139Strasz	(void) memset(payload, 0, sizeof (payload));
682220137Strasz	req.emr_cmd = MC_CMD_UNLINK_PIOBUF;
683242139Strasz	req.emr_in_buf = payload;
684242139Strasz	req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN;
685220137Strasz	req.emr_out_buf = payload;
686220137Strasz	req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN;
687220137Strasz
688220137Strasz	MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
689220137Strasz
690220137Strasz	efx_mcdi_execute(enp, &req);
691220137Strasz
692220137Strasz	if (req.emr_rc != 0) {
693242139Strasz		rc = req.emr_rc;
694242139Strasz		goto fail1;
695242139Strasz	}
696242139Strasz
697242139Strasz	return (0);
698242139Strasz
699242139Straszfail1:
700242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
701242139Strasz
702242139Strasz	return (rc);
703242139Strasz}
704242139Strasz
705242139Straszstatic			void
706242139Straszhunt_nic_alloc_piobufs(
707242139Strasz	__in		efx_nic_t *enp,
708242139Strasz	__in		uint32_t max_piobuf_count)
709242139Strasz{
710242139Strasz	efx_piobuf_handle_t *handlep;
711242139Strasz	unsigned int i;
712242139Strasz	efx_rc_t rc;
713242139Strasz
714242139Strasz	EFSYS_ASSERT3U(max_piobuf_count, <=,
715242139Strasz	    EFX_ARRAY_SIZE(enp->en_u.hunt.enu_piobuf_handle));
716242139Strasz
717242139Strasz	enp->en_u.hunt.enu_piobuf_count = 0;
718242139Strasz
719242139Strasz	for (i = 0; i < max_piobuf_count; i++) {
720220137Strasz		handlep = &enp->en_u.hunt.enu_piobuf_handle[i];
721242139Strasz
722220137Strasz		if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0)
723220137Strasz			goto fail1;
724220137Strasz
725220137Strasz		enp->en_u.hunt.enu_pio_alloc_map[i] = 0;
726220137Strasz		enp->en_u.hunt.enu_piobuf_count++;
727220137Strasz	}
728220137Strasz
729220137Strasz	return;
730220137Strasz
731220137Straszfail1:
732220137Strasz	for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) {
733220137Strasz		handlep = &enp->en_u.hunt.enu_piobuf_handle[i];
734220137Strasz
735220137Strasz		efx_mcdi_free_piobuf(enp, *handlep);
736220137Strasz		*handlep = EFX_PIOBUF_HANDLE_INVALID;
737220137Strasz	}
738220137Strasz	enp->en_u.hunt.enu_piobuf_count = 0;
739220137Strasz}
740220137Strasz
741220137Strasz
742220137Straszstatic			void
743220137Straszhunt_nic_free_piobufs(
744220137Strasz	__in		efx_nic_t *enp)
745220137Strasz{
746220137Strasz	efx_piobuf_handle_t *handlep;
747220137Strasz	unsigned int i;
748220137Strasz
749220137Strasz	for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) {
750220137Strasz		handlep = &enp->en_u.hunt.enu_piobuf_handle[i];
751220137Strasz
752220137Strasz		efx_mcdi_free_piobuf(enp, *handlep);
753220137Strasz		*handlep = EFX_PIOBUF_HANDLE_INVALID;
754220137Strasz	}
755220137Strasz	enp->en_u.hunt.enu_piobuf_count = 0;
756220137Strasz}
757220137Strasz
758220137Strasz/* Sub-allocate a block from a piobuf */
759220137Strasz	__checkReturn	efx_rc_t
760242139Straszhunt_nic_pio_alloc(
761242139Strasz	__inout		efx_nic_t *enp,
762242139Strasz	__out		uint32_t *bufnump,
763242139Strasz	__out		efx_piobuf_handle_t *handlep,
764242139Strasz	__out		uint32_t *blknump,
765242139Strasz	__out		uint32_t *offsetp,
766242139Strasz	__out		size_t *sizep)
767242139Strasz{
768242139Strasz	efx_drv_cfg_t *edcp = &enp->en_drv_cfg;
769242139Strasz	uint32_t blk_per_buf;
770242139Strasz	uint32_t buf, blk;
771242139Strasz	efx_rc_t rc;
772242139Strasz
773242139Strasz	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
774242139Strasz	EFSYS_ASSERT(bufnump);
775242139Strasz	EFSYS_ASSERT(handlep);
776220137Strasz	EFSYS_ASSERT(blknump);
777220137Strasz	EFSYS_ASSERT(offsetp);
778220137Strasz	EFSYS_ASSERT(sizep);
779220137Strasz
780220137Strasz	if ((edcp->edc_pio_alloc_size == 0) ||
781220137Strasz	    (enp->en_u.hunt.enu_piobuf_count == 0)) {
782220137Strasz		rc = ENOMEM;
783220137Strasz		goto fail1;
784220137Strasz	}
785220137Strasz	blk_per_buf = HUNT_PIOBUF_SIZE / edcp->edc_pio_alloc_size;
786220137Strasz
787220137Strasz	for (buf = 0; buf < enp->en_u.hunt.enu_piobuf_count; buf++) {
788242139Strasz		uint32_t *map = &enp->en_u.hunt.enu_pio_alloc_map[buf];
789243088Strasz
790220137Strasz		if (~(*map) == 0)
791220137Strasz			continue;
792220137Strasz
793243088Strasz		EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map)));
794243088Strasz		for (blk = 0; blk < blk_per_buf; blk++) {
795220137Strasz			if ((*map & (1u << blk)) == 0) {
796220137Strasz				*map |= (1u << blk);
797220137Strasz				goto done;
798220137Strasz			}
799220137Strasz		}
800220137Strasz	}
801220137Strasz	rc = ENOMEM;
802220137Strasz	goto fail2;
803220137Strasz
804220137Straszdone:
805220137Strasz	*handlep = enp->en_u.hunt.enu_piobuf_handle[buf];
806220137Strasz	*bufnump = buf;
807258622Savg	*blknump = blk;
808220137Strasz	*sizep = edcp->edc_pio_alloc_size;
809220137Strasz	*offsetp = blk * (*sizep);
810220137Strasz
811242139Strasz	return (0);
812243088Strasz
813220137Straszfail2:
814220137Strasz	EFSYS_PROBE(fail2);
815220137Straszfail1:
816220137Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
817220137Strasz
818221362Strasz	return (rc);
819221362Strasz}
820220137Strasz
821220137Strasz/* Free a piobuf sub-allocated block */
822220137Strasz	__checkReturn	efx_rc_t
823220137Straszhunt_nic_pio_free(
824220137Strasz	__inout		efx_nic_t *enp,
825220137Strasz	__in		uint32_t bufnum,
826220137Strasz	__in		uint32_t blknum)
827220137Strasz{
828220137Strasz	uint32_t *map;
829220137Strasz	efx_rc_t rc;
830220137Strasz
831220137Strasz	if ((bufnum >= enp->en_u.hunt.enu_piobuf_count) ||
832220137Strasz	    (blknum >= (8 * sizeof (*map)))) {
833220137Strasz		rc = EINVAL;
834220137Strasz		goto fail1;
835220137Strasz	}
836220137Strasz
837220137Strasz	map = &enp->en_u.hunt.enu_pio_alloc_map[bufnum];
838220137Strasz	if ((*map & (1u << blknum)) == 0) {
839220137Strasz		rc = ENOENT;
840220137Strasz		goto fail2;
841220137Strasz	}
842220137Strasz	*map &= ~(1u << blknum);
843220137Strasz
844220137Strasz	return (0);
845220137Strasz
846220137Straszfail2:
847220137Strasz	EFSYS_PROBE(fail2);
848220137Straszfail1:
849220137Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
850220137Strasz
851220137Strasz	return (rc);
852225981Strasz}
853225981Strasz
854225981Strasz	__checkReturn	efx_rc_t
855225981Straszhunt_nic_pio_link(
856225981Strasz	__inout		efx_nic_t *enp,
857225981Strasz	__in		uint32_t vi_index,
858242139Strasz	__in		efx_piobuf_handle_t handle)
859242139Strasz{
860242139Strasz	return (efx_mcdi_link_piobuf(enp, vi_index, handle));
861242139Strasz}
862220137Strasz
863220137Strasz	__checkReturn	efx_rc_t
864220137Straszhunt_nic_pio_unlink(
865220137Strasz	__inout		efx_nic_t *enp,
866220137Strasz	__in		uint32_t vi_index)
867223844Strasz{
868220137Strasz	return (efx_mcdi_unlink_piobuf(enp, vi_index));
869220137Strasz}
870220137Strasz
871220137Straszstatic	__checkReturn	efx_rc_t
872225938Straszhunt_get_datapath_caps(
873220137Strasz	__in		efx_nic_t *enp)
874220137Strasz{
875220137Strasz	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
876225944Strasz	efx_dword_t datapath_capabilities;
877225944Strasz	efx_rc_t rc;
878225944Strasz
879220137Strasz	if ((rc = efx_mcdi_get_capabilities(enp, &datapath_capabilities)) != 0)
880220137Strasz		goto fail1;
881220137Strasz
882220137Strasz	/*
883220137Strasz	 * Huntington RXDP firmware inserts a 0 or 14 byte prefix.
884235787Strasz	 * We only support the 14 byte prefix here.
885235787Strasz	 */
886235787Strasz	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
887220137Strasz		GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14) != 1) {
888220137Strasz		rc = ENOTSUP;
889220137Strasz		goto fail2;
890225940Strasz	}
891225940Strasz	encp->enc_rx_prefix_size = 14;
892225940Strasz
893225940Strasz	/* Check if the firmware supports TSO */
894220137Strasz	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
895225940Strasz				GET_CAPABILITIES_OUT_TX_TSO) == 1)
896225940Strasz		encp->enc_fw_assisted_tso_enabled = B_TRUE;
897225940Strasz	else
898225940Strasz		encp->enc_fw_assisted_tso_enabled = B_FALSE;
899225940Strasz
900225940Strasz	/* Check if the firmware has vadapter/vport/vswitch support */
901225940Strasz	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
902225940Strasz				GET_CAPABILITIES_OUT_EVB) == 1)
903225940Strasz		encp->enc_datapath_cap_evb = B_TRUE;
904225940Strasz	else
905225940Strasz		encp->enc_datapath_cap_evb = B_FALSE;
906225940Strasz
907225940Strasz	/* Check if the firmware supports VLAN insertion */
908225940Strasz	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
909220137Strasz				GET_CAPABILITIES_OUT_TX_VLAN_INSERTION) == 1)
910220137Strasz		encp->enc_hw_tx_insert_vlan_enabled = B_TRUE;
911225364Strasz	else
912220137Strasz		encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
913242139Strasz
914242139Strasz	/* Check if the firmware supports RX event batching */
915220137Strasz	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
916220137Strasz		GET_CAPABILITIES_OUT_RX_BATCHING) == 1) {
917220137Strasz		encp->enc_rx_batching_enabled = B_TRUE;
918220137Strasz		encp->enc_rx_batch_max = 16;
919220137Strasz	} else {
920220137Strasz		encp->enc_rx_batching_enabled = B_FALSE;
921220137Strasz	}
922220137Strasz
923220137Strasz	/* Check if the firmware supports disabling scatter on RXQs */
924220137Strasz	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
925220137Strasz			    GET_CAPABILITIES_OUT_RX_DISABLE_SCATTER) == 1) {
926220137Strasz		encp->enc_rx_disable_scatter_supported = B_TRUE;
927242139Strasz	} else {
928242139Strasz		encp->enc_rx_disable_scatter_supported = B_FALSE;
929242957Strasz	}
930242957Strasz
931242957Strasz	return (0);
932242957Strasz
933242957Straszfail2:
934242957Strasz	EFSYS_PROBE(fail2);
935242139Straszfail1:
936242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
937225364Strasz
938225364Strasz	return (rc);
939242139Strasz}
940220137Strasz
941225364Strasz/*
942225364Strasz * The external port mapping is a one-based numbering of the external
943225364Strasz * connectors on the board. It does not distinguish off-board separated
944225364Strasz * outputs such as multi-headed cables.
945225364Strasz * The number of ports that map to each external port connector
946225364Strasz * on the board is determined by the chip family and the port modes to
947225364Strasz * which the NIC can be configured. The mapping table lists modes with
948225364Strasz * port numbering requirements in increasing order.
949225364Strasz */
950220137Straszstatic struct {
951220137Strasz	efx_family_t	family;
952220137Strasz	uint32_t	modes_mask;
953220137Strasz	uint32_t	stride;
954220137Strasz}	__hunt_external_port_mappings[] = {
955220137Strasz	/* Supported modes requiring 1 output per port */
956220137Strasz	{
957220137Strasz		EFX_FAMILY_HUNTINGTON,
958220137Strasz		(1 << TLV_PORT_MODE_10G) |
959220137Strasz		(1 << TLV_PORT_MODE_10G_10G) |
960220137Strasz		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
961220137Strasz		1
962220137Strasz	},
963220137Strasz	/* Supported modes requiring 2 outputs per port */
964220137Strasz	{
965220137Strasz		EFX_FAMILY_HUNTINGTON,
966220137Strasz		(1 << TLV_PORT_MODE_40G) |
967220137Strasz		(1 << TLV_PORT_MODE_40G_40G) |
968220137Strasz		(1 << TLV_PORT_MODE_40G_10G_10G) |
969220137Strasz		(1 << TLV_PORT_MODE_10G_10G_40G),
970220137Strasz		2
971220137Strasz	}
972220137Strasz	/*
973220137Strasz	 * NOTE: Medford modes will require 4 outputs per port:
974220137Strasz	 *	TLV_PORT_MODE_10G_10G_10G_10G_Q
975220137Strasz	 *	TLV_PORT_MODE_10G_10G_10G_10G_Q2
976220137Strasz	 * The Q2 mode routes outputs to external port 2. Support for this
977220137Strasz	 * will require a new field specifying the number to add after
978220137Strasz	 * scaling by stride. This is fixed at 1 currently.
979220137Strasz	 */
980220137Strasz};
981220137Strasz
982220137Straszstatic	__checkReturn	efx_rc_t
983220137Straszhunt_external_port_mapping(
984220137Strasz	__in		efx_nic_t *enp,
985220137Strasz	__in		uint32_t port,
986220137Strasz	__out		uint8_t *external_portp)
987220137Strasz{
988220137Strasz	efx_rc_t rc;
989220137Strasz	int i;
990221362Strasz	uint32_t port_modes;
991221362Strasz	uint32_t matches;
992220137Strasz	uint32_t stride = 1; /* default 1-1 mapping */
993221362Strasz
994221362Strasz	if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) {
995220137Strasz		/* No port mode information available - use default mapping */
996220137Strasz		goto out;
997220137Strasz	}
998220137Strasz
999220137Strasz	/*
1000220137Strasz	 * Infer the internal port -> external port mapping from
1001220137Strasz	 * the possible port modes for this NIC.
1002220137Strasz	 */
1003232598Strasz	for (i = 0; i < EFX_ARRAY_SIZE(__hunt_external_port_mappings); ++i) {
1004232598Strasz		if (__hunt_external_port_mappings[i].family !=
1005232598Strasz		    enp->en_family)
1006232598Strasz			continue;
1007232598Strasz		matches = (__hunt_external_port_mappings[i].modes_mask &
1008232598Strasz		    port_modes);
1009232598Strasz		if (matches != 0) {
1010232598Strasz			stride = __hunt_external_port_mappings[i].stride;
1011232598Strasz			port_modes &= ~matches;
1012232598Strasz		}
1013232598Strasz	}
1014232598Strasz
1015220137Strasz	if (port_modes != 0) {
1016242139Strasz		/* Some advertised modes are not supported */
1017242139Strasz		rc = ENOTSUP;
1018242139Strasz		goto fail1;
1019242139Strasz	}
1020242139Strasz
1021242139Straszout:
1022242139Strasz	/*
1023242139Strasz	 * Scale as required by last matched mode and then convert to
1024242139Strasz	 * one-based numbering
1025242139Strasz	 */
1026242139Strasz	*external_portp = (uint8_t)(port / stride) + 1;
1027242139Strasz	return (0);
1028242139Strasz
1029242139Straszfail1:
1030242139Strasz	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1031242139Strasz
1032242139Strasz	return (rc);
1033242139Strasz}
1034242139Strasz
1035248298Straszstatic	__checkReturn	efx_rc_t
1036242139Straszhunt_board_cfg(
1037242139Strasz	__in		efx_nic_t *enp)
1038242139Strasz{
1039242139Strasz	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1040242139Strasz	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1041242139Strasz	uint8_t mac_addr[6];
1042242139Strasz	uint32_t board_type = 0;
1043242139Strasz	hunt_link_state_t hls;
1044242139Strasz	efx_port_t *epp = &(enp->en_port);
1045242139Strasz	uint32_t port;
1046242139Strasz	uint32_t pf;
1047242139Strasz	uint32_t vf;
1048242139Strasz	uint32_t mask;
1049242139Strasz	uint32_t flags;
1050242139Strasz	uint32_t sysclk;
1051242139Strasz	uint32_t base, nvec;
1052242139Strasz	efx_rc_t rc;
1053242139Strasz
1054242139Strasz	if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0)
1055242139Strasz		goto fail1;
1056242139Strasz
1057242139Strasz	/*
1058242139Strasz	 * NOTE: The MCDI protocol numbers ports from zero.
1059242139Strasz	 * The common code MCDI interface numbers ports from one.
1060242139Strasz	 */
1061248298Strasz	emip->emi_port = port + 1;
1062242139Strasz
1063242139Strasz	if ((rc = hunt_external_port_mapping(enp, port,
1064242139Strasz		    &encp->enc_external_port)) != 0)
1065242139Strasz		goto fail2;
1066242139Strasz
1067242139Strasz	/*
1068242139Strasz	 * Get PCIe function number from firmware (used for
1069242139Strasz	 * per-function privilege and dynamic config info).
1070242139Strasz	 *  - PCIe PF: pf = PF number, vf = 0xffff.
1071242139Strasz	 *  - PCIe VF: pf = parent PF, vf = VF number.
1072242139Strasz	 */
1073242139Strasz	if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0)
1074242139Strasz		goto fail3;
1075242139Strasz
1076242139Strasz	encp->enc_pf = pf;
1077242139Strasz	encp->enc_vf = vf;
1078242139Strasz
1079242139Strasz	/* MAC address for this function */
1080242139Strasz	if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1081242139Strasz		rc = efx_mcdi_get_mac_address_pf(enp, mac_addr);
1082242139Strasz		if ((rc == 0) && (mac_addr[0] & 0x02)) {
1083242139Strasz			/*
1084242139Strasz			 * If the static config does not include a global MAC
1085242139Strasz			 * address pool then the board may return a locally
1086242139Strasz			 * administered MAC address (this should only happen on
1087242139Strasz			 * incorrectly programmed boards).
1088242139Strasz			 */
1089242139Strasz			rc = EINVAL;
1090242139Strasz		}
1091242139Strasz	} else {
1092242139Strasz		rc = efx_mcdi_get_mac_address_vf(enp, mac_addr);
1093242139Strasz	}
1094242139Strasz	if (rc != 0)
1095242139Strasz		goto fail4;
1096242139Strasz
1097242139Strasz	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
1098242139Strasz
1099242139Strasz	/* Board configuration */
1100242139Strasz	rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL);
1101242139Strasz	if (rc != 0) {
1102242139Strasz		/* Unprivileged functions may not be able to read board cfg */
1103242139Strasz		if (rc == EACCES)
1104220137Strasz			board_type = 0;
1105220137Strasz		else
1106220137Strasz			goto fail5;
1107220137Strasz	}
1108220137Strasz
1109220137Strasz	encp->enc_board_type = board_type;
1110242139Strasz	encp->enc_clk_mult = 1; /* not used for Huntington */
1111220137Strasz
1112220137Strasz	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
1113242139Strasz	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
1114242139Strasz		goto fail6;
1115220137Strasz
1116220137Strasz	/* Obtain the default PHY advertised capabilities */
1117242139Strasz	if ((rc = hunt_phy_get_link(enp, &hls)) != 0)
1118242139Strasz		goto fail7;
1119242139Strasz	epp->ep_default_adv_cap_mask = hls.hls_adv_cap_mask;
1120242139Strasz	epp->ep_adv_cap_mask = hls.hls_adv_cap_mask;
1121242139Strasz
1122242139Strasz	/*
1123220137Strasz	 * Enable firmware workarounds for hardware errata.
1124242139Strasz	 * Expected responses are:
1125242139Strasz	 *  - 0 (zero):
1126242139Strasz	 *	Success: workaround enabled or disabled as requested.
1127220137Strasz	 *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
1128242139Strasz	 *	Firmware does not support the MC_CMD_WORKAROUND request.
1129220137Strasz	 *	(assume that the workaround is not supported).
1130220137Strasz	 *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
1131220137Strasz	 *	Firmware does not support the requested workaround.
1132220137Strasz	 *  - MC_CMD_ERR_EPERM  (reported as EACCES):
1133232782Strasz	 *	Unprivileged function cannot enable/disable workarounds.
1134220137Strasz	 *
1135220137Strasz	 * See efx_mcdi_request_errcode() for MCDI error translations.
1136220137Strasz	 */
1137220137Strasz
1138220137Strasz	/*
1139220137Strasz	 * If the bug35388 workaround is enabled, then use an indirect access
1140220137Strasz	 * method to avoid unsafe EVQ writes.
1141220137Strasz	 */
1142220137Strasz	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE,
1143220137Strasz	    NULL);
1144220137Strasz	if ((rc == 0) || (rc == EACCES))
1145242957Strasz		encp->enc_bug35388_workaround = B_TRUE;
1146242957Strasz	else if ((rc == ENOTSUP) || (rc == ENOENT))
1147242957Strasz		encp->enc_bug35388_workaround = B_FALSE;
1148242957Strasz	else
1149242957Strasz		goto fail8;
1150242957Strasz
1151242139Strasz	/*
1152220137Strasz	 * If the bug41750 workaround is enabled, then do not test interrupts,
1153242139Strasz	 * as the test will fail (seen with Greenport controllers).
1154220137Strasz	 */
1155220137Strasz	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE,
1156233126Sjh	    NULL);
1157233126Sjh	if (rc == 0) {
1158220137Strasz		encp->enc_bug41750_workaround = B_TRUE;
1159220137Strasz	} else if (rc == EACCES) {
1160220137Strasz		/* Assume a controller with 40G ports needs the workaround. */
1161242139Strasz		if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX)
1162242139Strasz			encp->enc_bug41750_workaround = B_TRUE;
1163242139Strasz		else
1164242139Strasz			encp->enc_bug41750_workaround = B_FALSE;
1165242139Strasz	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
1166242139Strasz		encp->enc_bug41750_workaround = B_FALSE;
1167242139Strasz	} else {
1168242139Strasz		goto fail9;
1169242139Strasz	}
1170242139Strasz	if (EFX_PCI_FUNCTION_IS_VF(encp)) {
1171242139Strasz		/* Interrupt testing does not work for VFs. See bug50084. */
1172242139Strasz		encp->enc_bug41750_workaround = B_TRUE;
1173242139Strasz	}
1174242139Strasz
1175242139Strasz	/*
1176242139Strasz	 * If the bug26807 workaround is enabled, then firmware has enabled
1177242139Strasz	 * support for chained multicast filters. Firmware will reset (FLR)
1178242139Strasz	 * functions which have filters in the hardware filter table when the
1179242139Strasz	 * workaround is enabled/disabled.
1180242139Strasz	 *
1181220137Strasz	 * We must recheck if the workaround is enabled after inserting the
1182220137Strasz	 * first hardware filter, in case it has been changed since this check.
1183220137Strasz	 */
1184220137Strasz	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807,
1185220137Strasz	    B_TRUE, &flags);
1186220137Strasz	if (rc == 0) {
1187220137Strasz		encp->enc_bug26807_workaround = B_TRUE;
1188220137Strasz		if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) {
1189220137Strasz			/*
1190220137Strasz			 * Other functions had installed filters before the
1191220137Strasz			 * workaround was enabled, and they have been reset
1192220137Strasz			 * by firmware.
1193220137Strasz			 */
1194220137Strasz			EFSYS_PROBE(bug26807_workaround_flr_done);
1195220137Strasz			/* FIXME: bump MC warm boot count ? */
1196220137Strasz		}
1197220137Strasz	} else if (rc == EACCES) {
1198220137Strasz		/*
1199220137Strasz		 * Unprivileged functions cannot enable the workaround in older
1200220137Strasz		 * firmware.
1201220137Strasz		 */
1202221362Strasz		encp->enc_bug26807_workaround = B_FALSE;
1203220137Strasz	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
1204220137Strasz		encp->enc_bug26807_workaround = B_FALSE;
1205220137Strasz	} else {
1206220137Strasz		goto fail10;
1207220137Strasz	}
1208220137Strasz
1209220137Strasz	/* Get sysclk frequency (in MHz). */
1210220137Strasz	if ((rc = efx_mcdi_get_clock(enp, &sysclk)) != 0)
1211220137Strasz		goto fail11;
1212220137Strasz
1213220137Strasz	/*
1214220137Strasz	 * The timer quantum is 1536 sysclk cycles, documented for the
1215220137Strasz	 * EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units.
1216220137Strasz	 */
1217220137Strasz	encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */
1218220137Strasz	if (encp->enc_bug35388_workaround) {
1219220137Strasz		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
1220220137Strasz		ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000;
1221220137Strasz	} else {
1222220137Strasz		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
1223220137Strasz		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
1224220137Strasz	}
1225220137Strasz
1226220137Strasz	/* Check capabilities of running datapath firmware */
1227220137Strasz	if ((rc = hunt_get_datapath_caps(enp)) != 0)
1228220137Strasz	    goto fail12;
1229220137Strasz
1230220137Strasz	/* Alignment for receive packet DMA buffers */
1231220137Strasz	encp->enc_rx_buf_align_start = 1;
1232220137Strasz	encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */
1233220137Strasz
1234220137Strasz	/* Alignment for WPTR updates */
1235220372Strasz	encp->enc_rx_push_align = HUNTINGTON_RX_WPTR_ALIGN;
1236220372Strasz
1237220372Strasz	/*
1238220372Strasz	 * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use
1239220372Strasz	 * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available
1240220137Strasz	 * resources (allocated to this PCIe function), which is zero until
1241220137Strasz	 * after we have allocated VIs.
1242220137Strasz	 */
1243220137Strasz	encp->enc_evq_limit = 1024;
1244220137Strasz	encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
1245220137Strasz	encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;
1246220137Strasz
1247220137Strasz	encp->enc_buftbl_limit = 0xFFFFFFFF;
1248220137Strasz
1249220137Strasz	encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS;
1250220137Strasz	encp->enc_piobuf_size = HUNT_PIOBUF_SIZE;
1251220137Strasz
1252220137Strasz	/*
1253220137Strasz	 * Get the current privilege mask. Note that this may be modified
1254220137Strasz	 * dynamically, so this value is informational only. DO NOT use
1255220137Strasz	 * the privilege mask to check for sufficient privileges, as that
1256220372Strasz	 * can result in time-of-check/time-of-use bugs.
1257220372Strasz	 */
1258220372Strasz	if ((rc = efx_mcdi_privilege_mask(enp, pf, vf, &mask)) != 0) {
1259220372Strasz		if (rc != ENOTSUP)
1260220372Strasz			goto fail13;
1261220372Strasz
1262220372Strasz		/* Fallback for old firmware without privilege mask support */
1263220137Strasz		if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1264220137Strasz			/* Assume PF has admin privilege */
1265220137Strasz			mask = HUNT_LEGACY_PF_PRIVILEGE_MASK;
1266220137Strasz		} else {
1267220137Strasz			/* VF is always unprivileged by default */
1268220137Strasz			mask = HUNT_LEGACY_VF_PRIVILEGE_MASK;
1269220137Strasz		}
1270220137Strasz	}
1271220137Strasz
1272220137Strasz	encp->enc_privilege_mask = mask;
1273220137Strasz
1274220137Strasz	/* Get interrupt vector limits */
1275220137Strasz	if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) {
1276220137Strasz		if (EFX_PCI_FUNCTION_IS_PF(encp))
1277220137Strasz			goto fail14;
1278220137Strasz
1279220137Strasz		/* Ignore error (cannot query vector limits from a VF). */
1280220137Strasz		base = 0;
1281225940Strasz		nvec = 1024;
1282225940Strasz	}
1283225940Strasz	encp->enc_intr_vec_base = base;
1284225940Strasz	encp->enc_intr_limit = nvec;
1285225940Strasz
1286220137Strasz	/*
1287220137Strasz	 * Maximum number of bytes into the frame the TCP header can start for
1288220137Strasz	 * firmware assisted TSO to work.
1289220137Strasz	 */
1290220137Strasz	encp->enc_tx_tso_tcp_header_offset_limit = 208;
1291
1292	return (0);
1293
1294fail14:
1295	EFSYS_PROBE(fail14);
1296fail13:
1297	EFSYS_PROBE(fail13);
1298fail12:
1299	EFSYS_PROBE(fail12);
1300fail11:
1301	EFSYS_PROBE(fail11);
1302fail10:
1303	EFSYS_PROBE(fail10);
1304fail9:
1305	EFSYS_PROBE(fail9);
1306fail8:
1307	EFSYS_PROBE(fail8);
1308fail7:
1309	EFSYS_PROBE(fail7);
1310fail6:
1311	EFSYS_PROBE(fail6);
1312fail5:
1313	EFSYS_PROBE(fail5);
1314fail4:
1315	EFSYS_PROBE(fail4);
1316fail3:
1317	EFSYS_PROBE(fail3);
1318fail2:
1319	EFSYS_PROBE(fail2);
1320fail1:
1321	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1322
1323	return (rc);
1324}
1325
1326
1327	__checkReturn	efx_rc_t
1328hunt_nic_probe(
1329	__in		efx_nic_t *enp)
1330{
1331	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1332	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1333	efx_rc_t rc;
1334
1335	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
1336
1337	/* Read and clear any assertion state */
1338	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1339		goto fail1;
1340
1341	/* Exit the assertion handler */
1342	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1343		if (rc != EACCES)
1344			goto fail2;
1345
1346	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
1347		goto fail3;
1348
1349	if ((rc = hunt_board_cfg(enp)) != 0)
1350		if (rc != EACCES)
1351			goto fail4;
1352
1353	/*
1354	 * Set default driver config limits (based on board config).
1355	 *
1356	 * FIXME: For now allocate a fixed number of VIs which is likely to be
1357	 * sufficient and small enough to allow multiple functions on the same
1358	 * port.
1359	 */
1360	edcp->edc_min_vi_count = edcp->edc_max_vi_count =
1361	    MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit));
1362
1363	/* The client driver must configure and enable PIO buffer support */
1364	edcp->edc_max_piobuf_count = 0;
1365	edcp->edc_pio_alloc_size = 0;
1366
1367#if EFSYS_OPT_MAC_STATS
1368	/* Wipe the MAC statistics */
1369	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
1370		goto fail5;
1371#endif
1372
1373#if EFSYS_OPT_LOOPBACK
1374	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
1375		goto fail6;
1376#endif
1377
1378#if EFSYS_OPT_MON_STATS
1379	if ((rc = mcdi_mon_cfg_build(enp)) != 0) {
1380		/* Unprivileged functions do not have access to sensors */
1381		if (rc != EACCES)
1382			goto fail7;
1383	}
1384#endif
1385
1386	encp->enc_features = enp->en_features;
1387
1388	return (0);
1389
1390#if EFSYS_OPT_MON_STATS
1391fail7:
1392	EFSYS_PROBE(fail7);
1393#endif
1394#if EFSYS_OPT_LOOPBACK
1395fail6:
1396	EFSYS_PROBE(fail6);
1397#endif
1398#if EFSYS_OPT_MAC_STATS
1399fail5:
1400	EFSYS_PROBE(fail5);
1401#endif
1402fail4:
1403	EFSYS_PROBE(fail4);
1404fail3:
1405	EFSYS_PROBE(fail3);
1406fail2:
1407	EFSYS_PROBE(fail2);
1408fail1:
1409	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1410
1411	return (rc);
1412}
1413
1414	__checkReturn	efx_rc_t
1415hunt_nic_set_drv_limits(
1416	__inout		efx_nic_t *enp,
1417	__in		efx_drv_limits_t *edlp)
1418{
1419	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1420	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1421	uint32_t min_evq_count, max_evq_count;
1422	uint32_t min_rxq_count, max_rxq_count;
1423	uint32_t min_txq_count, max_txq_count;
1424	efx_rc_t rc;
1425
1426	if (edlp == NULL) {
1427		rc = EINVAL;
1428		goto fail1;
1429	}
1430
1431	/* Get minimum required and maximum usable VI limits */
1432	min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit);
1433	min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit);
1434	min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit);
1435
1436	edcp->edc_min_vi_count =
1437	    MAX(min_evq_count, MAX(min_rxq_count, min_txq_count));
1438
1439	max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit);
1440	max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit);
1441	max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit);
1442
1443	edcp->edc_max_vi_count =
1444	    MAX(max_evq_count, MAX(max_rxq_count, max_txq_count));
1445
1446	/*
1447	 * Check limits for sub-allocated piobuf blocks.
1448	 * PIO is optional, so don't fail if the limits are incorrect.
1449	 */
1450	if ((encp->enc_piobuf_size == 0) ||
1451	    (encp->enc_piobuf_limit == 0) ||
1452	    (edlp->edl_min_pio_alloc_size == 0) ||
1453	    (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) {
1454		/* Disable PIO */
1455		edcp->edc_max_piobuf_count = 0;
1456		edcp->edc_pio_alloc_size = 0;
1457	} else {
1458		uint32_t blk_size, blk_count, blks_per_piobuf;
1459
1460		blk_size =
1461		    MAX(edlp->edl_min_pio_alloc_size, HUNT_MIN_PIO_ALLOC_SIZE);
1462
1463		blks_per_piobuf = encp->enc_piobuf_size / blk_size;
1464		EFSYS_ASSERT3U(blks_per_piobuf, <=, 32);
1465
1466		blk_count = (encp->enc_piobuf_limit * blks_per_piobuf);
1467
1468		/* A zero max pio alloc count means unlimited */
1469		if ((edlp->edl_max_pio_alloc_count > 0) &&
1470		    (edlp->edl_max_pio_alloc_count < blk_count)) {
1471			blk_count = edlp->edl_max_pio_alloc_count;
1472		}
1473
1474		edcp->edc_pio_alloc_size = blk_size;
1475		edcp->edc_max_piobuf_count =
1476		    (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf;
1477	}
1478
1479	return (0);
1480
1481fail1:
1482	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1483
1484	return (rc);
1485}
1486
1487
1488	__checkReturn	efx_rc_t
1489hunt_nic_reset(
1490	__in		efx_nic_t *enp)
1491{
1492	efx_mcdi_req_t req;
1493	uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN,
1494			    MC_CMD_ENTITY_RESET_OUT_LEN)];
1495	efx_rc_t rc;
1496
1497	/* hunt_nic_reset() is called to recover from BADASSERT failures. */
1498	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1499		goto fail1;
1500	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1501		goto fail2;
1502
1503	(void) memset(payload, 0, sizeof (payload));
1504	req.emr_cmd = MC_CMD_ENTITY_RESET;
1505	req.emr_in_buf = payload;
1506	req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN;
1507	req.emr_out_buf = payload;
1508	req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN;
1509
1510	MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG,
1511	    ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1);
1512
1513	efx_mcdi_execute(enp, &req);
1514
1515	if (req.emr_rc != 0) {
1516		rc = req.emr_rc;
1517		goto fail3;
1518	}
1519
1520	/* Clear RX/TX DMA queue errors */
1521	enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR);
1522
1523	return (0);
1524
1525fail3:
1526	EFSYS_PROBE(fail3);
1527fail2:
1528	EFSYS_PROBE(fail2);
1529fail1:
1530	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1531
1532	return (rc);
1533}
1534
1535	__checkReturn	efx_rc_t
1536hunt_nic_init(
1537	__in		efx_nic_t *enp)
1538{
1539	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1540	uint32_t min_vi_count, max_vi_count;
1541	uint32_t vi_count, vi_base;
1542	uint32_t i;
1543	uint32_t retry;
1544	uint32_t delay_us;
1545	efx_rc_t rc;
1546
1547	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
1548
1549	/* Enable reporting of some events (e.g. link change) */
1550	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
1551		goto fail1;
1552
1553	/* Allocate (optional) on-chip PIO buffers */
1554	hunt_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count);
1555
1556	/*
1557	 * For best performance, PIO writes should use a write-combined
1558	 * (WC) memory mapping. Using a separate WC mapping for the PIO
1559	 * aperture of each VI would be a burden to drivers (and not
1560	 * possible if the host page size is >4Kbyte).
1561	 *
1562	 * To avoid this we use a single uncached (UC) mapping for VI
1563	 * register access, and a single WC mapping for extra VIs used
1564	 * for PIO writes.
1565	 *
1566	 * Each piobuf must be linked to a VI in the WC mapping, and to
1567	 * each VI that is using a sub-allocated block from the piobuf.
1568	 */
1569	min_vi_count = edcp->edc_min_vi_count;
1570	max_vi_count = edcp->edc_max_vi_count + enp->en_u.hunt.enu_piobuf_count;
1571
1572	/* Ensure that the previously attached driver's VIs are freed */
1573	if ((rc = efx_mcdi_free_vis(enp)) != 0)
1574		goto fail2;
1575
1576	/*
1577	 * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this
1578	 * fails then retrying the request for fewer VI resources may succeed.
1579	 */
1580	vi_count = 0;
1581	if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count,
1582		    &vi_base, &vi_count)) != 0)
1583		goto fail3;
1584
1585	EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count);
1586
1587	if (vi_count < min_vi_count) {
1588		rc = ENOMEM;
1589		goto fail4;
1590	}
1591
1592	enp->en_u.hunt.enu_vi_base = vi_base;
1593	enp->en_u.hunt.enu_vi_count = vi_count;
1594
1595	if (vi_count < min_vi_count + enp->en_u.hunt.enu_piobuf_count) {
1596		/* Not enough extra VIs to map piobufs */
1597		hunt_nic_free_piobufs(enp);
1598	}
1599
1600	enp->en_u.hunt.enu_pio_write_vi_base =
1601	    vi_count - enp->en_u.hunt.enu_piobuf_count;
1602
1603	/* Save UC memory mapping details */
1604	enp->en_u.hunt.enu_uc_mem_map_offset = 0;
1605	if (enp->en_u.hunt.enu_piobuf_count > 0) {
1606		enp->en_u.hunt.enu_uc_mem_map_size =
1607		    (ER_DZ_TX_PIOBUF_STEP *
1608		    enp->en_u.hunt.enu_pio_write_vi_base);
1609	} else {
1610		enp->en_u.hunt.enu_uc_mem_map_size =
1611		    (ER_DZ_TX_PIOBUF_STEP *
1612		    enp->en_u.hunt.enu_vi_count);
1613	}
1614
1615	/* Save WC memory mapping details */
1616	enp->en_u.hunt.enu_wc_mem_map_offset =
1617	    enp->en_u.hunt.enu_uc_mem_map_offset +
1618	    enp->en_u.hunt.enu_uc_mem_map_size;
1619
1620	enp->en_u.hunt.enu_wc_mem_map_size =
1621	    (ER_DZ_TX_PIOBUF_STEP *
1622	    enp->en_u.hunt.enu_piobuf_count);
1623
1624	/* Link piobufs to extra VIs in WC mapping */
1625	if (enp->en_u.hunt.enu_piobuf_count > 0) {
1626		for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) {
1627			rc = efx_mcdi_link_piobuf(enp,
1628			    enp->en_u.hunt.enu_pio_write_vi_base + i,
1629			    enp->en_u.hunt.enu_piobuf_handle[i]);
1630			if (rc != 0)
1631				break;
1632		}
1633	}
1634
1635	/*
1636	 * Allocate a vAdaptor attached to our upstream vPort/pPort.
1637	 *
1638	 * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF
1639	 * driver has yet to bring up the EVB port. See bug 56147. In this case,
1640	 * retry the request several times after waiting a while. The wait time
1641	 * between retries starts small (10ms) and exponentially increases.
1642	 * Total wait time is a little over two seconds. Retry logic in the
1643	 * client driver may mean this whole loop is repeated if it continues to
1644	 * fail.
1645	 */
1646	retry = 0;
1647	delay_us = 10000;
1648	while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) {
1649		if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) ||
1650		    (rc != ENOENT)) {
1651			/*
1652			 * Do not retry alloc for PF, or for other errors on
1653			 * a VF.
1654			 */
1655			goto fail5;
1656		}
1657
1658		/* VF startup before PF is ready. Retry allocation. */
1659		if (retry > 5) {
1660			/* Too many attempts */
1661			rc = EINVAL;
1662			goto fail6;
1663		}
1664		EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry);
1665		EFSYS_SLEEP(delay_us);
1666		retry++;
1667		if (delay_us < 500000)
1668			delay_us <<= 2;
1669	}
1670
1671	enp->en_vport_id = EVB_PORT_ID_ASSIGNED;
1672
1673	return (0);
1674
1675fail6:
1676	EFSYS_PROBE(fail6);
1677fail5:
1678	EFSYS_PROBE(fail5);
1679fail4:
1680	EFSYS_PROBE(fail4);
1681fail3:
1682	EFSYS_PROBE(fail3);
1683fail2:
1684	EFSYS_PROBE(fail2);
1685
1686	hunt_nic_free_piobufs(enp);
1687
1688fail1:
1689	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1690
1691	return (rc);
1692}
1693
1694	__checkReturn	efx_rc_t
1695hunt_nic_get_vi_pool(
1696	__in		efx_nic_t *enp,
1697	__out		uint32_t *vi_countp)
1698{
1699	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
1700
1701	/*
1702	 * Report VIs that the client driver can use.
1703	 * Do not include VIs used for PIO buffer writes.
1704	 */
1705	*vi_countp = enp->en_u.hunt.enu_pio_write_vi_base;
1706
1707	return (0);
1708}
1709
1710	__checkReturn	efx_rc_t
1711hunt_nic_get_bar_region(
1712	__in		efx_nic_t *enp,
1713	__in		efx_nic_region_t region,
1714	__out		uint32_t *offsetp,
1715	__out		size_t *sizep)
1716{
1717	efx_rc_t rc;
1718
1719	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
1720
1721	/*
1722	 * TODO: Specify host memory mapping alignment and granularity
1723	 * in efx_drv_limits_t so that they can be taken into account
1724	 * when allocating extra VIs for PIO writes.
1725	 */
1726	switch (region) {
1727	case EFX_REGION_VI:
1728		/* UC mapped memory BAR region for VI registers */
1729		*offsetp = enp->en_u.hunt.enu_uc_mem_map_offset;
1730		*sizep = enp->en_u.hunt.enu_uc_mem_map_size;
1731		break;
1732
1733	case EFX_REGION_PIO_WRITE_VI:
1734		/* WC mapped memory BAR region for piobuf writes */
1735		*offsetp = enp->en_u.hunt.enu_wc_mem_map_offset;
1736		*sizep = enp->en_u.hunt.enu_wc_mem_map_size;
1737		break;
1738
1739	default:
1740		rc = EINVAL;
1741		goto fail1;
1742	}
1743
1744	return (0);
1745
1746fail1:
1747	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1748
1749	return (rc);
1750}
1751
1752			void
1753hunt_nic_fini(
1754	__in		efx_nic_t *enp)
1755{
1756	uint32_t i;
1757	efx_rc_t rc;
1758
1759	(void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id);
1760	enp->en_vport_id = 0;
1761
1762	/* Unlink piobufs from extra VIs in WC mapping */
1763	if (enp->en_u.hunt.enu_piobuf_count > 0) {
1764		for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) {
1765			rc = efx_mcdi_unlink_piobuf(enp,
1766			    enp->en_u.hunt.enu_pio_write_vi_base + i);
1767			if (rc != 0)
1768				break;
1769		}
1770	}
1771
1772	hunt_nic_free_piobufs(enp);
1773
1774	(void) efx_mcdi_free_vis(enp);
1775	enp->en_u.hunt.enu_vi_count = 0;
1776}
1777
1778			void
1779hunt_nic_unprobe(
1780	__in		efx_nic_t *enp)
1781{
1782#if EFSYS_OPT_MON_STATS
1783	mcdi_mon_cfg_free(enp);
1784#endif /* EFSYS_OPT_MON_STATS */
1785	(void) efx_mcdi_drv_attach(enp, B_FALSE);
1786}
1787
1788#if EFSYS_OPT_DIAG
1789
1790	__checkReturn	efx_rc_t
1791hunt_nic_register_test(
1792	__in		efx_nic_t *enp)
1793{
1794	efx_rc_t rc;
1795
1796	/* FIXME */
1797	_NOTE(ARGUNUSED(enp))
1798	if (B_FALSE) {
1799		rc = ENOTSUP;
1800		goto fail1;
1801	}
1802	/* FIXME */
1803
1804	return (0);
1805
1806fail1:
1807	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1808
1809	return (rc);
1810}
1811
1812#endif	/* EFSYS_OPT_DIAG */
1813
1814
1815
1816#endif	/* EFSYS_OPT_HUNTINGTON */
1817