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