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