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