]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sfxge/common/siena_vpd.c
Merge once more from ^/vendor/llvm-project/release-10.x, to get the
[FreeBSD/FreeBSD.git] / sys / dev / sfxge / common / siena_vpd.c
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$");
35
36 #include "efx.h"
37 #include "efx_impl.h"
38
39 #if EFSYS_OPT_VPD
40
41 #if EFSYS_OPT_SIENA
42
43 static  __checkReturn                   efx_rc_t
44 siena_vpd_get_static(
45         __in                            efx_nic_t *enp,
46         __in                            uint32_t partn,
47         __deref_out_bcount_opt(*sizep)  caddr_t *svpdp,
48         __out                           size_t *sizep)
49 {
50         siena_mc_static_config_hdr_t *scfg;
51         caddr_t svpd;
52         size_t size;
53         uint8_t cksum;
54         unsigned int vpd_offset;
55         unsigned int vpd_length;
56         unsigned int hdr_length;
57         unsigned int pos;
58         unsigned int region;
59         efx_rc_t rc;
60
61         EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
62                     partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
63
64         /* Allocate sufficient memory for the entire static cfg area */
65         if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
66                 goto fail1;
67
68         if (size < SIENA_NVRAM_CHUNK) {
69                 rc = EINVAL;
70                 goto fail2;
71         }
72
73         EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
74         if (scfg == NULL) {
75                 rc = ENOMEM;
76                 goto fail3;
77         }
78
79         if ((rc = siena_nvram_partn_read(enp, partn, 0,
80             (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
81                 goto fail4;
82
83         /* Verify the magic number */
84         if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
85             SIENA_MC_STATIC_CONFIG_MAGIC) {
86                 rc = EINVAL;
87                 goto fail5;
88         }
89
90         /* All future versions of the structure must be backwards compatible */
91         EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
92
93         hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
94         vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
95         vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
96
97         /* Verify the hdr doesn't overflow the sector size */
98         if (hdr_length > size || vpd_offset > size || vpd_length > size ||
99             vpd_length + vpd_offset > size) {
100                 rc = EINVAL;
101                 goto fail6;
102         }
103
104         /* Read the remainder of scfg + static vpd */
105         region = vpd_offset + vpd_length;
106         if (region > SIENA_NVRAM_CHUNK) {
107                 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
108                     (caddr_t)scfg + SIENA_NVRAM_CHUNK,
109                     region - SIENA_NVRAM_CHUNK)) != 0)
110                         goto fail7;
111         }
112
113         /* Verify checksum */
114         cksum = 0;
115         for (pos = 0; pos < hdr_length; pos++)
116                 cksum += ((uint8_t *)scfg)[pos];
117         if (cksum != 0) {
118                 rc = EINVAL;
119                 goto fail8;
120         }
121
122         if (vpd_length == 0)
123                 svpd = NULL;
124         else {
125                 /* Copy the vpd data out */
126                 EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
127                 if (svpd == NULL) {
128                         rc = ENOMEM;
129                         goto fail9;
130                 }
131                 memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
132         }
133
134         EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
135
136         *svpdp = svpd;
137         *sizep = vpd_length;
138
139         return (0);
140
141 fail9:
142         EFSYS_PROBE(fail9);
143 fail8:
144         EFSYS_PROBE(fail8);
145 fail7:
146         EFSYS_PROBE(fail7);
147 fail6:
148         EFSYS_PROBE(fail6);
149 fail5:
150         EFSYS_PROBE(fail5);
151 fail4:
152         EFSYS_PROBE(fail4);
153
154         EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
155
156 fail3:
157         EFSYS_PROBE(fail3);
158 fail2:
159         EFSYS_PROBE(fail2);
160 fail1:
161         EFSYS_PROBE1(fail1, efx_rc_t, rc);
162
163         return (rc);
164 }
165
166         __checkReturn           efx_rc_t
167 siena_vpd_init(
168         __in                    efx_nic_t *enp)
169 {
170         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
171         caddr_t svpd = NULL;
172         unsigned int partn;
173         size_t size = 0;
174         efx_rc_t rc;
175
176         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
177
178         partn = (emip->emi_port == 1)
179                 ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
180                 : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
181
182         /*
183          * We need the static VPD sector to present a unified static+dynamic
184          * VPD, that is, basically on every read, write, verify cycle. Since
185          * it should *never* change we can just cache it here.
186          */
187         if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
188                 goto fail1;
189
190         if (svpd != NULL && size > 0) {
191                 if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
192                         goto fail2;
193         }
194
195         enp->en_u.siena.enu_svpd = svpd;
196         enp->en_u.siena.enu_svpd_length = size;
197
198         return (0);
199
200 fail2:
201         EFSYS_PROBE(fail2);
202
203         EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
204 fail1:
205         EFSYS_PROBE1(fail1, efx_rc_t, rc);
206
207         return (rc);
208 }
209
210         __checkReturn           efx_rc_t
211 siena_vpd_size(
212         __in                    efx_nic_t *enp,
213         __out                   size_t *sizep)
214 {
215         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
216         uint32_t partn;
217         efx_rc_t rc;
218
219         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
220
221         /*
222          * This function returns the total size the user should allocate
223          * for all VPD operations. We've already cached the static vpd,
224          * so we just need to return an upper bound on the dynamic vpd.
225          * Since the dynamic_config structure can change under our feet,
226          * (as version numbers are inserted), just be safe and return the
227          * total size of the dynamic_config *sector*
228          */
229         partn = (emip->emi_port == 1)
230                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
231                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
232
233         if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
234                 goto fail1;
235
236         return (0);
237
238 fail1:
239         EFSYS_PROBE1(fail1, efx_rc_t, rc);
240
241         return (rc);
242 }
243
244         __checkReturn           efx_rc_t
245 siena_vpd_read(
246         __in                    efx_nic_t *enp,
247         __out_bcount(size)      caddr_t data,
248         __in                    size_t size)
249 {
250         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
251         siena_mc_dynamic_config_hdr_t *dcfg = NULL;
252         unsigned int vpd_length;
253         unsigned int vpd_offset;
254         unsigned int dcfg_partn;
255         size_t dcfg_size;
256         efx_rc_t rc;
257
258         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
259
260         dcfg_partn = (emip->emi_port == 1)
261                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
262                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
263
264         if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
265             B_TRUE, &dcfg, &dcfg_size)) != 0)
266                 goto fail1;
267
268         vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
269         vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
270
271         if (vpd_length > size) {
272                 rc = EFAULT;    /* Invalid dcfg: header bigger than sector */
273                 goto fail2;
274         }
275
276         EFSYS_ASSERT3U(vpd_length, <=, size);
277         memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
278
279         /* Pad data with all-1s, consistent with update operations */
280         memset(data + vpd_length, 0xff, size - vpd_length);
281
282         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
283
284         return (0);
285
286 fail2:
287         EFSYS_PROBE(fail2);
288
289         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
290 fail1:
291         EFSYS_PROBE1(fail1, efx_rc_t, rc);
292
293         return (rc);
294 }
295
296         __checkReturn           efx_rc_t
297 siena_vpd_verify(
298         __in                    efx_nic_t *enp,
299         __in_bcount(size)       caddr_t data,
300         __in                    size_t size)
301 {
302         efx_vpd_tag_t stag;
303         efx_vpd_tag_t dtag;
304         efx_vpd_keyword_t skey;
305         efx_vpd_keyword_t dkey;
306         unsigned int scont;
307         unsigned int dcont;
308
309         efx_rc_t rc;
310
311         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
312
313         /*
314          * Strictly you could take the view that dynamic vpd is optional.
315          * Instead, to conform more closely to the read/verify/reinit()
316          * paradigm, we require dynamic vpd. siena_vpd_reinit() will
317          * reinitialize it as required.
318          */
319         if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
320                 goto fail1;
321
322         /*
323          * Verify that there is no duplication between the static and
324          * dynamic cfg sectors.
325          */
326         if (enp->en_u.siena.enu_svpd_length == 0)
327                 goto done;
328
329         dcont = 0;
330         _NOTE(CONSTANTCONDITION)
331         while (1) {
332                 if ((rc = efx_vpd_hunk_next(data, size, &dtag,
333                     &dkey, NULL, NULL, &dcont)) != 0)
334                         goto fail2;
335                 if (dcont == 0)
336                         break;
337
338                 /*
339                  * Skip the RV keyword. It should be present in both the static
340                  * and dynamic cfg sectors.
341                  */
342                 if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
343                         continue;
344
345                 scont = 0;
346                 _NOTE(CONSTANTCONDITION)
347                 while (1) {
348                         if ((rc = efx_vpd_hunk_next(
349                             enp->en_u.siena.enu_svpd,
350                             enp->en_u.siena.enu_svpd_length, &stag, &skey,
351                             NULL, NULL, &scont)) != 0)
352                                 goto fail3;
353                         if (scont == 0)
354                                 break;
355
356                         if (stag == dtag && skey == dkey) {
357                                 rc = EEXIST;
358                                 goto fail4;
359                         }
360                 }
361         }
362
363 done:
364         return (0);
365
366 fail4:
367         EFSYS_PROBE(fail4);
368 fail3:
369         EFSYS_PROBE(fail3);
370 fail2:
371         EFSYS_PROBE(fail2);
372 fail1:
373         EFSYS_PROBE1(fail1, efx_rc_t, rc);
374
375         return (rc);
376 }
377
378         __checkReturn           efx_rc_t
379 siena_vpd_reinit(
380         __in                    efx_nic_t *enp,
381         __in_bcount(size)       caddr_t data,
382         __in                    size_t size)
383 {
384         boolean_t wantpid;
385         efx_rc_t rc;
386
387         /*
388          * Only create a PID if the dynamic cfg doesn't have one
389          */
390         if (enp->en_u.siena.enu_svpd_length == 0)
391                 wantpid = B_TRUE;
392         else {
393                 unsigned int offset;
394                 uint8_t length;
395
396                 rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
397                                     enp->en_u.siena.enu_svpd_length,
398                                     EFX_VPD_ID, 0, &offset, &length);
399                 if (rc == 0)
400                         wantpid = B_FALSE;
401                 else if (rc == ENOENT)
402                         wantpid = B_TRUE;
403                 else
404                         goto fail1;
405         }
406
407         if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
408                 goto fail2;
409
410         return (0);
411
412 fail2:
413         EFSYS_PROBE(fail2);
414 fail1:
415         EFSYS_PROBE1(fail1, efx_rc_t, rc);
416
417         return (rc);
418 }
419
420         __checkReturn           efx_rc_t
421 siena_vpd_get(
422         __in                    efx_nic_t *enp,
423         __in_bcount(size)       caddr_t data,
424         __in                    size_t size,
425         __inout                 efx_vpd_value_t *evvp)
426 {
427         unsigned int offset;
428         uint8_t length;
429         efx_rc_t rc;
430
431         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
432
433         /* Attempt to satisfy the request from svpd first */
434         if (enp->en_u.siena.enu_svpd_length > 0) {
435                 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
436                     enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
437                     evvp->evv_keyword, &offset, &length)) == 0) {
438                         evvp->evv_length = length;
439                         memcpy(evvp->evv_value,
440                             enp->en_u.siena.enu_svpd + offset, length);
441                         return (0);
442                 } else if (rc != ENOENT)
443                         goto fail1;
444         }
445
446         /* And then from the provided data buffer */
447         if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
448             evvp->evv_keyword, &offset, &length)) != 0) {
449                 if (rc == ENOENT)
450                         return (rc);
451
452                 goto fail2;
453         }
454
455         evvp->evv_length = length;
456         memcpy(evvp->evv_value, data + offset, length);
457
458         return (0);
459
460 fail2:
461         EFSYS_PROBE(fail2);
462 fail1:
463         EFSYS_PROBE1(fail1, efx_rc_t, rc);
464
465         return (rc);
466 }
467
468         __checkReturn           efx_rc_t
469 siena_vpd_set(
470         __in                    efx_nic_t *enp,
471         __in_bcount(size)       caddr_t data,
472         __in                    size_t size,
473         __in                    efx_vpd_value_t *evvp)
474 {
475         efx_rc_t rc;
476
477         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
478
479         /* If the provided (tag,keyword) exists in svpd, then it is readonly */
480         if (enp->en_u.siena.enu_svpd_length > 0) {
481                 unsigned int offset;
482                 uint8_t length;
483
484                 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
485                     enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
486                     evvp->evv_keyword, &offset, &length)) == 0) {
487                         rc = EACCES;
488                         goto fail1;
489                 }
490         }
491
492         if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
493                 goto fail2;
494
495         return (0);
496
497 fail2:
498         EFSYS_PROBE(fail2);
499 fail1:
500         EFSYS_PROBE1(fail1, efx_rc_t, rc);
501
502         return (rc);
503 }
504
505         __checkReturn           efx_rc_t
506 siena_vpd_next(
507         __in                    efx_nic_t *enp,
508         __in_bcount(size)       caddr_t data,
509         __in                    size_t size,
510         __out                   efx_vpd_value_t *evvp,
511         __inout                 unsigned int *contp)
512 {
513         _NOTE(ARGUNUSED(enp, data, size, evvp, contp))
514
515         return (ENOTSUP);
516 }
517
518         __checkReturn           efx_rc_t
519 siena_vpd_write(
520         __in                    efx_nic_t *enp,
521         __in_bcount(size)       caddr_t data,
522         __in                    size_t size)
523 {
524         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
525         siena_mc_dynamic_config_hdr_t *dcfg = NULL;
526         unsigned int vpd_offset;
527         unsigned int dcfg_partn;
528         unsigned int hdr_length;
529         unsigned int pos;
530         uint8_t cksum;
531         size_t partn_size, dcfg_size;
532         size_t vpd_length;
533         efx_rc_t rc;
534
535         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
536
537         /* Determine total length of all tags */
538         if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
539                 goto fail1;
540
541         /* Lock dynamic config sector for write, and read structure only */
542         dcfg_partn = (emip->emi_port == 1)
543                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
544                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
545
546         if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
547                 goto fail2;
548
549         if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
550                 goto fail3;
551
552         if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
553             B_FALSE, &dcfg, &dcfg_size)) != 0)
554                 goto fail4;
555
556         hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
557
558         /* Allocated memory should have room for the new VPD */
559         if (hdr_length + vpd_length > dcfg_size) {
560                 rc = ENOSPC;
561                 goto fail5;
562         }
563
564         /* Copy in new vpd and update header */
565         vpd_offset = dcfg_size - vpd_length;
566         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset);
567         memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
568         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length);
569
570         /* Update the checksum */
571         cksum = 0;
572         for (pos = 0; pos < hdr_length; pos++)
573                 cksum += ((uint8_t *)dcfg)[pos];
574         dcfg->csum.eb_u8[0] -= cksum;
575
576         /* Erase and write the new sector */
577         if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
578                 goto fail6;
579
580         /* Write out the new structure to nvram */
581         if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
582             vpd_offset + vpd_length)) != 0)
583                 goto fail7;
584
585         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
586
587         siena_nvram_partn_unlock(enp, dcfg_partn, NULL);
588
589         return (0);
590
591 fail7:
592         EFSYS_PROBE(fail7);
593 fail6:
594         EFSYS_PROBE(fail6);
595 fail5:
596         EFSYS_PROBE(fail5);
597
598         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
599 fail4:
600         EFSYS_PROBE(fail4);
601
602         siena_nvram_partn_unlock(enp, dcfg_partn, NULL);
603 fail3:
604         EFSYS_PROBE(fail3);
605 fail2:
606         EFSYS_PROBE(fail2);
607 fail1:
608         EFSYS_PROBE1(fail1, efx_rc_t, rc);
609
610         return (rc);
611 }
612
613                                 void
614 siena_vpd_fini(
615         __in                    efx_nic_t *enp)
616 {
617         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
618
619         if (enp->en_u.siena.enu_svpd_length > 0) {
620                 EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
621                                 enp->en_u.siena.enu_svpd);
622
623                 enp->en_u.siena.enu_svpd = NULL;
624                 enp->en_u.siena.enu_svpd_length = 0;
625         }
626 }
627
628 #endif  /* EFSYS_OPT_SIENA */
629
630 #endif  /* EFSYS_OPT_VPD */