]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sfxge/common/ef10_vpd.c
Merge lld trunk r351319, resolve conflicts, and update FREEBSD-Xlist.
[FreeBSD/FreeBSD.git] / sys / dev / sfxge / common / ef10_vpd.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 <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efx.h"
35 #include "efx_impl.h"
36
37
38 #if EFSYS_OPT_VPD
39
40 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
41
42 #include "ef10_tlv_layout.h"
43
44         __checkReturn           efx_rc_t
45 ef10_vpd_init(
46         __in                    efx_nic_t *enp)
47 {
48         caddr_t svpd;
49         size_t svpd_size;
50         uint32_t pci_pf;
51         uint32_t tag;
52         efx_rc_t rc;
53
54         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
55         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
56             enp->en_family == EFX_FAMILY_MEDFORD ||
57             enp->en_family == EFX_FAMILY_MEDFORD2);
58
59         if (enp->en_nic_cfg.enc_vpd_is_global) {
60                 tag = TLV_TAG_GLOBAL_STATIC_VPD;
61         } else {
62                 pci_pf = enp->en_nic_cfg.enc_pf;
63                 tag = TLV_TAG_PF_STATIC_VPD(pci_pf);
64         }
65
66         /*
67          * The VPD interface exposes VPD resources from the combined static and
68          * dynamic VPD storage. As the static VPD configuration should *never*
69          * change, we can cache it.
70          */
71         svpd = NULL;
72         svpd_size = 0;
73         rc = ef10_nvram_partn_read_tlv(enp,
74             NVRAM_PARTITION_TYPE_STATIC_CONFIG,
75             tag, &svpd, &svpd_size);
76         if (rc != 0) {
77                 if (rc == EACCES) {
78                         /* Unprivileged functions cannot access VPD */
79                         goto out;
80                 }
81                 goto fail1;
82         }
83
84         if (svpd != NULL && svpd_size > 0) {
85                 if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0)
86                         goto fail2;
87         }
88
89         enp->en_arch.ef10.ena_svpd = svpd;
90         enp->en_arch.ef10.ena_svpd_length = svpd_size;
91
92 out:
93         return (0);
94
95 fail2:
96         EFSYS_PROBE(fail2);
97
98         EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd);
99 fail1:
100         EFSYS_PROBE1(fail1, efx_rc_t, rc);
101
102         return (rc);
103 }
104
105         __checkReturn           efx_rc_t
106 ef10_vpd_size(
107         __in                    efx_nic_t *enp,
108         __out                   size_t *sizep)
109 {
110         efx_rc_t rc;
111
112         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
113             enp->en_family == EFX_FAMILY_MEDFORD ||
114             enp->en_family == EFX_FAMILY_MEDFORD2);
115
116         /*
117          * This function returns the total size the user should allocate
118          * for all VPD operations. We've already cached the static vpd,
119          * so we just need to return an upper bound on the dynamic vpd,
120          * which is the size of the DYNAMIC_CONFIG partition.
121          */
122         if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
123                     sizep, NULL, NULL, NULL)) != 0)
124                 goto fail1;
125
126         return (0);
127
128 fail1:
129         EFSYS_PROBE1(fail1, efx_rc_t, rc);
130
131         return (rc);
132 }
133
134         __checkReturn           efx_rc_t
135 ef10_vpd_read(
136         __in                    efx_nic_t *enp,
137         __out_bcount(size)      caddr_t data,
138         __in                    size_t size)
139 {
140         caddr_t dvpd;
141         size_t dvpd_size;
142         uint32_t pci_pf;
143         uint32_t tag;
144         efx_rc_t rc;
145
146         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
147             enp->en_family == EFX_FAMILY_MEDFORD ||
148             enp->en_family == EFX_FAMILY_MEDFORD2);
149
150         if (enp->en_nic_cfg.enc_vpd_is_global) {
151                 tag = TLV_TAG_GLOBAL_DYNAMIC_VPD;
152         } else {
153                 pci_pf = enp->en_nic_cfg.enc_pf;
154                 tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf);
155         }
156
157         if ((rc = ef10_nvram_partn_read_tlv(enp,
158                     NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
159                     tag, &dvpd, &dvpd_size)) != 0)
160                 goto fail1;
161
162         if (dvpd_size > size) {
163                 rc = ENOSPC;
164                 goto fail2;
165         }
166         if (dvpd != NULL)
167                 memcpy(data, dvpd, dvpd_size);
168
169         /* Pad data with all-1s, consistent with update operations */
170         memset(data + dvpd_size, 0xff, size - dvpd_size);
171
172         if (dvpd != NULL)
173                 EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
174
175         return (0);
176
177 fail2:
178         EFSYS_PROBE(fail2);
179
180         if (dvpd != NULL)
181                 EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
182 fail1:
183         EFSYS_PROBE1(fail1, efx_rc_t, rc);
184
185         return (rc);
186 }
187
188         __checkReturn           efx_rc_t
189 ef10_vpd_verify(
190         __in                    efx_nic_t *enp,
191         __in_bcount(size)       caddr_t data,
192         __in                    size_t size)
193 {
194         efx_vpd_tag_t stag;
195         efx_vpd_tag_t dtag;
196         efx_vpd_keyword_t skey;
197         efx_vpd_keyword_t dkey;
198         unsigned int scont;
199         unsigned int dcont;
200         efx_rc_t rc;
201
202         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
203             enp->en_family == EFX_FAMILY_MEDFORD ||
204             enp->en_family == EFX_FAMILY_MEDFORD2);
205
206         /*
207          * Strictly you could take the view that dynamic vpd is optional.
208          * Instead, to conform more closely to the read/verify/reinit()
209          * paradigm, we require dynamic vpd. ef10_vpd_reinit() will
210          * reinitialize it as required.
211          */
212         if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
213                 goto fail1;
214
215         /*
216          * Verify that there is no duplication between the static and
217          * dynamic cfg sectors.
218          */
219         if (enp->en_arch.ef10.ena_svpd_length == 0)
220                 goto done;
221
222         dcont = 0;
223         _NOTE(CONSTANTCONDITION)
224         while (1) {
225                 if ((rc = efx_vpd_hunk_next(data, size, &dtag,
226                     &dkey, NULL, NULL, &dcont)) != 0)
227                         goto fail2;
228                 if (dcont == 0)
229                         break;
230
231                 /*
232                  * Skip the RV keyword. It should be present in both the static
233                  * and dynamic cfg sectors.
234                  */
235                 if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
236                         continue;
237
238                 scont = 0;
239                 _NOTE(CONSTANTCONDITION)
240                 while (1) {
241                         if ((rc = efx_vpd_hunk_next(
242                             enp->en_arch.ef10.ena_svpd,
243                             enp->en_arch.ef10.ena_svpd_length, &stag, &skey,
244                             NULL, NULL, &scont)) != 0)
245                                 goto fail3;
246                         if (scont == 0)
247                                 break;
248
249                         if (stag == dtag && skey == dkey) {
250                                 rc = EEXIST;
251                                 goto fail4;
252                         }
253                 }
254         }
255
256 done:
257         return (0);
258
259 fail4:
260         EFSYS_PROBE(fail4);
261 fail3:
262         EFSYS_PROBE(fail3);
263 fail2:
264         EFSYS_PROBE(fail2);
265 fail1:
266         EFSYS_PROBE1(fail1, efx_rc_t, rc);
267
268         return (rc);
269 }
270
271         __checkReturn           efx_rc_t
272 ef10_vpd_reinit(
273         __in                    efx_nic_t *enp,
274         __in_bcount(size)       caddr_t data,
275         __in                    size_t size)
276 {
277         boolean_t wantpid;
278         efx_rc_t rc;
279
280         /*
281          * Only create an ID string if the dynamic cfg doesn't have one
282          */
283         if (enp->en_arch.ef10.ena_svpd_length == 0)
284                 wantpid = B_TRUE;
285         else {
286                 unsigned int offset;
287                 uint8_t length;
288
289                 rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
290                                     enp->en_arch.ef10.ena_svpd_length,
291                                     EFX_VPD_ID, 0, &offset, &length);
292                 if (rc == 0)
293                         wantpid = B_FALSE;
294                 else if (rc == ENOENT)
295                         wantpid = B_TRUE;
296                 else
297                         goto fail1;
298         }
299
300         if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
301                 goto fail2;
302
303         return (0);
304
305 fail2:
306         EFSYS_PROBE(fail2);
307 fail1:
308         EFSYS_PROBE1(fail1, efx_rc_t, rc);
309
310         return (rc);
311 }
312
313         __checkReturn           efx_rc_t
314 ef10_vpd_get(
315         __in                    efx_nic_t *enp,
316         __in_bcount(size)       caddr_t data,
317         __in                    size_t size,
318         __inout                 efx_vpd_value_t *evvp)
319 {
320         unsigned int offset;
321         uint8_t length;
322         efx_rc_t rc;
323
324         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
325             enp->en_family == EFX_FAMILY_MEDFORD ||
326             enp->en_family == EFX_FAMILY_MEDFORD2);
327
328         /* Attempt to satisfy the request from svpd first */
329         if (enp->en_arch.ef10.ena_svpd_length > 0) {
330                 if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
331                     enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
332                     evvp->evv_keyword, &offset, &length)) == 0) {
333                         evvp->evv_length = length;
334                         memcpy(evvp->evv_value,
335                             enp->en_arch.ef10.ena_svpd + offset, length);
336                         return (0);
337                 } else if (rc != ENOENT)
338                         goto fail1;
339         }
340
341         /* And then from the provided data buffer */
342         if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
343             evvp->evv_keyword, &offset, &length)) != 0) {
344                 if (rc == ENOENT)
345                         return (rc);
346                 goto fail2;
347         }
348
349         evvp->evv_length = length;
350         memcpy(evvp->evv_value, data + offset, length);
351
352         return (0);
353
354 fail2:
355         EFSYS_PROBE(fail2);
356 fail1:
357         EFSYS_PROBE1(fail1, efx_rc_t, rc);
358
359         return (rc);
360 }
361
362         __checkReturn           efx_rc_t
363 ef10_vpd_set(
364         __in                    efx_nic_t *enp,
365         __in_bcount(size)       caddr_t data,
366         __in                    size_t size,
367         __in                    efx_vpd_value_t *evvp)
368 {
369         efx_rc_t rc;
370
371         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
372             enp->en_family == EFX_FAMILY_MEDFORD ||
373             enp->en_family == EFX_FAMILY_MEDFORD2);
374
375         /* If the provided (tag,keyword) exists in svpd, then it is readonly */
376         if (enp->en_arch.ef10.ena_svpd_length > 0) {
377                 unsigned int offset;
378                 uint8_t length;
379
380                 if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
381                     enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
382                     evvp->evv_keyword, &offset, &length)) == 0) {
383                         rc = EACCES;
384                         goto fail1;
385                 }
386         }
387
388         if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
389                 goto fail2;
390
391         return (0);
392
393 fail2:
394         EFSYS_PROBE(fail2);
395 fail1:
396         EFSYS_PROBE1(fail1, efx_rc_t, rc);
397
398         return (rc);
399 }
400
401         __checkReturn           efx_rc_t
402 ef10_vpd_next(
403         __in                    efx_nic_t *enp,
404         __in_bcount(size)       caddr_t data,
405         __in                    size_t size,
406         __out                   efx_vpd_value_t *evvp,
407         __inout                 unsigned int *contp)
408 {
409         _NOTE(ARGUNUSED(enp, data, size, evvp, contp))
410
411         return (ENOTSUP);
412 }
413
414         __checkReturn           efx_rc_t
415 ef10_vpd_write(
416         __in                    efx_nic_t *enp,
417         __in_bcount(size)       caddr_t data,
418         __in                    size_t size)
419 {
420         size_t vpd_length;
421         uint32_t pci_pf;
422         uint32_t tag;
423         efx_rc_t rc;
424
425         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
426             enp->en_family == EFX_FAMILY_MEDFORD ||
427             enp->en_family == EFX_FAMILY_MEDFORD2);
428
429         if (enp->en_nic_cfg.enc_vpd_is_global) {
430                 tag = TLV_TAG_GLOBAL_DYNAMIC_VPD;
431         } else {
432                 pci_pf = enp->en_nic_cfg.enc_pf;
433                 tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf);
434         }
435
436         /* Determine total length of new dynamic VPD */
437         if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
438                 goto fail1;
439
440         /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */
441         if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
442                     NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
443                     tag, data, vpd_length, B_TRUE)) != 0) {
444                 goto fail2;
445         }
446
447         return (0);
448
449 fail2:
450         EFSYS_PROBE(fail2);
451
452 fail1:
453         EFSYS_PROBE1(fail1, efx_rc_t, rc);
454
455         return (rc);
456 }
457
458                                 void
459 ef10_vpd_fini(
460         __in                    efx_nic_t *enp)
461 {
462         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
463             enp->en_family == EFX_FAMILY_MEDFORD ||
464             enp->en_family == EFX_FAMILY_MEDFORD2);
465
466         if (enp->en_arch.ef10.ena_svpd_length > 0) {
467                 EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length,
468                                 enp->en_arch.ef10.ena_svpd);
469
470                 enp->en_arch.ef10.ena_svpd = NULL;
471                 enp->en_arch.ef10.ena_svpd_length = 0;
472         }
473 }
474
475 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
476
477 #endif  /* EFSYS_OPT_VPD */