f71bad3a23ddcb226148d694847560030c12a556
[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         memcpy(data, dvpd, dvpd_size);
140
141         /* Pad data with all-1s, consistent with update operations */
142         memset(data + dvpd_size, 0xff, size - dvpd_size);
143
144         EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
145
146         return (0);
147
148 fail2:
149         EFSYS_PROBE(fail2);
150
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(enp->en_family == EFX_FAMILY_HUNTINGTON ||
173             enp->en_family == EFX_FAMILY_MEDFORD ||
174             enp->en_family == EFX_FAMILY_MEDFORD2);
175
176         /*
177          * Strictly you could take the view that dynamic vpd is optional.
178          * Instead, to conform more closely to the read/verify/reinit()
179          * paradigm, we require dynamic vpd. ef10_vpd_reinit() will
180          * reinitialize it as required.
181          */
182         if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
183                 goto fail1;
184
185         /*
186          * Verify that there is no duplication between the static and
187          * dynamic cfg sectors.
188          */
189         if (enp->en_arch.ef10.ena_svpd_length == 0)
190                 goto done;
191
192         dcont = 0;
193         _NOTE(CONSTANTCONDITION)
194         while (1) {
195                 if ((rc = efx_vpd_hunk_next(data, size, &dtag,
196                     &dkey, NULL, NULL, &dcont)) != 0)
197                         goto fail2;
198                 if (dcont == 0)
199                         break;
200
201                 /*
202                  * Skip the RV keyword. It should be present in both the static
203                  * and dynamic cfg sectors.
204                  */
205                 if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
206                         continue;
207
208                 scont = 0;
209                 _NOTE(CONSTANTCONDITION)
210                 while (1) {
211                         if ((rc = efx_vpd_hunk_next(
212                             enp->en_arch.ef10.ena_svpd,
213                             enp->en_arch.ef10.ena_svpd_length, &stag, &skey,
214                             NULL, NULL, &scont)) != 0)
215                                 goto fail3;
216                         if (scont == 0)
217                                 break;
218
219                         if (stag == dtag && skey == dkey) {
220                                 rc = EEXIST;
221                                 goto fail4;
222                         }
223                 }
224         }
225
226 done:
227         return (0);
228
229 fail4:
230         EFSYS_PROBE(fail4);
231 fail3:
232         EFSYS_PROBE(fail3);
233 fail2:
234         EFSYS_PROBE(fail2);
235 fail1:
236         EFSYS_PROBE1(fail1, efx_rc_t, rc);
237
238         return (rc);
239 }
240
241         __checkReturn           efx_rc_t
242 ef10_vpd_reinit(
243         __in                    efx_nic_t *enp,
244         __in_bcount(size)       caddr_t data,
245         __in                    size_t size)
246 {
247         boolean_t wantpid;
248         efx_rc_t rc;
249
250         /*
251          * Only create an ID string if the dynamic cfg doesn't have one
252          */
253         if (enp->en_arch.ef10.ena_svpd_length == 0)
254                 wantpid = B_TRUE;
255         else {
256                 unsigned int offset;
257                 uint8_t length;
258
259                 rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
260                                     enp->en_arch.ef10.ena_svpd_length,
261                                     EFX_VPD_ID, 0, &offset, &length);
262                 if (rc == 0)
263                         wantpid = B_FALSE;
264                 else if (rc == ENOENT)
265                         wantpid = B_TRUE;
266                 else
267                         goto fail1;
268         }
269
270         if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
271                 goto fail2;
272
273         return (0);
274
275 fail2:
276         EFSYS_PROBE(fail2);
277 fail1:
278         EFSYS_PROBE1(fail1, efx_rc_t, rc);
279
280         return (rc);
281 }
282
283         __checkReturn           efx_rc_t
284 ef10_vpd_get(
285         __in                    efx_nic_t *enp,
286         __in_bcount(size)       caddr_t data,
287         __in                    size_t size,
288         __inout                 efx_vpd_value_t *evvp)
289 {
290         unsigned int offset;
291         uint8_t length;
292         efx_rc_t rc;
293
294         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
295             enp->en_family == EFX_FAMILY_MEDFORD ||
296             enp->en_family == EFX_FAMILY_MEDFORD2);
297
298         /* Attempt to satisfy the request from svpd first */
299         if (enp->en_arch.ef10.ena_svpd_length > 0) {
300                 if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
301                     enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
302                     evvp->evv_keyword, &offset, &length)) == 0) {
303                         evvp->evv_length = length;
304                         memcpy(evvp->evv_value,
305                             enp->en_arch.ef10.ena_svpd + offset, length);
306                         return (0);
307                 } else if (rc != ENOENT)
308                         goto fail1;
309         }
310
311         /* And then from the provided data buffer */
312         if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
313             evvp->evv_keyword, &offset, &length)) != 0) {
314                 if (rc == ENOENT)
315                         return (rc);
316                 goto fail2;
317         }
318
319         evvp->evv_length = length;
320         memcpy(evvp->evv_value, data + offset, length);
321
322         return (0);
323
324 fail2:
325         EFSYS_PROBE(fail2);
326 fail1:
327         EFSYS_PROBE1(fail1, efx_rc_t, rc);
328
329         return (rc);
330 }
331
332         __checkReturn           efx_rc_t
333 ef10_vpd_set(
334         __in                    efx_nic_t *enp,
335         __in_bcount(size)       caddr_t data,
336         __in                    size_t size,
337         __in                    efx_vpd_value_t *evvp)
338 {
339         efx_rc_t rc;
340
341         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
342             enp->en_family == EFX_FAMILY_MEDFORD ||
343             enp->en_family == EFX_FAMILY_MEDFORD2);
344
345         /* If the provided (tag,keyword) exists in svpd, then it is readonly */
346         if (enp->en_arch.ef10.ena_svpd_length > 0) {
347                 unsigned int offset;
348                 uint8_t length;
349
350                 if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
351                     enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
352                     evvp->evv_keyword, &offset, &length)) == 0) {
353                         rc = EACCES;
354                         goto fail1;
355                 }
356         }
357
358         if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
359                 goto fail2;
360
361         return (0);
362
363 fail2:
364         EFSYS_PROBE(fail2);
365 fail1:
366         EFSYS_PROBE1(fail1, efx_rc_t, rc);
367
368         return (rc);
369 }
370
371         __checkReturn           efx_rc_t
372 ef10_vpd_next(
373         __in                    efx_nic_t *enp,
374         __in_bcount(size)       caddr_t data,
375         __in                    size_t size,
376         __out                   efx_vpd_value_t *evvp,
377         __inout                 unsigned int *contp)
378 {
379         _NOTE(ARGUNUSED(enp, data, size, evvp, contp))
380
381         return (ENOTSUP);
382 }
383
384         __checkReturn           efx_rc_t
385 ef10_vpd_write(
386         __in                    efx_nic_t *enp,
387         __in_bcount(size)       caddr_t data,
388         __in                    size_t size)
389 {
390         size_t vpd_length;
391         uint32_t pci_pf;
392         uint32_t tag;
393         efx_rc_t rc;
394
395         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
396             enp->en_family == EFX_FAMILY_MEDFORD ||
397             enp->en_family == EFX_FAMILY_MEDFORD2);
398
399         if (enp->en_nic_cfg.enc_vpd_is_global) {
400                 tag = TLV_TAG_GLOBAL_DYNAMIC_VPD;
401         } else {
402                 pci_pf = enp->en_nic_cfg.enc_pf;
403                 tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf);
404         }
405
406         /* Determine total length of new dynamic VPD */
407         if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
408                 goto fail1;
409
410         /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */
411         if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
412                     NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
413                     tag, data, vpd_length, B_TRUE)) != 0) {
414                 goto fail2;
415         }
416
417         return (0);
418
419 fail2:
420         EFSYS_PROBE(fail2);
421
422 fail1:
423         EFSYS_PROBE1(fail1, efx_rc_t, rc);
424
425         return (rc);
426 }
427
428                                 void
429 ef10_vpd_fini(
430         __in                    efx_nic_t *enp)
431 {
432         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
433             enp->en_family == EFX_FAMILY_MEDFORD ||
434             enp->en_family == EFX_FAMILY_MEDFORD2);
435
436         if (enp->en_arch.ef10.ena_svpd_length > 0) {
437                 EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length,
438                                 enp->en_arch.ef10.ena_svpd);
439
440                 enp->en_arch.ef10.ena_svpd = NULL;
441                 enp->en_arch.ef10.ena_svpd_length = 0;
442         }
443 }
444
445 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
446
447 #endif  /* EFSYS_OPT_VPD */