ef10_vpd.c revision 293756
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 293756 2016-01-12 13:37:58Z 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
48293755Sarybchikef10_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);
57293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
58293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
59283514Sarybchik
60283514Sarybchik	pci_pf = enp->en_nic_cfg.enc_pf;
61283514Sarybchik	/*
62283514Sarybchik	 * The VPD interface exposes VPD resources from the combined static and
63283514Sarybchik	 * dynamic VPD storage. As the static VPD configuration should *never*
64283514Sarybchik	 * change, we can cache it.
65283514Sarybchik	 */
66283514Sarybchik	svpd = NULL;
67283514Sarybchik	svpd_size = 0;
68293756Sarybchik	rc = ef10_nvram_partn_read_tlv(enp,
69283514Sarybchik	    NVRAM_PARTITION_TYPE_STATIC_CONFIG,
70283514Sarybchik	    TLV_TAG_PF_STATIC_VPD(pci_pf),
71283514Sarybchik	    &svpd, &svpd_size);
72283514Sarybchik	if (rc != 0) {
73283514Sarybchik		if (rc == EACCES) {
74283514Sarybchik			/* Unpriviledged functions cannot access VPD */
75283514Sarybchik			goto out;
76283514Sarybchik		}
77283514Sarybchik		goto fail1;
78283514Sarybchik	}
79283514Sarybchik
80283514Sarybchik	if (svpd != NULL && svpd_size > 0) {
81283514Sarybchik		if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0)
82283514Sarybchik			goto fail2;
83283514Sarybchik	}
84283514Sarybchik
85293748Sarybchik	enp->en_arch.ef10.ena_svpd = svpd;
86293748Sarybchik	enp->en_arch.ef10.ena_svpd_length = svpd_size;
87283514Sarybchik
88283514Sarybchikout:
89283514Sarybchik	return (0);
90283514Sarybchik
91283514Sarybchikfail2:
92283514Sarybchik	EFSYS_PROBE(fail2);
93283514Sarybchik
94283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd);
95283514Sarybchikfail1:
96291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
97283514Sarybchik
98283514Sarybchik	return (rc);
99283514Sarybchik}
100283514Sarybchik
101291436Sarybchik	__checkReturn		efx_rc_t
102293755Sarybchikef10_vpd_size(
103283514Sarybchik	__in			efx_nic_t *enp,
104283514Sarybchik	__out			size_t *sizep)
105283514Sarybchik{
106291436Sarybchik	efx_rc_t rc;
107283514Sarybchik
108293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
109293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
110283514Sarybchik
111283514Sarybchik	/*
112283514Sarybchik	 * This function returns the total size the user should allocate
113283514Sarybchik	 * for all VPD operations. We've already cached the static vpd,
114283514Sarybchik	 * so we just need to return an upper bound on the dynamic vpd,
115283514Sarybchik	 * which is the size of the DYNAMIC_CONFIG partition.
116283514Sarybchik	 */
117283514Sarybchik	if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
118291746Sarybchik		    sizep, NULL, NULL, NULL)) != 0)
119283514Sarybchik		goto fail1;
120283514Sarybchik
121283514Sarybchik	return (0);
122283514Sarybchik
123283514Sarybchikfail1:
124291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
125283514Sarybchik
126283514Sarybchik	return (rc);
127283514Sarybchik}
128283514Sarybchik
129291436Sarybchik	__checkReturn		efx_rc_t
130293755Sarybchikef10_vpd_read(
131283514Sarybchik	__in			efx_nic_t *enp,
132283514Sarybchik	__out_bcount(size)	caddr_t data,
133283514Sarybchik	__in			size_t size)
134283514Sarybchik{
135283514Sarybchik	caddr_t dvpd;
136283514Sarybchik	size_t dvpd_size;
137283514Sarybchik	uint32_t pci_pf;
138291436Sarybchik	efx_rc_t rc;
139283514Sarybchik
140293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
141293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
142283514Sarybchik
143283514Sarybchik	pci_pf = enp->en_nic_cfg.enc_pf;
144283514Sarybchik
145293756Sarybchik	if ((rc = ef10_nvram_partn_read_tlv(enp,
146283514Sarybchik		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
147283514Sarybchik		    TLV_TAG_PF_DYNAMIC_VPD(pci_pf),
148283514Sarybchik		    &dvpd, &dvpd_size)) != 0)
149283514Sarybchik		goto fail1;
150283514Sarybchik
151283514Sarybchik	if (dvpd_size > size) {
152283514Sarybchik		rc = ENOSPC;
153283514Sarybchik		goto fail2;
154283514Sarybchik	}
155283514Sarybchik	memcpy(data, dvpd, dvpd_size);
156283514Sarybchik
157283514Sarybchik	/* Pad data with all-1s, consistent with update operations */
158283514Sarybchik	memset(data + dvpd_size, 0xff, size - dvpd_size);
159283514Sarybchik
160283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
161283514Sarybchik
162283514Sarybchik	return (0);
163283514Sarybchik
164283514Sarybchikfail2:
165283514Sarybchik	EFSYS_PROBE(fail2);
166283514Sarybchik
167283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
168283514Sarybchikfail1:
169291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
170283514Sarybchik
171283514Sarybchik	return (rc);
172283514Sarybchik}
173283514Sarybchik
174291436Sarybchik	__checkReturn		efx_rc_t
175293755Sarybchikef10_vpd_verify(
176283514Sarybchik	__in			efx_nic_t *enp,
177283514Sarybchik	__in_bcount(size)	caddr_t data,
178283514Sarybchik	__in			size_t size)
179283514Sarybchik{
180283514Sarybchik	efx_vpd_tag_t stag;
181283514Sarybchik	efx_vpd_tag_t dtag;
182283514Sarybchik	efx_vpd_keyword_t skey;
183283514Sarybchik	efx_vpd_keyword_t dkey;
184283514Sarybchik	unsigned int scont;
185283514Sarybchik	unsigned int dcont;
186291436Sarybchik	efx_rc_t rc;
187283514Sarybchik
188293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
189293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
190283514Sarybchik
191283514Sarybchik	/*
192283514Sarybchik	 * Strictly you could take the view that dynamic vpd is optional.
193283514Sarybchik	 * Instead, to conform more closely to the read/verify/reinit()
194293755Sarybchik	 * paradigm, we require dynamic vpd. ef10_vpd_reinit() will
195283514Sarybchik	 * reinitialize it as required.
196283514Sarybchik	 */
197283514Sarybchik	if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
198283514Sarybchik		goto fail1;
199283514Sarybchik
200283514Sarybchik	/*
201283514Sarybchik	 * Verify that there is no duplication between the static and
202283514Sarybchik	 * dynamic cfg sectors.
203283514Sarybchik	 */
204293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length == 0)
205283514Sarybchik		goto done;
206283514Sarybchik
207283514Sarybchik	dcont = 0;
208283514Sarybchik	_NOTE(CONSTANTCONDITION)
209283514Sarybchik	while (1) {
210283514Sarybchik		if ((rc = efx_vpd_hunk_next(data, size, &dtag,
211283514Sarybchik		    &dkey, NULL, NULL, &dcont)) != 0)
212283514Sarybchik			goto fail2;
213283514Sarybchik		if (dcont == 0)
214283514Sarybchik			break;
215283514Sarybchik
216283514Sarybchik		scont = 0;
217283514Sarybchik		_NOTE(CONSTANTCONDITION)
218283514Sarybchik		while (1) {
219283514Sarybchik			if ((rc = efx_vpd_hunk_next(
220293748Sarybchik			    enp->en_arch.ef10.ena_svpd,
221293748Sarybchik			    enp->en_arch.ef10.ena_svpd_length, &stag, &skey,
222283514Sarybchik			    NULL, NULL, &scont)) != 0)
223283514Sarybchik				goto fail3;
224283514Sarybchik			if (scont == 0)
225283514Sarybchik				break;
226283514Sarybchik
227283514Sarybchik			if (stag == dtag && skey == dkey) {
228283514Sarybchik				rc = EEXIST;
229283514Sarybchik				goto fail4;
230283514Sarybchik			}
231283514Sarybchik		}
232283514Sarybchik	}
233283514Sarybchik
234283514Sarybchikdone:
235283514Sarybchik	return (0);
236283514Sarybchik
237283514Sarybchikfail4:
238283514Sarybchik	EFSYS_PROBE(fail4);
239283514Sarybchikfail3:
240283514Sarybchik	EFSYS_PROBE(fail3);
241283514Sarybchikfail2:
242283514Sarybchik	EFSYS_PROBE(fail2);
243283514Sarybchikfail1:
244291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
245283514Sarybchik
246283514Sarybchik	return (rc);
247283514Sarybchik}
248283514Sarybchik
249291436Sarybchik	__checkReturn		efx_rc_t
250293755Sarybchikef10_vpd_reinit(
251283514Sarybchik	__in			efx_nic_t *enp,
252283514Sarybchik	__in_bcount(size)	caddr_t data,
253283514Sarybchik	__in			size_t size)
254283514Sarybchik{
255283514Sarybchik	boolean_t wantpid;
256291436Sarybchik	efx_rc_t rc;
257283514Sarybchik
258283514Sarybchik	/*
259283514Sarybchik	 * Only create an ID string if the dynamic cfg doesn't have one
260283514Sarybchik	 */
261293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length == 0)
262283514Sarybchik		wantpid = B_TRUE;
263283514Sarybchik	else {
264283514Sarybchik		unsigned int offset;
265283514Sarybchik		uint8_t length;
266283514Sarybchik
267293748Sarybchik		rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
268293748Sarybchik				    enp->en_arch.ef10.ena_svpd_length,
269283514Sarybchik				    EFX_VPD_ID, 0, &offset, &length);
270283514Sarybchik		if (rc == 0)
271283514Sarybchik			wantpid = B_FALSE;
272283514Sarybchik		else if (rc == ENOENT)
273283514Sarybchik			wantpid = B_TRUE;
274283514Sarybchik		else
275283514Sarybchik			goto fail1;
276283514Sarybchik	}
277283514Sarybchik
278283514Sarybchik	if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
279283514Sarybchik		goto fail2;
280283514Sarybchik
281283514Sarybchik	return (0);
282283514Sarybchik
283283514Sarybchikfail2:
284283514Sarybchik	EFSYS_PROBE(fail2);
285283514Sarybchikfail1:
286291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
287283514Sarybchik
288283514Sarybchik	return (rc);
289283514Sarybchik}
290283514Sarybchik
291291436Sarybchik	__checkReturn		efx_rc_t
292293755Sarybchikef10_vpd_get(
293283514Sarybchik	__in			efx_nic_t *enp,
294283514Sarybchik	__in_bcount(size)	caddr_t data,
295283514Sarybchik	__in			size_t size,
296283514Sarybchik	__inout			efx_vpd_value_t *evvp)
297283514Sarybchik{
298283514Sarybchik	unsigned int offset;
299283514Sarybchik	uint8_t length;
300291436Sarybchik	efx_rc_t rc;
301283514Sarybchik
302293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
303293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
304283514Sarybchik
305283514Sarybchik	/* Attempt to satisfy the request from svpd first */
306293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length > 0) {
307293748Sarybchik		if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
308293748Sarybchik		    enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
309283514Sarybchik		    evvp->evv_keyword, &offset, &length)) == 0) {
310283514Sarybchik			evvp->evv_length = length;
311283514Sarybchik			memcpy(evvp->evv_value,
312293748Sarybchik			    enp->en_arch.ef10.ena_svpd + offset, length);
313283514Sarybchik			return (0);
314283514Sarybchik		} else if (rc != ENOENT)
315283514Sarybchik			goto fail1;
316283514Sarybchik	}
317283514Sarybchik
318283514Sarybchik	/* And then from the provided data buffer */
319283514Sarybchik	if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
320283514Sarybchik	    evvp->evv_keyword, &offset, &length)) != 0)
321283514Sarybchik		goto fail2;
322283514Sarybchik
323283514Sarybchik	evvp->evv_length = length;
324283514Sarybchik	memcpy(evvp->evv_value, data + offset, length);
325283514Sarybchik
326283514Sarybchik	return (0);
327283514Sarybchik
328283514Sarybchikfail2:
329283514Sarybchik	EFSYS_PROBE(fail2);
330283514Sarybchikfail1:
331291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
332283514Sarybchik
333283514Sarybchik	return (rc);
334283514Sarybchik}
335283514Sarybchik
336291436Sarybchik	__checkReturn		efx_rc_t
337293755Sarybchikef10_vpd_set(
338283514Sarybchik	__in			efx_nic_t *enp,
339283514Sarybchik	__in_bcount(size)	caddr_t data,
340283514Sarybchik	__in			size_t size,
341283514Sarybchik	__in			efx_vpd_value_t *evvp)
342283514Sarybchik{
343291436Sarybchik	efx_rc_t rc;
344283514Sarybchik
345293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
346293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
347283514Sarybchik
348283514Sarybchik	/* If the provided (tag,keyword) exists in svpd, then it is readonly */
349293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length > 0) {
350283514Sarybchik		unsigned int offset;
351283514Sarybchik		uint8_t length;
352283514Sarybchik
353293748Sarybchik		if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
354293748Sarybchik		    enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
355283514Sarybchik		    evvp->evv_keyword, &offset, &length)) == 0) {
356283514Sarybchik			rc = EACCES;
357283514Sarybchik			goto fail1;
358283514Sarybchik		}
359283514Sarybchik	}
360283514Sarybchik
361283514Sarybchik	if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
362283514Sarybchik		goto fail2;
363283514Sarybchik
364283514Sarybchik	return (0);
365283514Sarybchik
366283514Sarybchikfail2:
367283514Sarybchik	EFSYS_PROBE(fail2);
368283514Sarybchikfail1:
369291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
370283514Sarybchik
371283514Sarybchik	return (rc);
372283514Sarybchik}
373283514Sarybchik
374291436Sarybchik	__checkReturn		efx_rc_t
375293755Sarybchikef10_vpd_next(
376283514Sarybchik	__in			efx_nic_t *enp,
377283514Sarybchik	__in_bcount(size)	caddr_t data,
378283514Sarybchik	__in			size_t size,
379283514Sarybchik	__out			efx_vpd_value_t *evvp,
380283514Sarybchik	__inout			unsigned int *contp)
381283514Sarybchik{
382283514Sarybchik	_NOTE(ARGUNUSED(enp, data, size, evvp, contp))
383283514Sarybchik
384283514Sarybchik	return (ENOTSUP);
385283514Sarybchik}
386283514Sarybchik
387291436Sarybchik	__checkReturn		efx_rc_t
388293755Sarybchikef10_vpd_write(
389283514Sarybchik	__in			efx_nic_t *enp,
390283514Sarybchik	__in_bcount(size)	caddr_t data,
391283514Sarybchik	__in			size_t size)
392283514Sarybchik{
393283514Sarybchik	size_t vpd_length;
394283514Sarybchik	uint32_t pci_pf;
395291436Sarybchik	efx_rc_t rc;
396283514Sarybchik
397293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
398293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
399283514Sarybchik
400283514Sarybchik	pci_pf = enp->en_nic_cfg.enc_pf;
401283514Sarybchik
402283514Sarybchik	/* Determine total length of new dynamic VPD */
403283514Sarybchik	if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
404283514Sarybchik		goto fail1;
405283514Sarybchik
406291432Sarybchik	/* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */
407293756Sarybchik	if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
408283514Sarybchik		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
409283514Sarybchik		    TLV_TAG_PF_DYNAMIC_VPD(pci_pf),
410291432Sarybchik		    data, vpd_length, B_TRUE)) != 0) {
411283514Sarybchik		goto fail2;
412283514Sarybchik	}
413283514Sarybchik
414283514Sarybchik	return (0);
415283514Sarybchik
416283514Sarybchikfail2:
417283514Sarybchik	EFSYS_PROBE(fail2);
418283514Sarybchik
419283514Sarybchikfail1:
420291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
421283514Sarybchik
422283514Sarybchik	return (rc);
423283514Sarybchik}
424283514Sarybchik
425283514Sarybchik				void
426293755Sarybchikef10_vpd_fini(
427283514Sarybchik	__in			efx_nic_t *enp)
428283514Sarybchik{
429293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
430293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
431283514Sarybchik
432293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length > 0) {
433293748Sarybchik		EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length,
434293748Sarybchik				enp->en_arch.ef10.ena_svpd);
435283514Sarybchik
436293748Sarybchik		enp->en_arch.ef10.ena_svpd = NULL;
437293748Sarybchik		enp->en_arch.ef10.ena_svpd_length = 0;
438283514Sarybchik	}
439283514Sarybchik}
440283514Sarybchik
441283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
442283514Sarybchik
443283514Sarybchik#endif	/* EFSYS_OPT_VPD */
444