xref: /freebsd-11-stable/sys/dev/sfxge/common/efx_nvram.c (revision 1aade74b2543987812b44590d73e487df99bfe22)
1 /*-
2  * Copyright (c) 2009-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$");
33 
34 #include "efx.h"
35 #include "efx_impl.h"
36 
37 #if EFSYS_OPT_NVRAM
38 
39 #if EFSYS_OPT_SIENA
40 
41 static const efx_nvram_ops_t	__efx_nvram_siena_ops = {
42 #if EFSYS_OPT_DIAG
43 	siena_nvram_test,		/* envo_test */
44 #endif	/* EFSYS_OPT_DIAG */
45 	siena_nvram_type_to_partn,	/* envo_type_to_partn */
46 	siena_nvram_partn_size,		/* envo_partn_size */
47 	siena_nvram_partn_rw_start,	/* envo_partn_rw_start */
48 	siena_nvram_partn_read,		/* envo_partn_read */
49 	siena_nvram_partn_erase,	/* envo_partn_erase */
50 	siena_nvram_partn_write,	/* envo_partn_write */
51 	siena_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
52 	siena_nvram_partn_get_version,	/* envo_partn_get_version */
53 	siena_nvram_partn_set_version,	/* envo_partn_set_version */
54 	NULL,				/* envo_partn_validate */
55 };
56 
57 #endif	/* EFSYS_OPT_SIENA */
58 
59 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
60 
61 static const efx_nvram_ops_t	__efx_nvram_ef10_ops = {
62 #if EFSYS_OPT_DIAG
63 	ef10_nvram_test,		/* envo_test */
64 #endif	/* EFSYS_OPT_DIAG */
65 	ef10_nvram_type_to_partn,	/* envo_type_to_partn */
66 	ef10_nvram_partn_size,		/* envo_partn_size */
67 	ef10_nvram_partn_rw_start,	/* envo_partn_rw_start */
68 	ef10_nvram_partn_read,		/* envo_partn_read */
69 	ef10_nvram_partn_erase,		/* envo_partn_erase */
70 	ef10_nvram_partn_write,		/* envo_partn_write */
71 	ef10_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
72 	ef10_nvram_partn_get_version,	/* envo_partn_get_version */
73 	ef10_nvram_partn_set_version,	/* envo_partn_set_version */
74 	ef10_nvram_buffer_validate,	/* envo_buffer_validate */
75 };
76 
77 #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
78 
79 	__checkReturn	efx_rc_t
efx_nvram_init(__in efx_nic_t * enp)80 efx_nvram_init(
81 	__in		efx_nic_t *enp)
82 {
83 	const efx_nvram_ops_t *envop;
84 	efx_rc_t rc;
85 
86 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
87 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
88 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
89 
90 	switch (enp->en_family) {
91 #if EFSYS_OPT_SIENA
92 	case EFX_FAMILY_SIENA:
93 		envop = &__efx_nvram_siena_ops;
94 		break;
95 #endif	/* EFSYS_OPT_SIENA */
96 
97 #if EFSYS_OPT_HUNTINGTON
98 	case EFX_FAMILY_HUNTINGTON:
99 		envop = &__efx_nvram_ef10_ops;
100 		break;
101 #endif	/* EFSYS_OPT_HUNTINGTON */
102 
103 #if EFSYS_OPT_MEDFORD
104 	case EFX_FAMILY_MEDFORD:
105 		envop = &__efx_nvram_ef10_ops;
106 		break;
107 #endif	/* EFSYS_OPT_MEDFORD */
108 
109 	default:
110 		EFSYS_ASSERT(0);
111 		rc = ENOTSUP;
112 		goto fail1;
113 	}
114 
115 	enp->en_envop = envop;
116 	enp->en_mod_flags |= EFX_MOD_NVRAM;
117 
118 	return (0);
119 
120 fail1:
121 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
122 
123 	return (rc);
124 }
125 
126 #if EFSYS_OPT_DIAG
127 
128 	__checkReturn		efx_rc_t
efx_nvram_test(__in efx_nic_t * enp)129 efx_nvram_test(
130 	__in			efx_nic_t *enp)
131 {
132 	const efx_nvram_ops_t *envop = enp->en_envop;
133 	efx_rc_t rc;
134 
135 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
136 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
137 
138 	if ((rc = envop->envo_test(enp)) != 0)
139 		goto fail1;
140 
141 	return (0);
142 
143 fail1:
144 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
145 
146 	return (rc);
147 }
148 
149 #endif	/* EFSYS_OPT_DIAG */
150 
151 	__checkReturn		efx_rc_t
efx_nvram_size(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out size_t * sizep)152 efx_nvram_size(
153 	__in			efx_nic_t *enp,
154 	__in			efx_nvram_type_t type,
155 	__out			size_t *sizep)
156 {
157 	const efx_nvram_ops_t *envop = enp->en_envop;
158 	uint32_t partn;
159 	efx_rc_t rc;
160 
161 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
162 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
163 
164 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
165 
166 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
167 		goto fail1;
168 
169 	if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0)
170 		goto fail2;
171 
172 	return (0);
173 
174 fail2:
175 	EFSYS_PROBE(fail2);
176 fail1:
177 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
178 	*sizep = 0;
179 
180 	return (rc);
181 }
182 
183 	__checkReturn		efx_rc_t
184 efx_nvram_get_version(
185 	__in			efx_nic_t *enp,
186 	__in			efx_nvram_type_t type,
187 	__out			uint32_t *subtypep,
188 	__out_ecount(4)		uint16_t version[4])
189 {
190 	const efx_nvram_ops_t *envop = enp->en_envop;
191 	uint32_t partn;
192 	efx_rc_t rc;
193 
194 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
195 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
196 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
197 
198 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
199 
200 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
201 		goto fail1;
202 
203 	if ((rc = envop->envo_partn_get_version(enp, partn,
204 		    subtypep, version)) != 0)
205 		goto fail2;
206 
207 	return (0);
208 
209 fail2:
210 	EFSYS_PROBE(fail2);
211 fail1:
212 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
213 
214 	return (rc);
215 }
216 
217 	__checkReturn		efx_rc_t
efx_nvram_rw_start(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out_opt size_t * chunk_sizep)218 efx_nvram_rw_start(
219 	__in			efx_nic_t *enp,
220 	__in			efx_nvram_type_t type,
221 	__out_opt		size_t *chunk_sizep)
222 {
223 	const efx_nvram_ops_t *envop = enp->en_envop;
224 	uint32_t partn;
225 	efx_rc_t rc;
226 
227 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
228 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
229 
230 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
231 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
232 
233 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
234 
235 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
236 		goto fail1;
237 
238 	if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0)
239 		goto fail2;
240 
241 	enp->en_nvram_locked = type;
242 
243 	return (0);
244 
245 fail2:
246 	EFSYS_PROBE(fail2);
247 fail1:
248 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
249 
250 	return (rc);
251 }
252 
253 	__checkReturn		efx_rc_t
efx_nvram_read_chunk(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)254 efx_nvram_read_chunk(
255 	__in			efx_nic_t *enp,
256 	__in			efx_nvram_type_t type,
257 	__in			unsigned int offset,
258 	__out_bcount(size)	caddr_t data,
259 	__in			size_t size)
260 {
261 	const efx_nvram_ops_t *envop = enp->en_envop;
262 	uint32_t partn;
263 	efx_rc_t rc;
264 
265 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
266 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
267 
268 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
269 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
270 
271 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
272 
273 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
274 		goto fail1;
275 
276 	if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0)
277 		goto fail2;
278 
279 	return (0);
280 
281 fail2:
282 	EFSYS_PROBE(fail2);
283 fail1:
284 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
285 
286 	return (rc);
287 }
288 
289 	__checkReturn		efx_rc_t
efx_nvram_erase(__in efx_nic_t * enp,__in efx_nvram_type_t type)290 efx_nvram_erase(
291 	__in			efx_nic_t *enp,
292 	__in			efx_nvram_type_t type)
293 {
294 	const efx_nvram_ops_t *envop = enp->en_envop;
295 	unsigned int offset = 0;
296 	size_t size = 0;
297 	uint32_t partn;
298 	efx_rc_t rc;
299 
300 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
301 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
302 
303 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
304 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
305 
306 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
307 
308 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
309 		goto fail1;
310 
311 	if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0)
312 		goto fail2;
313 
314 	if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0)
315 		goto fail3;
316 
317 	return (0);
318 
319 fail3:
320 	EFSYS_PROBE(fail3);
321 fail2:
322 	EFSYS_PROBE(fail2);
323 fail1:
324 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
325 
326 	return (rc);
327 }
328 
329 	__checkReturn		efx_rc_t
efx_nvram_write_chunk(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__in_bcount (size)caddr_t data,__in size_t size)330 efx_nvram_write_chunk(
331 	__in			efx_nic_t *enp,
332 	__in			efx_nvram_type_t type,
333 	__in			unsigned int offset,
334 	__in_bcount(size)	caddr_t data,
335 	__in			size_t size)
336 {
337 	const efx_nvram_ops_t *envop = enp->en_envop;
338 	uint32_t partn;
339 	efx_rc_t rc;
340 
341 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
342 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
343 
344 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
345 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
346 
347 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
348 
349 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
350 		goto fail1;
351 
352 	if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0)
353 		goto fail2;
354 
355 	return (0);
356 
357 fail2:
358 	EFSYS_PROBE(fail2);
359 fail1:
360 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
361 
362 	return (rc);
363 }
364 
365 	__checkReturn		efx_rc_t
efx_nvram_rw_finish(__in efx_nic_t * enp,__in efx_nvram_type_t type)366 efx_nvram_rw_finish(
367 	__in			efx_nic_t *enp,
368 	__in			efx_nvram_type_t type)
369 {
370 	const efx_nvram_ops_t *envop = enp->en_envop;
371 	uint32_t partn;
372 	efx_rc_t rc;
373 
374 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
375 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
376 
377 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
378 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
379 
380 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
381 
382 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
383 		goto fail1;
384 
385 	if ((rc = envop->envo_partn_rw_finish(enp, partn)) != 0)
386 		goto fail2;
387 
388 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
389 
390 	return (0);
391 
392 fail2:
393 	EFSYS_PROBE(fail2);
394 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
395 
396 fail1:
397 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
398 
399 	return (rc);
400 }
401 
402 	__checkReturn		efx_rc_t
403 efx_nvram_set_version(
404 	__in			efx_nic_t *enp,
405 	__in			efx_nvram_type_t type,
406 	__in_ecount(4)		uint16_t version[4])
407 {
408 	const efx_nvram_ops_t *envop = enp->en_envop;
409 	uint32_t partn;
410 	efx_rc_t rc;
411 
412 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
413 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
414 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
415 
416 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
417 
418 	/*
419 	 * The Siena implementation of envo_set_version() will attempt to
420 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
421 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
422 	 */
423 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
424 
425 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
426 		goto fail1;
427 
428 	if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
429 		goto fail2;
430 
431 	return (0);
432 
433 fail2:
434 	EFSYS_PROBE(fail2);
435 fail1:
436 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
437 
438 	return (rc);
439 }
440 
441 /* Validate buffer contents (before writing to flash) */
442 	__checkReturn		efx_rc_t
efx_nvram_validate(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in_bcount (partn_size)caddr_t partn_data,__in size_t partn_size)443 efx_nvram_validate(
444 	__in			efx_nic_t *enp,
445 	__in			efx_nvram_type_t type,
446 	__in_bcount(partn_size)	caddr_t partn_data,
447 	__in			size_t partn_size)
448 {
449 	const efx_nvram_ops_t *envop = enp->en_envop;
450 	uint32_t partn;
451 	efx_rc_t rc;
452 
453 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
454 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
455 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
456 
457 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
458 
459 
460 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
461 		goto fail1;
462 
463 	if (envop->envo_buffer_validate != NULL) {
464 		if ((rc = envop->envo_buffer_validate(enp, partn,
465 			    partn_data, partn_size)) != 0)
466 			goto fail2;
467 	}
468 
469 	return (0);
470 
471 fail2:
472 	EFSYS_PROBE(fail2);
473 fail1:
474 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
475 
476 	return (rc);
477 }
478 
479 
480 void
efx_nvram_fini(__in efx_nic_t * enp)481 efx_nvram_fini(
482 	__in		efx_nic_t *enp)
483 {
484 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
485 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
486 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
487 
488 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
489 
490 	enp->en_envop = NULL;
491 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
492 }
493 
494 #endif	/* EFSYS_OPT_NVRAM */
495 
496 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
497 
498 /*
499  * Internal MCDI request handling
500  */
501 
502 	__checkReturn		efx_rc_t
efx_mcdi_nvram_partitions(__in efx_nic_t * enp,__out_bcount (size)caddr_t data,__in size_t size,__out unsigned int * npartnp)503 efx_mcdi_nvram_partitions(
504 	__in			efx_nic_t *enp,
505 	__out_bcount(size)	caddr_t data,
506 	__in			size_t size,
507 	__out			unsigned int *npartnp)
508 {
509 	efx_mcdi_req_t req;
510 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_PARTITIONS_IN_LEN,
511 		MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX);
512 	unsigned int npartn;
513 	efx_rc_t rc;
514 
515 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
516 	req.emr_in_buf = payload;
517 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
518 	req.emr_out_buf = payload;
519 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
520 
521 	efx_mcdi_execute(enp, &req);
522 
523 	if (req.emr_rc != 0) {
524 		rc = req.emr_rc;
525 		goto fail1;
526 	}
527 
528 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
529 		rc = EMSGSIZE;
530 		goto fail2;
531 	}
532 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
533 
534 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
535 		rc = ENOENT;
536 		goto fail3;
537 	}
538 
539 	if (size < npartn * sizeof (uint32_t)) {
540 		rc = ENOSPC;
541 		goto fail3;
542 	}
543 
544 	*npartnp = npartn;
545 
546 	memcpy(data,
547 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
548 	    (npartn * sizeof (uint32_t)));
549 
550 	return (0);
551 
552 fail3:
553 	EFSYS_PROBE(fail3);
554 fail2:
555 	EFSYS_PROBE(fail2);
556 fail1:
557 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
558 
559 	return (rc);
560 }
561 
562 	__checkReturn		efx_rc_t
563 efx_mcdi_nvram_metadata(
564 	__in			efx_nic_t *enp,
565 	__in			uint32_t partn,
566 	__out			uint32_t *subtypep,
567 	__out_ecount(4)		uint16_t version[4],
568 	__out_bcount_opt(size)	char *descp,
569 	__in			size_t size)
570 {
571 	efx_mcdi_req_t req;
572 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_METADATA_IN_LEN,
573 		MC_CMD_NVRAM_METADATA_OUT_LENMAX);
574 	efx_rc_t rc;
575 
576 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
577 	req.emr_in_buf = payload;
578 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
579 	req.emr_out_buf = payload;
580 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
581 
582 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
583 
584 	efx_mcdi_execute(enp, &req);
585 
586 	if (req.emr_rc != 0) {
587 		rc = req.emr_rc;
588 		goto fail1;
589 	}
590 
591 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
592 		rc = EMSGSIZE;
593 		goto fail2;
594 	}
595 
596 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
597 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
598 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
599 	} else {
600 		*subtypep = 0;
601 	}
602 
603 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
604 		NVRAM_METADATA_OUT_VERSION_VALID)) {
605 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
606 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
607 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
608 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
609 	} else {
610 		version[0] = version[1] = version[2] = version[3] = 0;
611 	}
612 
613 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
614 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
615 		/* Return optional descrition string */
616 		if ((descp != NULL) && (size > 0)) {
617 			size_t desclen;
618 
619 			descp[0] = '\0';
620 			desclen = (req.emr_out_length_used
621 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
622 
623 			EFSYS_ASSERT3U(desclen, <=,
624 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
625 
626 			if (size < desclen) {
627 				rc = ENOSPC;
628 				goto fail3;
629 			}
630 
631 			memcpy(descp, MCDI_OUT2(req, char,
632 				NVRAM_METADATA_OUT_DESCRIPTION),
633 			    desclen);
634 
635 			/* Ensure string is NUL terminated */
636 			descp[desclen] = '\0';
637 		}
638 	}
639 
640 	return (0);
641 
642 fail3:
643 	EFSYS_PROBE(fail3);
644 fail2:
645 	EFSYS_PROBE(fail2);
646 fail1:
647 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
648 
649 	return (rc);
650 }
651 
652 	__checkReturn		efx_rc_t
efx_mcdi_nvram_info(__in efx_nic_t * enp,__in uint32_t partn,__out_opt size_t * sizep,__out_opt uint32_t * addressp,__out_opt uint32_t * erase_sizep,__out_opt uint32_t * write_sizep)653 efx_mcdi_nvram_info(
654 	__in			efx_nic_t *enp,
655 	__in			uint32_t partn,
656 	__out_opt		size_t *sizep,
657 	__out_opt		uint32_t *addressp,
658 	__out_opt		uint32_t *erase_sizep,
659 	__out_opt		uint32_t *write_sizep)
660 {
661 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_INFO_IN_LEN,
662 		MC_CMD_NVRAM_INFO_V2_OUT_LEN);
663 	efx_mcdi_req_t req;
664 	efx_rc_t rc;
665 
666 	req.emr_cmd = MC_CMD_NVRAM_INFO;
667 	req.emr_in_buf = payload;
668 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
669 	req.emr_out_buf = payload;
670 	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
671 
672 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
673 
674 	efx_mcdi_execute_quiet(enp, &req);
675 
676 	if (req.emr_rc != 0) {
677 		rc = req.emr_rc;
678 		goto fail1;
679 	}
680 
681 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
682 		rc = EMSGSIZE;
683 		goto fail2;
684 	}
685 
686 	if (sizep)
687 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
688 
689 	if (addressp)
690 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
691 
692 	if (erase_sizep)
693 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
694 
695 	if (write_sizep) {
696 		*write_sizep =
697 			(req.emr_out_length_used <
698 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
699 			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
700 	}
701 
702 	return (0);
703 
704 fail2:
705 	EFSYS_PROBE(fail2);
706 fail1:
707 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
708 
709 	return (rc);
710 }
711 
712 /*
713  * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
714  * NVRAM updates. Older firmware will ignore the flags field in the request.
715  */
716 	__checkReturn		efx_rc_t
efx_mcdi_nvram_update_start(__in efx_nic_t * enp,__in uint32_t partn)717 efx_mcdi_nvram_update_start(
718 	__in			efx_nic_t *enp,
719 	__in			uint32_t partn)
720 {
721 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
722 		MC_CMD_NVRAM_UPDATE_START_OUT_LEN);
723 	efx_mcdi_req_t req;
724 	efx_rc_t rc;
725 
726 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
727 	req.emr_in_buf = payload;
728 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
729 	req.emr_out_buf = payload;
730 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
731 
732 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
733 
734 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
735 	    NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
736 
737 	efx_mcdi_execute(enp, &req);
738 
739 	if (req.emr_rc != 0) {
740 		rc = req.emr_rc;
741 		goto fail1;
742 	}
743 
744 	return (0);
745 
746 fail1:
747 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
748 
749 	return (rc);
750 }
751 
752 	__checkReturn		efx_rc_t
efx_mcdi_nvram_read(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__out_bcount (size)caddr_t data,__in size_t size,__in uint32_t mode)753 efx_mcdi_nvram_read(
754 	__in			efx_nic_t *enp,
755 	__in			uint32_t partn,
756 	__in			uint32_t offset,
757 	__out_bcount(size)	caddr_t data,
758 	__in			size_t size,
759 	__in			uint32_t mode)
760 {
761 	efx_mcdi_req_t req;
762 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_READ_IN_V2_LEN,
763 		MC_CMD_NVRAM_READ_OUT_LENMAX);
764 	efx_rc_t rc;
765 
766 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
767 		rc = EINVAL;
768 		goto fail1;
769 	}
770 
771 	req.emr_cmd = MC_CMD_NVRAM_READ;
772 	req.emr_in_buf = payload;
773 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
774 	req.emr_out_buf = payload;
775 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
776 
777 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
778 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
779 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
780 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
781 
782 	efx_mcdi_execute(enp, &req);
783 
784 	if (req.emr_rc != 0) {
785 		rc = req.emr_rc;
786 		goto fail1;
787 	}
788 
789 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
790 		rc = EMSGSIZE;
791 		goto fail2;
792 	}
793 
794 	memcpy(data,
795 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
796 	    size);
797 
798 	return (0);
799 
800 fail2:
801 	EFSYS_PROBE(fail2);
802 fail1:
803 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
804 
805 	return (rc);
806 }
807 
808 	__checkReturn		efx_rc_t
efx_mcdi_nvram_erase(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__in size_t size)809 efx_mcdi_nvram_erase(
810 	__in			efx_nic_t *enp,
811 	__in			uint32_t partn,
812 	__in			uint32_t offset,
813 	__in			size_t size)
814 {
815 	efx_mcdi_req_t req;
816 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_ERASE_IN_LEN,
817 		MC_CMD_NVRAM_ERASE_OUT_LEN);
818 	efx_rc_t rc;
819 
820 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
821 	req.emr_in_buf = payload;
822 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
823 	req.emr_out_buf = payload;
824 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
825 
826 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
827 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
828 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
829 
830 	efx_mcdi_execute(enp, &req);
831 
832 	if (req.emr_rc != 0) {
833 		rc = req.emr_rc;
834 		goto fail1;
835 	}
836 
837 	return (0);
838 
839 fail1:
840 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
841 
842 	return (rc);
843 }
844 
845 /*
846  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
847  * Sienna and EF10 based boards.  However EF10 based boards support the use
848  * of this command with payloads up to the maximum MCDI V2 payload length.
849  */
850 	__checkReturn		efx_rc_t
efx_mcdi_nvram_write(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__in_bcount (size)caddr_t data,__in size_t size)851 efx_mcdi_nvram_write(
852 	__in			efx_nic_t *enp,
853 	__in			uint32_t partn,
854 	__in			uint32_t offset,
855 	__in_bcount(size)	caddr_t data,
856 	__in			size_t size)
857 {
858 	efx_mcdi_req_t req;
859 	uint8_t *payload;
860 	efx_rc_t rc;
861 	size_t max_data_size;
862 	size_t payload_len = enp->en_nic_cfg.enc_mcdi_max_payload_length;
863 
864 	max_data_size = payload_len - MC_CMD_NVRAM_WRITE_IN_LEN(0);
865 	EFSYS_ASSERT3U(payload_len, >, 0);
866 	EFSYS_ASSERT3U(max_data_size, <, payload_len);
867 
868 	if (size > max_data_size) {
869 		rc = EINVAL;
870 		goto fail1;
871 	}
872 
873 	EFSYS_KMEM_ALLOC(enp->en_esip, payload_len, payload);
874 	if (payload == NULL) {
875 		rc = ENOMEM;
876 		goto fail2;
877 	}
878 
879 	(void) memset(payload, 0, payload_len);
880 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
881 	req.emr_in_buf = payload;
882 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
883 	req.emr_out_buf = payload;
884 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
885 
886 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
887 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
888 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
889 
890 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
891 	    data, size);
892 
893 	efx_mcdi_execute(enp, &req);
894 
895 	if (req.emr_rc != 0) {
896 		rc = req.emr_rc;
897 		goto fail3;
898 	}
899 
900 	EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload);
901 
902 	return (0);
903 
904 fail3:
905 	EFSYS_PROBE(fail3);
906 	EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload);
907 fail2:
908 	EFSYS_PROBE(fail2);
909 fail1:
910 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
911 
912 	return (rc);
913 }
914 
915 
916 /*
917  * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
918  * NVRAM updates. Older firmware will ignore the flags field in the request.
919  */
920 	__checkReturn		efx_rc_t
efx_mcdi_nvram_update_finish(__in efx_nic_t * enp,__in uint32_t partn,__in boolean_t reboot,__out_opt uint32_t * resultp)921 efx_mcdi_nvram_update_finish(
922 	__in			efx_nic_t *enp,
923 	__in			uint32_t partn,
924 	__in			boolean_t reboot,
925 	__out_opt		uint32_t *resultp)
926 {
927 	const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
928 	efx_mcdi_req_t req;
929 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
930 		MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN);
931 	uint32_t result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
932 	efx_rc_t rc;
933 
934 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
935 	req.emr_in_buf = payload;
936 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
937 	req.emr_out_buf = payload;
938 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
939 
940 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
941 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
942 
943 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
944 	    NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
945 
946 	efx_mcdi_execute(enp, &req);
947 
948 	if (req.emr_rc != 0) {
949 		rc = req.emr_rc;
950 		goto fail1;
951 	}
952 
953 	if (encp->enc_fw_verified_nvram_update_required == B_FALSE) {
954 		/* Report success if verified updates are not supported. */
955 		result = MC_CMD_NVRAM_VERIFY_RC_SUCCESS;
956 	} else {
957 		/* Firmware-verified NVRAM updates are required */
958 		if (req.emr_out_length_used <
959 		    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
960 			rc = EMSGSIZE;
961 			goto fail2;
962 		}
963 		result =
964 		    MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
965 
966 		if (result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) {
967 			/* Mandatory verification failed */
968 			rc = EINVAL;
969 			goto fail3;
970 		}
971 	}
972 
973 	if (resultp != NULL)
974 		*resultp = result;
975 
976 	return (0);
977 
978 fail3:
979 	EFSYS_PROBE(fail3);
980 fail2:
981 	EFSYS_PROBE(fail2);
982 fail1:
983 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
984 
985 	/* Always report verification result */
986 	if (resultp != NULL)
987 		*resultp = result;
988 
989 	return (rc);
990 }
991 
992 #if EFSYS_OPT_DIAG
993 
994 	__checkReturn		efx_rc_t
efx_mcdi_nvram_test(__in efx_nic_t * enp,__in uint32_t partn)995 efx_mcdi_nvram_test(
996 	__in			efx_nic_t *enp,
997 	__in			uint32_t partn)
998 {
999 	efx_mcdi_req_t req;
1000 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_TEST_IN_LEN,
1001 		MC_CMD_NVRAM_TEST_OUT_LEN);
1002 	int result;
1003 	efx_rc_t rc;
1004 
1005 	req.emr_cmd = MC_CMD_NVRAM_TEST;
1006 	req.emr_in_buf = payload;
1007 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
1008 	req.emr_out_buf = payload;
1009 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
1010 
1011 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
1012 
1013 	efx_mcdi_execute(enp, &req);
1014 
1015 	if (req.emr_rc != 0) {
1016 		rc = req.emr_rc;
1017 		goto fail1;
1018 	}
1019 
1020 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
1021 		rc = EMSGSIZE;
1022 		goto fail2;
1023 	}
1024 
1025 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
1026 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
1027 
1028 		EFSYS_PROBE1(nvram_test_failure, int, partn);
1029 
1030 		rc = (EINVAL);
1031 		goto fail3;
1032 	}
1033 
1034 	return (0);
1035 
1036 fail3:
1037 	EFSYS_PROBE(fail3);
1038 fail2:
1039 	EFSYS_PROBE(fail2);
1040 fail1:
1041 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1042 
1043 	return (rc);
1044 }
1045 
1046 #endif	/* EFSYS_OPT_DIAG */
1047 
1048 
1049 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
1050