ef10_nic.c revision 300844
1/*-
2 * Copyright (c) 2012-2016 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 300844 2016-05-27 11:47:11Z 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	__out_opt	uint32_t *current_modep)
93{
94	efx_mcdi_req_t req;
95	uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN,
96			    MC_CMD_GET_PORT_MODES_OUT_LEN)];
97	efx_rc_t rc;
98
99	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
100		    enp->en_family == EFX_FAMILY_MEDFORD);
101
102	(void) memset(payload, 0, sizeof (payload));
103	req.emr_cmd = MC_CMD_GET_PORT_MODES;
104	req.emr_in_buf = payload;
105	req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN;
106	req.emr_out_buf = payload;
107	req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN;
108
109	efx_mcdi_execute(enp, &req);
110
111	if (req.emr_rc != 0) {
112		rc = req.emr_rc;
113		goto fail1;
114	}
115
116	/*
117	 * Require only Modes and DefaultMode fields, unless the current mode
118	 * was requested (CurrentMode field was added for Medford).
119	 */
120	if (req.emr_out_length_used <
121	    MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) {
122		rc = EMSGSIZE;
123		goto fail2;
124	}
125	if ((current_modep != NULL) && (req.emr_out_length_used <
126	    MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST + 4)) {
127		rc = EMSGSIZE;
128		goto fail3;
129	}
130
131	*modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES);
132
133	if (current_modep != NULL) {
134		*current_modep = MCDI_OUT_DWORD(req,
135					    GET_PORT_MODES_OUT_CURRENT_MODE);
136	}
137
138	return (0);
139
140fail3:
141	EFSYS_PROBE(fail3);
142fail2:
143	EFSYS_PROBE(fail2);
144fail1:
145	EFSYS_PROBE1(fail1, efx_rc_t, rc);
146
147	return (rc);
148}
149
150	__checkReturn	efx_rc_t
151ef10_nic_get_port_mode_bandwidth(
152	__in		uint32_t port_mode,
153	__out		uint32_t *bandwidth_mbpsp)
154{
155	uint32_t bandwidth;
156	efx_rc_t rc;
157
158	switch (port_mode) {
159	case TLV_PORT_MODE_10G:
160		bandwidth = 10000;
161		break;
162	case TLV_PORT_MODE_10G_10G:
163		bandwidth = 10000 * 2;
164		break;
165	case TLV_PORT_MODE_10G_10G_10G_10G:
166	case TLV_PORT_MODE_10G_10G_10G_10G_Q:
167	case TLV_PORT_MODE_10G_10G_10G_10G_Q2:
168		bandwidth = 10000 * 4;
169		break;
170	case TLV_PORT_MODE_40G:
171		bandwidth = 40000;
172		break;
173	case TLV_PORT_MODE_40G_40G:
174		bandwidth = 40000 * 2;
175		break;
176	case TLV_PORT_MODE_40G_10G_10G:
177	case TLV_PORT_MODE_10G_10G_40G:
178		bandwidth = 40000 + (10000 * 2);
179		break;
180	default:
181		rc = EINVAL;
182		goto fail1;
183	}
184
185	*bandwidth_mbpsp = bandwidth;
186
187	return (0);
188
189fail1:
190	EFSYS_PROBE1(fail1, efx_rc_t, rc);
191
192	return (rc);
193}
194
195static	__checkReturn		efx_rc_t
196efx_mcdi_vadaptor_alloc(
197	__in			efx_nic_t *enp,
198	__in			uint32_t port_id)
199{
200	efx_mcdi_req_t req;
201	uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN,
202			    MC_CMD_VADAPTOR_ALLOC_OUT_LEN)];
203	efx_rc_t rc;
204
205	EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL);
206
207	(void) memset(payload, 0, sizeof (payload));
208	req.emr_cmd = MC_CMD_VADAPTOR_ALLOC;
209	req.emr_in_buf = payload;
210	req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN;
211	req.emr_out_buf = payload;
212	req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN;
213
214	MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
215	MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS,
216	    VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED,
217	    enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 0);
218
219	efx_mcdi_execute(enp, &req);
220
221	if (req.emr_rc != 0) {
222		rc = req.emr_rc;
223		goto fail1;
224	}
225
226	return (0);
227
228fail1:
229	EFSYS_PROBE1(fail1, efx_rc_t, rc);
230
231	return (rc);
232}
233
234static	__checkReturn		efx_rc_t
235efx_mcdi_vadaptor_free(
236	__in			efx_nic_t *enp,
237	__in			uint32_t port_id)
238{
239	efx_mcdi_req_t req;
240	uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN,
241			    MC_CMD_VADAPTOR_FREE_OUT_LEN)];
242	efx_rc_t rc;
243
244	(void) memset(payload, 0, sizeof (payload));
245	req.emr_cmd = MC_CMD_VADAPTOR_FREE;
246	req.emr_in_buf = payload;
247	req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN;
248	req.emr_out_buf = payload;
249	req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN;
250
251	MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
252
253	efx_mcdi_execute(enp, &req);
254
255	if (req.emr_rc != 0) {
256		rc = req.emr_rc;
257		goto fail1;
258	}
259
260	return (0);
261
262fail1:
263	EFSYS_PROBE1(fail1, efx_rc_t, rc);
264
265	return (rc);
266}
267
268	__checkReturn	efx_rc_t
269efx_mcdi_get_mac_address_pf(
270	__in			efx_nic_t *enp,
271	__out_ecount_opt(6)	uint8_t mac_addrp[6])
272{
273	efx_mcdi_req_t req;
274	uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN,
275			    MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)];
276	efx_rc_t rc;
277
278	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
279		    enp->en_family == EFX_FAMILY_MEDFORD);
280
281	(void) memset(payload, 0, sizeof (payload));
282	req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES;
283	req.emr_in_buf = payload;
284	req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN;
285	req.emr_out_buf = payload;
286	req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN;
287
288	efx_mcdi_execute(enp, &req);
289
290	if (req.emr_rc != 0) {
291		rc = req.emr_rc;
292		goto fail1;
293	}
294
295	if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) {
296		rc = EMSGSIZE;
297		goto fail2;
298	}
299
300	if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) {
301		rc = ENOENT;
302		goto fail3;
303	}
304
305	if (mac_addrp != NULL) {
306		uint8_t *addrp;
307
308		addrp = MCDI_OUT2(req, uint8_t,
309		    GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE);
310
311		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
312	}
313
314	return (0);
315
316fail3:
317	EFSYS_PROBE(fail3);
318fail2:
319	EFSYS_PROBE(fail2);
320fail1:
321	EFSYS_PROBE1(fail1, efx_rc_t, rc);
322
323	return (rc);
324}
325
326	__checkReturn	efx_rc_t
327efx_mcdi_get_mac_address_vf(
328	__in			efx_nic_t *enp,
329	__out_ecount_opt(6)	uint8_t mac_addrp[6])
330{
331	efx_mcdi_req_t req;
332	uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN,
333			    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)];
334	efx_rc_t rc;
335
336	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
337		    enp->en_family == EFX_FAMILY_MEDFORD);
338
339	(void) memset(payload, 0, sizeof (payload));
340	req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES;
341	req.emr_in_buf = payload;
342	req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN;
343	req.emr_out_buf = payload;
344	req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX;
345
346	MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID,
347	    EVB_PORT_ID_ASSIGNED);
348
349	efx_mcdi_execute(enp, &req);
350
351	if (req.emr_rc != 0) {
352		rc = req.emr_rc;
353		goto fail1;
354	}
355
356	if (req.emr_out_length_used <
357	    MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) {
358		rc = EMSGSIZE;
359		goto fail2;
360	}
361
362	if (MCDI_OUT_DWORD(req,
363		VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) {
364		rc = ENOENT;
365		goto fail3;
366	}
367
368	if (mac_addrp != NULL) {
369		uint8_t *addrp;
370
371		addrp = MCDI_OUT2(req, uint8_t,
372		    VPORT_GET_MAC_ADDRESSES_OUT_MACADDR);
373
374		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
375	}
376
377	return (0);
378
379fail3:
380	EFSYS_PROBE(fail3);
381fail2:
382	EFSYS_PROBE(fail2);
383fail1:
384	EFSYS_PROBE1(fail1, efx_rc_t, rc);
385
386	return (rc);
387}
388
389	__checkReturn	efx_rc_t
390efx_mcdi_get_clock(
391	__in		efx_nic_t *enp,
392	__out		uint32_t *sys_freqp,
393	__out		uint32_t *dpcpu_freqp)
394{
395	efx_mcdi_req_t req;
396	uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN,
397			    MC_CMD_GET_CLOCK_OUT_LEN)];
398	efx_rc_t rc;
399
400	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
401		    enp->en_family == EFX_FAMILY_MEDFORD);
402
403	(void) memset(payload, 0, sizeof (payload));
404	req.emr_cmd = MC_CMD_GET_CLOCK;
405	req.emr_in_buf = payload;
406	req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN;
407	req.emr_out_buf = payload;
408	req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN;
409
410	efx_mcdi_execute(enp, &req);
411
412	if (req.emr_rc != 0) {
413		rc = req.emr_rc;
414		goto fail1;
415	}
416
417	if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) {
418		rc = EMSGSIZE;
419		goto fail2;
420	}
421
422	*sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ);
423	if (*sys_freqp == 0) {
424		rc = EINVAL;
425		goto fail3;
426	}
427	*dpcpu_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_DPCPU_FREQ);
428	if (*dpcpu_freqp == 0) {
429		rc = EINVAL;
430		goto fail4;
431	}
432
433	return (0);
434
435fail4:
436	EFSYS_PROBE(fail4);
437fail3:
438	EFSYS_PROBE(fail3);
439fail2:
440	EFSYS_PROBE(fail2);
441fail1:
442	EFSYS_PROBE1(fail1, efx_rc_t, rc);
443
444	return (rc);
445}
446
447	__checkReturn	efx_rc_t
448efx_mcdi_get_vector_cfg(
449	__in		efx_nic_t *enp,
450	__out_opt	uint32_t *vec_basep,
451	__out_opt	uint32_t *pf_nvecp,
452	__out_opt	uint32_t *vf_nvecp)
453{
454	efx_mcdi_req_t req;
455	uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN,
456			    MC_CMD_GET_VECTOR_CFG_OUT_LEN)];
457	efx_rc_t rc;
458
459	(void) memset(payload, 0, sizeof (payload));
460	req.emr_cmd = MC_CMD_GET_VECTOR_CFG;
461	req.emr_in_buf = payload;
462	req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN;
463	req.emr_out_buf = payload;
464	req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN;
465
466	efx_mcdi_execute(enp, &req);
467
468	if (req.emr_rc != 0) {
469		rc = req.emr_rc;
470		goto fail1;
471	}
472
473	if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) {
474		rc = EMSGSIZE;
475		goto fail2;
476	}
477
478	if (vec_basep != NULL)
479		*vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE);
480	if (pf_nvecp != NULL)
481		*pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF);
482	if (vf_nvecp != NULL)
483		*vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF);
484
485	return (0);
486
487fail2:
488	EFSYS_PROBE(fail2);
489fail1:
490	EFSYS_PROBE1(fail1, efx_rc_t, rc);
491
492	return (rc);
493}
494
495static	__checkReturn	efx_rc_t
496efx_mcdi_get_capabilities(
497	__in		efx_nic_t *enp,
498	__out		uint32_t *flagsp,
499	__out		uint32_t *flags2p)
500{
501	efx_mcdi_req_t req;
502	uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN,
503			    MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)];
504	efx_rc_t rc;
505
506	(void) memset(payload, 0, sizeof (payload));
507	req.emr_cmd = MC_CMD_GET_CAPABILITIES;
508	req.emr_in_buf = payload;
509	req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
510	req.emr_out_buf = payload;
511	req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN;
512
513	efx_mcdi_execute(enp, &req);
514
515	if (req.emr_rc != 0) {
516		rc = req.emr_rc;
517		goto fail1;
518	}
519
520	if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
521		rc = EMSGSIZE;
522		goto fail2;
523	}
524
525	*flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1);
526
527	if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)
528		*flags2p = 0;
529	else
530		*flags2p = MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2);
531
532	return (0);
533
534fail2:
535	EFSYS_PROBE(fail2);
536fail1:
537	EFSYS_PROBE1(fail1, efx_rc_t, rc);
538
539	return (rc);
540}
541
542
543static	__checkReturn	efx_rc_t
544efx_mcdi_alloc_vis(
545	__in		efx_nic_t *enp,
546	__in		uint32_t min_vi_count,
547	__in		uint32_t max_vi_count,
548	__out		uint32_t *vi_basep,
549	__out		uint32_t *vi_countp,
550	__out		uint32_t *vi_shiftp)
551{
552	efx_mcdi_req_t req;
553	uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN,
554			    MC_CMD_ALLOC_VIS_OUT_LEN)];
555	efx_rc_t rc;
556
557	if (vi_countp == NULL) {
558		rc = EINVAL;
559		goto fail1;
560	}
561
562	(void) memset(payload, 0, sizeof (payload));
563	req.emr_cmd = MC_CMD_ALLOC_VIS;
564	req.emr_in_buf = payload;
565	req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN;
566	req.emr_out_buf = payload;
567	req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN;
568
569	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count);
570	MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count);
571
572	efx_mcdi_execute(enp, &req);
573
574	if (req.emr_rc != 0) {
575		rc = req.emr_rc;
576		goto fail2;
577	}
578
579	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) {
580		rc = EMSGSIZE;
581		goto fail3;
582	}
583
584	*vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE);
585	*vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT);
586
587	/* Report VI_SHIFT if available (always zero for Huntington) */
588	if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN)
589		*vi_shiftp = 0;
590	else
591		*vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT);
592
593	return (0);
594
595fail3:
596	EFSYS_PROBE(fail3);
597fail2:
598	EFSYS_PROBE(fail2);
599fail1:
600	EFSYS_PROBE1(fail1, efx_rc_t, rc);
601
602	return (rc);
603}
604
605
606static	__checkReturn	efx_rc_t
607efx_mcdi_free_vis(
608	__in		efx_nic_t *enp)
609{
610	efx_mcdi_req_t req;
611	efx_rc_t rc;
612
613	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0);
614	EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0);
615
616	req.emr_cmd = MC_CMD_FREE_VIS;
617	req.emr_in_buf = NULL;
618	req.emr_in_length = 0;
619	req.emr_out_buf = NULL;
620	req.emr_out_length = 0;
621
622	efx_mcdi_execute_quiet(enp, &req);
623
624	/* Ignore ELREADY (no allocated VIs, so nothing to free) */
625	if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) {
626		rc = req.emr_rc;
627		goto fail1;
628	}
629
630	return (0);
631
632fail1:
633	EFSYS_PROBE1(fail1, efx_rc_t, rc);
634
635	return (rc);
636}
637
638
639static	__checkReturn	efx_rc_t
640efx_mcdi_alloc_piobuf(
641	__in		efx_nic_t *enp,
642	__out		efx_piobuf_handle_t *handlep)
643{
644	efx_mcdi_req_t req;
645	uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN,
646			    MC_CMD_ALLOC_PIOBUF_OUT_LEN)];
647	efx_rc_t rc;
648
649	if (handlep == NULL) {
650		rc = EINVAL;
651		goto fail1;
652	}
653
654	(void) memset(payload, 0, sizeof (payload));
655	req.emr_cmd = MC_CMD_ALLOC_PIOBUF;
656	req.emr_in_buf = payload;
657	req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN;
658	req.emr_out_buf = payload;
659	req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN;
660
661	efx_mcdi_execute_quiet(enp, &req);
662
663	if (req.emr_rc != 0) {
664		rc = req.emr_rc;
665		goto fail2;
666	}
667
668	if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) {
669		rc = EMSGSIZE;
670		goto fail3;
671	}
672
673	*handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE);
674
675	return (0);
676
677fail3:
678	EFSYS_PROBE(fail3);
679fail2:
680	EFSYS_PROBE(fail2);
681fail1:
682	EFSYS_PROBE1(fail1, efx_rc_t, rc);
683
684	return (rc);
685}
686
687static	__checkReturn	efx_rc_t
688efx_mcdi_free_piobuf(
689	__in		efx_nic_t *enp,
690	__in		efx_piobuf_handle_t handle)
691{
692	efx_mcdi_req_t req;
693	uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN,
694			    MC_CMD_FREE_PIOBUF_OUT_LEN)];
695	efx_rc_t rc;
696
697	(void) memset(payload, 0, sizeof (payload));
698	req.emr_cmd = MC_CMD_FREE_PIOBUF;
699	req.emr_in_buf = payload;
700	req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN;
701	req.emr_out_buf = payload;
702	req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN;
703
704	MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle);
705
706	efx_mcdi_execute_quiet(enp, &req);
707
708	if (req.emr_rc != 0) {
709		rc = req.emr_rc;
710		goto fail1;
711	}
712
713	return (0);
714
715fail1:
716	EFSYS_PROBE1(fail1, efx_rc_t, rc);
717
718	return (rc);
719}
720
721static	__checkReturn	efx_rc_t
722efx_mcdi_link_piobuf(
723	__in		efx_nic_t *enp,
724	__in		uint32_t vi_index,
725	__in		efx_piobuf_handle_t handle)
726{
727	efx_mcdi_req_t req;
728	uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN,
729			    MC_CMD_LINK_PIOBUF_OUT_LEN)];
730	efx_rc_t rc;
731
732	(void) memset(payload, 0, sizeof (payload));
733	req.emr_cmd = MC_CMD_LINK_PIOBUF;
734	req.emr_in_buf = payload;
735	req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN;
736	req.emr_out_buf = payload;
737	req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN;
738
739	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle);
740	MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
741
742	efx_mcdi_execute(enp, &req);
743
744	if (req.emr_rc != 0) {
745		rc = req.emr_rc;
746		goto fail1;
747	}
748
749	return (0);
750
751fail1:
752	EFSYS_PROBE1(fail1, efx_rc_t, rc);
753
754	return (rc);
755}
756
757static	__checkReturn	efx_rc_t
758efx_mcdi_unlink_piobuf(
759	__in		efx_nic_t *enp,
760	__in		uint32_t vi_index)
761{
762	efx_mcdi_req_t req;
763	uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN,
764			    MC_CMD_UNLINK_PIOBUF_OUT_LEN)];
765	efx_rc_t rc;
766
767	(void) memset(payload, 0, sizeof (payload));
768	req.emr_cmd = MC_CMD_UNLINK_PIOBUF;
769	req.emr_in_buf = payload;
770	req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN;
771	req.emr_out_buf = payload;
772	req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN;
773
774	MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index);
775
776	efx_mcdi_execute_quiet(enp, &req);
777
778	if (req.emr_rc != 0) {
779		rc = req.emr_rc;
780		goto fail1;
781	}
782
783	return (0);
784
785fail1:
786	EFSYS_PROBE1(fail1, efx_rc_t, rc);
787
788	return (rc);
789}
790
791static			void
792ef10_nic_alloc_piobufs(
793	__in		efx_nic_t *enp,
794	__in		uint32_t max_piobuf_count)
795{
796	efx_piobuf_handle_t *handlep;
797	unsigned int i;
798
799	EFSYS_ASSERT3U(max_piobuf_count, <=,
800	    EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle));
801
802	enp->en_arch.ef10.ena_piobuf_count = 0;
803
804	for (i = 0; i < max_piobuf_count; i++) {
805		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
806
807		if (efx_mcdi_alloc_piobuf(enp, handlep) != 0)
808			goto fail1;
809
810		enp->en_arch.ef10.ena_pio_alloc_map[i] = 0;
811		enp->en_arch.ef10.ena_piobuf_count++;
812	}
813
814	return;
815
816fail1:
817	for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
818		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
819
820		efx_mcdi_free_piobuf(enp, *handlep);
821		*handlep = EFX_PIOBUF_HANDLE_INVALID;
822	}
823	enp->en_arch.ef10.ena_piobuf_count = 0;
824}
825
826
827static			void
828ef10_nic_free_piobufs(
829	__in		efx_nic_t *enp)
830{
831	efx_piobuf_handle_t *handlep;
832	unsigned int i;
833
834	for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
835		handlep = &enp->en_arch.ef10.ena_piobuf_handle[i];
836
837		efx_mcdi_free_piobuf(enp, *handlep);
838		*handlep = EFX_PIOBUF_HANDLE_INVALID;
839	}
840	enp->en_arch.ef10.ena_piobuf_count = 0;
841}
842
843/* Sub-allocate a block from a piobuf */
844	__checkReturn	efx_rc_t
845ef10_nic_pio_alloc(
846	__inout		efx_nic_t *enp,
847	__out		uint32_t *bufnump,
848	__out		efx_piobuf_handle_t *handlep,
849	__out		uint32_t *blknump,
850	__out		uint32_t *offsetp,
851	__out		size_t *sizep)
852{
853	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
854	efx_drv_cfg_t *edcp = &enp->en_drv_cfg;
855	uint32_t blk_per_buf;
856	uint32_t buf, blk;
857	efx_rc_t rc;
858
859	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
860		    enp->en_family == EFX_FAMILY_MEDFORD);
861	EFSYS_ASSERT(bufnump);
862	EFSYS_ASSERT(handlep);
863	EFSYS_ASSERT(blknump);
864	EFSYS_ASSERT(offsetp);
865	EFSYS_ASSERT(sizep);
866
867	if ((edcp->edc_pio_alloc_size == 0) ||
868	    (enp->en_arch.ef10.ena_piobuf_count == 0)) {
869		rc = ENOMEM;
870		goto fail1;
871	}
872	blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size;
873
874	for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) {
875		uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf];
876
877		if (~(*map) == 0)
878			continue;
879
880		EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map)));
881		for (blk = 0; blk < blk_per_buf; blk++) {
882			if ((*map & (1u << blk)) == 0) {
883				*map |= (1u << blk);
884				goto done;
885			}
886		}
887	}
888	rc = ENOMEM;
889	goto fail2;
890
891done:
892	*handlep = enp->en_arch.ef10.ena_piobuf_handle[buf];
893	*bufnump = buf;
894	*blknump = blk;
895	*sizep = edcp->edc_pio_alloc_size;
896	*offsetp = blk * (*sizep);
897
898	return (0);
899
900fail2:
901	EFSYS_PROBE(fail2);
902fail1:
903	EFSYS_PROBE1(fail1, efx_rc_t, rc);
904
905	return (rc);
906}
907
908/* Free a piobuf sub-allocated block */
909	__checkReturn	efx_rc_t
910ef10_nic_pio_free(
911	__inout		efx_nic_t *enp,
912	__in		uint32_t bufnum,
913	__in		uint32_t blknum)
914{
915	uint32_t *map;
916	efx_rc_t rc;
917
918	if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) ||
919	    (blknum >= (8 * sizeof (*map)))) {
920		rc = EINVAL;
921		goto fail1;
922	}
923
924	map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum];
925	if ((*map & (1u << blknum)) == 0) {
926		rc = ENOENT;
927		goto fail2;
928	}
929	*map &= ~(1u << blknum);
930
931	return (0);
932
933fail2:
934	EFSYS_PROBE(fail2);
935fail1:
936	EFSYS_PROBE1(fail1, efx_rc_t, rc);
937
938	return (rc);
939}
940
941	__checkReturn	efx_rc_t
942ef10_nic_pio_link(
943	__inout		efx_nic_t *enp,
944	__in		uint32_t vi_index,
945	__in		efx_piobuf_handle_t handle)
946{
947	return (efx_mcdi_link_piobuf(enp, vi_index, handle));
948}
949
950	__checkReturn	efx_rc_t
951ef10_nic_pio_unlink(
952	__inout		efx_nic_t *enp,
953	__in		uint32_t vi_index)
954{
955	return (efx_mcdi_unlink_piobuf(enp, vi_index));
956}
957
958	__checkReturn	efx_rc_t
959ef10_get_datapath_caps(
960	__in		efx_nic_t *enp)
961{
962	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
963	uint32_t flags;
964	uint32_t flags2;
965	efx_rc_t rc;
966
967	if ((rc = efx_mcdi_get_capabilities(enp, &flags, &flags2)) != 0)
968		goto fail1;
969
970#define	CAP_FLAG(flags1, field)		\
971	((flags1) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN)))
972
973#define	CAP_FLAG2(flags2, field)	\
974	((flags2) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN)))
975
976	/*
977	 * Huntington RXDP firmware inserts a 0 or 14 byte prefix.
978	 * We only support the 14 byte prefix here.
979	 */
980	if (CAP_FLAG(flags, RX_PREFIX_LEN_14) == 0) {
981		rc = ENOTSUP;
982		goto fail2;
983	}
984	encp->enc_rx_prefix_size = 14;
985
986	/* Check if the firmware supports TSO */
987	encp->enc_fw_assisted_tso_enabled =
988	    CAP_FLAG(flags, TX_TSO) ? B_TRUE : B_FALSE;
989
990	/* Check if the firmware supports FATSOv2 */
991	encp->enc_fw_assisted_tso_v2_enabled =
992	    CAP_FLAG2(flags2, TX_TSO_V2) ? B_TRUE : B_FALSE;
993
994	/* Check if the firmware has vadapter/vport/vswitch support */
995	encp->enc_datapath_cap_evb =
996	    CAP_FLAG(flags, EVB) ? B_TRUE : B_FALSE;
997
998	/* Check if the firmware supports VLAN insertion */
999	encp->enc_hw_tx_insert_vlan_enabled =
1000	    CAP_FLAG(flags, TX_VLAN_INSERTION) ? B_TRUE : B_FALSE;
1001
1002	/* Check if the firmware supports RX event batching */
1003	encp->enc_rx_batching_enabled =
1004	    CAP_FLAG(flags, RX_BATCHING) ? B_TRUE : B_FALSE;
1005
1006	if (encp->enc_rx_batching_enabled)
1007		encp->enc_rx_batch_max = 16;
1008
1009	/* Check if the firmware supports disabling scatter on RXQs */
1010	encp->enc_rx_disable_scatter_supported =
1011	    CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE;
1012
1013	/* Check if the firmware supports set mac with running filters */
1014	encp->enc_allow_set_mac_with_installed_filters =
1015	    CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ?
1016	    B_TRUE : B_FALSE;
1017
1018	/*
1019	 * Check if firmware supports the extended MC_CMD_SET_MAC, which allows
1020	 * specifying which parameters to configure.
1021	 */
1022	encp->enc_enhanced_set_mac_supported =
1023		CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE;
1024
1025#undef CAP_FLAG
1026#undef CAP_FLAG2
1027
1028	return (0);
1029
1030fail2:
1031	EFSYS_PROBE(fail2);
1032fail1:
1033	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1034
1035	return (rc);
1036}
1037
1038
1039#define	EF10_LEGACY_PF_PRIVILEGE_MASK					\
1040	(MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN			|	\
1041	MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK			|	\
1042	MC_CMD_PRIVILEGE_MASK_IN_GRP_ONLOAD			|	\
1043	MC_CMD_PRIVILEGE_MASK_IN_GRP_PTP			|	\
1044	MC_CMD_PRIVILEGE_MASK_IN_GRP_INSECURE_FILTERS		|	\
1045	MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING		|	\
1046	MC_CMD_PRIVILEGE_MASK_IN_GRP_UNICAST			|	\
1047	MC_CMD_PRIVILEGE_MASK_IN_GRP_MULTICAST			|	\
1048	MC_CMD_PRIVILEGE_MASK_IN_GRP_BROADCAST			|	\
1049	MC_CMD_PRIVILEGE_MASK_IN_GRP_ALL_MULTICAST		|	\
1050	MC_CMD_PRIVILEGE_MASK_IN_GRP_PROMISCUOUS)
1051
1052#define	EF10_LEGACY_VF_PRIVILEGE_MASK	0
1053
1054
1055	__checkReturn		efx_rc_t
1056ef10_get_privilege_mask(
1057	__in			efx_nic_t *enp,
1058	__out			uint32_t *maskp)
1059{
1060	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1061	uint32_t mask;
1062	efx_rc_t rc;
1063
1064	if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf,
1065					    &mask)) != 0) {
1066		if (rc != ENOTSUP)
1067			goto fail1;
1068
1069		/* Fallback for old firmware without privilege mask support */
1070		if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1071			/* Assume PF has admin privilege */
1072			mask = EF10_LEGACY_PF_PRIVILEGE_MASK;
1073		} else {
1074			/* VF is always unprivileged by default */
1075			mask = EF10_LEGACY_VF_PRIVILEGE_MASK;
1076		}
1077	}
1078
1079	*maskp = mask;
1080
1081	return (0);
1082
1083fail1:
1084	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1085
1086	return (rc);
1087}
1088
1089
1090/*
1091 * The external port mapping is a one-based numbering of the external
1092 * connectors on the board. It does not distinguish off-board separated
1093 * outputs such as multi-headed cables.
1094 * The number of ports that map to each external port connector
1095 * on the board is determined by the chip family and the port modes to
1096 * which the NIC can be configured. The mapping table lists modes with
1097 * port numbering requirements in increasing order.
1098 */
1099static struct {
1100	efx_family_t	family;
1101	uint32_t	modes_mask;
1102	uint32_t	stride;
1103}	__ef10_external_port_mappings[] = {
1104	/* Supported modes requiring 1 output per port */
1105	{
1106		EFX_FAMILY_HUNTINGTON,
1107		(1 << TLV_PORT_MODE_10G) |
1108		(1 << TLV_PORT_MODE_10G_10G) |
1109		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
1110		1
1111	},
1112	{
1113		EFX_FAMILY_MEDFORD,
1114		(1 << TLV_PORT_MODE_10G) |
1115		(1 << TLV_PORT_MODE_10G_10G) |
1116		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
1117		1
1118	},
1119	/* Supported modes requiring 2 outputs per port */
1120	{
1121		EFX_FAMILY_HUNTINGTON,
1122		(1 << TLV_PORT_MODE_40G) |
1123		(1 << TLV_PORT_MODE_40G_40G) |
1124		(1 << TLV_PORT_MODE_40G_10G_10G) |
1125		(1 << TLV_PORT_MODE_10G_10G_40G),
1126		2
1127	},
1128	{
1129		EFX_FAMILY_MEDFORD,
1130		(1 << TLV_PORT_MODE_40G) |
1131		(1 << TLV_PORT_MODE_40G_40G) |
1132		(1 << TLV_PORT_MODE_40G_10G_10G) |
1133		(1 << TLV_PORT_MODE_10G_10G_40G),
1134		2
1135	},
1136	/* Supported modes requiring 4 outputs per port */
1137	{
1138		EFX_FAMILY_MEDFORD,
1139		(1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) |
1140		(1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2),
1141		4
1142	},
1143};
1144
1145	__checkReturn	efx_rc_t
1146ef10_external_port_mapping(
1147	__in		efx_nic_t *enp,
1148	__in		uint32_t port,
1149	__out		uint8_t *external_portp)
1150{
1151	efx_rc_t rc;
1152	int i;
1153	uint32_t port_modes;
1154	uint32_t matches;
1155	uint32_t stride = 1; /* default 1-1 mapping */
1156
1157	if ((rc = efx_mcdi_get_port_modes(enp, &port_modes, NULL)) != 0) {
1158		/* No port mode information available - use default mapping */
1159		goto out;
1160	}
1161
1162	/*
1163	 * Infer the internal port -> external port mapping from
1164	 * the possible port modes for this NIC.
1165	 */
1166	for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) {
1167		if (__ef10_external_port_mappings[i].family !=
1168		    enp->en_family)
1169			continue;
1170		matches = (__ef10_external_port_mappings[i].modes_mask &
1171		    port_modes);
1172		if (matches != 0) {
1173			stride = __ef10_external_port_mappings[i].stride;
1174			port_modes &= ~matches;
1175		}
1176	}
1177
1178	if (port_modes != 0) {
1179		/* Some advertised modes are not supported */
1180		rc = ENOTSUP;
1181		goto fail1;
1182	}
1183
1184out:
1185	/*
1186	 * Scale as required by last matched mode and then convert to
1187	 * one-based numbering
1188	 */
1189	*external_portp = (uint8_t)(port / stride) + 1;
1190	return (0);
1191
1192fail1:
1193	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1194
1195	return (rc);
1196}
1197
1198
1199	__checkReturn	efx_rc_t
1200ef10_nic_probe(
1201	__in		efx_nic_t *enp)
1202{
1203	const efx_nic_ops_t *enop = enp->en_enop;
1204	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1205	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1206	efx_rc_t rc;
1207
1208	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1209		    enp->en_family == EFX_FAMILY_MEDFORD);
1210
1211	/* Read and clear any assertion state */
1212	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1213		goto fail1;
1214
1215	/* Exit the assertion handler */
1216	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1217		if (rc != EACCES)
1218			goto fail2;
1219
1220	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
1221		goto fail3;
1222
1223	if ((rc = enop->eno_board_cfg(enp)) != 0)
1224		if (rc != EACCES)
1225			goto fail4;
1226
1227	/*
1228	 * Set default driver config limits (based on board config).
1229	 *
1230	 * FIXME: For now allocate a fixed number of VIs which is likely to be
1231	 * sufficient and small enough to allow multiple functions on the same
1232	 * port.
1233	 */
1234	edcp->edc_min_vi_count = edcp->edc_max_vi_count =
1235	    MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit));
1236
1237	/* The client driver must configure and enable PIO buffer support */
1238	edcp->edc_max_piobuf_count = 0;
1239	edcp->edc_pio_alloc_size = 0;
1240
1241#if EFSYS_OPT_MAC_STATS
1242	/* Wipe the MAC statistics */
1243	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
1244		goto fail5;
1245#endif
1246
1247#if EFSYS_OPT_LOOPBACK
1248	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
1249		goto fail6;
1250#endif
1251
1252#if EFSYS_OPT_MON_STATS
1253	if ((rc = mcdi_mon_cfg_build(enp)) != 0) {
1254		/* Unprivileged functions do not have access to sensors */
1255		if (rc != EACCES)
1256			goto fail7;
1257	}
1258#endif
1259
1260	encp->enc_features = enp->en_features;
1261
1262	return (0);
1263
1264#if EFSYS_OPT_MON_STATS
1265fail7:
1266	EFSYS_PROBE(fail7);
1267#endif
1268#if EFSYS_OPT_LOOPBACK
1269fail6:
1270	EFSYS_PROBE(fail6);
1271#endif
1272#if EFSYS_OPT_MAC_STATS
1273fail5:
1274	EFSYS_PROBE(fail5);
1275#endif
1276fail4:
1277	EFSYS_PROBE(fail4);
1278fail3:
1279	EFSYS_PROBE(fail3);
1280fail2:
1281	EFSYS_PROBE(fail2);
1282fail1:
1283	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1284
1285	return (rc);
1286}
1287
1288	__checkReturn	efx_rc_t
1289ef10_nic_set_drv_limits(
1290	__inout		efx_nic_t *enp,
1291	__in		efx_drv_limits_t *edlp)
1292{
1293	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1294	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1295	uint32_t min_evq_count, max_evq_count;
1296	uint32_t min_rxq_count, max_rxq_count;
1297	uint32_t min_txq_count, max_txq_count;
1298	efx_rc_t rc;
1299
1300	if (edlp == NULL) {
1301		rc = EINVAL;
1302		goto fail1;
1303	}
1304
1305	/* Get minimum required and maximum usable VI limits */
1306	min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit);
1307	min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit);
1308	min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit);
1309
1310	edcp->edc_min_vi_count =
1311	    MAX(min_evq_count, MAX(min_rxq_count, min_txq_count));
1312
1313	max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit);
1314	max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit);
1315	max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit);
1316
1317	edcp->edc_max_vi_count =
1318	    MAX(max_evq_count, MAX(max_rxq_count, max_txq_count));
1319
1320	/*
1321	 * Check limits for sub-allocated piobuf blocks.
1322	 * PIO is optional, so don't fail if the limits are incorrect.
1323	 */
1324	if ((encp->enc_piobuf_size == 0) ||
1325	    (encp->enc_piobuf_limit == 0) ||
1326	    (edlp->edl_min_pio_alloc_size == 0) ||
1327	    (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) {
1328		/* Disable PIO */
1329		edcp->edc_max_piobuf_count = 0;
1330		edcp->edc_pio_alloc_size = 0;
1331	} else {
1332		uint32_t blk_size, blk_count, blks_per_piobuf;
1333
1334		blk_size =
1335		    MAX(edlp->edl_min_pio_alloc_size,
1336			    encp->enc_piobuf_min_alloc_size);
1337
1338		blks_per_piobuf = encp->enc_piobuf_size / blk_size;
1339		EFSYS_ASSERT3U(blks_per_piobuf, <=, 32);
1340
1341		blk_count = (encp->enc_piobuf_limit * blks_per_piobuf);
1342
1343		/* A zero max pio alloc count means unlimited */
1344		if ((edlp->edl_max_pio_alloc_count > 0) &&
1345		    (edlp->edl_max_pio_alloc_count < blk_count)) {
1346			blk_count = edlp->edl_max_pio_alloc_count;
1347		}
1348
1349		edcp->edc_pio_alloc_size = blk_size;
1350		edcp->edc_max_piobuf_count =
1351		    (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf;
1352	}
1353
1354	return (0);
1355
1356fail1:
1357	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1358
1359	return (rc);
1360}
1361
1362
1363	__checkReturn	efx_rc_t
1364ef10_nic_reset(
1365	__in		efx_nic_t *enp)
1366{
1367	efx_mcdi_req_t req;
1368	uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN,
1369			    MC_CMD_ENTITY_RESET_OUT_LEN)];
1370	efx_rc_t rc;
1371
1372	/* ef10_nic_reset() is called to recover from BADASSERT failures. */
1373	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1374		goto fail1;
1375	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1376		goto fail2;
1377
1378	(void) memset(payload, 0, sizeof (payload));
1379	req.emr_cmd = MC_CMD_ENTITY_RESET;
1380	req.emr_in_buf = payload;
1381	req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN;
1382	req.emr_out_buf = payload;
1383	req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN;
1384
1385	MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG,
1386	    ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1);
1387
1388	efx_mcdi_execute(enp, &req);
1389
1390	if (req.emr_rc != 0) {
1391		rc = req.emr_rc;
1392		goto fail3;
1393	}
1394
1395	/* Clear RX/TX DMA queue errors */
1396	enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR);
1397
1398	return (0);
1399
1400fail3:
1401	EFSYS_PROBE(fail3);
1402fail2:
1403	EFSYS_PROBE(fail2);
1404fail1:
1405	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1406
1407	return (rc);
1408}
1409
1410	__checkReturn	efx_rc_t
1411ef10_nic_init(
1412	__in		efx_nic_t *enp)
1413{
1414	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1415	uint32_t min_vi_count, max_vi_count;
1416	uint32_t vi_count, vi_base, vi_shift;
1417	uint32_t i;
1418	uint32_t retry;
1419	uint32_t delay_us;
1420	efx_rc_t rc;
1421
1422	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1423		    enp->en_family == EFX_FAMILY_MEDFORD);
1424
1425	/* Enable reporting of some events (e.g. link change) */
1426	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
1427		goto fail1;
1428
1429	/* Allocate (optional) on-chip PIO buffers */
1430	ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count);
1431
1432	/*
1433	 * For best performance, PIO writes should use a write-combined
1434	 * (WC) memory mapping. Using a separate WC mapping for the PIO
1435	 * aperture of each VI would be a burden to drivers (and not
1436	 * possible if the host page size is >4Kbyte).
1437	 *
1438	 * To avoid this we use a single uncached (UC) mapping for VI
1439	 * register access, and a single WC mapping for extra VIs used
1440	 * for PIO writes.
1441	 *
1442	 * Each piobuf must be linked to a VI in the WC mapping, and to
1443	 * each VI that is using a sub-allocated block from the piobuf.
1444	 */
1445	min_vi_count = edcp->edc_min_vi_count;
1446	max_vi_count =
1447	    edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count;
1448
1449	/* Ensure that the previously attached driver's VIs are freed */
1450	if ((rc = efx_mcdi_free_vis(enp)) != 0)
1451		goto fail2;
1452
1453	/*
1454	 * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this
1455	 * fails then retrying the request for fewer VI resources may succeed.
1456	 */
1457	vi_count = 0;
1458	if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count,
1459		    &vi_base, &vi_count, &vi_shift)) != 0)
1460		goto fail3;
1461
1462	EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count);
1463
1464	if (vi_count < min_vi_count) {
1465		rc = ENOMEM;
1466		goto fail4;
1467	}
1468
1469	enp->en_arch.ef10.ena_vi_base = vi_base;
1470	enp->en_arch.ef10.ena_vi_count = vi_count;
1471	enp->en_arch.ef10.ena_vi_shift = vi_shift;
1472
1473	if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) {
1474		/* Not enough extra VIs to map piobufs */
1475		ef10_nic_free_piobufs(enp);
1476	}
1477
1478	enp->en_arch.ef10.ena_pio_write_vi_base =
1479	    vi_count - enp->en_arch.ef10.ena_piobuf_count;
1480
1481	/* Save UC memory mapping details */
1482	enp->en_arch.ef10.ena_uc_mem_map_offset = 0;
1483	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1484		enp->en_arch.ef10.ena_uc_mem_map_size =
1485		    (ER_DZ_TX_PIOBUF_STEP *
1486		    enp->en_arch.ef10.ena_pio_write_vi_base);
1487	} else {
1488		enp->en_arch.ef10.ena_uc_mem_map_size =
1489		    (ER_DZ_TX_PIOBUF_STEP *
1490		    enp->en_arch.ef10.ena_vi_count);
1491	}
1492
1493	/* Save WC memory mapping details */
1494	enp->en_arch.ef10.ena_wc_mem_map_offset =
1495	    enp->en_arch.ef10.ena_uc_mem_map_offset +
1496	    enp->en_arch.ef10.ena_uc_mem_map_size;
1497
1498	enp->en_arch.ef10.ena_wc_mem_map_size =
1499	    (ER_DZ_TX_PIOBUF_STEP *
1500	    enp->en_arch.ef10.ena_piobuf_count);
1501
1502	/* Link piobufs to extra VIs in WC mapping */
1503	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1504		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
1505			rc = efx_mcdi_link_piobuf(enp,
1506			    enp->en_arch.ef10.ena_pio_write_vi_base + i,
1507			    enp->en_arch.ef10.ena_piobuf_handle[i]);
1508			if (rc != 0)
1509				break;
1510		}
1511	}
1512
1513	/*
1514	 * Allocate a vAdaptor attached to our upstream vPort/pPort.
1515	 *
1516	 * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF
1517	 * driver has yet to bring up the EVB port. See bug 56147. In this case,
1518	 * retry the request several times after waiting a while. The wait time
1519	 * between retries starts small (10ms) and exponentially increases.
1520	 * Total wait time is a little over two seconds. Retry logic in the
1521	 * client driver may mean this whole loop is repeated if it continues to
1522	 * fail.
1523	 */
1524	retry = 0;
1525	delay_us = 10000;
1526	while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) {
1527		if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) ||
1528		    (rc != ENOENT)) {
1529			/*
1530			 * Do not retry alloc for PF, or for other errors on
1531			 * a VF.
1532			 */
1533			goto fail5;
1534		}
1535
1536		/* VF startup before PF is ready. Retry allocation. */
1537		if (retry > 5) {
1538			/* Too many attempts */
1539			rc = EINVAL;
1540			goto fail6;
1541		}
1542		EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry);
1543		EFSYS_SLEEP(delay_us);
1544		retry++;
1545		if (delay_us < 500000)
1546			delay_us <<= 2;
1547	}
1548
1549	enp->en_vport_id = EVB_PORT_ID_ASSIGNED;
1550	enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2;
1551
1552	return (0);
1553
1554fail6:
1555	EFSYS_PROBE(fail6);
1556fail5:
1557	EFSYS_PROBE(fail5);
1558fail4:
1559	EFSYS_PROBE(fail4);
1560fail3:
1561	EFSYS_PROBE(fail3);
1562fail2:
1563	EFSYS_PROBE(fail2);
1564
1565	ef10_nic_free_piobufs(enp);
1566
1567fail1:
1568	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1569
1570	return (rc);
1571}
1572
1573	__checkReturn	efx_rc_t
1574ef10_nic_get_vi_pool(
1575	__in		efx_nic_t *enp,
1576	__out		uint32_t *vi_countp)
1577{
1578	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1579		    enp->en_family == EFX_FAMILY_MEDFORD);
1580
1581	/*
1582	 * Report VIs that the client driver can use.
1583	 * Do not include VIs used for PIO buffer writes.
1584	 */
1585	*vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base;
1586
1587	return (0);
1588}
1589
1590	__checkReturn	efx_rc_t
1591ef10_nic_get_bar_region(
1592	__in		efx_nic_t *enp,
1593	__in		efx_nic_region_t region,
1594	__out		uint32_t *offsetp,
1595	__out		size_t *sizep)
1596{
1597	efx_rc_t rc;
1598
1599	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1600		    enp->en_family == EFX_FAMILY_MEDFORD);
1601
1602	/*
1603	 * TODO: Specify host memory mapping alignment and granularity
1604	 * in efx_drv_limits_t so that they can be taken into account
1605	 * when allocating extra VIs for PIO writes.
1606	 */
1607	switch (region) {
1608	case EFX_REGION_VI:
1609		/* UC mapped memory BAR region for VI registers */
1610		*offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset;
1611		*sizep = enp->en_arch.ef10.ena_uc_mem_map_size;
1612		break;
1613
1614	case EFX_REGION_PIO_WRITE_VI:
1615		/* WC mapped memory BAR region for piobuf writes */
1616		*offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset;
1617		*sizep = enp->en_arch.ef10.ena_wc_mem_map_size;
1618		break;
1619
1620	default:
1621		rc = EINVAL;
1622		goto fail1;
1623	}
1624
1625	return (0);
1626
1627fail1:
1628	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1629
1630	return (rc);
1631}
1632
1633			void
1634ef10_nic_fini(
1635	__in		efx_nic_t *enp)
1636{
1637	uint32_t i;
1638	efx_rc_t rc;
1639
1640	(void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id);
1641	enp->en_vport_id = 0;
1642
1643	/* Unlink piobufs from extra VIs in WC mapping */
1644	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1645		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
1646			rc = efx_mcdi_unlink_piobuf(enp,
1647			    enp->en_arch.ef10.ena_pio_write_vi_base + i);
1648			if (rc != 0)
1649				break;
1650		}
1651	}
1652
1653	ef10_nic_free_piobufs(enp);
1654
1655	(void) efx_mcdi_free_vis(enp);
1656	enp->en_arch.ef10.ena_vi_count = 0;
1657}
1658
1659			void
1660ef10_nic_unprobe(
1661	__in		efx_nic_t *enp)
1662{
1663#if EFSYS_OPT_MON_STATS
1664	mcdi_mon_cfg_free(enp);
1665#endif /* EFSYS_OPT_MON_STATS */
1666	(void) efx_mcdi_drv_attach(enp, B_FALSE);
1667}
1668
1669#if EFSYS_OPT_DIAG
1670
1671	__checkReturn	efx_rc_t
1672ef10_nic_register_test(
1673	__in		efx_nic_t *enp)
1674{
1675	efx_rc_t rc;
1676
1677	/* FIXME */
1678	_NOTE(ARGUNUSED(enp))
1679	_NOTE(CONSTANTCONDITION)
1680	if (B_FALSE) {
1681		rc = ENOTSUP;
1682		goto fail1;
1683	}
1684	/* FIXME */
1685
1686	return (0);
1687
1688fail1:
1689	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1690
1691	return (rc);
1692}
1693
1694#endif	/* EFSYS_OPT_DIAG */
1695
1696
1697#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1698