ef10_nic.c revision 291393
1193323Sed/*-
2193323Sed * Copyright (c) 2012-2015 Solarflare Communications Inc.
3193323Sed * All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that the following conditions are met:
7193323Sed *
8193323Sed * 1. Redistributions of source code must retain the above copyright notice,
9193323Sed *    this list of conditions and the following disclaimer.
10193323Sed * 2. Redistributions in binary form must reproduce the above copyright notice,
11193323Sed *    this list of conditions and the following disclaimer in the documentation
12193323Sed *    and/or other materials provided with the distribution.
13193323Sed *
14210299Sed * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15193323Sed * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16218893Sdim * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17193323Sed * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18226633Sdim * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19193323Sed * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20193323Sed * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21193323Sed * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22193323Sed * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23193323Sed * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24198090Srdivacky * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25193323Sed *
26193323Sed * The views and conclusions contained in the software and documentation are
27193323Sed * those of the authors and should not be interpreted as representing official
28193323Sed * policies, either expressed or implied, of the FreeBSD Project.
29193323Sed */
30193323Sed
31193323Sed#include <sys/cdefs.h>
32207631Srdivacky__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_nic.c 291393 2015-11-27 16:03:51Z arybchik $");
33193323Sed
34193323Sed#include "efsys.h"
35198090Srdivacky#include "efx.h"
36198090Srdivacky#include "efx_impl.h"
37198090Srdivacky#include "mcdi_mon.h"
38193323Sed
39193323Sed#if EFSYS_OPT_HUNTINGTON
40212904Sdim
41212904Sdim#include "ef10_tlv_layout.h"
42212904Sdim
43212904Sdimstatic	__checkReturn	int
44212904Sdimefx_mcdi_get_port_assignment(
45218893Sdim	__in		efx_nic_t *enp,
46218893Sdim	__out		uint32_t *portp)
47218893Sdim{
48221345Sdim	efx_mcdi_req_t req;
49218893Sdim	uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN,
50193323Sed			    MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)];
51193323Sed	int rc;
52193323Sed
53193323Sed	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
54193323Sed
55218893Sdim	(void) memset(payload, 0, sizeof (payload));
56218893Sdim	req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT;
57218893Sdim	req.emr_in_buf = payload;
58218893Sdim	req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN;
59218893Sdim	req.emr_out_buf = payload;
60218893Sdim	req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN;
61193323Sed
62195098Sed	efx_mcdi_execute(enp, &req);
63218893Sdim
64193323Sed	if (req.emr_rc != 0) {
65193323Sed		rc = req.emr_rc;
66193323Sed		goto fail1;
67193323Sed	}
68193323Sed
69193323Sed	if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) {
70198090Srdivacky		rc = EMSGSIZE;
71198090Srdivacky		goto fail2;
72198090Srdivacky	}
73218893Sdim
74218893Sdim	*portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT);
75193323Sed
76193323Sed	return (0);
77193323Sed
78193323Sedfail2:
79194612Sed	EFSYS_PROBE(fail2);
80194612Sedfail1:
81198090Srdivacky	EFSYS_PROBE1(fail1, int, rc);
82198090Srdivacky
83194612Sed	return (rc);
84194612Sed}
85194612Sed
86194612Sedstatic	__checkReturn	int
87202375Srdivackyefx_mcdi_get_port_modes(
88203954Srdivacky	__in		efx_nic_t *enp,
89218893Sdim	__out		uint32_t *modesp)
90218893Sdim{
91218893Sdim	efx_mcdi_req_t req;
92218893Sdim	uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN,
93226633Sdim			    MC_CMD_GET_PORT_MODES_OUT_LEN)];
94221345Sdim	int rc;
95221345Sdim
96226633Sdim	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
97226633Sdim
98226633Sdim	(void) memset(payload, 0, sizeof (payload));
99221345Sdim	req.emr_cmd = MC_CMD_GET_PORT_MODES;
100221345Sdim	req.emr_in_buf = payload;
101226633Sdim	req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN;
102221345Sdim	req.emr_out_buf = payload;
103226633Sdim	req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN;
104226633Sdim
105226633Sdim	efx_mcdi_execute(enp, &req);
106226633Sdim
107226633Sdim	if (req.emr_rc != 0) {
108221345Sdim		rc = req.emr_rc;
109218893Sdim		goto fail1;
110218893Sdim	}
111218893Sdim
112218893Sdim	/* Accept pre-Medford size (8 bytes - no CurrentMode field) */
113218893Sdim	if (req.emr_out_length_used <
114218893Sdim	    MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) {
115218893Sdim		rc = EMSGSIZE;
116218893Sdim		goto fail2;
117218893Sdim	}
118218893Sdim
119218893Sdim	*modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES);
120218893Sdim
121218893Sdim	return (0);
122218893Sdim
123218893Sdimfail2:
124218893Sdim	EFSYS_PROBE(fail2);
125218893Sdimfail1:
126218893Sdim	EFSYS_PROBE1(fail1, int, rc);
127218893Sdim
128218893Sdim	return (rc);
129218893Sdim}
130218893Sdim
131218893Sdim
132226633Sdimstatic	__checkReturn		int
133193323Sedefx_mcdi_vadaptor_alloc(
134226633Sdim	__in			efx_nic_t *enp,
135226633Sdim	__in			uint32_t port_id)
136226633Sdim{
137226633Sdim	efx_mcdi_req_t req;
138226633Sdim	uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN,
139218893Sdim			    MC_CMD_VADAPTOR_ALLOC_OUT_LEN)];
140193323Sed	int rc;
141202375Srdivacky
142193323Sed	EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL);
143218893Sdim
144193323Sed	(void) memset(payload, 0, sizeof (payload));
145218893Sdim	req.emr_cmd = MC_CMD_VADAPTOR_ALLOC;
146219077Sdim	req.emr_in_buf = payload;
147193323Sed	req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN;
148218893Sdim	req.emr_out_buf = payload;
149193323Sed	req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN;
150218893Sdim
151218893Sdim	MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
152218893Sdim
153218893Sdim	efx_mcdi_execute(enp, &req);
154218893Sdim
155218893Sdim	if (req.emr_rc != 0) {
156218893Sdim		rc = req.emr_rc;
157218893Sdim		goto fail1;
158218893Sdim	}
159218893Sdim
160218893Sdim	return (0);
161218893Sdim
162218893Sdimfail1:
163218893Sdim	EFSYS_PROBE1(fail1, int, rc);
164218893Sdim
165218893Sdim	return (rc);
166193323Sed}
167218893Sdim
168218893Sdimstatic	__checkReturn		int
169195098Sedefx_mcdi_vadaptor_free(
170218893Sdim	__in			efx_nic_t *enp,
171218893Sdim	__in			uint32_t port_id)
172195340Sed{
173202375Srdivacky	efx_mcdi_req_t req;
174195340Sed	uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN,
175218893Sdim			    MC_CMD_VADAPTOR_FREE_OUT_LEN)];
176195340Sed	int rc;
177195340Sed
178218893Sdim	(void) memset(payload, 0, sizeof (payload));
179218893Sdim	req.emr_cmd = MC_CMD_VADAPTOR_FREE;
180218893Sdim	req.emr_in_buf = payload;
181218893Sdim	req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN;
182218893Sdim	req.emr_out_buf = payload;
183218893Sdim	req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN;
184218893Sdim
185218893Sdim	MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
186218893Sdim
187218893Sdim	efx_mcdi_execute(enp, &req);
188218893Sdim
189218893Sdim	if (req.emr_rc != 0) {
190218893Sdim		rc = req.emr_rc;
191218893Sdim		goto fail1;
192218893Sdim	}
193218893Sdim
194193323Sed	return (0);
195193323Sed
196193323Sedfail1:
197193323Sed	EFSYS_PROBE1(fail1, int, rc);
198195340Sed
199195340Sed	return (rc);
200202375Srdivacky}
201202375Srdivacky
202195340Sedstatic	__checkReturn	int
203206083Srdivackyefx_mcdi_get_mac_address_pf(
204206083Srdivacky	__in			efx_nic_t *enp,
205198090Srdivacky	__out_ecount_opt(6)	uint8_t mac_addrp[6])
206206083Srdivacky{
207218893Sdim	efx_mcdi_req_t req;
208239462Sdim	uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN,
209239462Sdim			    MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)];
210198090Srdivacky	int rc;
211198113Srdivacky
212206083Srdivacky	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
213198113Srdivacky
214206083Srdivacky	(void) memset(payload, 0, sizeof (payload));
215218893Sdim	req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES;
216239462Sdim	req.emr_in_buf = payload;
217239462Sdim	req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN;
218198113Srdivacky	req.emr_out_buf = payload;
219198090Srdivacky	req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN;
220198090Srdivacky
221218893Sdim	efx_mcdi_execute(enp, &req);
222218893Sdim
223218893Sdim	if (req.emr_rc != 0) {
224239462Sdim		rc = req.emr_rc;
225198090Srdivacky		goto fail1;
226218893Sdim	}
227218893Sdim
228218893Sdim	if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) {
229218893Sdim		rc = EMSGSIZE;
230239462Sdim		goto fail2;
231218893Sdim	}
232210299Sed
233210299Sed	if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) {
234210299Sed		rc = ENOENT;
235210299Sed		goto fail3;
236210299Sed	}
237198090Srdivacky
238207618Srdivacky	if (mac_addrp != NULL) {
239198090Srdivacky		uint8_t *addrp;
240199989Srdivacky
241202375Srdivacky		addrp = MCDI_OUT2(req, uint8_t,
242202375Srdivacky		    GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE);
243199989Srdivacky
244199989Srdivacky		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
245202375Srdivacky	}
246199989Srdivacky
247199989Srdivacky	return (0);
248218893Sdim
249199989Srdivackyfail3:
250199989Srdivacky	EFSYS_PROBE(fail3);
251218893Sdimfail2:
252199989Srdivacky	EFSYS_PROBE(fail2);
253199989Srdivackyfail1:
254199989Srdivacky	EFSYS_PROBE1(fail1, int, rc);
255226633Sdim
256226633Sdim	return (rc);
257226633Sdim}
258208599Srdivacky
259208599Srdivackystatic	__checkReturn	int
260226633Sdimefx_mcdi_get_mac_address_vf(
261226633Sdim	__in			efx_nic_t *enp,
262195340Sed	__out_ecount_opt(6)	uint8_t mac_addrp[6])
263195340Sed{
264195340Sed	efx_mcdi_req_t req;
265195340Sed	uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN,
266195340Sed			    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)];
267198090Srdivacky	int rc;
268210299Sed
269210299Sed	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
270198090Srdivacky
271208599Srdivacky	(void) memset(payload, 0, sizeof (payload));
272208599Srdivacky	req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES;
273210299Sed	req.emr_in_buf = payload;
274210299Sed	req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN;
275208599Srdivacky	req.emr_out_buf = payload;
276208599Srdivacky	req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX;
277208599Srdivacky
278218893Sdim	MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID,
279218893Sdim	    EVB_PORT_ID_ASSIGNED);
280193323Sed
281193323Sed	efx_mcdi_execute(enp, &req);
282193323Sed
283198090Srdivacky	if (req.emr_rc != 0) {
284198090Srdivacky		rc = req.emr_rc;
285198090Srdivacky		goto fail1;
286198090Srdivacky	}
287198090Srdivacky
288198090Srdivacky	if (req.emr_out_length_used <
289198090Srdivacky	    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) {
290198090Srdivacky		rc = EMSGSIZE;
291198090Srdivacky		goto fail2;
292198090Srdivacky	}
293198090Srdivacky
294198090Srdivacky	if (MCDI_OUT_DWORD(req,
295198090Srdivacky		VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) {
296198090Srdivacky		rc = ENOENT;
297198090Srdivacky		goto fail3;
298198090Srdivacky	}
299198090Srdivacky
300198090Srdivacky	if (mac_addrp != NULL) {
301198090Srdivacky		uint8_t *addrp;
302198090Srdivacky
303198090Srdivacky		addrp = MCDI_OUT2(req, uint8_t,
304198090Srdivacky		    VPORT_GET_MAC_ADDRESSES_OUT_MACADDR);
305198090Srdivacky
306198090Srdivacky		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
307218893Sdim	}
308243830Sdim
309218893Sdim	return (0);
310218893Sdim
311226633Sdimfail3:
312218893Sdim	EFSYS_PROBE(fail3);
313218893Sdimfail2:
314226633Sdim	EFSYS_PROBE(fail2);
315198090Srdivackyfail1:
316218893Sdim	EFSYS_PROBE1(fail1, int, rc);
317218893Sdim
318218893Sdim	return (rc);
319218893Sdim}
320218893Sdim
321218893Sdimstatic	__checkReturn	int
322218893Sdimefx_mcdi_get_clock(
323218893Sdim	__in		efx_nic_t *enp,
324218893Sdim	__out		uint32_t *sys_freqp)
325218893Sdim{
326218893Sdim	efx_mcdi_req_t req;
327218893Sdim	uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN,
328218893Sdim			    MC_CMD_GET_CLOCK_OUT_LEN)];
329218893Sdim	int rc;
330218893Sdim
331218893Sdim	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
332218893Sdim
333218893Sdim	(void) memset(payload, 0, sizeof (payload));
334218893Sdim	req.emr_cmd = MC_CMD_GET_CLOCK;
335218893Sdim	req.emr_in_buf = payload;
336218893Sdim	req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN;
337218893Sdim	req.emr_out_buf = payload;
338218893Sdim	req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN;
339243830Sdim
340243830Sdim	efx_mcdi_execute(enp, &req);
341218893Sdim
342218893Sdim	if (req.emr_rc != 0) {
343218893Sdim		rc = req.emr_rc;
344218893Sdim		goto fail1;
345218893Sdim	}
346218893Sdim
347218893Sdim	if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) {
348218893Sdim		rc = EMSGSIZE;
349218893Sdim		goto fail2;
350224145Sdim	}
351224145Sdim
352218893Sdim	*sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ);
353224145Sdim	if (*sys_freqp == 0) {
354218893Sdim		rc = EINVAL;
355218893Sdim		goto fail3;
356218893Sdim	}
357218893Sdim
358218893Sdim	return (0);
359218893Sdim
360218893Sdimfail3:
361218893Sdim	EFSYS_PROBE(fail3);
362218893Sdimfail2:
363218893Sdim	EFSYS_PROBE(fail2);
364218893Sdimfail1:
365218893Sdim	EFSYS_PROBE1(fail1, int, rc);
366218893Sdim
367218893Sdim	return (rc);
368218893Sdim}
369218893Sdim
370218893Sdimstatic 	__checkReturn	int
371218893Sdimefx_mcdi_get_vector_cfg(
372218893Sdim	__in		efx_nic_t *enp,
373218893Sdim	__out_opt	uint32_t *vec_basep,
374218893Sdim	__out_opt	uint32_t *pf_nvecp,
375218893Sdim	__out_opt	uint32_t *vf_nvecp)
376218893Sdim{
377218893Sdim	efx_mcdi_req_t req;
378243830Sdim	uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN,
379218893Sdim			    MC_CMD_GET_VECTOR_CFG_OUT_LEN)];
380218893Sdim	int rc;
381218893Sdim
382218893Sdim	(void) memset(payload, 0, sizeof (payload));
383243830Sdim	req.emr_cmd = MC_CMD_GET_VECTOR_CFG;
384243830Sdim	req.emr_in_buf = payload;
385218893Sdim	req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN;
386218893Sdim	req.emr_out_buf = payload;
387226633Sdim	req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN;
388195340Sed
389226633Sdim	efx_mcdi_execute(enp, &req);
390226633Sdim
391226633Sdim	if (req.emr_rc != 0) {
392226633Sdim		rc = req.emr_rc;
393226633Sdim		goto fail1;
394226633Sdim	}
395226633Sdim
396226633Sdim	if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) {
397226633Sdim		rc = EMSGSIZE;
398226633Sdim		goto fail2;
399226633Sdim	}
400226633Sdim
401226633Sdim	if (vec_basep != NULL)
402226633Sdim		*vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE);
403226633Sdim	if (pf_nvecp != NULL)
404226633Sdim		*pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF);
405226633Sdim	if (vf_nvecp != NULL)
406226633Sdim		*vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF);
407226633Sdim
408226633Sdim	return (0);
409226633Sdim
410226633Sdimfail2:
411226633Sdim	EFSYS_PROBE(fail2);
412195340Sedfail1:
413221345Sdim	EFSYS_PROBE1(fail1, int, rc);
414221345Sdim
415212904Sdim	return (rc);
416212904Sdim}
417212904Sdim
418226633Sdimstatic	__checkReturn	int
419195340Sedefx_mcdi_get_capabilities(
420195340Sed	__in		efx_nic_t *enp,
421195340Sed	__out		efx_dword_t *flagsp)
422195340Sed{
423198090Srdivacky	efx_mcdi_req_t req;
424195340Sed	uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN,
425195340Sed			    MC_CMD_GET_CAPABILITIES_OUT_LEN)];
426226633Sdim	int rc;
427226633Sdim
428226633Sdim	(void) memset(payload, 0, sizeof (payload));
429226633Sdim	req.emr_cmd = MC_CMD_GET_CAPABILITIES;
430226633Sdim	req.emr_in_buf = payload;
431226633Sdim	req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
432195340Sed	req.emr_out_buf = payload;
433195340Sed	req.emr_out_length = MC_CMD_GET_CAPABILITIES_OUT_LEN;
434195340Sed
435195340Sed	efx_mcdi_execute(enp, &req);
436195340Sed
437226633Sdim	if (req.emr_rc != 0) {
438218893Sdim		rc = req.emr_rc;
439218893Sdim		goto fail1;
440218893Sdim	}
441218893Sdim
442218893Sdim	if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
443218893Sdim		rc = EMSGSIZE;
444218893Sdim		goto fail2;
445218893Sdim	}
446218893Sdim
447218893Sdim	*flagsp = *MCDI_OUT2(req, efx_dword_t, GET_CAPABILITIES_OUT_FLAGS1);
448218893Sdim
449218893Sdim	return (0);
450218893Sdim
451218893Sdimfail2:
452218893Sdim	EFSYS_PROBE(fail2);
453221345Sdimfail1:
454218893Sdim	EFSYS_PROBE1(fail1, int, rc);
455218893Sdim
456218893Sdim	return (rc);
457218893Sdim}
458218893Sdim
459218893Sdim
460218893Sdimstatic	__checkReturn	int
461218893Sdimefx_mcdi_alloc_vis(
462218893Sdim	__in		efx_nic_t *enp,
463218893Sdim	__in		uint32_t min_vi_count,
464218893Sdim	__in		uint32_t max_vi_count,
465218893Sdim	__out_opt	uint32_t *vi_basep,
466218893Sdim	__out		uint32_t *vi_countp)
467218893Sdim
468218893Sdim{
469218893Sdim	efx_mcdi_req_t req;
470218893Sdim	uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN,
471218893Sdim			    MC_CMD_ALLOC_VIS_OUT_LEN)];
472218893Sdim	int rc;
473218893Sdim
474218893Sdim	if (vi_countp == NULL) {
475218893Sdim		rc = EINVAL;
476218893Sdim		goto fail1;
477218893Sdim	}
478218893Sdim
479218893Sdim	(void) memset(payload, 0, sizeof (payload));
480218893Sdim	req.emr_cmd = MC_CMD_ALLOC_VIS;
481218893Sdim	req.emr_in_buf = payload;
482218893Sdim	req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN;
483218893Sdim	req.emr_out_buf = payload;
484218893Sdim	req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN;
485218893Sdim
486218893Sdim	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count);
487218893Sdim	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count);
488218893Sdim
489193323Sed	efx_mcdi_execute(enp, &req);
490218893Sdim
491243830Sdim	if (req.emr_rc != 0) {
492193323Sed		rc = req.emr_rc;
493193323Sed		goto fail2;
494193323Sed	}
495193323Sed
496193323Sed	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) {
497193323Sed		rc = EMSGSIZE;
498193323Sed		goto fail3;
499193323Sed	}
500193323Sed
501193323Sed	if (vi_basep != NULL)
502193323Sed		*vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE);
503193323Sed
504193323Sed	if (vi_countp != NULL)
505193323Sed		*vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT);
506193323Sed
507193323Sed	return (0);
508193323Sed
509193323Sedfail3:
510193323Sed	EFSYS_PROBE(fail3);
511193323Sedfail2:
512193323Sed	EFSYS_PROBE(fail2);
513193323Sedfail1:
514218893Sdim	EFSYS_PROBE1(fail1, int, rc);
515218893Sdim
516218893Sdim	return (rc);
517218893Sdim}
518218893Sdim
519218893Sdim
520218893Sdimstatic	__checkReturn	int
521218893Sdimefx_mcdi_free_vis(
522218893Sdim	__in		efx_nic_t *enp)
523218893Sdim{
524218893Sdim	efx_mcdi_req_t req;
525218893Sdim	int rc;
526218893Sdim
527218893Sdim	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0);
528218893Sdim	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0);
529226633Sdim
530226633Sdim	req.emr_cmd = MC_CMD_FREE_VIS;
531218893Sdim	req.emr_in_buf = NULL;
532218893Sdim	req.emr_in_length = 0;
533218893Sdim	req.emr_out_buf = NULL;
534218893Sdim	req.emr_out_length = 0;
535218893Sdim
536218893Sdim	efx_mcdi_execute_quiet(enp, &req);
537218893Sdim
538218893Sdim	/* Ignore ELREADY (no allocated VIs, so nothing to free) */
539218893Sdim	if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) {
540218893Sdim		rc = req.emr_rc;
541218893Sdim		goto fail1;
542218893Sdim	}
543218893Sdim
544218893Sdim	return (0);
545218893Sdim
546218893Sdimfail1:
547218893Sdim	EFSYS_PROBE1(fail1, int, rc);
548218893Sdim
549218893Sdim	return (rc);
550218893Sdim}
551218893Sdim
552218893Sdim
553218893Sdimstatic	__checkReturn	int
554218893Sdimefx_mcdi_alloc_piobuf(
555243830Sdim	__in		efx_nic_t *enp,
556243830Sdim	__out		efx_piobuf_handle_t *handlep)
557226633Sdim{
558218893Sdim	efx_mcdi_req_t req;
559218893Sdim	uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN,
560218893Sdim			    MC_CMD_ALLOC_PIOBUF_OUT_LEN)];
561218893Sdim	int rc;
562218893Sdim
563218893Sdim	if (handlep == NULL) {
564226633Sdim		rc = EINVAL;
565218893Sdim		goto fail1;
566218893Sdim	}
567218893Sdim
568218893Sdim	(void) memset(payload, 0, sizeof (payload));
569218893Sdim	req.emr_cmd = MC_CMD_ALLOC_PIOBUF;
570218893Sdim	req.emr_in_buf = payload;
571218893Sdim	req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN;
572218893Sdim	req.emr_out_buf = payload;
573218893Sdim	req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN;
574218893Sdim
575218893Sdim	efx_mcdi_execute_quiet(enp, &req);
576218893Sdim
577218893Sdim	if (req.emr_rc != 0) {
578218893Sdim		rc = req.emr_rc;
579218893Sdim		goto fail2;
580218893Sdim	}
581218893Sdim
582218893Sdim	if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) {
583218893Sdim		rc = EMSGSIZE;
584218893Sdim		goto fail3;
585218893Sdim	}
586218893Sdim
587218893Sdim	*handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE);
588218893Sdim
589218893Sdim	return (0);
590243830Sdim
591218893Sdimfail3:
592218893Sdim	EFSYS_PROBE(fail3);
593218893Sdimfail2:
594218893Sdim	EFSYS_PROBE(fail2);
595218893Sdimfail1:
596218893Sdim	EFSYS_PROBE1(fail1, int, rc);
597218893Sdim
598218893Sdim	return (rc);
599218893Sdim}
600218893Sdim
601218893Sdimstatic	__checkReturn	int
602218893Sdimefx_mcdi_free_piobuf(
603218893Sdim	__in		efx_nic_t *enp,
604218893Sdim	__in		efx_piobuf_handle_t handle)
605218893Sdim{
606218893Sdim	efx_mcdi_req_t req;
607218893Sdim	uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN,
608218893Sdim			    MC_CMD_FREE_PIOBUF_OUT_LEN)];
609218893Sdim	int rc;
610218893Sdim
611218893Sdim	(void) memset(payload, 0, sizeof (payload));
612218893Sdim	req.emr_cmd = MC_CMD_FREE_PIOBUF;
613218893Sdim	req.emr_in_buf = payload;
614218893Sdim	req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN;
615218893Sdim	req.emr_out_buf = payload;
616193323Sed	req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN;
617193323Sed
618193323Sed	MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle);
619193323Sed
620199989Srdivacky	efx_mcdi_execute_quiet(enp, &req);
621199989Srdivacky
622199989Srdivacky	if (req.emr_rc != 0) {
623193323Sed		rc = req.emr_rc;
624193323Sed		goto fail1;
625193323Sed	}
626193323Sed
627193323Sed	return (0);
628193323Sed
629218893Sdimfail1:
630193323Sed	EFSYS_PROBE1(fail1, int, rc);
631198090Srdivacky
632193323Sed	return (rc);
633218893Sdim}
634218893Sdim
635218893Sdimstatic	__checkReturn	int
636218893Sdimefx_mcdi_link_piobuf(
637218893Sdim	__in		efx_nic_t *enp,
638218893Sdim	__in		uint32_t vi_index,
639218893Sdim	__in		efx_piobuf_handle_t handle)
640218893Sdim{
641218893Sdim	efx_mcdi_req_t req;
642218893Sdim	uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN,
643193323Sed			    MC_CMD_LINK_PIOBUF_OUT_LEN)];
644218893Sdim	int rc;
645218893Sdim
646218893Sdim	(void) memset(payload, 0, sizeof (payload));
647218893Sdim	req.emr_cmd = MC_CMD_LINK_PIOBUF;
648193323Sed	req.emr_in_buf = payload;
649218893Sdim	req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN;
650218893Sdim	req.emr_out_buf = payload;
651218893Sdim	req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN;
652218893Sdim
653193323Sed	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle);
654218893Sdim	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
655198090Srdivacky
656243830Sdim	efx_mcdi_execute(enp, &req);
657218893Sdim
658218893Sdim	if (req.emr_rc != 0) {
659218893Sdim		rc = req.emr_rc;
660218893Sdim		goto fail1;
661218893Sdim	}
662218893Sdim
663218893Sdim	return (0);
664218893Sdim
665218893Sdimfail1:
666198892Srdivacky	EFSYS_PROBE1(fail1, int, rc);
667218893Sdim
668226633Sdim	return (rc);
669226633Sdim}
670193323Sed
671198090Srdivackystatic	__checkReturn	int
672193323Sedefx_mcdi_unlink_piobuf(
673193323Sed	__in		efx_nic_t *enp,
674198090Srdivacky	__in		uint32_t vi_index)
675193323Sed{
676193323Sed	efx_mcdi_req_t req;
677193323Sed	uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN,
678193323Sed			    MC_CMD_UNLINK_PIOBUF_OUT_LEN)];
679193323Sed	int rc;
680193323Sed
681218893Sdim	(void) memset(payload, 0, sizeof (payload));
682218893Sdim	req.emr_cmd = MC_CMD_UNLINK_PIOBUF;
683218893Sdim	req.emr_in_buf = payload;
684218893Sdim	req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN;
685218893Sdim	req.emr_out_buf = payload;
686218893Sdim	req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN;
687193323Sed
688193323Sed	MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
689193323Sed
690193323Sed	efx_mcdi_execute(enp, &req);
691198090Srdivacky
692193323Sed	if (req.emr_rc != 0) {
693218893Sdim		rc = req.emr_rc;
694243830Sdim		goto fail1;
695243830Sdim	}
696226633Sdim
697193323Sed	return (0);
698193323Sed
699193323Sedfail1:
700193323Sed	EFSYS_PROBE1(fail1, int, rc);
701193323Sed
702193323Sed	return (rc);
703226633Sdim}
704218893Sdim
705218893Sdimstatic			void
706218893Sdimhunt_nic_alloc_piobufs(
707218893Sdim	__in		efx_nic_t *enp,
708218893Sdim	__in		uint32_t max_piobuf_count)
709218893Sdim{
710193323Sed	efx_piobuf_handle_t *handlep;
711193323Sed	unsigned int i;
712193323Sed	int rc;
713193323Sed
714193323Sed	EFSYS_ASSERT3U(max_piobuf_count, <=,
715198090Srdivacky	    EFX_ARRAY_SIZE(enp->en_u.hunt.enu_piobuf_handle));
716193323Sed
717193323Sed	enp->en_u.hunt.enu_piobuf_count = 0;
718218893Sdim
719193323Sed	for (i = 0; i < max_piobuf_count; i++) {
720193323Sed		handlep = &enp->en_u.hunt.enu_piobuf_handle[i];
721226633Sdim
722193323Sed		if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0)
723202375Srdivacky			goto fail1;
724193323Sed
725193323Sed		enp->en_u.hunt.enu_pio_alloc_map[i] = 0;
726193323Sed		enp->en_u.hunt.enu_piobuf_count++;
727193323Sed	}
728193323Sed
729218893Sdim	return;
730226633Sdim
731226633Sdimfail1:
732193323Sed	for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) {
733193323Sed		handlep = &enp->en_u.hunt.enu_piobuf_handle[i];
734226633Sdim
735193323Sed		efx_mcdi_free_piobuf(enp, *handlep);
736193323Sed		*handlep = EFX_PIOBUF_HANDLE_INVALID;
737193323Sed	}
738193323Sed	enp->en_u.hunt.enu_piobuf_count = 0;
739193323Sed}
740193323Sed
741218893Sdim
742218893Sdimstatic			void
743218893Sdimhunt_nic_free_piobufs(
744218893Sdim	__in		efx_nic_t *enp)
745218893Sdim{
746218893Sdim	efx_piobuf_handle_t *handlep;
747193323Sed	unsigned int i;
748193323Sed
749193323Sed	for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) {
750193323Sed		handlep = &enp->en_u.hunt.enu_piobuf_handle[i];
751193323Sed
752193323Sed		efx_mcdi_free_piobuf(enp, *handlep);
753193323Sed		*handlep = EFX_PIOBUF_HANDLE_INVALID;
754193323Sed	}
755193323Sed	enp->en_u.hunt.enu_piobuf_count = 0;
756193323Sed}
757226633Sdim
758226633Sdim/* Sub-allocate a block from a piobuf */
759226633Sdim	__checkReturn	int
760226633Sdimhunt_nic_pio_alloc(
761226633Sdim	__inout		efx_nic_t *enp,
762226633Sdim	__out		uint32_t *bufnump,
763226633Sdim	__out		efx_piobuf_handle_t *handlep,
764226633Sdim	__out		uint32_t *blknump,
765226633Sdim	__out		uint32_t *offsetp,
766226633Sdim	__out		size_t *sizep)
767226633Sdim{
768226633Sdim	efx_drv_cfg_t *edcp = &enp->en_drv_cfg;
769226633Sdim	uint32_t blk_per_buf;
770226633Sdim	uint32_t buf, blk;
771226633Sdim	int rc;
772193323Sed
773226633Sdim	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
774226633Sdim	EFSYS_ASSERT(bufnump);
775226633Sdim	EFSYS_ASSERT(handlep);
776226633Sdim	EFSYS_ASSERT(blknump);
777226633Sdim	EFSYS_ASSERT(offsetp);
778226633Sdim	EFSYS_ASSERT(sizep);
779226633Sdim
780226633Sdim	if ((edcp->edc_pio_alloc_size == 0) ||
781226633Sdim	    (enp->en_u.hunt.enu_piobuf_count == 0)) {
782226633Sdim		rc = ENOMEM;
783226633Sdim		goto fail1;
784226633Sdim	}
785226633Sdim	blk_per_buf = HUNT_PIOBUF_SIZE / edcp->edc_pio_alloc_size;
786226633Sdim
787226633Sdim	for (buf = 0; buf < enp->en_u.hunt.enu_piobuf_count; buf++) {
788226633Sdim		uint32_t *map = &enp->en_u.hunt.enu_pio_alloc_map[buf];
789226633Sdim
790226633Sdim		if (~(*map) == 0)
791226633Sdim			continue;
792226633Sdim
793226633Sdim		EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map)));
794226633Sdim		for (blk = 0; blk < blk_per_buf; blk++) {
795226633Sdim			if ((*map & (1u << blk)) == 0) {
796226633Sdim				*map |= (1u << blk);
797226633Sdim				goto done;
798226633Sdim			}
799226633Sdim		}
800226633Sdim	}
801226633Sdim	rc = ENOMEM;
802218893Sdim	goto fail2;
803193323Sed
804193323Seddone:
805193323Sed	*handlep = enp->en_u.hunt.enu_piobuf_handle[buf];
806193323Sed	*bufnump = buf;
807193323Sed	*blknump = blk;
808193323Sed	*sizep = edcp->edc_pio_alloc_size;
809193323Sed	*offsetp = blk * (*sizep);
810193323Sed
811193323Sed	return (0);
812198090Srdivacky
813218893Sdimfail2:
814193323Sed	EFSYS_PROBE(fail2);
815193323Sedfail1:
816193323Sed	EFSYS_PROBE1(fail1, int, rc);
817193323Sed
818193323Sed	return (rc);
819193323Sed}
820193323Sed
821193323Sed/* Free a piobuf sub-allocated block */
822193323Sed	__checkReturn	int
823198090Srdivackyhunt_nic_pio_free(
824193323Sed	__inout		efx_nic_t *enp,
825218893Sdim	__in		uint32_t bufnum,
826218893Sdim	__in		uint32_t blknum)
827218893Sdim{
828218893Sdim	uint32_t *map;
829218893Sdim	int rc;
830218893Sdim
831218893Sdim	if ((bufnum >= enp->en_u.hunt.enu_piobuf_count) ||
832218893Sdim	    (blknum >= (8 * sizeof (*map)))) {
833218893Sdim		rc = EINVAL;
834193323Sed		goto fail1;
835218893Sdim	}
836218893Sdim
837218893Sdim	map = &enp->en_u.hunt.enu_pio_alloc_map[bufnum];
838218893Sdim	if ((*map & (1u << blknum)) == 0) {
839193323Sed		rc = ENOENT;
840218893Sdim		goto fail2;
841218893Sdim	}
842193323Sed	*map &= ~(1u << blknum);
843198090Srdivacky
844193323Sed	return (0);
845193323Sed
846193323Sedfail2:
847193323Sed	EFSYS_PROBE(fail2);
848193323Sedfail1:
849193323Sed	EFSYS_PROBE1(fail1, int, rc);
850202375Srdivacky
851193323Sed	return (rc);
852202375Srdivacky}
853193323Sed
854193323Sed	__checkReturn	int
855193323Sedhunt_nic_pio_link(
856193323Sed	__inout		efx_nic_t *enp,
857193323Sed	__in		uint32_t vi_index,
858218893Sdim	__in		efx_piobuf_handle_t handle)
859218893Sdim{
860218893Sdim	return (efx_mcdi_link_piobuf(enp, vi_index, handle));
861218893Sdim}
862218893Sdim
863193323Sed	__checkReturn	int
864193323Sedhunt_nic_pio_unlink(
865193323Sed	__inout		efx_nic_t *enp,
866193323Sed	__in		uint32_t vi_index)
867193323Sed{
868193323Sed	return (efx_mcdi_unlink_piobuf(enp, vi_index));
869193323Sed}
870218893Sdim
871193323Sedstatic	__checkReturn	int
872218893Sdimhunt_get_datapath_caps(
873193323Sed	__in		efx_nic_t *enp)
874193323Sed{
875193323Sed	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
876193323Sed	efx_dword_t datapath_capabilities;
877199989Srdivacky	int rc;
878199989Srdivacky
879199989Srdivacky	if ((rc = efx_mcdi_get_capabilities(enp, &datapath_capabilities)) != 0)
880193323Sed		goto fail1;
881193323Sed
882193323Sed	/*
883193323Sed	 * Huntington RXDP firmware inserts a 0 or 14 byte prefix.
884193323Sed	 * We only support the 14 byte prefix here.
885193323Sed	 */
886198090Srdivacky	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
887193323Sed		GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14) != 1) {
888218893Sdim		rc = ENOTSUP;
889218893Sdim		goto fail2;
890218893Sdim	}
891218893Sdim	encp->enc_rx_prefix_size = 14;
892218893Sdim
893218893Sdim	/* Check if the firmware supports TSO */
894218893Sdim	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
895218893Sdim				GET_CAPABILITIES_OUT_TX_TSO) == 1)
896193323Sed		encp->enc_fw_assisted_tso_enabled = B_TRUE;
897218893Sdim	else
898218893Sdim		encp->enc_fw_assisted_tso_enabled = B_FALSE;
899218893Sdim
900218893Sdim	/* Check if the firmware has vadapter/vport/vswitch support */
901193323Sed	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
902218893Sdim				GET_CAPABILITIES_OUT_EVB) == 1)
903218893Sdim		encp->enc_datapath_cap_evb = B_TRUE;
904218893Sdim	else
905193323Sed		encp->enc_datapath_cap_evb = B_FALSE;
906198090Srdivacky
907193323Sed	/* Check if the firmware supports VLAN insertion */
908193323Sed	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
909193323Sed				GET_CAPABILITIES_OUT_TX_VLAN_INSERTION) == 1)
910193323Sed		encp->enc_hw_tx_insert_vlan_enabled = B_TRUE;
911193323Sed	else
912193323Sed		encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
913218893Sdim
914218893Sdim	/* Check if the firmware supports RX event batching */
915195340Sed	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
916218893Sdim		GET_CAPABILITIES_OUT_RX_BATCHING) == 1) {
917218893Sdim		encp->enc_rx_batching_enabled = B_TRUE;
918218893Sdim		encp->enc_rx_batch_max = 16;
919218893Sdim	} else {
920218893Sdim		encp->enc_rx_batching_enabled = B_FALSE;
921218893Sdim	}
922218893Sdim
923234353Sdim	return (0);
924218893Sdim
925218893Sdimfail2:
926218893Sdim	EFSYS_PROBE(fail2);
927218893Sdimfail1:
928218893Sdim	EFSYS_PROBE1(fail1, int, rc);
929218893Sdim
930218893Sdim	return (rc);
931218893Sdim}
932218893Sdim
933195340Sed/*
934195340Sed * The external port mapping is a one-based numbering of the external
935195340Sed * connectors on the board. It does not distinguish off-board separated
936219077Sdim * outputs such as multi-headed cables.
937219077Sdim * The number of ports that map to each external port connector
938219077Sdim * on the board is determined by the chip family and the port modes to
939219077Sdim * which the NIC can be configured. The mapping table lists modes with
940219077Sdim * port numbering requirements in increasing order.
941219077Sdim */
942219077Sdimstatic struct {
943219077Sdim	efx_family_t	family;
944219077Sdim	uint32_t	modes_mask;
945219077Sdim	uint32_t	stride;
946219077Sdim}	__hunt_external_port_mappings[] = {
947219077Sdim	/* Supported modes requiring 1 output per port */
948219077Sdim	{
949219077Sdim		EFX_FAMILY_HUNTINGTON,
950218893Sdim		(1 << TLV_PORT_MODE_10G) |
951198090Srdivacky		(1 << TLV_PORT_MODE_10G_10G) |
952193323Sed		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
953193323Sed		1
954193323Sed	},
955218893Sdim	/* Supported modes requiring 2 outputs per port */
956218893Sdim	{
957193323Sed		EFX_FAMILY_HUNTINGTON,
958193323Sed		(1 << TLV_PORT_MODE_40G) |
959218893Sdim		(1 << TLV_PORT_MODE_40G_40G) |
960193323Sed		(1 << TLV_PORT_MODE_40G_10G_10G) |
961193323Sed		(1 << TLV_PORT_MODE_10G_10G_40G),
962193323Sed		2
963218893Sdim	}
964218893Sdim	/*
965218893Sdim	 * NOTE: Medford modes will require 4 outputs per port:
966218893Sdim	 *	TLV_PORT_MODE_10G_10G_10G_10G_Q
967218893Sdim	 *	TLV_PORT_MODE_10G_10G_10G_10G_Q2
968218893Sdim	 * The Q2 mode routes outputs to external port 2. Support for this
969193323Sed	 * will require a new field specifying the number to add after
970218893Sdim	 * scaling by stride. This is fixed at 1 currently.
971198090Srdivacky	 */
972210299Sed};
973198090Srdivacky
974198090Srdivackystatic	__checkReturn	int
975198090Srdivackyhunt_external_port_mapping(
976193323Sed	__in		efx_nic_t *enp,
977193323Sed	__in		uint32_t port,
978193323Sed	__out		uint8_t *external_portp)
979193323Sed{
980193323Sed	int rc;
981193323Sed	int i;
982193323Sed	uint32_t port_modes;
983193323Sed	uint32_t matches;
984193323Sed	uint32_t stride = 1; /* default 1-1 mapping */
985218893Sdim
986218893Sdim	if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) {
987193323Sed		/* No port mode information available - use default mapping */
988193323Sed		goto out;
989218893Sdim	}
990193323Sed
991218893Sdim	/*
992193323Sed	 * Infer the internal port -> external port mapping from
993193323Sed	 * the possible port modes for this NIC.
994193323Sed	 */
995193323Sed	for (i = 0; i < EFX_ARRAY_SIZE(__hunt_external_port_mappings); ++i) {
996193323Sed		if (__hunt_external_port_mappings[i].family !=
997218893Sdim		    enp->en_family)
998218893Sdim			continue;
999218893Sdim		matches = (__hunt_external_port_mappings[i].modes_mask &
1000218893Sdim		    port_modes);
1001218893Sdim		if (matches != 0) {
1002218893Sdim			stride = __hunt_external_port_mappings[i].stride;
1003218893Sdim			port_modes &= ~matches;
1004218893Sdim		}
1005218893Sdim	}
1006218893Sdim
1007218893Sdim	if (port_modes != 0) {
1008218893Sdim		/* Some advertised modes are not supported */
1009218893Sdim		rc = ENOTSUP;
1010218893Sdim		goto fail1;
1011218893Sdim	}
1012218893Sdim
1013218893Sdimout:
1014218893Sdim	/*
1015218893Sdim	 * Scale as required by last matched mode and then convert to
1016218893Sdim	 * one-based numbering
1017218893Sdim	 */
1018218893Sdim	*external_portp = (uint8_t)(port / stride) + 1;
1019218893Sdim	return (0);
1020218893Sdim
1021218893Sdimfail1:
1022218893Sdim	EFSYS_PROBE1(fail1, int, rc);
1023218893Sdim
1024218893Sdim	return (rc);
1025218893Sdim}
1026218893Sdim
1027218893Sdimstatic	__checkReturn	int
1028218893Sdimhunt_board_cfg(
1029218893Sdim	__in		efx_nic_t *enp)
1030218893Sdim{
1031218893Sdim	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1032218893Sdim	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1033218893Sdim	uint8_t mac_addr[6];
1034218893Sdim	uint32_t board_type = 0;
1035218893Sdim	hunt_link_state_t hls;
1036218893Sdim	efx_port_t *epp = &(enp->en_port);
1037218893Sdim	uint32_t port;
1038218893Sdim	uint32_t pf;
1039218893Sdim	uint32_t vf;
1040218893Sdim	uint32_t mask;
1041218893Sdim	uint32_t flags;
1042218893Sdim	uint32_t sysclk;
1043218893Sdim	uint32_t base, nvec;
1044218893Sdim	int rc;
1045218893Sdim
1046218893Sdim	if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0)
1047218893Sdim		goto fail1;
1048199989Srdivacky
1049218893Sdim	/*
1050218893Sdim	 * NOTE: The MCDI protocol numbers ports from zero.
1051218893Sdim	 * The common code MCDI interface numbers ports from one.
1052218893Sdim	 */
1053218893Sdim	emip->emi_port = port + 1;
1054218893Sdim
1055199989Srdivacky	if ((rc = hunt_external_port_mapping(enp, port,
1056199989Srdivacky		    &encp->enc_external_port)) != 0)
1057199989Srdivacky		goto fail2;
1058218893Sdim
1059199989Srdivacky	/*
1060218893Sdim	 * Get PCIe function number from firmware (used for
1061199989Srdivacky	 * per-function privilege and dynamic config info).
1062193323Sed	 *  - PCIe PF: pf = PF number, vf = 0xffff.
1063193323Sed	 *  - PCIe VF: pf = parent PF, vf = VF number.
1064193323Sed	 */
1065193323Sed	if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0)
1066193323Sed		goto fail3;
1067193323Sed
1068193323Sed	encp->enc_pf = pf;
1069193323Sed	encp->enc_vf = vf;
1070218893Sdim
1071218893Sdim	/* MAC address for this function */
1072218893Sdim	if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1073218893Sdim		rc = efx_mcdi_get_mac_address_pf(enp, mac_addr);
1074218893Sdim	} else {
1075218893Sdim		rc = efx_mcdi_get_mac_address_vf(enp, mac_addr);
1076218893Sdim	}
1077218893Sdim	if ((rc == 0) && (mac_addr[0] & 0x02)) {
1078193323Sed		/*
1079193323Sed		 * If the static config does not include a global MAC address
1080193323Sed		 * pool then the board may return a locally administered MAC
1081193323Sed		 * address (this should only happen on incorrectly programmed
1082193323Sed		 * boards).
1083193323Sed		 */
1084218893Sdim		rc = EINVAL;
1085218893Sdim	}
1086218893Sdim	if (rc != 0)
1087218893Sdim		goto fail4;
1088218893Sdim
1089193323Sed	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
1090193323Sed
1091193323Sed	/* Board configuration */
1092193323Sed	rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL);
1093193323Sed	if (rc != 0) {
1094193323Sed		/* Unprivileged functions may not be able to read board cfg */
1095193323Sed		if (rc == EACCES)
1096218893Sdim			board_type = 0;
1097218893Sdim		else
1098218893Sdim			goto fail5;
1099218893Sdim	}
1100193323Sed
1101193323Sed	encp->enc_board_type = board_type;
1102218893Sdim	encp->enc_clk_mult = 1; /* not used for Huntington */
1103218893Sdim
1104218893Sdim	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
1105218893Sdim	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
1106193323Sed		goto fail6;
1107193323Sed
1108218893Sdim	/* Obtain the default PHY advertised capabilities */
1109218893Sdim	if ((rc = hunt_phy_get_link(enp, &hls)) != 0)
1110218893Sdim		goto fail7;
1111218893Sdim	epp->ep_default_adv_cap_mask = hls.hls_adv_cap_mask;
1112193323Sed	epp->ep_adv_cap_mask = hls.hls_adv_cap_mask;
1113193323Sed
1114218893Sdim	/*
1115218893Sdim	 * Enable firmware workarounds for hardware errata.
1116193323Sed	 * Expected responses are:
1117193323Sed	 *  - 0 (zero):
1118193323Sed	 *	Success: workaround enabled or disabled as requested.
1119193323Sed	 *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
1120193323Sed	 *	Firmware does not support the MC_CMD_WORKAROUND request.
1121193323Sed	 *	(assume that the workaround is not supported).
1122193323Sed	 *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
1123218893Sdim	 *	Firmware does not support the requested workaround.
1124193323Sed	 *  - MC_CMD_ERR_EPERM  (reported as EACCES):
1125193323Sed	 *	Unprivileged function cannot enable/disable workarounds.
1126193323Sed	 *
1127193323Sed	 * See efx_mcdi_request_errcode() for MCDI error translations.
1128193323Sed	 */
1129193323Sed
1130218893Sdim	/*
1131218893Sdim	 * If the bug35388 workaround is enabled, then use an indirect access
1132218893Sdim	 * method to avoid unsafe EVQ writes.
1133218893Sdim	 */
1134218893Sdim	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE,
1135218893Sdim	    NULL);
1136193323Sed	if ((rc == 0) || (rc == EACCES))
1137218893Sdim		encp->enc_bug35388_workaround = B_TRUE;
1138218893Sdim	else if ((rc == ENOTSUP) || (rc == ENOENT))
1139193323Sed		encp->enc_bug35388_workaround = B_FALSE;
1140193323Sed	else
1141198090Srdivacky		goto fail8;
1142193323Sed
1143193323Sed	/*
1144193323Sed	 * If the bug41750 workaround is enabled, then do not test interrupts,
1145218893Sdim	 * as the test will fail (seen with Greenport controllers).
1146218893Sdim	 */
1147218893Sdim	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE,
1148218893Sdim	    NULL);
1149218893Sdim	if (rc == 0) {
1150218893Sdim		encp->enc_bug41750_workaround = B_TRUE;
1151218893Sdim	} else if (rc == EACCES) {
1152195098Sed		/* Assume a controller with 40G ports needs the workaround. */
1153212904Sdim		if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX)
1154212904Sdim			encp->enc_bug41750_workaround = B_TRUE;
1155212904Sdim		else
1156226633Sdim			encp->enc_bug41750_workaround = B_FALSE;
1157195098Sed	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
1158195098Sed		encp->enc_bug41750_workaround = B_FALSE;
1159195098Sed	} else {
1160195098Sed		goto fail9;
1161195098Sed	}
1162195098Sed	if (EFX_PCI_FUNCTION_IS_VF(encp)) {
1163195098Sed		/* Interrupt testing does not work for VFs. See bug50084. */
1164195098Sed		encp->enc_bug41750_workaround = B_TRUE;
1165195098Sed	}
1166195098Sed
1167195098Sed	/*
1168195098Sed	 * If the bug26807 workaround is enabled, then firmware has enabled
1169195098Sed	 * support for chained multicast filters. Firmware will reset (FLR)
1170195098Sed	 * functions which have filters in the hardware filter table when the
1171195098Sed	 * workaround is enabled/disabled.
1172195098Sed	 *
1173218893Sdim	 * We must recheck if the workaround is enabled after inserting the
1174195340Sed	 * first hardware filter, in case it has been changed since this check.
1175195340Sed	 */
1176195340Sed	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807,
1177198090Srdivacky	    B_TRUE, &flags);
1178218893Sdim	if (rc == 0) {
1179218893Sdim		encp->enc_bug26807_workaround = B_TRUE;
1180198090Srdivacky		if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) {
1181218893Sdim			/*
1182198090Srdivacky			 * Other functions had installed filters before the
1183198090Srdivacky			 * workaround was enabled, and they have been reset
1184198090Srdivacky			 * by firmware.
1185198090Srdivacky			 */
1186218893Sdim			EFSYS_PROBE(bug26807_workaround_flr_done);
1187221345Sdim			/* FIXME: bump MC warm boot count ? */
1188218893Sdim		}
1189199989Srdivacky	} else if (rc == EACCES) {
1190199989Srdivacky		/*
1191198090Srdivacky		 * Unprivileged functions cannot enable the workaround in older
1192198090Srdivacky		 * firmware.
1193198090Srdivacky		 */
1194198090Srdivacky		encp->enc_bug26807_workaround = B_FALSE;
1195198090Srdivacky	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
1196198090Srdivacky		encp->enc_bug26807_workaround = B_FALSE;
1197198090Srdivacky	} else {
1198198090Srdivacky		goto fail10;
1199198090Srdivacky	}
1200195340Sed
1201218893Sdim	/* Get sysclk frequency (in MHz). */
1202198090Srdivacky	if ((rc = efx_mcdi_get_clock(enp, &sysclk)) != 0)
1203198090Srdivacky		goto fail11;
1204198090Srdivacky
1205195340Sed	/*
1206198090Srdivacky	 * The timer quantum is 1536 sysclk cycles, documented for the
1207198090Srdivacky	 * EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units.
1208198090Srdivacky	 */
1209198090Srdivacky	encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */
1210195340Sed	if (encp->enc_bug35388_workaround) {
1211198090Srdivacky		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
1212198090Srdivacky		ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000;
1213198090Srdivacky	} else {
1214198090Srdivacky		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
1215195340Sed		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
1216195340Sed	}
1217195340Sed
1218195340Sed	/* Check capabilities of running datapath firmware */
1219195340Sed	if ((rc = hunt_get_datapath_caps(enp)) != 0)
1220198090Srdivacky	    goto fail12;
1221198090Srdivacky
1222198090Srdivacky	/* Alignment for receive packet DMA buffers */
1223198090Srdivacky	encp->enc_rx_buf_align_start = 1;
1224195340Sed	encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */
1225195340Sed
1226218893Sdim	/* Alignment for WPTR updates */
1227195340Sed	encp->enc_rx_push_align = HUNTINGTON_RX_WPTR_ALIGN;
1228198090Srdivacky
1229218893Sdim	/*
1230218893Sdim	 * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use
1231218893Sdim	 * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available
1232221345Sdim	 * resources (allocated to this PCIe function), which is zero until
1233218893Sdim	 * after we have allocated VIs.
1234218893Sdim	 */
1235218893Sdim	encp->enc_evq_limit = 1024;
1236218893Sdim	encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
1237198090Srdivacky	encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;
1238218893Sdim
1239218893Sdim	encp->enc_buftbl_limit = 0xFFFFFFFF;
1240218893Sdim
1241218893Sdim	encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS;
1242218893Sdim	encp->enc_piobuf_size = HUNT_PIOBUF_SIZE;
1243195340Sed
1244218893Sdim	/*
1245218893Sdim	 * Get the current privilege mask. Note that this may be modified
1246195340Sed	 * dynamically, so this value is informational only. DO NOT use
1247195340Sed	 * the privilege mask to check for sufficient privileges, as that
1248195340Sed	 * can result in time-of-check/time-of-use bugs.
1249195340Sed	 */
1250195340Sed	if ((rc = efx_mcdi_privilege_mask(enp, pf, vf, &mask)) != 0) {
1251195340Sed		if (rc != ENOTSUP)
1252202375Srdivacky			goto fail13;
1253195340Sed
1254202375Srdivacky		/* Fallback for old firmware without privilege mask support */
1255195340Sed		if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1256195340Sed			/* Assume PF has admin privilege */
1257195340Sed			mask = HUNT_LEGACY_PF_PRIVILEGE_MASK;
1258218893Sdim		} else {
1259218893Sdim			/* VF is always unprivileged by default */
1260218893Sdim			mask = HUNT_LEGACY_VF_PRIVILEGE_MASK;
1261218893Sdim		}
1262218893Sdim	}
1263218893Sdim
1264195340Sed	encp->enc_privilege_mask = mask;
1265195340Sed
1266195340Sed	/* Get interrupt vector limits */
1267195340Sed	if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) {
1268195340Sed		if (EFX_PCI_FUNCTION_IS_PF(encp))
1269218893Sdim			goto fail14;
1270195340Sed
1271195340Sed		/* Ignore error (cannot query vector limits from a VF). */
1272198090Srdivacky		base = 0;
1273218893Sdim		nvec = 1024;
1274198090Srdivacky	}
1275198090Srdivacky	encp->enc_intr_vec_base = base;
1276198090Srdivacky	encp->enc_intr_limit = nvec;
1277198090Srdivacky
1278198090Srdivacky	/*
1279198090Srdivacky	 * Maximum number of bytes into the frame the TCP header can start for
1280198090Srdivacky	 * firmware assisted TSO to work.
1281198090Srdivacky	 */
1282198090Srdivacky	encp->enc_tx_tso_tcp_header_offset_limit = 208;
1283195340Sed
1284195340Sed	return (0);
1285195340Sed
1286195340Sedfail14:
1287195340Sed	EFSYS_PROBE(fail14);
1288195340Sedfail13:
1289195340Sed	EFSYS_PROBE(fail13);
1290195340Sedfail12:
1291226633Sdim	EFSYS_PROBE(fail12);
1292195340Sedfail11:
1293226633Sdim	EFSYS_PROBE(fail11);
1294195340Sedfail10:
1295195340Sed	EFSYS_PROBE(fail10);
1296198090Srdivackyfail9:
1297198090Srdivacky	EFSYS_PROBE(fail9);
1298195340Sedfail8:
1299195340Sed	EFSYS_PROBE(fail8);
1300195340Sedfail7:
1301195340Sed	EFSYS_PROBE(fail7);
1302195340Sedfail6:
1303218893Sdim	EFSYS_PROBE(fail6);
1304218893Sdimfail5:
1305218893Sdim	EFSYS_PROBE(fail5);
1306195340Sedfail4:
1307195340Sed	EFSYS_PROBE(fail4);
1308218893Sdimfail3:
1309195340Sed	EFSYS_PROBE(fail3);
1310195340Sedfail2:
1311195340Sed	EFSYS_PROBE(fail2);
1312198090Srdivackyfail1:
1313198090Srdivacky	EFSYS_PROBE1(fail1, int, rc);
1314195340Sed
1315195340Sed	return (rc);
1316195340Sed}
1317195340Sed
1318195340Sed
1319195340Sed	__checkReturn	int
1320195340Sedhunt_nic_probe(
1321193323Sed	__in		efx_nic_t *enp)
1322193323Sed{
1323193323Sed	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1324193323Sed	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1325193323Sed	int rc;
1326202375Srdivacky
1327202375Srdivacky	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
1328195340Sed
1329195340Sed	/* Read and clear any assertion state */
1330195340Sed	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1331193323Sed		goto fail1;
1332198090Srdivacky
1333195340Sed	/* Exit the assertion handler */
1334195340Sed	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1335195340Sed		if (rc != EACCES)
1336195340Sed			goto fail2;
1337226633Sdim
1338226633Sdim	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
1339226633Sdim		goto fail3;
1340195340Sed
1341226633Sdim	if ((rc = hunt_board_cfg(enp)) != 0)
1342226633Sdim		if (rc != EACCES)
1343226633Sdim			goto fail4;
1344226633Sdim
1345226633Sdim	/*
1346226633Sdim	 * Set default driver config limits (based on board config).
1347226633Sdim	 *
1348226633Sdim	 * FIXME: For now allocate a fixed number of VIs which is likely to be
1349226633Sdim	 * sufficient and small enough to allow multiple functions on the same
1350195340Sed	 * port.
1351202375Srdivacky	 */
1352195340Sed	edcp->edc_min_vi_count = edcp->edc_max_vi_count =
1353195340Sed	    MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit));
1354195340Sed
1355195340Sed	/* The client driver must configure and enable PIO buffer support */
1356195340Sed	edcp->edc_max_piobuf_count = 0;
1357195340Sed	edcp->edc_pio_alloc_size = 0;
1358202375Srdivacky
1359195340Sed#if EFSYS_OPT_MAC_STATS
1360195340Sed	/* Wipe the MAC statistics */
1361195340Sed	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
1362195340Sed		goto fail5;
1363226633Sdim#endif
1364226633Sdim
1365195340Sed#if EFSYS_OPT_LOOPBACK
1366226633Sdim	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
1367226633Sdim		goto fail6;
1368226633Sdim#endif
1369226633Sdim
1370226633Sdim#if EFSYS_OPT_MON_STATS
1371226633Sdim	if ((rc = mcdi_mon_cfg_build(enp)) != 0) {
1372226633Sdim		/* Unprivileged functions do not have access to sensors */
1373226633Sdim		if (rc != EACCES)
1374195340Sed			goto fail7;
1375195340Sed	}
1376195340Sed#endif
1377195340Sed
1378195340Sed	encp->enc_features = enp->en_features;
1379226633Sdim
1380226633Sdim	return (0);
1381226633Sdim
1382226633Sdim#if EFSYS_OPT_MON_STATS
1383226633Sdimfail7:
1384226633Sdim	EFSYS_PROBE(fail7);
1385226633Sdim#endif
1386226633Sdim#if EFSYS_OPT_LOOPBACK
1387226633Sdimfail6:
1388226633Sdim	EFSYS_PROBE(fail6);
1389226633Sdim#endif
1390226633Sdim#if EFSYS_OPT_MAC_STATS
1391226633Sdimfail5:
1392226633Sdim	EFSYS_PROBE(fail5);
1393226633Sdim#endif
1394195340Sedfail4:
1395195340Sed	EFSYS_PROBE(fail4);
1396195340Sedfail3:
1397195340Sed	EFSYS_PROBE(fail3);
1398195340Sedfail2:
1399202375Srdivacky	EFSYS_PROBE(fail2);
1400202375Srdivackyfail1:
1401195340Sed	EFSYS_PROBE1(fail1, int, rc);
1402195340Sed
1403195340Sed	return (rc);
1404195340Sed}
1405198090Srdivacky
1406195340Sed	__checkReturn	int
1407195340Sedhunt_nic_set_drv_limits(
1408195340Sed	__inout		efx_nic_t *enp,
1409195340Sed	__in		efx_drv_limits_t *edlp)
1410195340Sed{
1411202375Srdivacky	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1412198090Srdivacky	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1413195340Sed	uint32_t min_evq_count, max_evq_count;
1414195340Sed	uint32_t min_rxq_count, max_rxq_count;
1415195340Sed	uint32_t min_txq_count, max_txq_count;
1416195340Sed	int rc;
1417195340Sed
1418195340Sed	if (edlp == NULL) {
1419195340Sed		rc = EINVAL;
1420195340Sed		goto fail1;
1421195340Sed	}
1422195340Sed
1423195340Sed	/* Get minimum required and maximum usable VI limits */
1424195340Sed	min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit);
1425195340Sed	min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit);
1426195340Sed	min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit);
1427195340Sed
1428195340Sed	edcp->edc_min_vi_count =
1429195340Sed	    MAX(min_evq_count, MAX(min_rxq_count, min_txq_count));
1430195340Sed
1431195340Sed	max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit);
1432195340Sed	max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit);
1433195340Sed	max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit);
1434195340Sed
1435195340Sed	edcp->edc_max_vi_count =
1436195340Sed	    MAX(max_evq_count, MAX(max_rxq_count, max_txq_count));
1437195340Sed
1438195340Sed	/*
1439195340Sed	 * Check limits for sub-allocated piobuf blocks.
1440202375Srdivacky	 * PIO is optional, so don't fail if the limits are incorrect.
1441198090Srdivacky	 */
1442195340Sed	if ((encp->enc_piobuf_size == 0) ||
1443195340Sed	    (encp->enc_piobuf_limit == 0) ||
1444195340Sed	    (edlp->edl_min_pio_alloc_size == 0) ||
1445195340Sed	    (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) {
1446195340Sed		/* Disable PIO */
1447210299Sed		edcp->edc_max_piobuf_count = 0;
1448210299Sed		edcp->edc_pio_alloc_size = 0;
1449210299Sed	} else {
1450210299Sed		uint32_t blk_size, blk_count, blks_per_piobuf;
1451224145Sdim
1452224145Sdim		blk_size =
1453210299Sed		    MAX(edlp->edl_min_pio_alloc_size, HUNT_MIN_PIO_ALLOC_SIZE);
1454210299Sed
1455224145Sdim		blks_per_piobuf = encp->enc_piobuf_size / blk_size;
1456224145Sdim		EFSYS_ASSERT3U(blks_per_piobuf, <=, 32);
1457210299Sed
1458210299Sed		blk_count = (encp->enc_piobuf_limit * blks_per_piobuf);
1459208599Srdivacky
1460208599Srdivacky		/* A zero max pio alloc count means unlimited */
1461198090Srdivacky		if ((edlp->edl_max_pio_alloc_count > 0) &&
1462198090Srdivacky		    (edlp->edl_max_pio_alloc_count < blk_count)) {
1463224145Sdim			blk_count = edlp->edl_max_pio_alloc_count;
1464208599Srdivacky		}
1465208599Srdivacky
1466224145Sdim		edcp->edc_pio_alloc_size = blk_size;
1467224145Sdim		edcp->edc_max_piobuf_count =
1468198090Srdivacky		    (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf;
1469198090Srdivacky	}
1470208599Srdivacky
1471208599Srdivacky	return (0);
1472208599Srdivacky
1473208599Srdivackyfail1:
1474224145Sdim	EFSYS_PROBE1(fail1, int, rc);
1475208599Srdivacky
1476208599Srdivacky	return (rc);
1477224145Sdim}
1478224145Sdim
1479208599Srdivacky
1480208599Srdivacky	__checkReturn	int
1481210299Sedhunt_nic_reset(
1482210299Sed	__in		efx_nic_t *enp)
1483210299Sed{
1484210299Sed	efx_mcdi_req_t req;
1485210299Sed	uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN,
1486224145Sdim			    MC_CMD_ENTITY_RESET_OUT_LEN)];
1487224145Sdim	int rc;
1488210299Sed
1489210299Sed	/* hunt_nic_reset() is called to recover from BADASSERT failures. */
1490210299Sed	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1491210299Sed		goto fail1;
1492224145Sdim	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1493224145Sdim		goto fail2;
1494224145Sdim
1495210299Sed	(void) memset(payload, 0, sizeof (payload));
1496210299Sed	req.emr_cmd = MC_CMD_ENTITY_RESET;
1497208599Srdivacky	req.emr_in_buf = payload;
1498208599Srdivacky	req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN;
1499208599Srdivacky	req.emr_out_buf = payload;
1500208599Srdivacky	req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN;
1501208599Srdivacky
1502224145Sdim	MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG,
1503208599Srdivacky	    ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1);
1504208599Srdivacky
1505208599Srdivacky	efx_mcdi_execute(enp, &req);
1506208599Srdivacky
1507224145Sdim	if (req.emr_rc != 0) {
1508224145Sdim		rc = req.emr_rc;
1509224145Sdim		goto fail3;
1510208599Srdivacky	}
1511208599Srdivacky
1512208599Srdivacky	/* Clear RX/TX DMA queue errors */
1513208599Srdivacky	enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR);
1514208599Srdivacky
1515208599Srdivacky	return (0);
1516208599Srdivacky
1517224145Sdimfail3:
1518208599Srdivacky	EFSYS_PROBE(fail3);
1519208599Srdivackyfail2:
1520208599Srdivacky	EFSYS_PROBE(fail2);
1521208599Srdivackyfail1:
1522224145Sdim	EFSYS_PROBE1(fail1, int, rc);
1523224145Sdim
1524224145Sdim	return (rc);
1525208599Srdivacky}
1526208599Srdivacky
1527218893Sdim	__checkReturn	int
1528218893Sdimhunt_nic_init(
1529218893Sdim	__in		efx_nic_t *enp)
1530218893Sdim{
1531218893Sdim	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1532218893Sdim	uint32_t min_vi_count, max_vi_count;
1533218893Sdim	uint32_t vi_count, vi_base;
1534218893Sdim	uint32_t i;
1535208599Srdivacky	int rc;
1536218893Sdim
1537218893Sdim	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
1538218893Sdim
1539218893Sdim	/* Enable reporting of some events (e.g. link change) */
1540218893Sdim	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
1541218893Sdim		goto fail1;
1542218893Sdim
1543218893Sdim	/* Allocate (optional) on-chip PIO buffers */
1544218893Sdim	hunt_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count);
1545218893Sdim
1546218893Sdim	/*
1547198090Srdivacky	 * For best performance, PIO writes should use a write-combined
1548198090Srdivacky	 * (WC) memory mapping. Using a separate WC mapping for the PIO
1549234353Sdim	 * aperture of each VI would be a burden to drivers (and not
1550234353Sdim	 * possible if the host page size is >4Kbyte).
1551234353Sdim	 *
1552234353Sdim	 * To avoid this we use a single uncached (UC) mapping for VI
1553234353Sdim	 * register access, and a single WC mapping for extra VIs used
1554234353Sdim	 * for PIO writes.
1555234353Sdim	 *
1556234353Sdim	 * Each piobuf must be linked to a VI in the WC mapping, and to
1557234353Sdim	 * each VI that is using a sub-allocated block from the piobuf.
1558234353Sdim	 */
1559234353Sdim	min_vi_count = edcp->edc_min_vi_count;
1560234353Sdim	max_vi_count = edcp->edc_max_vi_count + enp->en_u.hunt.enu_piobuf_count;
1561234353Sdim
1562234353Sdim	/* Ensure that the previously attached driver's VIs are freed */
1563234353Sdim	if ((rc = efx_mcdi_free_vis(enp)) != 0)
1564234353Sdim		goto fail2;
1565234353Sdim
1566234353Sdim	/*
1567234353Sdim	 * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this
1568234353Sdim	 * fails then retrying the request for fewer VI resources may succeed.
1569234353Sdim	 */
1570234353Sdim	vi_count = 0;
1571234353Sdim	if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count,
1572234353Sdim		    &vi_base, &vi_count)) != 0)
1573234353Sdim		goto fail3;
1574234353Sdim
1575234353Sdim	EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count);
1576234353Sdim
1577234353Sdim	if (vi_count < min_vi_count) {
1578234353Sdim		rc = ENOMEM;
1579234353Sdim		goto fail4;
1580234353Sdim	}
1581234353Sdim
1582234353Sdim	enp->en_u.hunt.enu_vi_base = vi_base;
1583234353Sdim	enp->en_u.hunt.enu_vi_count = vi_count;
1584234353Sdim
1585234353Sdim	if (vi_count < min_vi_count + enp->en_u.hunt.enu_piobuf_count) {
1586234353Sdim		/* Not enough extra VIs to map piobufs */
1587234353Sdim		hunt_nic_free_piobufs(enp);
1588234353Sdim	}
1589234353Sdim
1590234353Sdim	enp->en_u.hunt.enu_pio_write_vi_base =
1591234353Sdim	    vi_count - enp->en_u.hunt.enu_piobuf_count;
1592234353Sdim
1593234353Sdim	/* Save UC memory mapping details */
1594234353Sdim	enp->en_u.hunt.enu_uc_mem_map_offset = 0;
1595218893Sdim	if (enp->en_u.hunt.enu_piobuf_count > 0) {
1596239462Sdim		enp->en_u.hunt.enu_uc_mem_map_size =
1597239462Sdim		    (ER_DZ_TX_PIOBUF_STEP *
1598239462Sdim		    enp->en_u.hunt.enu_pio_write_vi_base);
1599206083Srdivacky	} else {
1600198090Srdivacky		enp->en_u.hunt.enu_uc_mem_map_size =
1601198090Srdivacky		    (ER_DZ_TX_PIOBUF_STEP *
1602205407Srdivacky		    enp->en_u.hunt.enu_vi_count);
1603218893Sdim	}
1604218893Sdim
1605198090Srdivacky	/* Save WC memory mapping details */
1606198090Srdivacky	enp->en_u.hunt.enu_wc_mem_map_offset =
1607198090Srdivacky	    enp->en_u.hunt.enu_uc_mem_map_offset +
1608198090Srdivacky	    enp->en_u.hunt.enu_uc_mem_map_size;
1609198090Srdivacky
1610218893Sdim	enp->en_u.hunt.enu_wc_mem_map_size =
1611198090Srdivacky	    (ER_DZ_TX_PIOBUF_STEP *
1612198090Srdivacky	    enp->en_u.hunt.enu_piobuf_count);
1613198090Srdivacky
1614198090Srdivacky	/* Link piobufs to extra VIs in WC mapping */
1615198090Srdivacky	if (enp->en_u.hunt.enu_piobuf_count > 0) {
1616198090Srdivacky		for (i = 0; i < enp->en_u.hunt.enu_piobuf_count; i++) {
1617198090Srdivacky			rc = efx_mcdi_link_piobuf(enp,
1618198090Srdivacky			    enp->en_u.hunt.enu_pio_write_vi_base + i,
1619198090Srdivacky			    enp->en_u.hunt.enu_piobuf_handle[i]);
1620198090Srdivacky			if (rc != 0)
1621198090Srdivacky				break;
1622198090Srdivacky		}
1623198090Srdivacky	}
1624198090Srdivacky
1625198090Srdivacky	/* Allocate a vAdapter attached to our upstream vPort/pPort */
1626206083Srdivacky	if ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0)
1627206083Srdivacky		goto fail5;
1628206083Srdivacky
1629198090Srdivacky	enp->en_vport_id = EVB_PORT_ID_ASSIGNED;
1630198090Srdivacky
1631212904Sdim	return (0);
1632212904Sdim
1633212904Sdimfail5:
1634212904Sdim	EFSYS_PROBE(fail5);
1635212904Sdimfail4:
1636212904Sdim	EFSYS_PROBE(fail4);
1637212904Sdimfail3:
1638212904Sdim	EFSYS_PROBE(fail3);
1639212904Sdimfail2:
1640218893Sdim	EFSYS_PROBE(fail2);
1641218893Sdim
1642218893Sdim	hunt_nic_free_piobufs(enp);
1643218893Sdim
1644218893Sdimfail1:
1645212904Sdim	EFSYS_PROBE1(fail1, int, rc);
1646207618Srdivacky
1647205407Srdivacky	return (rc);
1648218893Sdim}
1649218893Sdim
1650208599Srdivacky	__checkReturn	int
1651218893Sdimhunt_nic_get_vi_pool(
1652218893Sdim	__in		efx_nic_t *enp,
1653218893Sdim	__out		uint32_t *vi_countp)
1654218893Sdim{
1655218893Sdim	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
1656218893Sdim
1657218893Sdim	/*
1658218893Sdim	 * Report VIs that the client driver can use.
1659234353Sdim	 * Do not include VIs used for PIO buffer writes.
1660234353Sdim	 */
1661234353Sdim	*vi_countp = enp->en_u.hunt.enu_pio_write_vi_base;
1662234353Sdim
1663234353Sdim	return (0);
1664234353Sdim}
1665234353Sdim
1666234353Sdim	__checkReturn	int
1667234353Sdimhunt_nic_get_bar_region(
1668208599Srdivacky	__in		efx_nic_t *enp,
1669218893Sdim	__in		efx_nic_region_t region,
1670218893Sdim	__out		uint32_t *offsetp,
1671218893Sdim	__out		size_t *sizep)
1672218893Sdim{
1673198090Srdivacky	int rc;
1674198090Srdivacky
1675198090Srdivacky	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
1676198090Srdivacky
1677212904Sdim	/*
1678198090Srdivacky	 * TODO: Specify host memory mapping alignment and granularity
1679218893Sdim	 * in efx_drv_limits_t so that they can be taken into account
1680218893Sdim	 * when allocating extra VIs for PIO writes.
1681212904Sdim	 */
1682212904Sdim	switch (region) {
1683212904Sdim	case EFX_REGION_VI:
1684218893Sdim		/* UC mapped memory BAR region for VI registers */
1685218893Sdim		*offsetp = enp->en_u.hunt.enu_uc_mem_map_offset;
1686212904Sdim		*sizep = enp->en_u.hunt.enu_uc_mem_map_size;
1687198090Srdivacky		break;
1688198113Srdivacky
1689218893Sdim	case EFX_REGION_PIO_WRITE_VI:
1690218893Sdim		/* WC mapped memory BAR region for piobuf writes */
1691218893Sdim		*offsetp = enp->en_u.hunt.enu_wc_mem_map_offset;
1692218893Sdim		*sizep = enp->en_u.hunt.enu_wc_mem_map_size;
1693218893Sdim		break;
1694218893Sdim
1695218893Sdim	default:
1696218893Sdim		rc = EINVAL;
1697218893Sdim		goto fail1;
1698218893Sdim	}
1699218893Sdim
1700218893Sdim	return (0);
1701218893Sdim
1702218893Sdimfail1:
1703218893Sdim	EFSYS_PROBE1(fail1, int, rc);
1704212904Sdim
1705198090Srdivacky	return (rc);
1706221345Sdim}
1707221345Sdim
1708221345Sdim			void
1709221345Sdimhunt_nic_fini(
1710221345Sdim	__in		efx_nic_t *enp)
1711218893Sdim{
1712218893Sdim	(void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id);
1713218893Sdim	enp->en_vport_id = 0;
1714218893Sdim
1715218893Sdim	/* FIXME: do we need to unlink piobufs ? */
1716218893Sdim	hunt_nic_free_piobufs(enp);
1717218893Sdim
1718218893Sdim	(void) efx_mcdi_free_vis(enp);
1719218893Sdim	enp->en_u.hunt.enu_vi_count = 0;
1720218893Sdim}
1721218893Sdim
1722218893Sdim			void
1723218893Sdimhunt_nic_unprobe(
1724218893Sdim	__in		efx_nic_t *enp)
1725198090Srdivacky{
1726198090Srdivacky#if EFSYS_OPT_MON_STATS
1727198090Srdivacky	mcdi_mon_cfg_free(enp);
1728218893Sdim#endif /* EFSYS_OPT_MON_STATS */
1729239462Sdim	(void) efx_mcdi_drv_attach(enp, B_FALSE);
1730239462Sdim}
1731239462Sdim
1732210299Sed#if EFSYS_OPT_DIAG
1733198113Srdivacky
1734198113Srdivacky	__checkReturn	int
1735205407Srdivackyhunt_nic_register_test(
1736218893Sdim	__in		efx_nic_t *enp)
1737218893Sdim{
1738218893Sdim	int rc;
1739198113Srdivacky
1740198113Srdivacky	/* FIXME */
1741221345Sdim	_NOTE(ARGUNUSED(enp))
1742221345Sdim	if (B_FALSE) {
1743221345Sdim		rc = ENOTSUP;
1744198113Srdivacky		goto fail1;
1745218893Sdim	}
1746198113Srdivacky	/* FIXME */
1747218893Sdim
1748198113Srdivacky	return (0);
1749198113Srdivacky
1750198113Srdivackyfail1:
1751198113Srdivacky	EFSYS_PROBE1(fail1, int, rc);
1752198113Srdivacky
1753198113Srdivacky	return (rc);
1754198113Srdivacky}
1755198113Srdivacky
1756198113Srdivacky#endif	/* EFSYS_OPT_DIAG */
1757198113Srdivacky
1758198113Srdivacky
1759198113Srdivacky
1760198113Srdivacky#endif	/* EFSYS_OPT_HUNTINGTON */
1761198113Srdivacky