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