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