ef10_nic.c revision 301309
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 301309 2016-06-04 09:20:46Z 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	/*
1007	 * Even if batching isn't reported as supported, we may still get
1008	 * batched events.
1009	 */
1010	encp->enc_rx_batch_max = 16;
1011
1012	/* Check if the firmware supports disabling scatter on RXQs */
1013	encp->enc_rx_disable_scatter_supported =
1014	    CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE;
1015
1016	/* Check if the firmware supports set mac with running filters */
1017	encp->enc_allow_set_mac_with_installed_filters =
1018	    CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ?
1019	    B_TRUE : B_FALSE;
1020
1021	/*
1022	 * Check if firmware supports the extended MC_CMD_SET_MAC, which allows
1023	 * specifying which parameters to configure.
1024	 */
1025	encp->enc_enhanced_set_mac_supported =
1026		CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE;
1027
1028#undef CAP_FLAG
1029#undef CAP_FLAG2
1030
1031	return (0);
1032
1033fail2:
1034	EFSYS_PROBE(fail2);
1035fail1:
1036	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1037
1038	return (rc);
1039}
1040
1041
1042#define	EF10_LEGACY_PF_PRIVILEGE_MASK					\
1043	(MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN			|	\
1044	MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK			|	\
1045	MC_CMD_PRIVILEGE_MASK_IN_GRP_ONLOAD			|	\
1046	MC_CMD_PRIVILEGE_MASK_IN_GRP_PTP			|	\
1047	MC_CMD_PRIVILEGE_MASK_IN_GRP_INSECURE_FILTERS		|	\
1048	MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING		|	\
1049	MC_CMD_PRIVILEGE_MASK_IN_GRP_UNICAST			|	\
1050	MC_CMD_PRIVILEGE_MASK_IN_GRP_MULTICAST			|	\
1051	MC_CMD_PRIVILEGE_MASK_IN_GRP_BROADCAST			|	\
1052	MC_CMD_PRIVILEGE_MASK_IN_GRP_ALL_MULTICAST		|	\
1053	MC_CMD_PRIVILEGE_MASK_IN_GRP_PROMISCUOUS)
1054
1055#define	EF10_LEGACY_VF_PRIVILEGE_MASK	0
1056
1057
1058	__checkReturn		efx_rc_t
1059ef10_get_privilege_mask(
1060	__in			efx_nic_t *enp,
1061	__out			uint32_t *maskp)
1062{
1063	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1064	uint32_t mask;
1065	efx_rc_t rc;
1066
1067	if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf,
1068					    &mask)) != 0) {
1069		if (rc != ENOTSUP)
1070			goto fail1;
1071
1072		/* Fallback for old firmware without privilege mask support */
1073		if (EFX_PCI_FUNCTION_IS_PF(encp)) {
1074			/* Assume PF has admin privilege */
1075			mask = EF10_LEGACY_PF_PRIVILEGE_MASK;
1076		} else {
1077			/* VF is always unprivileged by default */
1078			mask = EF10_LEGACY_VF_PRIVILEGE_MASK;
1079		}
1080	}
1081
1082	*maskp = mask;
1083
1084	return (0);
1085
1086fail1:
1087	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1088
1089	return (rc);
1090}
1091
1092
1093/*
1094 * The external port mapping is a one-based numbering of the external
1095 * connectors on the board. It does not distinguish off-board separated
1096 * outputs such as multi-headed cables.
1097 * The number of ports that map to each external port connector
1098 * on the board is determined by the chip family and the port modes to
1099 * which the NIC can be configured. The mapping table lists modes with
1100 * port numbering requirements in increasing order.
1101 */
1102static struct {
1103	efx_family_t	family;
1104	uint32_t	modes_mask;
1105	uint32_t	stride;
1106}	__ef10_external_port_mappings[] = {
1107	/* Supported modes requiring 1 output per port */
1108	{
1109		EFX_FAMILY_HUNTINGTON,
1110		(1 << TLV_PORT_MODE_10G) |
1111		(1 << TLV_PORT_MODE_10G_10G) |
1112		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
1113		1
1114	},
1115	{
1116		EFX_FAMILY_MEDFORD,
1117		(1 << TLV_PORT_MODE_10G) |
1118		(1 << TLV_PORT_MODE_10G_10G) |
1119		(1 << TLV_PORT_MODE_10G_10G_10G_10G),
1120		1
1121	},
1122	/* Supported modes requiring 2 outputs per port */
1123	{
1124		EFX_FAMILY_HUNTINGTON,
1125		(1 << TLV_PORT_MODE_40G) |
1126		(1 << TLV_PORT_MODE_40G_40G) |
1127		(1 << TLV_PORT_MODE_40G_10G_10G) |
1128		(1 << TLV_PORT_MODE_10G_10G_40G),
1129		2
1130	},
1131	{
1132		EFX_FAMILY_MEDFORD,
1133		(1 << TLV_PORT_MODE_40G) |
1134		(1 << TLV_PORT_MODE_40G_40G) |
1135		(1 << TLV_PORT_MODE_40G_10G_10G) |
1136		(1 << TLV_PORT_MODE_10G_10G_40G),
1137		2
1138	},
1139	/* Supported modes requiring 4 outputs per port */
1140	{
1141		EFX_FAMILY_MEDFORD,
1142		(1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) |
1143		(1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2),
1144		4
1145	},
1146};
1147
1148	__checkReturn	efx_rc_t
1149ef10_external_port_mapping(
1150	__in		efx_nic_t *enp,
1151	__in		uint32_t port,
1152	__out		uint8_t *external_portp)
1153{
1154	efx_rc_t rc;
1155	int i;
1156	uint32_t port_modes;
1157	uint32_t matches;
1158	uint32_t stride = 1; /* default 1-1 mapping */
1159
1160	if ((rc = efx_mcdi_get_port_modes(enp, &port_modes, NULL)) != 0) {
1161		/* No port mode information available - use default mapping */
1162		goto out;
1163	}
1164
1165	/*
1166	 * Infer the internal port -> external port mapping from
1167	 * the possible port modes for this NIC.
1168	 */
1169	for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) {
1170		if (__ef10_external_port_mappings[i].family !=
1171		    enp->en_family)
1172			continue;
1173		matches = (__ef10_external_port_mappings[i].modes_mask &
1174		    port_modes);
1175		if (matches != 0) {
1176			stride = __ef10_external_port_mappings[i].stride;
1177			port_modes &= ~matches;
1178		}
1179	}
1180
1181	if (port_modes != 0) {
1182		/* Some advertised modes are not supported */
1183		rc = ENOTSUP;
1184		goto fail1;
1185	}
1186
1187out:
1188	/*
1189	 * Scale as required by last matched mode and then convert to
1190	 * one-based numbering
1191	 */
1192	*external_portp = (uint8_t)(port / stride) + 1;
1193	return (0);
1194
1195fail1:
1196	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1197
1198	return (rc);
1199}
1200
1201
1202	__checkReturn	efx_rc_t
1203ef10_nic_probe(
1204	__in		efx_nic_t *enp)
1205{
1206	const efx_nic_ops_t *enop = enp->en_enop;
1207	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1208	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1209	efx_rc_t rc;
1210
1211	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1212		    enp->en_family == EFX_FAMILY_MEDFORD);
1213
1214	/* Read and clear any assertion state */
1215	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1216		goto fail1;
1217
1218	/* Exit the assertion handler */
1219	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1220		if (rc != EACCES)
1221			goto fail2;
1222
1223	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
1224		goto fail3;
1225
1226	if ((rc = enop->eno_board_cfg(enp)) != 0)
1227		if (rc != EACCES)
1228			goto fail4;
1229
1230	/*
1231	 * Set default driver config limits (based on board config).
1232	 *
1233	 * FIXME: For now allocate a fixed number of VIs which is likely to be
1234	 * sufficient and small enough to allow multiple functions on the same
1235	 * port.
1236	 */
1237	edcp->edc_min_vi_count = edcp->edc_max_vi_count =
1238	    MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit));
1239
1240	/* The client driver must configure and enable PIO buffer support */
1241	edcp->edc_max_piobuf_count = 0;
1242	edcp->edc_pio_alloc_size = 0;
1243
1244#if EFSYS_OPT_MAC_STATS
1245	/* Wipe the MAC statistics */
1246	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
1247		goto fail5;
1248#endif
1249
1250#if EFSYS_OPT_LOOPBACK
1251	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
1252		goto fail6;
1253#endif
1254
1255#if EFSYS_OPT_MON_STATS
1256	if ((rc = mcdi_mon_cfg_build(enp)) != 0) {
1257		/* Unprivileged functions do not have access to sensors */
1258		if (rc != EACCES)
1259			goto fail7;
1260	}
1261#endif
1262
1263	encp->enc_features = enp->en_features;
1264
1265	return (0);
1266
1267#if EFSYS_OPT_MON_STATS
1268fail7:
1269	EFSYS_PROBE(fail7);
1270#endif
1271#if EFSYS_OPT_LOOPBACK
1272fail6:
1273	EFSYS_PROBE(fail6);
1274#endif
1275#if EFSYS_OPT_MAC_STATS
1276fail5:
1277	EFSYS_PROBE(fail5);
1278#endif
1279fail4:
1280	EFSYS_PROBE(fail4);
1281fail3:
1282	EFSYS_PROBE(fail3);
1283fail2:
1284	EFSYS_PROBE(fail2);
1285fail1:
1286	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1287
1288	return (rc);
1289}
1290
1291	__checkReturn	efx_rc_t
1292ef10_nic_set_drv_limits(
1293	__inout		efx_nic_t *enp,
1294	__in		efx_drv_limits_t *edlp)
1295{
1296	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1297	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1298	uint32_t min_evq_count, max_evq_count;
1299	uint32_t min_rxq_count, max_rxq_count;
1300	uint32_t min_txq_count, max_txq_count;
1301	efx_rc_t rc;
1302
1303	if (edlp == NULL) {
1304		rc = EINVAL;
1305		goto fail1;
1306	}
1307
1308	/* Get minimum required and maximum usable VI limits */
1309	min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit);
1310	min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit);
1311	min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit);
1312
1313	edcp->edc_min_vi_count =
1314	    MAX(min_evq_count, MAX(min_rxq_count, min_txq_count));
1315
1316	max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit);
1317	max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit);
1318	max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit);
1319
1320	edcp->edc_max_vi_count =
1321	    MAX(max_evq_count, MAX(max_rxq_count, max_txq_count));
1322
1323	/*
1324	 * Check limits for sub-allocated piobuf blocks.
1325	 * PIO is optional, so don't fail if the limits are incorrect.
1326	 */
1327	if ((encp->enc_piobuf_size == 0) ||
1328	    (encp->enc_piobuf_limit == 0) ||
1329	    (edlp->edl_min_pio_alloc_size == 0) ||
1330	    (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) {
1331		/* Disable PIO */
1332		edcp->edc_max_piobuf_count = 0;
1333		edcp->edc_pio_alloc_size = 0;
1334	} else {
1335		uint32_t blk_size, blk_count, blks_per_piobuf;
1336
1337		blk_size =
1338		    MAX(edlp->edl_min_pio_alloc_size,
1339			    encp->enc_piobuf_min_alloc_size);
1340
1341		blks_per_piobuf = encp->enc_piobuf_size / blk_size;
1342		EFSYS_ASSERT3U(blks_per_piobuf, <=, 32);
1343
1344		blk_count = (encp->enc_piobuf_limit * blks_per_piobuf);
1345
1346		/* A zero max pio alloc count means unlimited */
1347		if ((edlp->edl_max_pio_alloc_count > 0) &&
1348		    (edlp->edl_max_pio_alloc_count < blk_count)) {
1349			blk_count = edlp->edl_max_pio_alloc_count;
1350		}
1351
1352		edcp->edc_pio_alloc_size = blk_size;
1353		edcp->edc_max_piobuf_count =
1354		    (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf;
1355	}
1356
1357	return (0);
1358
1359fail1:
1360	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1361
1362	return (rc);
1363}
1364
1365
1366	__checkReturn	efx_rc_t
1367ef10_nic_reset(
1368	__in		efx_nic_t *enp)
1369{
1370	efx_mcdi_req_t req;
1371	uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN,
1372			    MC_CMD_ENTITY_RESET_OUT_LEN)];
1373	efx_rc_t rc;
1374
1375	/* ef10_nic_reset() is called to recover from BADASSERT failures. */
1376	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
1377		goto fail1;
1378	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
1379		goto fail2;
1380
1381	(void) memset(payload, 0, sizeof (payload));
1382	req.emr_cmd = MC_CMD_ENTITY_RESET;
1383	req.emr_in_buf = payload;
1384	req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN;
1385	req.emr_out_buf = payload;
1386	req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN;
1387
1388	MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG,
1389	    ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1);
1390
1391	efx_mcdi_execute(enp, &req);
1392
1393	if (req.emr_rc != 0) {
1394		rc = req.emr_rc;
1395		goto fail3;
1396	}
1397
1398	/* Clear RX/TX DMA queue errors */
1399	enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR);
1400
1401	return (0);
1402
1403fail3:
1404	EFSYS_PROBE(fail3);
1405fail2:
1406	EFSYS_PROBE(fail2);
1407fail1:
1408	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1409
1410	return (rc);
1411}
1412
1413	__checkReturn	efx_rc_t
1414ef10_nic_init(
1415	__in		efx_nic_t *enp)
1416{
1417	efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
1418	uint32_t min_vi_count, max_vi_count;
1419	uint32_t vi_count, vi_base, vi_shift;
1420	uint32_t i;
1421	uint32_t retry;
1422	uint32_t delay_us;
1423	efx_rc_t rc;
1424
1425	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1426		    enp->en_family == EFX_FAMILY_MEDFORD);
1427
1428	/* Enable reporting of some events (e.g. link change) */
1429	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
1430		goto fail1;
1431
1432	/* Allocate (optional) on-chip PIO buffers */
1433	ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count);
1434
1435	/*
1436	 * For best performance, PIO writes should use a write-combined
1437	 * (WC) memory mapping. Using a separate WC mapping for the PIO
1438	 * aperture of each VI would be a burden to drivers (and not
1439	 * possible if the host page size is >4Kbyte).
1440	 *
1441	 * To avoid this we use a single uncached (UC) mapping for VI
1442	 * register access, and a single WC mapping for extra VIs used
1443	 * for PIO writes.
1444	 *
1445	 * Each piobuf must be linked to a VI in the WC mapping, and to
1446	 * each VI that is using a sub-allocated block from the piobuf.
1447	 */
1448	min_vi_count = edcp->edc_min_vi_count;
1449	max_vi_count =
1450	    edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count;
1451
1452	/* Ensure that the previously attached driver's VIs are freed */
1453	if ((rc = efx_mcdi_free_vis(enp)) != 0)
1454		goto fail2;
1455
1456	/*
1457	 * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this
1458	 * fails then retrying the request for fewer VI resources may succeed.
1459	 */
1460	vi_count = 0;
1461	if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count,
1462		    &vi_base, &vi_count, &vi_shift)) != 0)
1463		goto fail3;
1464
1465	EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count);
1466
1467	if (vi_count < min_vi_count) {
1468		rc = ENOMEM;
1469		goto fail4;
1470	}
1471
1472	enp->en_arch.ef10.ena_vi_base = vi_base;
1473	enp->en_arch.ef10.ena_vi_count = vi_count;
1474	enp->en_arch.ef10.ena_vi_shift = vi_shift;
1475
1476	if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) {
1477		/* Not enough extra VIs to map piobufs */
1478		ef10_nic_free_piobufs(enp);
1479	}
1480
1481	enp->en_arch.ef10.ena_pio_write_vi_base =
1482	    vi_count - enp->en_arch.ef10.ena_piobuf_count;
1483
1484	/* Save UC memory mapping details */
1485	enp->en_arch.ef10.ena_uc_mem_map_offset = 0;
1486	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1487		enp->en_arch.ef10.ena_uc_mem_map_size =
1488		    (ER_DZ_TX_PIOBUF_STEP *
1489		    enp->en_arch.ef10.ena_pio_write_vi_base);
1490	} else {
1491		enp->en_arch.ef10.ena_uc_mem_map_size =
1492		    (ER_DZ_TX_PIOBUF_STEP *
1493		    enp->en_arch.ef10.ena_vi_count);
1494	}
1495
1496	/* Save WC memory mapping details */
1497	enp->en_arch.ef10.ena_wc_mem_map_offset =
1498	    enp->en_arch.ef10.ena_uc_mem_map_offset +
1499	    enp->en_arch.ef10.ena_uc_mem_map_size;
1500
1501	enp->en_arch.ef10.ena_wc_mem_map_size =
1502	    (ER_DZ_TX_PIOBUF_STEP *
1503	    enp->en_arch.ef10.ena_piobuf_count);
1504
1505	/* Link piobufs to extra VIs in WC mapping */
1506	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1507		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
1508			rc = efx_mcdi_link_piobuf(enp,
1509			    enp->en_arch.ef10.ena_pio_write_vi_base + i,
1510			    enp->en_arch.ef10.ena_piobuf_handle[i]);
1511			if (rc != 0)
1512				break;
1513		}
1514	}
1515
1516	/*
1517	 * Allocate a vAdaptor attached to our upstream vPort/pPort.
1518	 *
1519	 * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF
1520	 * driver has yet to bring up the EVB port. See bug 56147. In this case,
1521	 * retry the request several times after waiting a while. The wait time
1522	 * between retries starts small (10ms) and exponentially increases.
1523	 * Total wait time is a little over two seconds. Retry logic in the
1524	 * client driver may mean this whole loop is repeated if it continues to
1525	 * fail.
1526	 */
1527	retry = 0;
1528	delay_us = 10000;
1529	while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) {
1530		if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) ||
1531		    (rc != ENOENT)) {
1532			/*
1533			 * Do not retry alloc for PF, or for other errors on
1534			 * a VF.
1535			 */
1536			goto fail5;
1537		}
1538
1539		/* VF startup before PF is ready. Retry allocation. */
1540		if (retry > 5) {
1541			/* Too many attempts */
1542			rc = EINVAL;
1543			goto fail6;
1544		}
1545		EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry);
1546		EFSYS_SLEEP(delay_us);
1547		retry++;
1548		if (delay_us < 500000)
1549			delay_us <<= 2;
1550	}
1551
1552	enp->en_vport_id = EVB_PORT_ID_ASSIGNED;
1553	enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2;
1554
1555	return (0);
1556
1557fail6:
1558	EFSYS_PROBE(fail6);
1559fail5:
1560	EFSYS_PROBE(fail5);
1561fail4:
1562	EFSYS_PROBE(fail4);
1563fail3:
1564	EFSYS_PROBE(fail3);
1565fail2:
1566	EFSYS_PROBE(fail2);
1567
1568	ef10_nic_free_piobufs(enp);
1569
1570fail1:
1571	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1572
1573	return (rc);
1574}
1575
1576	__checkReturn	efx_rc_t
1577ef10_nic_get_vi_pool(
1578	__in		efx_nic_t *enp,
1579	__out		uint32_t *vi_countp)
1580{
1581	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1582		    enp->en_family == EFX_FAMILY_MEDFORD);
1583
1584	/*
1585	 * Report VIs that the client driver can use.
1586	 * Do not include VIs used for PIO buffer writes.
1587	 */
1588	*vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base;
1589
1590	return (0);
1591}
1592
1593	__checkReturn	efx_rc_t
1594ef10_nic_get_bar_region(
1595	__in		efx_nic_t *enp,
1596	__in		efx_nic_region_t region,
1597	__out		uint32_t *offsetp,
1598	__out		size_t *sizep)
1599{
1600	efx_rc_t rc;
1601
1602	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
1603		    enp->en_family == EFX_FAMILY_MEDFORD);
1604
1605	/*
1606	 * TODO: Specify host memory mapping alignment and granularity
1607	 * in efx_drv_limits_t so that they can be taken into account
1608	 * when allocating extra VIs for PIO writes.
1609	 */
1610	switch (region) {
1611	case EFX_REGION_VI:
1612		/* UC mapped memory BAR region for VI registers */
1613		*offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset;
1614		*sizep = enp->en_arch.ef10.ena_uc_mem_map_size;
1615		break;
1616
1617	case EFX_REGION_PIO_WRITE_VI:
1618		/* WC mapped memory BAR region for piobuf writes */
1619		*offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset;
1620		*sizep = enp->en_arch.ef10.ena_wc_mem_map_size;
1621		break;
1622
1623	default:
1624		rc = EINVAL;
1625		goto fail1;
1626	}
1627
1628	return (0);
1629
1630fail1:
1631	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1632
1633	return (rc);
1634}
1635
1636			void
1637ef10_nic_fini(
1638	__in		efx_nic_t *enp)
1639{
1640	uint32_t i;
1641	efx_rc_t rc;
1642
1643	(void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id);
1644	enp->en_vport_id = 0;
1645
1646	/* Unlink piobufs from extra VIs in WC mapping */
1647	if (enp->en_arch.ef10.ena_piobuf_count > 0) {
1648		for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) {
1649			rc = efx_mcdi_unlink_piobuf(enp,
1650			    enp->en_arch.ef10.ena_pio_write_vi_base + i);
1651			if (rc != 0)
1652				break;
1653		}
1654	}
1655
1656	ef10_nic_free_piobufs(enp);
1657
1658	(void) efx_mcdi_free_vis(enp);
1659	enp->en_arch.ef10.ena_vi_count = 0;
1660}
1661
1662			void
1663ef10_nic_unprobe(
1664	__in		efx_nic_t *enp)
1665{
1666#if EFSYS_OPT_MON_STATS
1667	mcdi_mon_cfg_free(enp);
1668#endif /* EFSYS_OPT_MON_STATS */
1669	(void) efx_mcdi_drv_attach(enp, B_FALSE);
1670}
1671
1672#if EFSYS_OPT_DIAG
1673
1674	__checkReturn	efx_rc_t
1675ef10_nic_register_test(
1676	__in		efx_nic_t *enp)
1677{
1678	efx_rc_t rc;
1679
1680	/* FIXME */
1681	_NOTE(ARGUNUSED(enp))
1682	_NOTE(CONSTANTCONDITION)
1683	if (B_FALSE) {
1684		rc = ENOTSUP;
1685		goto fail1;
1686	}
1687	/* FIXME */
1688
1689	return (0);
1690
1691fail1:
1692	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1693
1694	return (rc);
1695}
1696
1697#endif	/* EFSYS_OPT_DIAG */
1698
1699
1700#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1701