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