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