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