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