ef10_nic.c revision 299601
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/ef10_nic.c 299601 2016-05-13 07:03:04Z 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 || EFSYS_OPT_MEDFORD
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		uint32_t *flagsp,
434	__out		uint32_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_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1);
461
462	if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)
463		*flags2p = 0;
464	else
465		*flags2p = MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2);
466
467	return (0);
468
469fail2:
470	EFSYS_PROBE(fail2);
471fail1:
472	EFSYS_PROBE1(fail1, efx_rc_t, rc);
473
474	return (rc);
475}
476
477
478static	__checkReturn	efx_rc_t
479efx_mcdi_alloc_vis(
480	__in		efx_nic_t *enp,
481	__in		uint32_t min_vi_count,
482	__in		uint32_t max_vi_count,
483	__out		uint32_t *vi_basep,
484	__out		uint32_t *vi_countp,
485	__out		uint32_t *vi_shiftp)
486{
487	efx_mcdi_req_t req;
488	uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN,
489			    MC_CMD_ALLOC_VIS_OUT_LEN)];
490	efx_rc_t rc;
491
492	if (vi_countp == NULL) {
493		rc = EINVAL;
494		goto fail1;
495	}
496
497	(void) memset(payload, 0, sizeof (payload));
498	req.emr_cmd = MC_CMD_ALLOC_VIS;
499	req.emr_in_buf = payload;
500	req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN;
501	req.emr_out_buf = payload;
502	req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN;
503
504	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count);
505	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count);
506
507	efx_mcdi_execute(enp, &req);
508
509	if (req.emr_rc != 0) {
510		rc = req.emr_rc;
511		goto fail2;
512	}
513
514	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) {
515		rc = EMSGSIZE;
516		goto fail3;
517	}
518
519	*vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE);
520	*vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT);
521
522	/* Report VI_SHIFT if available (always zero for Huntington) */
523	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN)
524		*vi_shiftp = 0;
525	else
526		*vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT);
527
528	return (0);
529
530fail3:
531	EFSYS_PROBE(fail3);
532fail2:
533	EFSYS_PROBE(fail2);
534fail1:
535	EFSYS_PROBE1(fail1, efx_rc_t, rc);
536
537	return (rc);
538}
539
540
541static	__checkReturn	efx_rc_t
542efx_mcdi_free_vis(
543	__in		efx_nic_t *enp)
544{
545	efx_mcdi_req_t req;
546	efx_rc_t rc;
547
548	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0);
549	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0);
550
551	req.emr_cmd = MC_CMD_FREE_VIS;
552	req.emr_in_buf = NULL;
553	req.emr_in_length = 0;
554	req.emr_out_buf = NULL;
555	req.emr_out_length = 0;
556
557	efx_mcdi_execute_quiet(enp, &req);
558
559	/* Ignore ELREADY (no allocated VIs, so nothing to free) */
560	if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) {
561		rc = req.emr_rc;
562		goto fail1;
563	}
564
565	return (0);
566
567fail1:
568	EFSYS_PROBE1(fail1, efx_rc_t, rc);
569
570	return (rc);
571}
572
573
574static	__checkReturn	efx_rc_t
575efx_mcdi_alloc_piobuf(
576	__in		efx_nic_t *enp,
577	__out		efx_piobuf_handle_t *handlep)
578{
579	efx_mcdi_req_t req;
580	uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN,
581			    MC_CMD_ALLOC_PIOBUF_OUT_LEN)];
582	efx_rc_t rc;
583
584	if (handlep == NULL) {
585		rc = EINVAL;
586		goto fail1;
587	}
588
589	(void) memset(payload, 0, sizeof (payload));
590	req.emr_cmd = MC_CMD_ALLOC_PIOBUF;
591	req.emr_in_buf = payload;
592	req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN;
593	req.emr_out_buf = payload;
594	req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN;
595
596	efx_mcdi_execute_quiet(enp, &req);
597
598	if (req.emr_rc != 0) {
599		rc = req.emr_rc;
600		goto fail2;
601	}
602
603	if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) {
604		rc = EMSGSIZE;
605		goto fail3;
606	}
607
608	*handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE);
609
610	return (0);
611
612fail3:
613	EFSYS_PROBE(fail3);
614fail2:
615	EFSYS_PROBE(fail2);
616fail1:
617	EFSYS_PROBE1(fail1, efx_rc_t, rc);
618
619	return (rc);
620}
621
622static	__checkReturn	efx_rc_t
623efx_mcdi_free_piobuf(
624	__in		efx_nic_t *enp,
625	__in		efx_piobuf_handle_t handle)
626{
627	efx_mcdi_req_t req;
628	uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN,
629			    MC_CMD_FREE_PIOBUF_OUT_LEN)];
630	efx_rc_t rc;
631
632	(void) memset(payload, 0, sizeof (payload));
633	req.emr_cmd = MC_CMD_FREE_PIOBUF;
634	req.emr_in_buf = payload;
635	req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN;
636	req.emr_out_buf = payload;
637	req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN;
638
639	MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle);
640
641	efx_mcdi_execute_quiet(enp, &req);
642
643	if (req.emr_rc != 0) {
644		rc = req.emr_rc;
645		goto fail1;
646	}
647
648	return (0);
649
650fail1:
651	EFSYS_PROBE1(fail1, efx_rc_t, rc);
652
653	return (rc);
654}
655
656static	__checkReturn	efx_rc_t
657efx_mcdi_link_piobuf(
658	__in		efx_nic_t *enp,
659	__in		uint32_t vi_index,
660	__in		efx_piobuf_handle_t handle)
661{
662	efx_mcdi_req_t req;
663	uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN,
664			    MC_CMD_LINK_PIOBUF_OUT_LEN)];
665	efx_rc_t rc;
666
667	(void) memset(payload, 0, sizeof (payload));
668	req.emr_cmd = MC_CMD_LINK_PIOBUF;
669	req.emr_in_buf = payload;
670	req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN;
671	req.emr_out_buf = payload;
672	req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN;
673
674	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle);
675	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
676
677	efx_mcdi_execute(enp, &req);
678
679	if (req.emr_rc != 0) {
680		rc = req.emr_rc;
681		goto fail1;
682	}
683
684	return (0);
685
686fail1:
687	EFSYS_PROBE1(fail1, efx_rc_t, rc);
688
689	return (rc);
690}
691
692static	__checkReturn	efx_rc_t
693efx_mcdi_unlink_piobuf(
694	__in		efx_nic_t *enp,
695	__in		uint32_t vi_index)
696{
697	efx_mcdi_req_t req;
698	uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN,
699			    MC_CMD_UNLINK_PIOBUF_OUT_LEN)];
700	efx_rc_t rc;
701
702	(void) memset(payload, 0, sizeof (payload));
703	req.emr_cmd = MC_CMD_UNLINK_PIOBUF;
704	req.emr_in_buf = payload;
705	req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN;
706	req.emr_out_buf = payload;
707	req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN;
708
709	MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
710
711	efx_mcdi_execute(enp, &req);
712
713	if (req.emr_rc != 0) {
714		rc = req.emr_rc;
715		goto fail1;
716	}
717
718	return (0);
719
720fail1:
721	EFSYS_PROBE1(fail1, efx_rc_t, rc);
722
723	return (rc);
724}
725
726static			void
727ef10_nic_alloc_piobufs(
728	__in		efx_nic_t *enp,
729	__in		uint32_t max_piobuf_count)
730{
731	efx_piobuf_handle_t *handlep;
732	unsigned int i;
733	efx_rc_t rc;
734
735	EFSYS_ASSERT3U(max_piobuf_count, <=,
736	    EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle));
737
738	enp->en_arch.ef10.ena_piobuf_count = 0;
739
740	for (i = 0; i < max_piobuf_count; i++) {
741		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
742
743		if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0)
744			goto fail1;
745
746		enp->en_arch.ef10.ena_pio_alloc_map[i] = 0;
747		enp->en_arch.ef10.ena_piobuf_count++;
748	}
749
750	return;
751
752fail1:
753	for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
754		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
755
756		efx_mcdi_free_piobuf(enp, *handlep);
757		*handlep = EFX_PIOBUF_HANDLE_INVALID;
758	}
759	enp->en_arch.ef10.ena_piobuf_count = 0;
760}
761
762
763static			void
764ef10_nic_free_piobufs(
765	__in		efx_nic_t *enp)
766{
767	efx_piobuf_handle_t *handlep;
768	unsigned int i;
769
770	for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
771		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
772
773		efx_mcdi_free_piobuf(enp, *handlep);
774		*handlep = EFX_PIOBUF_HANDLE_INVALID;
775	}
776	enp->en_arch.ef10.ena_piobuf_count = 0;
777}
778
779/* Sub-allocate a block from a piobuf */
780	__checkReturn	efx_rc_t
781ef10_nic_pio_alloc(
782	__inout		efx_nic_t *enp,
783	__out		uint32_t *bufnump,
784	__out		efx_piobuf_handle_t *handlep,
785	__out		uint32_t *blknump,
786	__out		uint32_t *offsetp,
787	__out		size_t *sizep)
788{
789	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
790	efx_drv_cfg_t *edcp = &enp->en_drv_cfg;
791	uint32_t blk_per_buf;
792	uint32_t buf, blk;
793	efx_rc_t rc;
794
795	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
796		    enp->en_family == EFX_FAMILY_MEDFORD);
797	EFSYS_ASSERT(bufnump);
798	EFSYS_ASSERT(handlep);
799	EFSYS_ASSERT(blknump);
800	EFSYS_ASSERT(offsetp);
801	EFSYS_ASSERT(sizep);
802
803	if ((edcp->edc_pio_alloc_size == 0) ||
804	    (enp->en_arch.ef10.ena_piobuf_count == 0)) {
805		rc = ENOMEM;
806		goto fail1;
807	}
808	blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size;
809
810	for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) {
811		uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf];
812
813		if (~(*map) == 0)
814			continue;
815
816		EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map)));
817		for (blk = 0; blk < blk_per_buf; blk++) {
818			if ((*map & (1u << blk)) == 0) {
819				*map |= (1u << blk);
820				goto done;
821			}
822		}
823	}
824	rc = ENOMEM;
825	goto fail2;
826
827done:
828	*handlep = enp->en_arch.ef10.ena_piobuf_handle[buf];
829	*bufnump = buf;
830	*blknump = blk;
831	*sizep = edcp->edc_pio_alloc_size;
832	*offsetp = blk * (*sizep);
833
834	return (0);
835
836fail2:
837	EFSYS_PROBE(fail2);
838fail1:
839	EFSYS_PROBE1(fail1, efx_rc_t, rc);
840
841	return (rc);
842}
843
844/* Free a piobuf sub-allocated block */
845	__checkReturn	efx_rc_t
846ef10_nic_pio_free(
847	__inout		efx_nic_t *enp,
848	__in		uint32_t bufnum,
849	__in		uint32_t blknum)
850{
851	uint32_t *map;
852	efx_rc_t rc;
853
854	if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) ||
855	    (blknum >= (8 * sizeof (*map)))) {
856		rc = EINVAL;
857		goto fail1;
858	}
859
860	map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum];
861	if ((*map & (1u << blknum)) == 0) {
862		rc = ENOENT;
863		goto fail2;
864	}
865	*map &= ~(1u << blknum);
866
867	return (0);
868
869fail2:
870	EFSYS_PROBE(fail2);
871fail1:
872	EFSYS_PROBE1(fail1, efx_rc_t, rc);
873
874	return (rc);
875}
876
877	__checkReturn	efx_rc_t
878ef10_nic_pio_link(
879	__inout		efx_nic_t *enp,
880	__in		uint32_t vi_index,
881	__in		efx_piobuf_handle_t handle)
882{
883	return (efx_mcdi_link_piobuf(enp, vi_index, handle));
884}
885
886	__checkReturn	efx_rc_t
887ef10_nic_pio_unlink(
888	__inout		efx_nic_t *enp,
889	__in		uint32_t vi_index)
890{
891	return (efx_mcdi_unlink_piobuf(enp, vi_index));
892}
893
894	__checkReturn	efx_rc_t
895ef10_get_datapath_caps(
896	__in		efx_nic_t *enp)
897{
898	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
899	uint32_t flags;
900	uint32_t flags2;
901	efx_rc_t rc;
902
903	if ((rc = efx_mcdi_get_capabilities(enp, &flags, &flags2)) != 0)
904		goto fail1;
905
906#define	CAP_FLAG(flags1, field)		\
907	((flags1) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN)))
908
909#define	CAP_FLAG2(flags2, field)	\
910	((flags2) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN)))
911
912	/*
913	 * Huntington RXDP firmware inserts a 0 or 14 byte prefix.
914	 * We only support the 14 byte prefix here.
915	 */
916	if (CAP_FLAG(flags, RX_PREFIX_LEN_14) == 0) {
917		rc = ENOTSUP;
918		goto fail2;
919	}
920	encp->enc_rx_prefix_size = 14;
921
922	/* Check if the firmware supports TSO */
923	encp->enc_fw_assisted_tso_enabled =
924	    CAP_FLAG(flags, TX_TSO) ? B_TRUE : B_FALSE;
925
926	/* Check if the firmware supports FATSOv2 */
927	encp->enc_fw_assisted_tso_v2_enabled =
928	    CAP_FLAG2(flags2, TX_TSO_V2) ? B_TRUE : B_FALSE;
929
930	/* Check if the firmware has vadapter/vport/vswitch support */
931	encp->enc_datapath_cap_evb =
932	    CAP_FLAG(flags, EVB) ? B_TRUE : B_FALSE;
933
934	/* Check if the firmware supports VLAN insertion */
935	encp->enc_hw_tx_insert_vlan_enabled =
936	    CAP_FLAG(flags, TX_VLAN_INSERTION) ? B_TRUE : B_FALSE;
937
938	/* Check if the firmware supports RX event batching */
939	encp->enc_rx_batching_enabled =
940	    CAP_FLAG(flags, RX_BATCHING) ? B_TRUE : B_FALSE;
941
942	if (encp->enc_rx_batching_enabled)
943		encp->enc_rx_batch_max = 16;
944
945	/* Check if the firmware supports disabling scatter on RXQs */
946	encp->enc_rx_disable_scatter_supported =
947	    CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE;
948
949	/* Check if the firmware supports set mac with running filters */
950	encp->enc_allow_set_mac_with_installed_filters =
951	    CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ?
952	    B_TRUE : B_FALSE;
953
954	/*
955	 * Check if firmware supports the extended MC_CMD_SET_MAC, which allows
956	 * specifying which parameters to configure.
957	 */
958	encp->enc_enhanced_set_mac_supported =
959		CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE;
960
961#undef CAP_FLAG
962#undef CAP_FLAG2
963
964	return (0);
965
966fail2:
967	EFSYS_PROBE(fail2);
968fail1:
969	EFSYS_PROBE1(fail1, efx_rc_t, rc);
970
971	return (rc);
972}
973
974
975	__checkReturn		efx_rc_t
976ef10_get_privilege_mask(
977	__in			efx_nic_t *enp,
978	__out			uint32_t *maskp)
979{
980	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
981	uint32_t mask;
982	efx_rc_t rc;
983
984	if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf,
985					    &mask)) != 0) {
986		if (rc != ENOTSUP)
987			goto fail1;
988
989		/* Fallback for old firmware without privilege mask support */
990		if (EFX_PCI_FUNCTION_IS_PF(encp)) {
991			/* Assume PF has admin privilege */
992			mask = EF10_LEGACY_PF_PRIVILEGE_MASK;
993		} else {
994			/* VF is always unprivileged by default */
995			mask = EF10_LEGACY_VF_PRIVILEGE_MASK;
996		}
997	}
998
999	*maskp = mask;
1000
1001	return (0);
1002
1003fail1:
1004	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1005
1006	return (rc);
1007}
1008
1009
1010/*
1011 * The external port mapping is a one-based numbering of the external
1012 * connectors on the board. It does not distinguish off-board separated
1013 * outputs such as multi-headed cables.
1014 * The number of ports that map to each external port connector
1015 * on the board is determined by the chip family and the port modes to
1016 * which the NIC can be configured. The mapping table lists modes with
1017 * port numbering requirements in increasing order.
1018 */
1019static struct {
1020	efx_family_t	family;
1021	uint32_t	modes_mask;
1022	uint32_t	stride;
1023}	__ef10_external_port_mappings[] = {
1024	/* Supported modes requiring 1 output per port */
1025	{
1026		EFX_FAMILY_HUNTINGTON,
1027		(1 << TLV_PORT_MODE_10G) |
1028		(1 << TLV_PORT_MODE_10G_10G) |
1029		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
1030		1
1031	},
1032	{
1033		EFX_FAMILY_MEDFORD,
1034		(1 << TLV_PORT_MODE_10G) |
1035		(1 << TLV_PORT_MODE_10G_10G) |
1036		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
1037		1
1038	},
1039	/* Supported modes requiring 2 outputs per port */
1040	{
1041		EFX_FAMILY_HUNTINGTON,
1042		(1 << TLV_PORT_MODE_40G) |
1043		(1 << TLV_PORT_MODE_40G_40G) |
1044		(1 << TLV_PORT_MODE_40G_10G_10G) |
1045		(1 << TLV_PORT_MODE_10G_10G_40G),
1046		2
1047	},
1048	{
1049		EFX_FAMILY_MEDFORD,
1050		(1 << TLV_PORT_MODE_40G) |
1051		(1 << TLV_PORT_MODE_40G_40G) |
1052		(1 << TLV_PORT_MODE_40G_10G_10G) |
1053		(1 << TLV_PORT_MODE_10G_10G_40G),
1054		2
1055	},
1056	/* Supported modes requiring 4 outputs per port */
1057	{
1058		EFX_FAMILY_MEDFORD,
1059		(1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) |
1060		(1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2),
1061		4
1062	},
1063};
1064
1065	__checkReturn	efx_rc_t
1066ef10_external_port_mapping(
1067	__in		efx_nic_t *enp,
1068	__in		uint32_t port,
1069	__out		uint8_t *external_portp)
1070{
1071	efx_rc_t rc;
1072	int i;
1073	uint32_t port_modes;
1074	uint32_t matches;
1075	uint32_t stride = 1; /* default 1-1 mapping */
1076
1077	if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) {
1078		/* No port mode information available - use default mapping */
1079		goto out;
1080	}
1081
1082	/*
1083	 * Infer the internal port -> external port mapping from
1084	 * the possible port modes for this NIC.
1085	 */
1086	for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) {
1087		if (__ef10_external_port_mappings[i].family !=
1088		    enp->en_family)
1089			continue;
1090		matches = (__ef10_external_port_mappings[i].modes_mask &
1091		    port_modes);
1092		if (matches != 0) {
1093			stride = __ef10_external_port_mappings[i].stride;
1094			port_modes &= ~matches;
1095		}
1096	}
1097
1098	if (port_modes != 0) {
1099		/* Some advertised modes are not supported */
1100		rc = ENOTSUP;
1101		goto fail1;
1102	}
1103
1104out:
1105	/*
1106	 * Scale as required by last matched mode and then convert to
1107	 * one-based numbering
1108	 */
1109	*external_portp = (uint8_t)(port / stride) + 1;
1110	return (0);
1111
1112fail1:
1113	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1114
1115	return (rc);
1116}
1117
1118
1119	__checkReturn	efx_rc_t
1120ef10_nic_probe(
1121	__in		efx_nic_t *enp)
1122{
1123	const efx_nic_ops_t *enop = enp->en_enop;
1124	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1125	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1126	efx_rc_t rc;
1127
1128	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1129		    enp->en_family == EFX_FAMILY_MEDFORD);
1130
1131	/* Read and clear any assertion state */
1132	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1133		goto fail1;
1134
1135	/* Exit the assertion handler */
1136	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1137		if (rc != EACCES)
1138			goto fail2;
1139
1140	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
1141		goto fail3;
1142
1143	if ((rc = enop->eno_board_cfg(enp)) != 0)
1144		if (rc != EACCES)
1145			goto fail4;
1146
1147	/*
1148	 * Set default driver config limits (based on board config).
1149	 *
1150	 * FIXME: For now allocate a fixed number of VIs which is likely to be
1151	 * sufficient and small enough to allow multiple functions on the same
1152	 * port.
1153	 */
1154	edcp->edc_min_vi_count = edcp->edc_max_vi_count =
1155	    MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit));
1156
1157	/* The client driver must configure and enable PIO buffer support */
1158	edcp->edc_max_piobuf_count = 0;
1159	edcp->edc_pio_alloc_size = 0;
1160
1161#if EFSYS_OPT_MAC_STATS
1162	/* Wipe the MAC statistics */
1163	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
1164		goto fail5;
1165#endif
1166
1167#if EFSYS_OPT_LOOPBACK
1168	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
1169		goto fail6;
1170#endif
1171
1172#if EFSYS_OPT_MON_STATS
1173	if ((rc = mcdi_mon_cfg_build(enp)) != 0) {
1174		/* Unprivileged functions do not have access to sensors */
1175		if (rc != EACCES)
1176			goto fail7;
1177	}
1178#endif
1179
1180	encp->enc_features = enp->en_features;
1181
1182	return (0);
1183
1184#if EFSYS_OPT_MON_STATS
1185fail7:
1186	EFSYS_PROBE(fail7);
1187#endif
1188#if EFSYS_OPT_LOOPBACK
1189fail6:
1190	EFSYS_PROBE(fail6);
1191#endif
1192#if EFSYS_OPT_MAC_STATS
1193fail5:
1194	EFSYS_PROBE(fail5);
1195#endif
1196fail4:
1197	EFSYS_PROBE(fail4);
1198fail3:
1199	EFSYS_PROBE(fail3);
1200fail2:
1201	EFSYS_PROBE(fail2);
1202fail1:
1203	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1204
1205	return (rc);
1206}
1207
1208	__checkReturn	efx_rc_t
1209ef10_nic_set_drv_limits(
1210	__inout		efx_nic_t *enp,
1211	__in		efx_drv_limits_t *edlp)
1212{
1213	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1214	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1215	uint32_t min_evq_count, max_evq_count;
1216	uint32_t min_rxq_count, max_rxq_count;
1217	uint32_t min_txq_count, max_txq_count;
1218	efx_rc_t rc;
1219
1220	if (edlp == NULL) {
1221		rc = EINVAL;
1222		goto fail1;
1223	}
1224
1225	/* Get minimum required and maximum usable VI limits */
1226	min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit);
1227	min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit);
1228	min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit);
1229
1230	edcp->edc_min_vi_count =
1231	    MAX(min_evq_count, MAX(min_rxq_count, min_txq_count));
1232
1233	max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit);
1234	max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit);
1235	max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit);
1236
1237	edcp->edc_max_vi_count =
1238	    MAX(max_evq_count, MAX(max_rxq_count, max_txq_count));
1239
1240	/*
1241	 * Check limits for sub-allocated piobuf blocks.
1242	 * PIO is optional, so don't fail if the limits are incorrect.
1243	 */
1244	if ((encp->enc_piobuf_size == 0) ||
1245	    (encp->enc_piobuf_limit == 0) ||
1246	    (edlp->edl_min_pio_alloc_size == 0) ||
1247	    (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) {
1248		/* Disable PIO */
1249		edcp->edc_max_piobuf_count = 0;
1250		edcp->edc_pio_alloc_size = 0;
1251	} else {
1252		uint32_t blk_size, blk_count, blks_per_piobuf;
1253
1254		blk_size =
1255		    MAX(edlp->edl_min_pio_alloc_size,
1256			    encp->enc_piobuf_min_alloc_size);
1257
1258		blks_per_piobuf = encp->enc_piobuf_size / blk_size;
1259		EFSYS_ASSERT3U(blks_per_piobuf, <=, 32);
1260
1261		blk_count = (encp->enc_piobuf_limit * blks_per_piobuf);
1262
1263		/* A zero max pio alloc count means unlimited */
1264		if ((edlp->edl_max_pio_alloc_count > 0) &&
1265		    (edlp->edl_max_pio_alloc_count < blk_count)) {
1266			blk_count = edlp->edl_max_pio_alloc_count;
1267		}
1268
1269		edcp->edc_pio_alloc_size = blk_size;
1270		edcp->edc_max_piobuf_count =
1271		    (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf;
1272	}
1273
1274	return (0);
1275
1276fail1:
1277	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1278
1279	return (rc);
1280}
1281
1282
1283	__checkReturn	efx_rc_t
1284ef10_nic_reset(
1285	__in		efx_nic_t *enp)
1286{
1287	efx_mcdi_req_t req;
1288	uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN,
1289			    MC_CMD_ENTITY_RESET_OUT_LEN)];
1290	efx_rc_t rc;
1291
1292	/* ef10_nic_reset() is called to recover from BADASSERT failures. */
1293	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1294		goto fail1;
1295	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1296		goto fail2;
1297
1298	(void) memset(payload, 0, sizeof (payload));
1299	req.emr_cmd = MC_CMD_ENTITY_RESET;
1300	req.emr_in_buf = payload;
1301	req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN;
1302	req.emr_out_buf = payload;
1303	req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN;
1304
1305	MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG,
1306	    ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1);
1307
1308	efx_mcdi_execute(enp, &req);
1309
1310	if (req.emr_rc != 0) {
1311		rc = req.emr_rc;
1312		goto fail3;
1313	}
1314
1315	/* Clear RX/TX DMA queue errors */
1316	enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR);
1317
1318	return (0);
1319
1320fail3:
1321	EFSYS_PROBE(fail3);
1322fail2:
1323	EFSYS_PROBE(fail2);
1324fail1:
1325	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1326
1327	return (rc);
1328}
1329
1330	__checkReturn	efx_rc_t
1331ef10_nic_init(
1332	__in		efx_nic_t *enp)
1333{
1334	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1335	uint32_t min_vi_count, max_vi_count;
1336	uint32_t vi_count, vi_base, vi_shift;
1337	uint32_t i;
1338	uint32_t retry;
1339	uint32_t delay_us;
1340	efx_rc_t rc;
1341
1342	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1343		    enp->en_family == EFX_FAMILY_MEDFORD);
1344
1345	/* Enable reporting of some events (e.g. link change) */
1346	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
1347		goto fail1;
1348
1349	/* Allocate (optional) on-chip PIO buffers */
1350	ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count);
1351
1352	/*
1353	 * For best performance, PIO writes should use a write-combined
1354	 * (WC) memory mapping. Using a separate WC mapping for the PIO
1355	 * aperture of each VI would be a burden to drivers (and not
1356	 * possible if the host page size is >4Kbyte).
1357	 *
1358	 * To avoid this we use a single uncached (UC) mapping for VI
1359	 * register access, and a single WC mapping for extra VIs used
1360	 * for PIO writes.
1361	 *
1362	 * Each piobuf must be linked to a VI in the WC mapping, and to
1363	 * each VI that is using a sub-allocated block from the piobuf.
1364	 */
1365	min_vi_count = edcp->edc_min_vi_count;
1366	max_vi_count =
1367	    edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count;
1368
1369	/* Ensure that the previously attached driver's VIs are freed */
1370	if ((rc = efx_mcdi_free_vis(enp)) != 0)
1371		goto fail2;
1372
1373	/*
1374	 * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this
1375	 * fails then retrying the request for fewer VI resources may succeed.
1376	 */
1377	vi_count = 0;
1378	if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count,
1379		    &vi_base, &vi_count, &vi_shift)) != 0)
1380		goto fail3;
1381
1382	EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count);
1383
1384	if (vi_count < min_vi_count) {
1385		rc = ENOMEM;
1386		goto fail4;
1387	}
1388
1389	enp->en_arch.ef10.ena_vi_base = vi_base;
1390	enp->en_arch.ef10.ena_vi_count = vi_count;
1391	enp->en_arch.ef10.ena_vi_shift = vi_shift;
1392
1393	if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) {
1394		/* Not enough extra VIs to map piobufs */
1395		ef10_nic_free_piobufs(enp);
1396	}
1397
1398	enp->en_arch.ef10.ena_pio_write_vi_base =
1399	    vi_count - enp->en_arch.ef10.ena_piobuf_count;
1400
1401	/* Save UC memory mapping details */
1402	enp->en_arch.ef10.ena_uc_mem_map_offset = 0;
1403	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1404		enp->en_arch.ef10.ena_uc_mem_map_size =
1405		    (ER_DZ_TX_PIOBUF_STEP *
1406		    enp->en_arch.ef10.ena_pio_write_vi_base);
1407	} else {
1408		enp->en_arch.ef10.ena_uc_mem_map_size =
1409		    (ER_DZ_TX_PIOBUF_STEP *
1410		    enp->en_arch.ef10.ena_vi_count);
1411	}
1412
1413	/* Save WC memory mapping details */
1414	enp->en_arch.ef10.ena_wc_mem_map_offset =
1415	    enp->en_arch.ef10.ena_uc_mem_map_offset +
1416	    enp->en_arch.ef10.ena_uc_mem_map_size;
1417
1418	enp->en_arch.ef10.ena_wc_mem_map_size =
1419	    (ER_DZ_TX_PIOBUF_STEP *
1420	    enp->en_arch.ef10.ena_piobuf_count);
1421
1422	/* Link piobufs to extra VIs in WC mapping */
1423	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1424		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
1425			rc = efx_mcdi_link_piobuf(enp,
1426			    enp->en_arch.ef10.ena_pio_write_vi_base + i,
1427			    enp->en_arch.ef10.ena_piobuf_handle[i]);
1428			if (rc != 0)
1429				break;
1430		}
1431	}
1432
1433	/*
1434	 * Allocate a vAdaptor attached to our upstream vPort/pPort.
1435	 *
1436	 * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF
1437	 * driver has yet to bring up the EVB port. See bug 56147. In this case,
1438	 * retry the request several times after waiting a while. The wait time
1439	 * between retries starts small (10ms) and exponentially increases.
1440	 * Total wait time is a little over two seconds. Retry logic in the
1441	 * client driver may mean this whole loop is repeated if it continues to
1442	 * fail.
1443	 */
1444	retry = 0;
1445	delay_us = 10000;
1446	while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) {
1447		if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) ||
1448		    (rc != ENOENT)) {
1449			/*
1450			 * Do not retry alloc for PF, or for other errors on
1451			 * a VF.
1452			 */
1453			goto fail5;
1454		}
1455
1456		/* VF startup before PF is ready. Retry allocation. */
1457		if (retry > 5) {
1458			/* Too many attempts */
1459			rc = EINVAL;
1460			goto fail6;
1461		}
1462		EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry);
1463		EFSYS_SLEEP(delay_us);
1464		retry++;
1465		if (delay_us < 500000)
1466			delay_us <<= 2;
1467	}
1468
1469	enp->en_vport_id = EVB_PORT_ID_ASSIGNED;
1470	enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2;
1471
1472	return (0);
1473
1474fail6:
1475	EFSYS_PROBE(fail6);
1476fail5:
1477	EFSYS_PROBE(fail5);
1478fail4:
1479	EFSYS_PROBE(fail4);
1480fail3:
1481	EFSYS_PROBE(fail3);
1482fail2:
1483	EFSYS_PROBE(fail2);
1484
1485	ef10_nic_free_piobufs(enp);
1486
1487fail1:
1488	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1489
1490	return (rc);
1491}
1492
1493	__checkReturn	efx_rc_t
1494ef10_nic_get_vi_pool(
1495	__in		efx_nic_t *enp,
1496	__out		uint32_t *vi_countp)
1497{
1498	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1499		    enp->en_family == EFX_FAMILY_MEDFORD);
1500
1501	/*
1502	 * Report VIs that the client driver can use.
1503	 * Do not include VIs used for PIO buffer writes.
1504	 */
1505	*vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base;
1506
1507	return (0);
1508}
1509
1510	__checkReturn	efx_rc_t
1511ef10_nic_get_bar_region(
1512	__in		efx_nic_t *enp,
1513	__in		efx_nic_region_t region,
1514	__out		uint32_t *offsetp,
1515	__out		size_t *sizep)
1516{
1517	efx_rc_t rc;
1518
1519	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1520		    enp->en_family == EFX_FAMILY_MEDFORD);
1521
1522	/*
1523	 * TODO: Specify host memory mapping alignment and granularity
1524	 * in efx_drv_limits_t so that they can be taken into account
1525	 * when allocating extra VIs for PIO writes.
1526	 */
1527	switch (region) {
1528	case EFX_REGION_VI:
1529		/* UC mapped memory BAR region for VI registers */
1530		*offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset;
1531		*sizep = enp->en_arch.ef10.ena_uc_mem_map_size;
1532		break;
1533
1534	case EFX_REGION_PIO_WRITE_VI:
1535		/* WC mapped memory BAR region for piobuf writes */
1536		*offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset;
1537		*sizep = enp->en_arch.ef10.ena_wc_mem_map_size;
1538		break;
1539
1540	default:
1541		rc = EINVAL;
1542		goto fail1;
1543	}
1544
1545	return (0);
1546
1547fail1:
1548	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1549
1550	return (rc);
1551}
1552
1553			void
1554ef10_nic_fini(
1555	__in		efx_nic_t *enp)
1556{
1557	uint32_t i;
1558	efx_rc_t rc;
1559
1560	(void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id);
1561	enp->en_vport_id = 0;
1562
1563	/* Unlink piobufs from extra VIs in WC mapping */
1564	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1565		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
1566			rc = efx_mcdi_unlink_piobuf(enp,
1567			    enp->en_arch.ef10.ena_pio_write_vi_base + i);
1568			if (rc != 0)
1569				break;
1570		}
1571	}
1572
1573	ef10_nic_free_piobufs(enp);
1574
1575	(void) efx_mcdi_free_vis(enp);
1576	enp->en_arch.ef10.ena_vi_count = 0;
1577}
1578
1579			void
1580ef10_nic_unprobe(
1581	__in		efx_nic_t *enp)
1582{
1583#if EFSYS_OPT_MON_STATS
1584	mcdi_mon_cfg_free(enp);
1585#endif /* EFSYS_OPT_MON_STATS */
1586	(void) efx_mcdi_drv_attach(enp, B_FALSE);
1587}
1588
1589#if EFSYS_OPT_DIAG
1590
1591	__checkReturn	efx_rc_t
1592ef10_nic_register_test(
1593	__in		efx_nic_t *enp)
1594{
1595	efx_rc_t rc;
1596
1597	/* FIXME */
1598	_NOTE(ARGUNUSED(enp))
1599	if (B_FALSE) {
1600		rc = ENOTSUP;
1601		goto fail1;
1602	}
1603	/* FIXME */
1604
1605	return (0);
1606
1607fail1:
1608	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1609
1610	return (rc);
1611}
1612
1613#endif	/* EFSYS_OPT_DIAG */
1614
1615
1616#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1617