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