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