ef10_vpd.c revision 291436
1283514Sarybchik/*-
2283514Sarybchik * Copyright (c) 2009-2015 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7283514Sarybchik *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29283514Sarybchik */
30283514Sarybchik
31283514Sarybchik#include <sys/cdefs.h>
32283514Sarybchik__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_vpd.c 291436 2015-11-29 05:42:49Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efsys.h"
35283514Sarybchik#include "efx.h"
36283514Sarybchik#include "efx_types.h"
37283514Sarybchik#include "efx_regs.h"
38283514Sarybchik#include "efx_impl.h"
39283514Sarybchik
40283514Sarybchik
41283514Sarybchik#if EFSYS_OPT_VPD
42283514Sarybchik
43283514Sarybchik#if EFSYS_OPT_HUNTINGTON
44283514Sarybchik
45283514Sarybchik#include "ef10_tlv_layout.h"
46283514Sarybchik
47291436Sarybchik	__checkReturn		efx_rc_t
48283514Sarybchikhunt_vpd_init(
49283514Sarybchik	__in			efx_nic_t *enp)
50283514Sarybchik{
51283514Sarybchik	caddr_t svpd;
52283514Sarybchik	size_t svpd_size;
53283514Sarybchik	uint32_t pci_pf;
54291436Sarybchik	efx_rc_t rc;
55283514Sarybchik
56283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
57283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
58283514Sarybchik
59283514Sarybchik	pci_pf = enp->en_nic_cfg.enc_pf;
60283514Sarybchik	/*
61283514Sarybchik	 * The VPD interface exposes VPD resources from the combined static and
62283514Sarybchik	 * dynamic VPD storage. As the static VPD configuration should *never*
63283514Sarybchik	 * change, we can cache it.
64283514Sarybchik	 */
65283514Sarybchik	svpd = NULL;
66283514Sarybchik	svpd_size = 0;
67283514Sarybchik	rc = hunt_nvram_partn_read_tlv(enp,
68283514Sarybchik	    NVRAM_PARTITION_TYPE_STATIC_CONFIG,
69283514Sarybchik	    TLV_TAG_PF_STATIC_VPD(pci_pf),
70283514Sarybchik	    &svpd, &svpd_size);
71283514Sarybchik	if (rc != 0) {
72283514Sarybchik		if (rc == EACCES) {
73283514Sarybchik			/* Unpriviledged functions cannot access VPD */
74283514Sarybchik			goto out;
75283514Sarybchik		}
76283514Sarybchik		goto fail1;
77283514Sarybchik	}
78283514Sarybchik
79283514Sarybchik	if (svpd != NULL && svpd_size > 0) {
80283514Sarybchik		if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0)
81283514Sarybchik			goto fail2;
82283514Sarybchik	}
83283514Sarybchik
84283514Sarybchik	enp->en_u.hunt.enu_svpd = svpd;
85283514Sarybchik	enp->en_u.hunt.enu_svpd_length = svpd_size;
86283514Sarybchik
87283514Sarybchikout:
88283514Sarybchik	return (0);
89283514Sarybchik
90283514Sarybchikfail2:
91283514Sarybchik	EFSYS_PROBE(fail2);
92283514Sarybchik
93283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd);
94283514Sarybchikfail1:
95291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
96283514Sarybchik
97283514Sarybchik	return (rc);
98283514Sarybchik}
99283514Sarybchik
100291436Sarybchik	__checkReturn		efx_rc_t
101283514Sarybchikhunt_vpd_size(
102283514Sarybchik	__in			efx_nic_t *enp,
103283514Sarybchik	__out			size_t *sizep)
104283514Sarybchik{
105291436Sarybchik	efx_rc_t rc;
106283514Sarybchik
107283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
108283514Sarybchik
109283514Sarybchik	/*
110283514Sarybchik	 * This function returns the total size the user should allocate
111283514Sarybchik	 * for all VPD operations. We've already cached the static vpd,
112283514Sarybchik	 * so we just need to return an upper bound on the dynamic vpd,
113283514Sarybchik	 * which is the size of the DYNAMIC_CONFIG partition.
114283514Sarybchik	 */
115283514Sarybchik	if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
116283514Sarybchik		    sizep, NULL, NULL)) != 0)
117283514Sarybchik		goto fail1;
118283514Sarybchik
119283514Sarybchik	return (0);
120283514Sarybchik
121283514Sarybchikfail1:
122291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
123283514Sarybchik
124283514Sarybchik	return (rc);
125283514Sarybchik}
126283514Sarybchik
127291436Sarybchik	__checkReturn		efx_rc_t
128283514Sarybchikhunt_vpd_read(
129283514Sarybchik	__in			efx_nic_t *enp,
130283514Sarybchik	__out_bcount(size)	caddr_t data,
131283514Sarybchik	__in			size_t size)
132283514Sarybchik{
133283514Sarybchik	caddr_t dvpd;
134283514Sarybchik	size_t dvpd_size;
135283514Sarybchik	uint32_t pci_pf;
136291436Sarybchik	efx_rc_t rc;
137283514Sarybchik
138283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
139283514Sarybchik
140283514Sarybchik	pci_pf = enp->en_nic_cfg.enc_pf;
141283514Sarybchik
142283514Sarybchik	if ((rc = hunt_nvram_partn_read_tlv(enp,
143283514Sarybchik		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
144283514Sarybchik		    TLV_TAG_PF_DYNAMIC_VPD(pci_pf),
145283514Sarybchik		    &dvpd, &dvpd_size)) != 0)
146283514Sarybchik		goto fail1;
147283514Sarybchik
148283514Sarybchik	if (dvpd_size > size) {
149283514Sarybchik		rc = ENOSPC;
150283514Sarybchik		goto fail2;
151283514Sarybchik	}
152283514Sarybchik	memcpy(data, dvpd, dvpd_size);
153283514Sarybchik
154283514Sarybchik	/* Pad data with all-1s, consistent with update operations */
155283514Sarybchik	memset(data + dvpd_size, 0xff, size - dvpd_size);
156283514Sarybchik
157283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
158283514Sarybchik
159283514Sarybchik	return (0);
160283514Sarybchik
161283514Sarybchikfail2:
162283514Sarybchik	EFSYS_PROBE(fail2);
163283514Sarybchik
164283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
165283514Sarybchikfail1:
166291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
167283514Sarybchik
168283514Sarybchik	return (rc);
169283514Sarybchik}
170283514Sarybchik
171291436Sarybchik	__checkReturn		efx_rc_t
172283514Sarybchikhunt_vpd_verify(
173283514Sarybchik	__in			efx_nic_t *enp,
174283514Sarybchik	__in_bcount(size)	caddr_t data,
175283514Sarybchik	__in			size_t size)
176283514Sarybchik{
177283514Sarybchik	efx_vpd_tag_t stag;
178283514Sarybchik	efx_vpd_tag_t dtag;
179283514Sarybchik	efx_vpd_keyword_t skey;
180283514Sarybchik	efx_vpd_keyword_t dkey;
181283514Sarybchik	unsigned int scont;
182283514Sarybchik	unsigned int dcont;
183291436Sarybchik	efx_rc_t rc;
184283514Sarybchik
185283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
186283514Sarybchik
187283514Sarybchik	/*
188283514Sarybchik	 * Strictly you could take the view that dynamic vpd is optional.
189283514Sarybchik	 * Instead, to conform more closely to the read/verify/reinit()
190283514Sarybchik	 * paradigm, we require dynamic vpd. hunt_vpd_reinit() will
191283514Sarybchik	 * reinitialize it as required.
192283514Sarybchik	 */
193283514Sarybchik	if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
194283514Sarybchik		goto fail1;
195283514Sarybchik
196283514Sarybchik	/*
197283514Sarybchik	 * Verify that there is no duplication between the static and
198283514Sarybchik	 * dynamic cfg sectors.
199283514Sarybchik	 */
200283514Sarybchik	if (enp->en_u.hunt.enu_svpd_length == 0)
201283514Sarybchik		goto done;
202283514Sarybchik
203283514Sarybchik	dcont = 0;
204283514Sarybchik	_NOTE(CONSTANTCONDITION)
205283514Sarybchik	while (1) {
206283514Sarybchik		if ((rc = efx_vpd_hunk_next(data, size, &dtag,
207283514Sarybchik		    &dkey, NULL, NULL, &dcont)) != 0)
208283514Sarybchik			goto fail2;
209283514Sarybchik		if (dcont == 0)
210283514Sarybchik			break;
211283514Sarybchik
212283514Sarybchik		scont = 0;
213283514Sarybchik		_NOTE(CONSTANTCONDITION)
214283514Sarybchik		while (1) {
215283514Sarybchik			if ((rc = efx_vpd_hunk_next(
216283514Sarybchik			    enp->en_u.hunt.enu_svpd,
217283514Sarybchik			    enp->en_u.hunt.enu_svpd_length, &stag, &skey,
218283514Sarybchik			    NULL, NULL, &scont)) != 0)
219283514Sarybchik				goto fail3;
220283514Sarybchik			if (scont == 0)
221283514Sarybchik				break;
222283514Sarybchik
223283514Sarybchik			if (stag == dtag && skey == dkey) {
224283514Sarybchik				rc = EEXIST;
225283514Sarybchik				goto fail4;
226283514Sarybchik			}
227283514Sarybchik		}
228283514Sarybchik	}
229283514Sarybchik
230283514Sarybchikdone:
231283514Sarybchik	return (0);
232283514Sarybchik
233283514Sarybchikfail4:
234283514Sarybchik	EFSYS_PROBE(fail4);
235283514Sarybchikfail3:
236283514Sarybchik	EFSYS_PROBE(fail3);
237283514Sarybchikfail2:
238283514Sarybchik	EFSYS_PROBE(fail2);
239283514Sarybchikfail1:
240291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
241283514Sarybchik
242283514Sarybchik	return (rc);
243283514Sarybchik}
244283514Sarybchik
245291436Sarybchik	__checkReturn		efx_rc_t
246283514Sarybchikhunt_vpd_reinit(
247283514Sarybchik	__in			efx_nic_t *enp,
248283514Sarybchik	__in_bcount(size)	caddr_t data,
249283514Sarybchik	__in			size_t size)
250283514Sarybchik{
251283514Sarybchik	boolean_t wantpid;
252291436Sarybchik	efx_rc_t rc;
253283514Sarybchik
254283514Sarybchik	/*
255283514Sarybchik	 * Only create an ID string if the dynamic cfg doesn't have one
256283514Sarybchik	 */
257283514Sarybchik	if (enp->en_u.hunt.enu_svpd_length == 0)
258283514Sarybchik		wantpid = B_TRUE;
259283514Sarybchik	else {
260283514Sarybchik		unsigned int offset;
261283514Sarybchik		uint8_t length;
262283514Sarybchik
263283514Sarybchik		rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd,
264283514Sarybchik				    enp->en_u.hunt.enu_svpd_length,
265283514Sarybchik				    EFX_VPD_ID, 0, &offset, &length);
266283514Sarybchik		if (rc == 0)
267283514Sarybchik			wantpid = B_FALSE;
268283514Sarybchik		else if (rc == ENOENT)
269283514Sarybchik			wantpid = B_TRUE;
270283514Sarybchik		else
271283514Sarybchik			goto fail1;
272283514Sarybchik	}
273283514Sarybchik
274283514Sarybchik	if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
275283514Sarybchik		goto fail2;
276283514Sarybchik
277283514Sarybchik	return (0);
278283514Sarybchik
279283514Sarybchikfail2:
280283514Sarybchik	EFSYS_PROBE(fail2);
281283514Sarybchikfail1:
282291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
283283514Sarybchik
284283514Sarybchik	return (rc);
285283514Sarybchik}
286283514Sarybchik
287291436Sarybchik	__checkReturn		efx_rc_t
288283514Sarybchikhunt_vpd_get(
289283514Sarybchik	__in			efx_nic_t *enp,
290283514Sarybchik	__in_bcount(size)	caddr_t data,
291283514Sarybchik	__in			size_t size,
292283514Sarybchik	__inout			efx_vpd_value_t *evvp)
293283514Sarybchik{
294283514Sarybchik	unsigned int offset;
295283514Sarybchik	uint8_t length;
296291436Sarybchik	efx_rc_t rc;
297283514Sarybchik
298283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
299283514Sarybchik
300283514Sarybchik	/* Attempt to satisfy the request from svpd first */
301283514Sarybchik	if (enp->en_u.hunt.enu_svpd_length > 0) {
302283514Sarybchik		if ((rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd,
303283514Sarybchik		    enp->en_u.hunt.enu_svpd_length, evvp->evv_tag,
304283514Sarybchik		    evvp->evv_keyword, &offset, &length)) == 0) {
305283514Sarybchik			evvp->evv_length = length;
306283514Sarybchik			memcpy(evvp->evv_value,
307283514Sarybchik			    enp->en_u.hunt.enu_svpd + offset, length);
308283514Sarybchik			return (0);
309283514Sarybchik		} else if (rc != ENOENT)
310283514Sarybchik			goto fail1;
311283514Sarybchik	}
312283514Sarybchik
313283514Sarybchik	/* And then from the provided data buffer */
314283514Sarybchik	if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
315283514Sarybchik	    evvp->evv_keyword, &offset, &length)) != 0)
316283514Sarybchik		goto fail2;
317283514Sarybchik
318283514Sarybchik	evvp->evv_length = length;
319283514Sarybchik	memcpy(evvp->evv_value, data + offset, length);
320283514Sarybchik
321283514Sarybchik	return (0);
322283514Sarybchik
323283514Sarybchikfail2:
324283514Sarybchik	EFSYS_PROBE(fail2);
325283514Sarybchikfail1:
326291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
327283514Sarybchik
328283514Sarybchik	return (rc);
329283514Sarybchik}
330283514Sarybchik
331291436Sarybchik	__checkReturn		efx_rc_t
332283514Sarybchikhunt_vpd_set(
333283514Sarybchik	__in			efx_nic_t *enp,
334283514Sarybchik	__in_bcount(size)	caddr_t data,
335283514Sarybchik	__in			size_t size,
336283514Sarybchik	__in			efx_vpd_value_t *evvp)
337283514Sarybchik{
338291436Sarybchik	efx_rc_t rc;
339283514Sarybchik
340283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
341283514Sarybchik
342283514Sarybchik	/* If the provided (tag,keyword) exists in svpd, then it is readonly */
343283514Sarybchik	if (enp->en_u.hunt.enu_svpd_length > 0) {
344283514Sarybchik		unsigned int offset;
345283514Sarybchik		uint8_t length;
346283514Sarybchik
347283514Sarybchik		if ((rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd,
348283514Sarybchik		    enp->en_u.hunt.enu_svpd_length, evvp->evv_tag,
349283514Sarybchik		    evvp->evv_keyword, &offset, &length)) == 0) {
350283514Sarybchik			rc = EACCES;
351283514Sarybchik			goto fail1;
352283514Sarybchik		}
353283514Sarybchik	}
354283514Sarybchik
355283514Sarybchik	if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
356283514Sarybchik		goto fail2;
357283514Sarybchik
358283514Sarybchik	return (0);
359283514Sarybchik
360283514Sarybchikfail2:
361283514Sarybchik	EFSYS_PROBE(fail2);
362283514Sarybchikfail1:
363291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
364283514Sarybchik
365283514Sarybchik	return (rc);
366283514Sarybchik}
367283514Sarybchik
368291436Sarybchik	__checkReturn		efx_rc_t
369283514Sarybchikhunt_vpd_next(
370283514Sarybchik	__in			efx_nic_t *enp,
371283514Sarybchik	__in_bcount(size)	caddr_t data,
372283514Sarybchik	__in			size_t size,
373283514Sarybchik	__out			efx_vpd_value_t *evvp,
374283514Sarybchik	__inout			unsigned int *contp)
375283514Sarybchik{
376283514Sarybchik	_NOTE(ARGUNUSED(enp, data, size, evvp, contp))
377283514Sarybchik
378283514Sarybchik	return (ENOTSUP);
379283514Sarybchik}
380283514Sarybchik
381291436Sarybchik	__checkReturn		efx_rc_t
382283514Sarybchikhunt_vpd_write(
383283514Sarybchik	__in			efx_nic_t *enp,
384283514Sarybchik	__in_bcount(size)	caddr_t data,
385283514Sarybchik	__in			size_t size)
386283514Sarybchik{
387283514Sarybchik	size_t vpd_length;
388283514Sarybchik	uint32_t pci_pf;
389291436Sarybchik	efx_rc_t rc;
390283514Sarybchik
391283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
392283514Sarybchik
393283514Sarybchik	pci_pf = enp->en_nic_cfg.enc_pf;
394283514Sarybchik
395283514Sarybchik	/* Determine total length of new dynamic VPD */
396283514Sarybchik	if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
397283514Sarybchik		goto fail1;
398283514Sarybchik
399291432Sarybchik	/* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */
400291432Sarybchik	if ((rc = hunt_nvram_partn_write_segment_tlv(enp,
401283514Sarybchik		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
402283514Sarybchik		    TLV_TAG_PF_DYNAMIC_VPD(pci_pf),
403291432Sarybchik		    data, vpd_length, B_TRUE)) != 0) {
404283514Sarybchik		goto fail2;
405283514Sarybchik	}
406283514Sarybchik
407283514Sarybchik	return (0);
408283514Sarybchik
409283514Sarybchikfail2:
410283514Sarybchik	EFSYS_PROBE(fail2);
411283514Sarybchik
412283514Sarybchikfail1:
413291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
414283514Sarybchik
415283514Sarybchik	return (rc);
416283514Sarybchik}
417283514Sarybchik
418283514Sarybchik				void
419283514Sarybchikhunt_vpd_fini(
420283514Sarybchik	__in			efx_nic_t *enp)
421283514Sarybchik{
422283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
423283514Sarybchik
424283514Sarybchik	if (enp->en_u.hunt.enu_svpd_length > 0) {
425283514Sarybchik		EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.hunt.enu_svpd_length,
426283514Sarybchik				enp->en_u.hunt.enu_svpd);
427283514Sarybchik
428283514Sarybchik		enp->en_u.hunt.enu_svpd = NULL;
429283514Sarybchik		enp->en_u.hunt.enu_svpd_length = 0;
430283514Sarybchik	}
431283514Sarybchik}
432283514Sarybchik
433283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
434283514Sarybchik
435283514Sarybchik#endif	/* EFSYS_OPT_VPD */
436