71123a9098b15b829ffbb5bcb2d8d11664c8fd16
[deb_dpdk.git] / drivers / net / sfc / base / 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 "efx.h"
32 #include "efx_impl.h"
33
34
35 #if EFSYS_OPT_VPD
36
37 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
38
39 #include "ef10_tlv_layout.h"
40
41         __checkReturn           efx_rc_t
42 ef10_vpd_init(
43         __in                    efx_nic_t *enp)
44 {
45         caddr_t svpd;
46         size_t svpd_size;
47         uint32_t pci_pf;
48         uint32_t tag;
49         efx_rc_t rc;
50
51         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
52         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
53                     enp->en_family == EFX_FAMILY_MEDFORD);
54
55         if (enp->en_nic_cfg.enc_vpd_is_global) {
56                 tag = TLV_TAG_GLOBAL_STATIC_VPD;
57         } else {
58                 pci_pf = enp->en_nic_cfg.enc_pf;
59                 tag = TLV_TAG_PF_STATIC_VPD(pci_pf);
60         }
61
62         /*
63          * The VPD interface exposes VPD resources from the combined static and
64          * dynamic VPD storage. As the static VPD configuration should *never*
65          * change, we can cache it.
66          */
67         svpd = NULL;
68         svpd_size = 0;
69         rc = ef10_nvram_partn_read_tlv(enp,
70             NVRAM_PARTITION_TYPE_STATIC_CONFIG,
71             tag, &svpd, &svpd_size);
72         if (rc != 0) {
73                 if (rc == EACCES) {
74                         /* Unprivileged functions cannot access VPD */
75                         goto out;
76                 }
77                 goto fail1;
78         }
79
80         if (svpd != NULL && svpd_size > 0) {
81                 if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0)
82                         goto fail2;
83         }
84
85         enp->en_arch.ef10.ena_svpd = svpd;
86         enp->en_arch.ef10.ena_svpd_length = svpd_size;
87
88 out:
89         return (0);
90
91 fail2:
92         EFSYS_PROBE(fail2);
93
94         EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd);
95 fail1:
96         EFSYS_PROBE1(fail1, efx_rc_t, rc);
97
98         return (rc);
99 }
100
101         __checkReturn           efx_rc_t
102 ef10_vpd_size(
103         __in                    efx_nic_t *enp,
104         __out                   size_t *sizep)
105 {
106         efx_rc_t rc;
107
108         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
109                     enp->en_family == EFX_FAMILY_MEDFORD);
110
111         /*
112          * This function returns the total size the user should allocate
113          * for all VPD operations. We've already cached the static vpd,
114          * so we just need to return an upper bound on the dynamic vpd,
115          * which is the size of the DYNAMIC_CONFIG partition.
116          */
117         if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
118                     sizep, NULL, NULL, NULL)) != 0)
119                 goto fail1;
120
121         return (0);
122
123 fail1:
124         EFSYS_PROBE1(fail1, efx_rc_t, rc);
125
126         return (rc);
127 }
128
129         __checkReturn           efx_rc_t
130 ef10_vpd_read(
131         __in                    efx_nic_t *enp,
132         __out_bcount(size)      caddr_t data,
133         __in                    size_t size)
134 {
135         caddr_t dvpd;
136         size_t dvpd_size;
137         uint32_t pci_pf;
138         uint32_t tag;
139         efx_rc_t rc;
140
141         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
142                     enp->en_family == EFX_FAMILY_MEDFORD);
143
144         if (enp->en_nic_cfg.enc_vpd_is_global) {
145                 tag = TLV_TAG_GLOBAL_DYNAMIC_VPD;
146         } else {
147                 pci_pf = enp->en_nic_cfg.enc_pf;
148                 tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf);
149         }
150
151         if ((rc = ef10_nvram_partn_read_tlv(enp,
152                     NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
153                     tag, &dvpd, &dvpd_size)) != 0)
154                 goto fail1;
155
156         if (dvpd_size > size) {
157                 rc = ENOSPC;
158                 goto fail2;
159         }
160         memcpy(data, dvpd, dvpd_size);
161
162         /* Pad data with all-1s, consistent with update operations */
163         memset(data + dvpd_size, 0xff, size - dvpd_size);
164
165         EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
166
167         return (0);
168
169 fail2:
170         EFSYS_PROBE(fail2);
171
172         EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
173 fail1:
174         EFSYS_PROBE1(fail1, efx_rc_t, rc);
175
176         return (rc);
177 }
178
179         __checkReturn           efx_rc_t
180 ef10_vpd_verify(
181         __in                    efx_nic_t *enp,
182         __in_bcount(size)       caddr_t data,
183         __in                    size_t size)
184 {
185         efx_vpd_tag_t stag;
186         efx_vpd_tag_t dtag;
187         efx_vpd_keyword_t skey;
188         efx_vpd_keyword_t dkey;
189         unsigned int scont;
190         unsigned int dcont;
191         efx_rc_t rc;
192
193         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
194                     enp->en_family == EFX_FAMILY_MEDFORD);
195
196         /*
197          * Strictly you could take the view that dynamic vpd is optional.
198          * Instead, to conform more closely to the read/verify/reinit()
199          * paradigm, we require dynamic vpd. ef10_vpd_reinit() will
200          * reinitialize it as required.
201          */
202         if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
203                 goto fail1;
204
205         /*
206          * Verify that there is no duplication between the static and
207          * dynamic cfg sectors.
208          */
209         if (enp->en_arch.ef10.ena_svpd_length == 0)
210                 goto done;
211
212         dcont = 0;
213         _NOTE(CONSTANTCONDITION)
214         while (1) {
215                 if ((rc = efx_vpd_hunk_next(data, size, &dtag,
216                     &dkey, NULL, NULL, &dcont)) != 0)
217                         goto fail2;
218                 if (dcont == 0)
219                         break;
220
221                 /*
222                  * Skip the RV keyword. It should be present in both the static
223                  * and dynamic cfg sectors.
224                  */
225                 if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
226                         continue;
227
228                 scont = 0;
229                 _NOTE(CONSTANTCONDITION)
230                 while (1) {
231                         if ((rc = efx_vpd_hunk_next(
232                             enp->en_arch.ef10.ena_svpd,
233                             enp->en_arch.ef10.ena_svpd_length, &stag, &skey,
234                             NULL, NULL, &scont)) != 0)
235                                 goto fail3;
236                         if (scont == 0)
237                                 break;
238
239                         if (stag == dtag && skey == dkey) {
240                                 rc = EEXIST;
241                                 goto fail4;
242                         }
243                 }
244         }
245
246 done:
247         return (0);
248
249 fail4:
250         EFSYS_PROBE(fail4);
251 fail3:
252         EFSYS_PROBE(fail3);
253 fail2:
254         EFSYS_PROBE(fail2);
255 fail1:
256         EFSYS_PROBE1(fail1, efx_rc_t, rc);
257
258         return (rc);
259 }
260
261         __checkReturn           efx_rc_t
262 ef10_vpd_reinit(
263         __in                    efx_nic_t *enp,
264         __in_bcount(size)       caddr_t data,
265         __in                    size_t size)
266 {
267         boolean_t wantpid;
268         efx_rc_t rc;
269
270         /*
271          * Only create an ID string if the dynamic cfg doesn't have one
272          */
273         if (enp->en_arch.ef10.ena_svpd_length == 0)
274                 wantpid = B_TRUE;
275         else {
276                 unsigned int offset;
277                 uint8_t length;
278
279                 rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
280                                     enp->en_arch.ef10.ena_svpd_length,
281                                     EFX_VPD_ID, 0, &offset, &length);
282                 if (rc == 0)
283                         wantpid = B_FALSE;
284                 else if (rc == ENOENT)
285                         wantpid = B_TRUE;
286                 else
287                         goto fail1;
288         }
289
290         if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
291                 goto fail2;
292
293         return (0);
294
295 fail2:
296         EFSYS_PROBE(fail2);
297 fail1:
298         EFSYS_PROBE1(fail1, efx_rc_t, rc);
299
300         return (rc);
301 }
302
303         __checkReturn           efx_rc_t
304 ef10_vpd_get(
305         __in                    efx_nic_t *enp,
306         __in_bcount(size)       caddr_t data,
307         __in                    size_t size,
308         __inout                 efx_vpd_value_t *evvp)
309 {
310         unsigned int offset;
311         uint8_t length;
312         efx_rc_t rc;
313
314         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
315                     enp->en_family == EFX_FAMILY_MEDFORD);
316
317         /* Attempt to satisfy the request from svpd first */
318         if (enp->en_arch.ef10.ena_svpd_length > 0) {
319                 if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
320                     enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
321                     evvp->evv_keyword, &offset, &length)) == 0) {
322                         evvp->evv_length = length;
323                         memcpy(evvp->evv_value,
324                             enp->en_arch.ef10.ena_svpd + offset, length);
325                         return (0);
326                 } else if (rc != ENOENT)
327                         goto fail1;
328         }
329
330         /* And then from the provided data buffer */
331         if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
332             evvp->evv_keyword, &offset, &length)) != 0) {
333                 if (rc == ENOENT)
334                         return (rc);
335                 goto fail2;
336         }
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 || EFSYS_OPT_MEDFORD */
462
463 #endif  /* EFSYS_OPT_VPD */