hunt_nic.c revision 294079
1/*-
2 * Copyright (c) 2012-2015 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 *    this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_nic.c 294079 2016-01-15 06:27:51Z arybchik $");
33
34#include "efx.h"
35#include "efx_impl.h"
36#if EFSYS_OPT_MON_MCDI
37#include "mcdi_mon.h"
38#endif
39
40#if EFSYS_OPT_HUNTINGTON
41
42#include "ef10_tlv_layout.h"
43
44	__checkReturn	efx_rc_t
45efx_mcdi_get_port_assignment(
46	__in		efx_nic_t *enp,
47	__out		uint32_t *portp)
48{
49	efx_mcdi_req_t req;
50	uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN,
51			    MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)];
52	efx_rc_t rc;
53
54	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
55		    enp->en_family == EFX_FAMILY_MEDFORD);
56
57	(void) memset(payload, 0, sizeof (payload));
58	req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT;
59	req.emr_in_buf = payload;
60	req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN;
61	req.emr_out_buf = payload;
62	req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN;
63
64	efx_mcdi_execute(enp, &req);
65
66	if (req.emr_rc != 0) {
67		rc = req.emr_rc;
68		goto fail1;
69	}
70
71	if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) {
72		rc = EMSGSIZE;
73		goto fail2;
74	}
75
76	*portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT);
77
78	return (0);
79
80fail2:
81	EFSYS_PROBE(fail2);
82fail1:
83	EFSYS_PROBE1(fail1, efx_rc_t, rc);
84
85	return (rc);
86}
87
88	__checkReturn	efx_rc_t
89efx_mcdi_get_port_modes(
90	__in		efx_nic_t *enp,
91	__out		uint32_t *modesp)
92{
93	efx_mcdi_req_t req;
94	uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN,
95			    MC_CMD_GET_PORT_MODES_OUT_LEN)];
96	efx_rc_t rc;
97
98	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
99		    enp->en_family == EFX_FAMILY_MEDFORD);
100
101	(void) memset(payload, 0, sizeof (payload));
102	req.emr_cmd = MC_CMD_GET_PORT_MODES;
103	req.emr_in_buf = payload;
104	req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN;
105	req.emr_out_buf = payload;
106	req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN;
107
108	efx_mcdi_execute(enp, &req);
109
110	if (req.emr_rc != 0) {
111		rc = req.emr_rc;
112		goto fail1;
113	}
114
115	/*
116	 * Require only Modes and DefaultMode fields.
117	 * (CurrentMode field was added for Medford)
118	 */
119	if (req.emr_out_length_used <
120	    MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) {
121		rc = EMSGSIZE;
122		goto fail2;
123	}
124
125	*modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES);
126
127	return (0);
128
129fail2:
130	EFSYS_PROBE(fail2);
131fail1:
132	EFSYS_PROBE1(fail1, efx_rc_t, rc);
133
134	return (rc);
135}
136
137
138static	__checkReturn		efx_rc_t
139efx_mcdi_vadaptor_alloc(
140	__in			efx_nic_t *enp,
141	__in			uint32_t port_id)
142{
143	efx_mcdi_req_t req;
144	uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN,
145			    MC_CMD_VADAPTOR_ALLOC_OUT_LEN)];
146	efx_rc_t rc;
147
148	EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL);
149
150	(void) memset(payload, 0, sizeof (payload));
151	req.emr_cmd = MC_CMD_VADAPTOR_ALLOC;
152	req.emr_in_buf = payload;
153	req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN;
154	req.emr_out_buf = payload;
155	req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN;
156
157	MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
158	MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS,
159	    VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED,
160	    enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 0);
161
162	efx_mcdi_execute(enp, &req);
163
164	if (req.emr_rc != 0) {
165		rc = req.emr_rc;
166		goto fail1;
167	}
168
169	return (0);
170
171fail1:
172	EFSYS_PROBE1(fail1, efx_rc_t, rc);
173
174	return (rc);
175}
176
177static	__checkReturn		efx_rc_t
178efx_mcdi_vadaptor_free(
179	__in			efx_nic_t *enp,
180	__in			uint32_t port_id)
181{
182	efx_mcdi_req_t req;
183	uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN,
184			    MC_CMD_VADAPTOR_FREE_OUT_LEN)];
185	efx_rc_t rc;
186
187	(void) memset(payload, 0, sizeof (payload));
188	req.emr_cmd = MC_CMD_VADAPTOR_FREE;
189	req.emr_in_buf = payload;
190	req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN;
191	req.emr_out_buf = payload;
192	req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN;
193
194	MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
195
196	efx_mcdi_execute(enp, &req);
197
198	if (req.emr_rc != 0) {
199		rc = req.emr_rc;
200		goto fail1;
201	}
202
203	return (0);
204
205fail1:
206	EFSYS_PROBE1(fail1, efx_rc_t, rc);
207
208	return (rc);
209}
210
211	__checkReturn	efx_rc_t
212efx_mcdi_get_mac_address_pf(
213	__in			efx_nic_t *enp,
214	__out_ecount_opt(6)	uint8_t mac_addrp[6])
215{
216	efx_mcdi_req_t req;
217	uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN,
218			    MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)];
219	efx_rc_t rc;
220
221	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
222		    enp->en_family == EFX_FAMILY_MEDFORD);
223
224	(void) memset(payload, 0, sizeof (payload));
225	req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES;
226	req.emr_in_buf = payload;
227	req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN;
228	req.emr_out_buf = payload;
229	req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN;
230
231	efx_mcdi_execute(enp, &req);
232
233	if (req.emr_rc != 0) {
234		rc = req.emr_rc;
235		goto fail1;
236	}
237
238	if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) {
239		rc = EMSGSIZE;
240		goto fail2;
241	}
242
243	if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) {
244		rc = ENOENT;
245		goto fail3;
246	}
247
248	if (mac_addrp != NULL) {
249		uint8_t *addrp;
250
251		addrp = MCDI_OUT2(req, uint8_t,
252		    GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE);
253
254		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
255	}
256
257	return (0);
258
259fail3:
260	EFSYS_PROBE(fail3);
261fail2:
262	EFSYS_PROBE(fail2);
263fail1:
264	EFSYS_PROBE1(fail1, efx_rc_t, rc);
265
266	return (rc);
267}
268
269	__checkReturn	efx_rc_t
270efx_mcdi_get_mac_address_vf(
271	__in			efx_nic_t *enp,
272	__out_ecount_opt(6)	uint8_t mac_addrp[6])
273{
274	efx_mcdi_req_t req;
275	uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN,
276			    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)];
277	efx_rc_t rc;
278
279	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
280		    enp->en_family == EFX_FAMILY_MEDFORD);
281
282	(void) memset(payload, 0, sizeof (payload));
283	req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES;
284	req.emr_in_buf = payload;
285	req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN;
286	req.emr_out_buf = payload;
287	req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX;
288
289	MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID,
290	    EVB_PORT_ID_ASSIGNED);
291
292	efx_mcdi_execute(enp, &req);
293
294	if (req.emr_rc != 0) {
295		rc = req.emr_rc;
296		goto fail1;
297	}
298
299	if (req.emr_out_length_used <
300	    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) {
301		rc = EMSGSIZE;
302		goto fail2;
303	}
304
305	if (MCDI_OUT_DWORD(req,
306		VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) {
307		rc = ENOENT;
308		goto fail3;
309	}
310
311	if (mac_addrp != NULL) {
312		uint8_t *addrp;
313
314		addrp = MCDI_OUT2(req, uint8_t,
315		    VPORT_GET_MAC_ADDRESSES_OUT_MACADDR);
316
317		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
318	}
319
320	return (0);
321
322fail3:
323	EFSYS_PROBE(fail3);
324fail2:
325	EFSYS_PROBE(fail2);
326fail1:
327	EFSYS_PROBE1(fail1, efx_rc_t, rc);
328
329	return (rc);
330}
331
332	__checkReturn	efx_rc_t
333efx_mcdi_get_clock(
334	__in		efx_nic_t *enp,
335	__out		uint32_t *sys_freqp)
336{
337	efx_mcdi_req_t req;
338	uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN,
339			    MC_CMD_GET_CLOCK_OUT_LEN)];
340	efx_rc_t rc;
341
342	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
343		    enp->en_family == EFX_FAMILY_MEDFORD);
344
345	(void) memset(payload, 0, sizeof (payload));
346	req.emr_cmd = MC_CMD_GET_CLOCK;
347	req.emr_in_buf = payload;
348	req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN;
349	req.emr_out_buf = payload;
350	req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN;
351
352	efx_mcdi_execute(enp, &req);
353
354	if (req.emr_rc != 0) {
355		rc = req.emr_rc;
356		goto fail1;
357	}
358
359	if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) {
360		rc = EMSGSIZE;
361		goto fail2;
362	}
363
364	*sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ);
365	if (*sys_freqp == 0) {
366		rc = EINVAL;
367		goto fail3;
368	}
369
370	return (0);
371
372fail3:
373	EFSYS_PROBE(fail3);
374fail2:
375	EFSYS_PROBE(fail2);
376fail1:
377	EFSYS_PROBE1(fail1, efx_rc_t, rc);
378
379	return (rc);
380}
381
382	__checkReturn	efx_rc_t
383efx_mcdi_get_vector_cfg(
384	__in		efx_nic_t *enp,
385	__out_opt	uint32_t *vec_basep,
386	__out_opt	uint32_t *pf_nvecp,
387	__out_opt	uint32_t *vf_nvecp)
388{
389	efx_mcdi_req_t req;
390	uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN,
391			    MC_CMD_GET_VECTOR_CFG_OUT_LEN)];
392	efx_rc_t rc;
393
394	(void) memset(payload, 0, sizeof (payload));
395	req.emr_cmd = MC_CMD_GET_VECTOR_CFG;
396	req.emr_in_buf = payload;
397	req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN;
398	req.emr_out_buf = payload;
399	req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN;
400
401	efx_mcdi_execute(enp, &req);
402
403	if (req.emr_rc != 0) {
404		rc = req.emr_rc;
405		goto fail1;
406	}
407
408	if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) {
409		rc = EMSGSIZE;
410		goto fail2;
411	}
412
413	if (vec_basep != NULL)
414		*vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE);
415	if (pf_nvecp != NULL)
416		*pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF);
417	if (vf_nvecp != NULL)
418		*vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF);
419
420	return (0);
421
422fail2:
423	EFSYS_PROBE(fail2);
424fail1:
425	EFSYS_PROBE1(fail1, efx_rc_t, rc);
426
427	return (rc);
428}
429
430static	__checkReturn	efx_rc_t
431efx_mcdi_get_capabilities(
432	__in		efx_nic_t *enp,
433	__out		efx_dword_t *flagsp,
434	__out		efx_dword_t *flags2p)
435{
436	efx_mcdi_req_t req;
437	uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN,
438			    MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)];
439	efx_rc_t rc;
440
441	(void) memset(payload, 0, sizeof (payload));
442	req.emr_cmd = MC_CMD_GET_CAPABILITIES;
443	req.emr_in_buf = payload;
444	req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
445	req.emr_out_buf = payload;
446	req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN;
447
448	efx_mcdi_execute(enp, &req);
449
450	if (req.emr_rc != 0) {
451		rc = req.emr_rc;
452		goto fail1;
453	}
454
455	if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
456		rc = EMSGSIZE;
457		goto fail2;
458	}
459
460	*flagsp = *MCDI_OUT2(req, efx_dword_t, GET_CAPABILITIES_OUT_FLAGS1);
461
462	if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)
463		EFX_ZERO_DWORD(*flags2p);
464	else
465		*flags2p = *MCDI_OUT2(req, efx_dword_t,
466		    GET_CAPABILITIES_V2_OUT_FLAGS2);
467
468	return (0);
469
470fail2:
471	EFSYS_PROBE(fail2);
472fail1:
473	EFSYS_PROBE1(fail1, efx_rc_t, rc);
474
475	return (rc);
476}
477
478
479static	__checkReturn	efx_rc_t
480efx_mcdi_alloc_vis(
481	__in		efx_nic_t *enp,
482	__in		uint32_t min_vi_count,
483	__in		uint32_t max_vi_count,
484	__out		uint32_t *vi_basep,
485	__out		uint32_t *vi_countp,
486	__out		uint32_t *vi_shiftp)
487{
488	efx_mcdi_req_t req;
489	uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN,
490			    MC_CMD_ALLOC_VIS_OUT_LEN)];
491	efx_rc_t rc;
492
493	if (vi_countp == NULL) {
494		rc = EINVAL;
495		goto fail1;
496	}
497
498	(void) memset(payload, 0, sizeof (payload));
499	req.emr_cmd = MC_CMD_ALLOC_VIS;
500	req.emr_in_buf = payload;
501	req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN;
502	req.emr_out_buf = payload;
503	req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN;
504
505	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count);
506	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count);
507
508	efx_mcdi_execute(enp, &req);
509
510	if (req.emr_rc != 0) {
511		rc = req.emr_rc;
512		goto fail2;
513	}
514
515	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) {
516		rc = EMSGSIZE;
517		goto fail3;
518	}
519
520	*vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE);
521	*vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT);
522
523	/* Report VI_SHIFT if available (always zero for Huntington) */
524	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN)
525		*vi_shiftp = 0;
526	else
527		*vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT);
528
529	return (0);
530
531fail3:
532	EFSYS_PROBE(fail3);
533fail2:
534	EFSYS_PROBE(fail2);
535fail1:
536	EFSYS_PROBE1(fail1, efx_rc_t, rc);
537
538	return (rc);
539}
540
541
542static	__checkReturn	efx_rc_t
543efx_mcdi_free_vis(
544	__in		efx_nic_t *enp)
545{
546	efx_mcdi_req_t req;
547	efx_rc_t rc;
548
549	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0);
550	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0);
551
552	req.emr_cmd = MC_CMD_FREE_VIS;
553	req.emr_in_buf = NULL;
554	req.emr_in_length = 0;
555	req.emr_out_buf = NULL;
556	req.emr_out_length = 0;
557
558	efx_mcdi_execute_quiet(enp, &req);
559
560	/* Ignore ELREADY (no allocated VIs, so nothing to free) */
561	if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) {
562		rc = req.emr_rc;
563		goto fail1;
564	}
565
566	return (0);
567
568fail1:
569	EFSYS_PROBE1(fail1, efx_rc_t, rc);
570
571	return (rc);
572}
573
574
575static	__checkReturn	efx_rc_t
576efx_mcdi_alloc_piobuf(
577	__in		efx_nic_t *enp,
578	__out		efx_piobuf_handle_t *handlep)
579{
580	efx_mcdi_req_t req;
581	uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN,
582			    MC_CMD_ALLOC_PIOBUF_OUT_LEN)];
583	efx_rc_t rc;
584
585	if (handlep == NULL) {
586		rc = EINVAL;
587		goto fail1;
588	}
589
590	(void) memset(payload, 0, sizeof (payload));
591	req.emr_cmd = MC_CMD_ALLOC_PIOBUF;
592	req.emr_in_buf = payload;
593	req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN;
594	req.emr_out_buf = payload;
595	req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN;
596
597	efx_mcdi_execute_quiet(enp, &req);
598
599	if (req.emr_rc != 0) {
600		rc = req.emr_rc;
601		goto fail2;
602	}
603
604	if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) {
605		rc = EMSGSIZE;
606		goto fail3;
607	}
608
609	*handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE);
610
611	return (0);
612
613fail3:
614	EFSYS_PROBE(fail3);
615fail2:
616	EFSYS_PROBE(fail2);
617fail1:
618	EFSYS_PROBE1(fail1, efx_rc_t, rc);
619
620	return (rc);
621}
622
623static	__checkReturn	efx_rc_t
624efx_mcdi_free_piobuf(
625	__in		efx_nic_t *enp,
626	__in		efx_piobuf_handle_t handle)
627{
628	efx_mcdi_req_t req;
629	uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN,
630			    MC_CMD_FREE_PIOBUF_OUT_LEN)];
631	efx_rc_t rc;
632
633	(void) memset(payload, 0, sizeof (payload));
634	req.emr_cmd = MC_CMD_FREE_PIOBUF;
635	req.emr_in_buf = payload;
636	req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN;
637	req.emr_out_buf = payload;
638	req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN;
639
640	MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle);
641
642	efx_mcdi_execute_quiet(enp, &req);
643
644	if (req.emr_rc != 0) {
645		rc = req.emr_rc;
646		goto fail1;
647	}
648
649	return (0);
650
651fail1:
652	EFSYS_PROBE1(fail1, efx_rc_t, rc);
653
654	return (rc);
655}
656
657static	__checkReturn	efx_rc_t
658efx_mcdi_link_piobuf(
659	__in		efx_nic_t *enp,
660	__in		uint32_t vi_index,
661	__in		efx_piobuf_handle_t handle)
662{
663	efx_mcdi_req_t req;
664	uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN,
665			    MC_CMD_LINK_PIOBUF_OUT_LEN)];
666	efx_rc_t rc;
667
668	(void) memset(payload, 0, sizeof (payload));
669	req.emr_cmd = MC_CMD_LINK_PIOBUF;
670	req.emr_in_buf = payload;
671	req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN;
672	req.emr_out_buf = payload;
673	req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN;
674
675	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle);
676	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
677
678	efx_mcdi_execute(enp, &req);
679
680	if (req.emr_rc != 0) {
681		rc = req.emr_rc;
682		goto fail1;
683	}
684
685	return (0);
686
687fail1:
688	EFSYS_PROBE1(fail1, efx_rc_t, rc);
689
690	return (rc);
691}
692
693static	__checkReturn	efx_rc_t
694efx_mcdi_unlink_piobuf(
695	__in		efx_nic_t *enp,
696	__in		uint32_t vi_index)
697{
698	efx_mcdi_req_t req;
699	uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN,
700			    MC_CMD_UNLINK_PIOBUF_OUT_LEN)];
701	efx_rc_t rc;
702
703	(void) memset(payload, 0, sizeof (payload));
704	req.emr_cmd = MC_CMD_UNLINK_PIOBUF;
705	req.emr_in_buf = payload;
706	req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN;
707	req.emr_out_buf = payload;
708	req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN;
709
710	MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
711
712	efx_mcdi_execute(enp, &req);
713
714	if (req.emr_rc != 0) {
715		rc = req.emr_rc;
716		goto fail1;
717	}
718
719	return (0);
720
721fail1:
722	EFSYS_PROBE1(fail1, efx_rc_t, rc);
723
724	return (rc);
725}
726
727static			void
728ef10_nic_alloc_piobufs(
729	__in		efx_nic_t *enp,
730	__in		uint32_t max_piobuf_count)
731{
732	efx_piobuf_handle_t *handlep;
733	unsigned int i;
734	efx_rc_t rc;
735
736	EFSYS_ASSERT3U(max_piobuf_count, <=,
737	    EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle));
738
739	enp->en_arch.ef10.ena_piobuf_count = 0;
740
741	for (i = 0; i < max_piobuf_count; i++) {
742		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
743
744		if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0)
745			goto fail1;
746
747		enp->en_arch.ef10.ena_pio_alloc_map[i] = 0;
748		enp->en_arch.ef10.ena_piobuf_count++;
749	}
750
751	return;
752
753fail1:
754	for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
755		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
756
757		efx_mcdi_free_piobuf(enp, *handlep);
758		*handlep = EFX_PIOBUF_HANDLE_INVALID;
759	}
760	enp->en_arch.ef10.ena_piobuf_count = 0;
761}
762
763
764static			void
765ef10_nic_free_piobufs(
766	__in		efx_nic_t *enp)
767{
768	efx_piobuf_handle_t *handlep;
769	unsigned int i;
770
771	for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
772		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
773
774		efx_mcdi_free_piobuf(enp, *handlep);
775		*handlep = EFX_PIOBUF_HANDLE_INVALID;
776	}
777	enp->en_arch.ef10.ena_piobuf_count = 0;
778}
779
780/* Sub-allocate a block from a piobuf */
781	__checkReturn	efx_rc_t
782ef10_nic_pio_alloc(
783	__inout		efx_nic_t *enp,
784	__out		uint32_t *bufnump,
785	__out		efx_piobuf_handle_t *handlep,
786	__out		uint32_t *blknump,
787	__out		uint32_t *offsetp,
788	__out		size_t *sizep)
789{
790	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
791	efx_drv_cfg_t *edcp = &enp->en_drv_cfg;
792	uint32_t blk_per_buf;
793	uint32_t buf, blk;
794	efx_rc_t rc;
795
796	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
797		    enp->en_family == EFX_FAMILY_MEDFORD);
798	EFSYS_ASSERT(bufnump);
799	EFSYS_ASSERT(handlep);
800	EFSYS_ASSERT(blknump);
801	EFSYS_ASSERT(offsetp);
802	EFSYS_ASSERT(sizep);
803
804	if ((edcp->edc_pio_alloc_size == 0) ||
805	    (enp->en_arch.ef10.ena_piobuf_count == 0)) {
806		rc = ENOMEM;
807		goto fail1;
808	}
809	blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size;
810
811	for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) {
812		uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf];
813
814		if (~(*map) == 0)
815			continue;
816
817		EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map)));
818		for (blk = 0; blk < blk_per_buf; blk++) {
819			if ((*map & (1u << blk)) == 0) {
820				*map |= (1u << blk);
821				goto done;
822			}
823		}
824	}
825	rc = ENOMEM;
826	goto fail2;
827
828done:
829	*handlep = enp->en_arch.ef10.ena_piobuf_handle[buf];
830	*bufnump = buf;
831	*blknump = blk;
832	*sizep = edcp->edc_pio_alloc_size;
833	*offsetp = blk * (*sizep);
834
835	return (0);
836
837fail2:
838	EFSYS_PROBE(fail2);
839fail1:
840	EFSYS_PROBE1(fail1, efx_rc_t, rc);
841
842	return (rc);
843}
844
845/* Free a piobuf sub-allocated block */
846	__checkReturn	efx_rc_t
847ef10_nic_pio_free(
848	__inout		efx_nic_t *enp,
849	__in		uint32_t bufnum,
850	__in		uint32_t blknum)
851{
852	uint32_t *map;
853	efx_rc_t rc;
854
855	if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) ||
856	    (blknum >= (8 * sizeof (*map)))) {
857		rc = EINVAL;
858		goto fail1;
859	}
860
861	map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum];
862	if ((*map & (1u << blknum)) == 0) {
863		rc = ENOENT;
864		goto fail2;
865	}
866	*map &= ~(1u << blknum);
867
868	return (0);
869
870fail2:
871	EFSYS_PROBE(fail2);
872fail1:
873	EFSYS_PROBE1(fail1, efx_rc_t, rc);
874
875	return (rc);
876}
877
878	__checkReturn	efx_rc_t
879ef10_nic_pio_link(
880	__inout		efx_nic_t *enp,
881	__in		uint32_t vi_index,
882	__in		efx_piobuf_handle_t handle)
883{
884	return (efx_mcdi_link_piobuf(enp, vi_index, handle));
885}
886
887	__checkReturn	efx_rc_t
888ef10_nic_pio_unlink(
889	__inout		efx_nic_t *enp,
890	__in		uint32_t vi_index)
891{
892	return (efx_mcdi_unlink_piobuf(enp, vi_index));
893}
894
895	__checkReturn	efx_rc_t
896ef10_get_datapath_caps(
897	__in		efx_nic_t *enp)
898{
899	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
900	efx_dword_t datapath_capabilities;
901	efx_dword_t datapath_capabilities_v2;
902	efx_rc_t rc;
903
904	if ((rc = efx_mcdi_get_capabilities(enp, &datapath_capabilities,
905					    &datapath_capabilities_v2)) != 0)
906		goto fail1;
907
908	/*
909	 * Huntington RXDP firmware inserts a 0 or 14 byte prefix.
910	 * We only support the 14 byte prefix here.
911	 */
912	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
913		GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14) != 1) {
914		rc = ENOTSUP;
915		goto fail2;
916	}
917	encp->enc_rx_prefix_size = 14;
918
919	/* Check if the firmware supports TSO */
920	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
921				GET_CAPABILITIES_OUT_TX_TSO) == 1)
922		encp->enc_fw_assisted_tso_enabled = B_TRUE;
923	else
924		encp->enc_fw_assisted_tso_enabled = B_FALSE;
925
926	/* Check if the firmware supports FATSOv2 */
927	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities_v2,
928				GET_CAPABILITIES_V2_OUT_TX_TSO_V2) == 1)
929		encp->enc_fw_assisted_tso_v2_enabled = B_TRUE;
930	else
931		encp->enc_fw_assisted_tso_v2_enabled = B_FALSE;
932
933	/* Check if the firmware has vadapter/vport/vswitch support */
934	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
935				GET_CAPABILITIES_OUT_EVB) == 1)
936		encp->enc_datapath_cap_evb = B_TRUE;
937	else
938		encp->enc_datapath_cap_evb = B_FALSE;
939
940	/* Check if the firmware supports VLAN insertion */
941	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
942				GET_CAPABILITIES_OUT_TX_VLAN_INSERTION) == 1)
943		encp->enc_hw_tx_insert_vlan_enabled = B_TRUE;
944	else
945		encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
946
947	/* Check if the firmware supports RX event batching */
948	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
949		GET_CAPABILITIES_OUT_RX_BATCHING) == 1) {
950		encp->enc_rx_batching_enabled = B_TRUE;
951		encp->enc_rx_batch_max = 16;
952	} else {
953		encp->enc_rx_batching_enabled = B_FALSE;
954	}
955
956	/* Check if the firmware supports disabling scatter on RXQs */
957	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
958			    GET_CAPABILITIES_OUT_RX_DISABLE_SCATTER) == 1) {
959		encp->enc_rx_disable_scatter_supported = B_TRUE;
960	} else {
961		encp->enc_rx_disable_scatter_supported = B_FALSE;
962	}
963
964	/* Check if the firmware supports set mac with running filters */
965	if (MCDI_CMD_DWORD_FIELD(&datapath_capabilities,
966	    GET_CAPABILITIES_OUT_VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED)
967	    == 1) {
968		encp->enc_allow_set_mac_with_installed_filters = B_TRUE;
969	} else {
970		encp->enc_allow_set_mac_with_installed_filters = B_FALSE;
971	}
972
973	return (0);
974
975fail2:
976	EFSYS_PROBE(fail2);
977fail1:
978	EFSYS_PROBE1(fail1, efx_rc_t, rc);
979
980	return (rc);
981}
982
983
984	__checkReturn		efx_rc_t
985ef10_get_privilege_mask(
986	__in			efx_nic_t *enp,
987	__out			uint32_t *maskp)
988{
989	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
990	uint32_t mask;
991	efx_rc_t rc;
992
993	if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf,
994					    &mask)) != 0) {
995		if (rc != ENOTSUP)
996			goto fail1;
997
998		/* Fallback for old firmware without privilege mask support */
999		if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1000			/* Assume PF has admin privilege */
1001			mask = EF10_LEGACY_PF_PRIVILEGE_MASK;
1002		} else {
1003			/* VF is always unprivileged by default */
1004			mask = EF10_LEGACY_VF_PRIVILEGE_MASK;
1005		}
1006	}
1007
1008	*maskp = mask;
1009
1010	return (0);
1011
1012fail1:
1013	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1014
1015	return (rc);
1016}
1017
1018
1019/*
1020 * The external port mapping is a one-based numbering of the external
1021 * connectors on the board. It does not distinguish off-board separated
1022 * outputs such as multi-headed cables.
1023 * The number of ports that map to each external port connector
1024 * on the board is determined by the chip family and the port modes to
1025 * which the NIC can be configured. The mapping table lists modes with
1026 * port numbering requirements in increasing order.
1027 */
1028static struct {
1029	efx_family_t	family;
1030	uint32_t	modes_mask;
1031	uint32_t	stride;
1032}	__ef10_external_port_mappings[] = {
1033	/* Supported modes requiring 1 output per port */
1034	{
1035		EFX_FAMILY_HUNTINGTON,
1036		(1 << TLV_PORT_MODE_10G) |
1037		(1 << TLV_PORT_MODE_10G_10G) |
1038		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
1039		1
1040	},
1041	{
1042		EFX_FAMILY_MEDFORD,
1043		(1 << TLV_PORT_MODE_10G) |
1044		(1 << TLV_PORT_MODE_10G_10G) |
1045		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
1046		1
1047	},
1048	/* Supported modes requiring 2 outputs per port */
1049	{
1050		EFX_FAMILY_HUNTINGTON,
1051		(1 << TLV_PORT_MODE_40G) |
1052		(1 << TLV_PORT_MODE_40G_40G) |
1053		(1 << TLV_PORT_MODE_40G_10G_10G) |
1054		(1 << TLV_PORT_MODE_10G_10G_40G),
1055		2
1056	},
1057	{
1058		EFX_FAMILY_MEDFORD,
1059		(1 << TLV_PORT_MODE_40G) |
1060		(1 << TLV_PORT_MODE_40G_40G) |
1061		(1 << TLV_PORT_MODE_40G_10G_10G) |
1062		(1 << TLV_PORT_MODE_10G_10G_40G),
1063		2
1064	},
1065	/* Supported modes requiring 4 outputs per port */
1066	{
1067		EFX_FAMILY_MEDFORD,
1068		(1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) |
1069		(1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2),
1070		4
1071	},
1072};
1073
1074	__checkReturn	efx_rc_t
1075ef10_external_port_mapping(
1076	__in		efx_nic_t *enp,
1077	__in		uint32_t port,
1078	__out		uint8_t *external_portp)
1079{
1080	efx_rc_t rc;
1081	int i;
1082	uint32_t port_modes;
1083	uint32_t matches;
1084	uint32_t stride = 1; /* default 1-1 mapping */
1085
1086	if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) {
1087		/* No port mode information available - use default mapping */
1088		goto out;
1089	}
1090
1091	/*
1092	 * Infer the internal port -> external port mapping from
1093	 * the possible port modes for this NIC.
1094	 */
1095	for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) {
1096		if (__ef10_external_port_mappings[i].family !=
1097		    enp->en_family)
1098			continue;
1099		matches = (__ef10_external_port_mappings[i].modes_mask &
1100		    port_modes);
1101		if (matches != 0) {
1102			stride = __ef10_external_port_mappings[i].stride;
1103			port_modes &= ~matches;
1104		}
1105	}
1106
1107	if (port_modes != 0) {
1108		/* Some advertised modes are not supported */
1109		rc = ENOTSUP;
1110		goto fail1;
1111	}
1112
1113out:
1114	/*
1115	 * Scale as required by last matched mode and then convert to
1116	 * one-based numbering
1117	 */
1118	*external_portp = (uint8_t)(port / stride) + 1;
1119	return (0);
1120
1121fail1:
1122	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1123
1124	return (rc);
1125}
1126
1127	__checkReturn	efx_rc_t
1128hunt_board_cfg(
1129	__in		efx_nic_t *enp)
1130{
1131	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1132	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1133	uint8_t mac_addr[6];
1134	uint32_t board_type = 0;
1135	ef10_link_state_t els;
1136	efx_port_t *epp = &(enp->en_port);
1137	uint32_t port;
1138	uint32_t pf;
1139	uint32_t vf;
1140	uint32_t mask;
1141	uint32_t flags;
1142	uint32_t sysclk;
1143	uint32_t base, nvec;
1144	efx_rc_t rc;
1145
1146	if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0)
1147		goto fail1;
1148
1149	/*
1150	 * NOTE: The MCDI protocol numbers ports from zero.
1151	 * The common code MCDI interface numbers ports from one.
1152	 */
1153	emip->emi_port = port + 1;
1154
1155	if ((rc = ef10_external_port_mapping(enp, port,
1156		    &encp->enc_external_port)) != 0)
1157		goto fail2;
1158
1159	/*
1160	 * Get PCIe function number from firmware (used for
1161	 * per-function privilege and dynamic config info).
1162	 *  - PCIe PF: pf = PF number, vf = 0xffff.
1163	 *  - PCIe VF: pf = parent PF, vf = VF number.
1164	 */
1165	if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0)
1166		goto fail3;
1167
1168	encp->enc_pf = pf;
1169	encp->enc_vf = vf;
1170
1171	/* MAC address for this function */
1172	if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1173		rc = efx_mcdi_get_mac_address_pf(enp, mac_addr);
1174		if ((rc == 0) && (mac_addr[0] & 0x02)) {
1175			/*
1176			 * If the static config does not include a global MAC
1177			 * address pool then the board may return a locally
1178			 * administered MAC address (this should only happen on
1179			 * incorrectly programmed boards).
1180			 */
1181			rc = EINVAL;
1182		}
1183	} else {
1184		rc = efx_mcdi_get_mac_address_vf(enp, mac_addr);
1185	}
1186	if (rc != 0)
1187		goto fail4;
1188
1189	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
1190
1191	/* Board configuration */
1192	rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL);
1193	if (rc != 0) {
1194		/* Unprivileged functions may not be able to read board cfg */
1195		if (rc == EACCES)
1196			board_type = 0;
1197		else
1198			goto fail5;
1199	}
1200
1201	encp->enc_board_type = board_type;
1202	encp->enc_clk_mult = 1; /* not used for Huntington */
1203
1204	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
1205	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
1206		goto fail6;
1207
1208	/* Obtain the default PHY advertised capabilities */
1209	if ((rc = hunt_phy_get_link(enp, &els)) != 0)
1210		goto fail7;
1211	epp->ep_default_adv_cap_mask = els.els_adv_cap_mask;
1212	epp->ep_adv_cap_mask = els.els_adv_cap_mask;
1213
1214	/*
1215	 * Enable firmware workarounds for hardware errata.
1216	 * Expected responses are:
1217	 *  - 0 (zero):
1218	 *	Success: workaround enabled or disabled as requested.
1219	 *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
1220	 *	Firmware does not support the MC_CMD_WORKAROUND request.
1221	 *	(assume that the workaround is not supported).
1222	 *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
1223	 *	Firmware does not support the requested workaround.
1224	 *  - MC_CMD_ERR_EPERM  (reported as EACCES):
1225	 *	Unprivileged function cannot enable/disable workarounds.
1226	 *
1227	 * See efx_mcdi_request_errcode() for MCDI error translations.
1228	 */
1229
1230	/*
1231	 * If the bug35388 workaround is enabled, then use an indirect access
1232	 * method to avoid unsafe EVQ writes.
1233	 */
1234	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE,
1235	    NULL);
1236	if ((rc == 0) || (rc == EACCES))
1237		encp->enc_bug35388_workaround = B_TRUE;
1238	else if ((rc == ENOTSUP) || (rc == ENOENT))
1239		encp->enc_bug35388_workaround = B_FALSE;
1240	else
1241		goto fail8;
1242
1243	/*
1244	 * If the bug41750 workaround is enabled, then do not test interrupts,
1245	 * as the test will fail (seen with Greenport controllers).
1246	 */
1247	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE,
1248	    NULL);
1249	if (rc == 0) {
1250		encp->enc_bug41750_workaround = B_TRUE;
1251	} else if (rc == EACCES) {
1252		/* Assume a controller with 40G ports needs the workaround. */
1253		if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX)
1254			encp->enc_bug41750_workaround = B_TRUE;
1255		else
1256			encp->enc_bug41750_workaround = B_FALSE;
1257	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
1258		encp->enc_bug41750_workaround = B_FALSE;
1259	} else {
1260		goto fail9;
1261	}
1262	if (EFX_PCI_FUNCTION_IS_VF(encp)) {
1263		/* Interrupt testing does not work for VFs. See bug50084. */
1264		encp->enc_bug41750_workaround = B_TRUE;
1265	}
1266
1267	/*
1268	 * If the bug26807 workaround is enabled, then firmware has enabled
1269	 * support for chained multicast filters. Firmware will reset (FLR)
1270	 * functions which have filters in the hardware filter table when the
1271	 * workaround is enabled/disabled.
1272	 *
1273	 * We must recheck if the workaround is enabled after inserting the
1274	 * first hardware filter, in case it has been changed since this check.
1275	 */
1276	rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807,
1277	    B_TRUE, &flags);
1278	if (rc == 0) {
1279		encp->enc_bug26807_workaround = B_TRUE;
1280		if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) {
1281			/*
1282			 * Other functions had installed filters before the
1283			 * workaround was enabled, and they have been reset
1284			 * by firmware.
1285			 */
1286			EFSYS_PROBE(bug26807_workaround_flr_done);
1287			/* FIXME: bump MC warm boot count ? */
1288		}
1289	} else if (rc == EACCES) {
1290		/*
1291		 * Unprivileged functions cannot enable the workaround in older
1292		 * firmware.
1293		 */
1294		encp->enc_bug26807_workaround = B_FALSE;
1295	} else if ((rc == ENOTSUP) || (rc == ENOENT)) {
1296		encp->enc_bug26807_workaround = B_FALSE;
1297	} else {
1298		goto fail10;
1299	}
1300
1301	/* Get sysclk frequency (in MHz). */
1302	if ((rc = efx_mcdi_get_clock(enp, &sysclk)) != 0)
1303		goto fail11;
1304
1305	/*
1306	 * The timer quantum is 1536 sysclk cycles, documented for the
1307	 * EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units.
1308	 */
1309	encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */
1310	if (encp->enc_bug35388_workaround) {
1311		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
1312		ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000;
1313	} else {
1314		encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
1315		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
1316	}
1317
1318	/* Check capabilities of running datapath firmware */
1319	if ((rc = ef10_get_datapath_caps(enp)) != 0)
1320	    goto fail12;
1321
1322	/* Alignment for receive packet DMA buffers */
1323	encp->enc_rx_buf_align_start = 1;
1324	encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */
1325
1326	/* Alignment for WPTR updates */
1327	encp->enc_rx_push_align = EF10_RX_WPTR_ALIGN;
1328
1329	/*
1330	 * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use
1331	 * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available
1332	 * resources (allocated to this PCIe function), which is zero until
1333	 * after we have allocated VIs.
1334	 */
1335	encp->enc_evq_limit = 1024;
1336	encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
1337	encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;
1338
1339	encp->enc_buftbl_limit = 0xFFFFFFFF;
1340
1341	encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS;
1342	encp->enc_piobuf_size = HUNT_PIOBUF_SIZE;
1343	encp->enc_piobuf_min_alloc_size = HUNT_MIN_PIO_ALLOC_SIZE;
1344
1345	/*
1346	 * Get the current privilege mask. Note that this may be modified
1347	 * dynamically, so this value is informational only. DO NOT use
1348	 * the privilege mask to check for sufficient privileges, as that
1349	 * can result in time-of-check/time-of-use bugs.
1350	 */
1351	if ((rc = ef10_get_privilege_mask(enp, &mask)) != 0)
1352		goto fail13;
1353	encp->enc_privilege_mask = mask;
1354
1355	/* Get interrupt vector limits */
1356	if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) {
1357		if (EFX_PCI_FUNCTION_IS_PF(encp))
1358			goto fail14;
1359
1360		/* Ignore error (cannot query vector limits from a VF). */
1361		base = 0;
1362		nvec = 1024;
1363	}
1364	encp->enc_intr_vec_base = base;
1365	encp->enc_intr_limit = nvec;
1366
1367	/*
1368	 * Maximum number of bytes into the frame the TCP header can start for
1369	 * firmware assisted TSO to work.
1370	 */
1371	encp->enc_tx_tso_tcp_header_offset_limit = EF10_TCP_HEADER_OFFSET_LIMIT;
1372
1373	return (0);
1374
1375fail14:
1376	EFSYS_PROBE(fail14);
1377fail13:
1378	EFSYS_PROBE(fail13);
1379fail12:
1380	EFSYS_PROBE(fail12);
1381fail11:
1382	EFSYS_PROBE(fail11);
1383fail10:
1384	EFSYS_PROBE(fail10);
1385fail9:
1386	EFSYS_PROBE(fail9);
1387fail8:
1388	EFSYS_PROBE(fail8);
1389fail7:
1390	EFSYS_PROBE(fail7);
1391fail6:
1392	EFSYS_PROBE(fail6);
1393fail5:
1394	EFSYS_PROBE(fail5);
1395fail4:
1396	EFSYS_PROBE(fail4);
1397fail3:
1398	EFSYS_PROBE(fail3);
1399fail2:
1400	EFSYS_PROBE(fail2);
1401fail1:
1402	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1403
1404	return (rc);
1405}
1406
1407
1408	__checkReturn	efx_rc_t
1409ef10_nic_probe(
1410	__in		efx_nic_t *enp)
1411{
1412	efx_nic_ops_t *enop = enp->en_enop;
1413	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1414	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1415	efx_rc_t rc;
1416
1417	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1418		    enp->en_family == EFX_FAMILY_MEDFORD);
1419
1420	/* Read and clear any assertion state */
1421	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1422		goto fail1;
1423
1424	/* Exit the assertion handler */
1425	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1426		if (rc != EACCES)
1427			goto fail2;
1428
1429	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
1430		goto fail3;
1431
1432	if ((rc = enop->eno_board_cfg(enp)) != 0)
1433		if (rc != EACCES)
1434			goto fail4;
1435
1436	/*
1437	 * Set default driver config limits (based on board config).
1438	 *
1439	 * FIXME: For now allocate a fixed number of VIs which is likely to be
1440	 * sufficient and small enough to allow multiple functions on the same
1441	 * port.
1442	 */
1443	edcp->edc_min_vi_count = edcp->edc_max_vi_count =
1444	    MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit));
1445
1446	/* The client driver must configure and enable PIO buffer support */
1447	edcp->edc_max_piobuf_count = 0;
1448	edcp->edc_pio_alloc_size = 0;
1449
1450#if EFSYS_OPT_MAC_STATS
1451	/* Wipe the MAC statistics */
1452	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
1453		goto fail5;
1454#endif
1455
1456#if EFSYS_OPT_LOOPBACK
1457	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
1458		goto fail6;
1459#endif
1460
1461#if EFSYS_OPT_MON_STATS
1462	if ((rc = mcdi_mon_cfg_build(enp)) != 0) {
1463		/* Unprivileged functions do not have access to sensors */
1464		if (rc != EACCES)
1465			goto fail7;
1466	}
1467#endif
1468
1469	encp->enc_features = enp->en_features;
1470
1471	return (0);
1472
1473#if EFSYS_OPT_MON_STATS
1474fail7:
1475	EFSYS_PROBE(fail7);
1476#endif
1477#if EFSYS_OPT_LOOPBACK
1478fail6:
1479	EFSYS_PROBE(fail6);
1480#endif
1481#if EFSYS_OPT_MAC_STATS
1482fail5:
1483	EFSYS_PROBE(fail5);
1484#endif
1485fail4:
1486	EFSYS_PROBE(fail4);
1487fail3:
1488	EFSYS_PROBE(fail3);
1489fail2:
1490	EFSYS_PROBE(fail2);
1491fail1:
1492	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1493
1494	return (rc);
1495}
1496
1497	__checkReturn	efx_rc_t
1498ef10_nic_set_drv_limits(
1499	__inout		efx_nic_t *enp,
1500	__in		efx_drv_limits_t *edlp)
1501{
1502	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1503	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1504	uint32_t min_evq_count, max_evq_count;
1505	uint32_t min_rxq_count, max_rxq_count;
1506	uint32_t min_txq_count, max_txq_count;
1507	efx_rc_t rc;
1508
1509	if (edlp == NULL) {
1510		rc = EINVAL;
1511		goto fail1;
1512	}
1513
1514	/* Get minimum required and maximum usable VI limits */
1515	min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit);
1516	min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit);
1517	min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit);
1518
1519	edcp->edc_min_vi_count =
1520	    MAX(min_evq_count, MAX(min_rxq_count, min_txq_count));
1521
1522	max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit);
1523	max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit);
1524	max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit);
1525
1526	edcp->edc_max_vi_count =
1527	    MAX(max_evq_count, MAX(max_rxq_count, max_txq_count));
1528
1529	/*
1530	 * Check limits for sub-allocated piobuf blocks.
1531	 * PIO is optional, so don't fail if the limits are incorrect.
1532	 */
1533	if ((encp->enc_piobuf_size == 0) ||
1534	    (encp->enc_piobuf_limit == 0) ||
1535	    (edlp->edl_min_pio_alloc_size == 0) ||
1536	    (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) {
1537		/* Disable PIO */
1538		edcp->edc_max_piobuf_count = 0;
1539		edcp->edc_pio_alloc_size = 0;
1540	} else {
1541		uint32_t blk_size, blk_count, blks_per_piobuf;
1542
1543		blk_size =
1544		    MAX(edlp->edl_min_pio_alloc_size,
1545			    encp->enc_piobuf_min_alloc_size);
1546
1547		blks_per_piobuf = encp->enc_piobuf_size / blk_size;
1548		EFSYS_ASSERT3U(blks_per_piobuf, <=, 32);
1549
1550		blk_count = (encp->enc_piobuf_limit * blks_per_piobuf);
1551
1552		/* A zero max pio alloc count means unlimited */
1553		if ((edlp->edl_max_pio_alloc_count > 0) &&
1554		    (edlp->edl_max_pio_alloc_count < blk_count)) {
1555			blk_count = edlp->edl_max_pio_alloc_count;
1556		}
1557
1558		edcp->edc_pio_alloc_size = blk_size;
1559		edcp->edc_max_piobuf_count =
1560		    (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf;
1561	}
1562
1563	return (0);
1564
1565fail1:
1566	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1567
1568	return (rc);
1569}
1570
1571
1572	__checkReturn	efx_rc_t
1573ef10_nic_reset(
1574	__in		efx_nic_t *enp)
1575{
1576	efx_mcdi_req_t req;
1577	uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN,
1578			    MC_CMD_ENTITY_RESET_OUT_LEN)];
1579	efx_rc_t rc;
1580
1581	/* ef10_nic_reset() is called to recover from BADASSERT failures. */
1582	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1583		goto fail1;
1584	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1585		goto fail2;
1586
1587	(void) memset(payload, 0, sizeof (payload));
1588	req.emr_cmd = MC_CMD_ENTITY_RESET;
1589	req.emr_in_buf = payload;
1590	req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN;
1591	req.emr_out_buf = payload;
1592	req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN;
1593
1594	MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG,
1595	    ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1);
1596
1597	efx_mcdi_execute(enp, &req);
1598
1599	if (req.emr_rc != 0) {
1600		rc = req.emr_rc;
1601		goto fail3;
1602	}
1603
1604	/* Clear RX/TX DMA queue errors */
1605	enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR);
1606
1607	return (0);
1608
1609fail3:
1610	EFSYS_PROBE(fail3);
1611fail2:
1612	EFSYS_PROBE(fail2);
1613fail1:
1614	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1615
1616	return (rc);
1617}
1618
1619	__checkReturn	efx_rc_t
1620ef10_nic_init(
1621	__in		efx_nic_t *enp)
1622{
1623	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1624	uint32_t min_vi_count, max_vi_count;
1625	uint32_t vi_count, vi_base, vi_shift;
1626	uint32_t i;
1627	uint32_t retry;
1628	uint32_t delay_us;
1629	efx_rc_t rc;
1630
1631	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1632		    enp->en_family == EFX_FAMILY_MEDFORD);
1633
1634	/* Enable reporting of some events (e.g. link change) */
1635	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
1636		goto fail1;
1637
1638	/* Allocate (optional) on-chip PIO buffers */
1639	ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count);
1640
1641	/*
1642	 * For best performance, PIO writes should use a write-combined
1643	 * (WC) memory mapping. Using a separate WC mapping for the PIO
1644	 * aperture of each VI would be a burden to drivers (and not
1645	 * possible if the host page size is >4Kbyte).
1646	 *
1647	 * To avoid this we use a single uncached (UC) mapping for VI
1648	 * register access, and a single WC mapping for extra VIs used
1649	 * for PIO writes.
1650	 *
1651	 * Each piobuf must be linked to a VI in the WC mapping, and to
1652	 * each VI that is using a sub-allocated block from the piobuf.
1653	 */
1654	min_vi_count = edcp->edc_min_vi_count;
1655	max_vi_count =
1656	    edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count;
1657
1658	/* Ensure that the previously attached driver's VIs are freed */
1659	if ((rc = efx_mcdi_free_vis(enp)) != 0)
1660		goto fail2;
1661
1662	/*
1663	 * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this
1664	 * fails then retrying the request for fewer VI resources may succeed.
1665	 */
1666	vi_count = 0;
1667	if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count,
1668		    &vi_base, &vi_count, &vi_shift)) != 0)
1669		goto fail3;
1670
1671	EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count);
1672
1673	if (vi_count < min_vi_count) {
1674		rc = ENOMEM;
1675		goto fail4;
1676	}
1677
1678	enp->en_arch.ef10.ena_vi_base = vi_base;
1679	enp->en_arch.ef10.ena_vi_count = vi_count;
1680	enp->en_arch.ef10.ena_vi_shift = vi_shift;
1681
1682	if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) {
1683		/* Not enough extra VIs to map piobufs */
1684		ef10_nic_free_piobufs(enp);
1685	}
1686
1687	enp->en_arch.ef10.ena_pio_write_vi_base =
1688	    vi_count - enp->en_arch.ef10.ena_piobuf_count;
1689
1690	/* Save UC memory mapping details */
1691	enp->en_arch.ef10.ena_uc_mem_map_offset = 0;
1692	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1693		enp->en_arch.ef10.ena_uc_mem_map_size =
1694		    (ER_DZ_TX_PIOBUF_STEP *
1695		    enp->en_arch.ef10.ena_pio_write_vi_base);
1696	} else {
1697		enp->en_arch.ef10.ena_uc_mem_map_size =
1698		    (ER_DZ_TX_PIOBUF_STEP *
1699		    enp->en_arch.ef10.ena_vi_count);
1700	}
1701
1702	/* Save WC memory mapping details */
1703	enp->en_arch.ef10.ena_wc_mem_map_offset =
1704	    enp->en_arch.ef10.ena_uc_mem_map_offset +
1705	    enp->en_arch.ef10.ena_uc_mem_map_size;
1706
1707	enp->en_arch.ef10.ena_wc_mem_map_size =
1708	    (ER_DZ_TX_PIOBUF_STEP *
1709	    enp->en_arch.ef10.ena_piobuf_count);
1710
1711	/* Link piobufs to extra VIs in WC mapping */
1712	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1713		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
1714			rc = efx_mcdi_link_piobuf(enp,
1715			    enp->en_arch.ef10.ena_pio_write_vi_base + i,
1716			    enp->en_arch.ef10.ena_piobuf_handle[i]);
1717			if (rc != 0)
1718				break;
1719		}
1720	}
1721
1722	/*
1723	 * Allocate a vAdaptor attached to our upstream vPort/pPort.
1724	 *
1725	 * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF
1726	 * driver has yet to bring up the EVB port. See bug 56147. In this case,
1727	 * retry the request several times after waiting a while. The wait time
1728	 * between retries starts small (10ms) and exponentially increases.
1729	 * Total wait time is a little over two seconds. Retry logic in the
1730	 * client driver may mean this whole loop is repeated if it continues to
1731	 * fail.
1732	 */
1733	retry = 0;
1734	delay_us = 10000;
1735	while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) {
1736		if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) ||
1737		    (rc != ENOENT)) {
1738			/*
1739			 * Do not retry alloc for PF, or for other errors on
1740			 * a VF.
1741			 */
1742			goto fail5;
1743		}
1744
1745		/* VF startup before PF is ready. Retry allocation. */
1746		if (retry > 5) {
1747			/* Too many attempts */
1748			rc = EINVAL;
1749			goto fail6;
1750		}
1751		EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry);
1752		EFSYS_SLEEP(delay_us);
1753		retry++;
1754		if (delay_us < 500000)
1755			delay_us <<= 2;
1756	}
1757
1758	enp->en_vport_id = EVB_PORT_ID_ASSIGNED;
1759	enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2;
1760
1761	return (0);
1762
1763fail6:
1764	EFSYS_PROBE(fail6);
1765fail5:
1766	EFSYS_PROBE(fail5);
1767fail4:
1768	EFSYS_PROBE(fail4);
1769fail3:
1770	EFSYS_PROBE(fail3);
1771fail2:
1772	EFSYS_PROBE(fail2);
1773
1774	ef10_nic_free_piobufs(enp);
1775
1776fail1:
1777	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1778
1779	return (rc);
1780}
1781
1782	__checkReturn	efx_rc_t
1783ef10_nic_get_vi_pool(
1784	__in		efx_nic_t *enp,
1785	__out		uint32_t *vi_countp)
1786{
1787	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1788		    enp->en_family == EFX_FAMILY_MEDFORD);
1789
1790	/*
1791	 * Report VIs that the client driver can use.
1792	 * Do not include VIs used for PIO buffer writes.
1793	 */
1794	*vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base;
1795
1796	return (0);
1797}
1798
1799	__checkReturn	efx_rc_t
1800ef10_nic_get_bar_region(
1801	__in		efx_nic_t *enp,
1802	__in		efx_nic_region_t region,
1803	__out		uint32_t *offsetp,
1804	__out		size_t *sizep)
1805{
1806	efx_rc_t rc;
1807
1808	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1809		    enp->en_family == EFX_FAMILY_MEDFORD);
1810
1811	/*
1812	 * TODO: Specify host memory mapping alignment and granularity
1813	 * in efx_drv_limits_t so that they can be taken into account
1814	 * when allocating extra VIs for PIO writes.
1815	 */
1816	switch (region) {
1817	case EFX_REGION_VI:
1818		/* UC mapped memory BAR region for VI registers */
1819		*offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset;
1820		*sizep = enp->en_arch.ef10.ena_uc_mem_map_size;
1821		break;
1822
1823	case EFX_REGION_PIO_WRITE_VI:
1824		/* WC mapped memory BAR region for piobuf writes */
1825		*offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset;
1826		*sizep = enp->en_arch.ef10.ena_wc_mem_map_size;
1827		break;
1828
1829	default:
1830		rc = EINVAL;
1831		goto fail1;
1832	}
1833
1834	return (0);
1835
1836fail1:
1837	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1838
1839	return (rc);
1840}
1841
1842			void
1843ef10_nic_fini(
1844	__in		efx_nic_t *enp)
1845{
1846	uint32_t i;
1847	efx_rc_t rc;
1848
1849	(void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id);
1850	enp->en_vport_id = 0;
1851
1852	/* Unlink piobufs from extra VIs in WC mapping */
1853	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1854		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
1855			rc = efx_mcdi_unlink_piobuf(enp,
1856			    enp->en_arch.ef10.ena_pio_write_vi_base + i);
1857			if (rc != 0)
1858				break;
1859		}
1860	}
1861
1862	ef10_nic_free_piobufs(enp);
1863
1864	(void) efx_mcdi_free_vis(enp);
1865	enp->en_arch.ef10.ena_vi_count = 0;
1866}
1867
1868			void
1869ef10_nic_unprobe(
1870	__in		efx_nic_t *enp)
1871{
1872#if EFSYS_OPT_MON_STATS
1873	mcdi_mon_cfg_free(enp);
1874#endif /* EFSYS_OPT_MON_STATS */
1875	(void) efx_mcdi_drv_attach(enp, B_FALSE);
1876}
1877
1878#if EFSYS_OPT_DIAG
1879
1880	__checkReturn	efx_rc_t
1881ef10_nic_register_test(
1882	__in		efx_nic_t *enp)
1883{
1884	efx_rc_t rc;
1885
1886	/* FIXME */
1887	_NOTE(ARGUNUSED(enp))
1888	if (B_FALSE) {
1889		rc = ENOTSUP;
1890		goto fail1;
1891	}
1892	/* FIXME */
1893
1894	return (0);
1895
1896fail1:
1897	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1898
1899	return (rc);
1900}
1901
1902#endif	/* EFSYS_OPT_DIAG */
1903
1904
1905
1906#endif	/* EFSYS_OPT_HUNTINGTON */
1907