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