1283514Sarybchik/*-
2300607Sarybchik * Copyright (c) 2009-2016 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$");
33283514Sarybchik
34283514Sarybchik#include "efx.h"
35283514Sarybchik#include "efx_impl.h"
36283514Sarybchik
37283514Sarybchik
38283514Sarybchik#if EFSYS_OPT_VPD
39283514Sarybchik
40299606Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
41283514Sarybchik
42283514Sarybchik#include "ef10_tlv_layout.h"
43283514Sarybchik
44291436Sarybchik	__checkReturn		efx_rc_t
45293755Sarybchikef10_vpd_init(
46283514Sarybchik	__in			efx_nic_t *enp)
47283514Sarybchik{
48283514Sarybchik	caddr_t svpd;
49283514Sarybchik	size_t svpd_size;
50283514Sarybchik	uint32_t pci_pf;
51294078Sarybchik	uint32_t tag;
52291436Sarybchik	efx_rc_t rc;
53283514Sarybchik
54283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
55293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
56293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
57283514Sarybchik
58294078Sarybchik	if (enp->en_nic_cfg.enc_vpd_is_global) {
59294078Sarybchik		tag = TLV_TAG_GLOBAL_STATIC_VPD;
60294078Sarybchik	} else {
61294078Sarybchik		pci_pf = enp->en_nic_cfg.enc_pf;
62294078Sarybchik		tag = TLV_TAG_PF_STATIC_VPD(pci_pf);
63294078Sarybchik	}
64294078Sarybchik
65283514Sarybchik	/*
66283514Sarybchik	 * The VPD interface exposes VPD resources from the combined static and
67283514Sarybchik	 * dynamic VPD storage. As the static VPD configuration should *never*
68283514Sarybchik	 * change, we can cache it.
69283514Sarybchik	 */
70283514Sarybchik	svpd = NULL;
71283514Sarybchik	svpd_size = 0;
72293756Sarybchik	rc = ef10_nvram_partn_read_tlv(enp,
73283514Sarybchik	    NVRAM_PARTITION_TYPE_STATIC_CONFIG,
74294078Sarybchik	    tag, &svpd, &svpd_size);
75283514Sarybchik	if (rc != 0) {
76283514Sarybchik		if (rc == EACCES) {
77299345Sarybchik			/* Unprivileged functions cannot access VPD */
78283514Sarybchik			goto out;
79283514Sarybchik		}
80283514Sarybchik		goto fail1;
81283514Sarybchik	}
82283514Sarybchik
83283514Sarybchik	if (svpd != NULL && svpd_size > 0) {
84283514Sarybchik		if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0)
85283514Sarybchik			goto fail2;
86283514Sarybchik	}
87283514Sarybchik
88293748Sarybchik	enp->en_arch.ef10.ena_svpd = svpd;
89293748Sarybchik	enp->en_arch.ef10.ena_svpd_length = svpd_size;
90283514Sarybchik
91283514Sarybchikout:
92283514Sarybchik	return (0);
93283514Sarybchik
94283514Sarybchikfail2:
95283514Sarybchik	EFSYS_PROBE(fail2);
96283514Sarybchik
97283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd);
98283514Sarybchikfail1:
99291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
100283514Sarybchik
101283514Sarybchik	return (rc);
102283514Sarybchik}
103283514Sarybchik
104291436Sarybchik	__checkReturn		efx_rc_t
105293755Sarybchikef10_vpd_size(
106283514Sarybchik	__in			efx_nic_t *enp,
107283514Sarybchik	__out			size_t *sizep)
108283514Sarybchik{
109291436Sarybchik	efx_rc_t rc;
110283514Sarybchik
111293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
112293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
113283514Sarybchik
114283514Sarybchik	/*
115283514Sarybchik	 * This function returns the total size the user should allocate
116283514Sarybchik	 * for all VPD operations. We've already cached the static vpd,
117283514Sarybchik	 * so we just need to return an upper bound on the dynamic vpd,
118283514Sarybchik	 * which is the size of the DYNAMIC_CONFIG partition.
119283514Sarybchik	 */
120283514Sarybchik	if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
121291746Sarybchik		    sizep, NULL, NULL, NULL)) != 0)
122283514Sarybchik		goto fail1;
123283514Sarybchik
124283514Sarybchik	return (0);
125283514Sarybchik
126283514Sarybchikfail1:
127291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
128283514Sarybchik
129283514Sarybchik	return (rc);
130283514Sarybchik}
131283514Sarybchik
132291436Sarybchik	__checkReturn		efx_rc_t
133293755Sarybchikef10_vpd_read(
134283514Sarybchik	__in			efx_nic_t *enp,
135283514Sarybchik	__out_bcount(size)	caddr_t data,
136283514Sarybchik	__in			size_t size)
137283514Sarybchik{
138283514Sarybchik	caddr_t dvpd;
139283514Sarybchik	size_t dvpd_size;
140283514Sarybchik	uint32_t pci_pf;
141294078Sarybchik	uint32_t tag;
142291436Sarybchik	efx_rc_t rc;
143283514Sarybchik
144293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
145293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
146283514Sarybchik
147294078Sarybchik	if (enp->en_nic_cfg.enc_vpd_is_global) {
148294078Sarybchik		tag = TLV_TAG_GLOBAL_DYNAMIC_VPD;
149294078Sarybchik	} else {
150294078Sarybchik		pci_pf = enp->en_nic_cfg.enc_pf;
151294078Sarybchik		tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf);
152294078Sarybchik	}
153283514Sarybchik
154293756Sarybchik	if ((rc = ef10_nvram_partn_read_tlv(enp,
155283514Sarybchik		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
156294078Sarybchik		    tag, &dvpd, &dvpd_size)) != 0)
157283514Sarybchik		goto fail1;
158283514Sarybchik
159283514Sarybchik	if (dvpd_size > size) {
160283514Sarybchik		rc = ENOSPC;
161283514Sarybchik		goto fail2;
162283514Sarybchik	}
163283514Sarybchik	memcpy(data, dvpd, dvpd_size);
164283514Sarybchik
165283514Sarybchik	/* Pad data with all-1s, consistent with update operations */
166283514Sarybchik	memset(data + dvpd_size, 0xff, size - dvpd_size);
167283514Sarybchik
168283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
169283514Sarybchik
170283514Sarybchik	return (0);
171283514Sarybchik
172283514Sarybchikfail2:
173283514Sarybchik	EFSYS_PROBE(fail2);
174283514Sarybchik
175283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
176283514Sarybchikfail1:
177291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
178283514Sarybchik
179283514Sarybchik	return (rc);
180283514Sarybchik}
181283514Sarybchik
182291436Sarybchik	__checkReturn		efx_rc_t
183293755Sarybchikef10_vpd_verify(
184283514Sarybchik	__in			efx_nic_t *enp,
185283514Sarybchik	__in_bcount(size)	caddr_t data,
186283514Sarybchik	__in			size_t size)
187283514Sarybchik{
188283514Sarybchik	efx_vpd_tag_t stag;
189283514Sarybchik	efx_vpd_tag_t dtag;
190283514Sarybchik	efx_vpd_keyword_t skey;
191283514Sarybchik	efx_vpd_keyword_t dkey;
192283514Sarybchik	unsigned int scont;
193283514Sarybchik	unsigned int dcont;
194291436Sarybchik	efx_rc_t rc;
195283514Sarybchik
196293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
197293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
198283514Sarybchik
199283514Sarybchik	/*
200283514Sarybchik	 * Strictly you could take the view that dynamic vpd is optional.
201283514Sarybchik	 * Instead, to conform more closely to the read/verify/reinit()
202293755Sarybchik	 * paradigm, we require dynamic vpd. ef10_vpd_reinit() will
203283514Sarybchik	 * reinitialize it as required.
204283514Sarybchik	 */
205283514Sarybchik	if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
206283514Sarybchik		goto fail1;
207283514Sarybchik
208283514Sarybchik	/*
209283514Sarybchik	 * Verify that there is no duplication between the static and
210283514Sarybchik	 * dynamic cfg sectors.
211283514Sarybchik	 */
212293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length == 0)
213283514Sarybchik		goto done;
214283514Sarybchik
215283514Sarybchik	dcont = 0;
216283514Sarybchik	_NOTE(CONSTANTCONDITION)
217283514Sarybchik	while (1) {
218283514Sarybchik		if ((rc = efx_vpd_hunk_next(data, size, &dtag,
219283514Sarybchik		    &dkey, NULL, NULL, &dcont)) != 0)
220283514Sarybchik			goto fail2;
221283514Sarybchik		if (dcont == 0)
222283514Sarybchik			break;
223283514Sarybchik
224293895Sarybchik		/*
225293895Sarybchik		 * Skip the RV keyword. It should be present in both the static
226293895Sarybchik		 * and dynamic cfg sectors.
227293895Sarybchik		 */
228293895Sarybchik		if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
229293895Sarybchik			continue;
230293895Sarybchik
231283514Sarybchik		scont = 0;
232283514Sarybchik		_NOTE(CONSTANTCONDITION)
233283514Sarybchik		while (1) {
234283514Sarybchik			if ((rc = efx_vpd_hunk_next(
235293748Sarybchik			    enp->en_arch.ef10.ena_svpd,
236293748Sarybchik			    enp->en_arch.ef10.ena_svpd_length, &stag, &skey,
237283514Sarybchik			    NULL, NULL, &scont)) != 0)
238283514Sarybchik				goto fail3;
239283514Sarybchik			if (scont == 0)
240283514Sarybchik				break;
241283514Sarybchik
242283514Sarybchik			if (stag == dtag && skey == dkey) {
243283514Sarybchik				rc = EEXIST;
244283514Sarybchik				goto fail4;
245283514Sarybchik			}
246283514Sarybchik		}
247283514Sarybchik	}
248283514Sarybchik
249283514Sarybchikdone:
250283514Sarybchik	return (0);
251283514Sarybchik
252283514Sarybchikfail4:
253283514Sarybchik	EFSYS_PROBE(fail4);
254283514Sarybchikfail3:
255283514Sarybchik	EFSYS_PROBE(fail3);
256283514Sarybchikfail2:
257283514Sarybchik	EFSYS_PROBE(fail2);
258283514Sarybchikfail1:
259291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
260283514Sarybchik
261283514Sarybchik	return (rc);
262283514Sarybchik}
263283514Sarybchik
264291436Sarybchik	__checkReturn		efx_rc_t
265293755Sarybchikef10_vpd_reinit(
266283514Sarybchik	__in			efx_nic_t *enp,
267283514Sarybchik	__in_bcount(size)	caddr_t data,
268283514Sarybchik	__in			size_t size)
269283514Sarybchik{
270283514Sarybchik	boolean_t wantpid;
271291436Sarybchik	efx_rc_t rc;
272283514Sarybchik
273283514Sarybchik	/*
274283514Sarybchik	 * Only create an ID string if the dynamic cfg doesn't have one
275283514Sarybchik	 */
276293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length == 0)
277283514Sarybchik		wantpid = B_TRUE;
278283514Sarybchik	else {
279283514Sarybchik		unsigned int offset;
280283514Sarybchik		uint8_t length;
281283514Sarybchik
282293748Sarybchik		rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
283293748Sarybchik				    enp->en_arch.ef10.ena_svpd_length,
284283514Sarybchik				    EFX_VPD_ID, 0, &offset, &length);
285283514Sarybchik		if (rc == 0)
286283514Sarybchik			wantpid = B_FALSE;
287283514Sarybchik		else if (rc == ENOENT)
288283514Sarybchik			wantpid = B_TRUE;
289283514Sarybchik		else
290283514Sarybchik			goto fail1;
291283514Sarybchik	}
292283514Sarybchik
293283514Sarybchik	if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
294283514Sarybchik		goto fail2;
295283514Sarybchik
296283514Sarybchik	return (0);
297283514Sarybchik
298283514Sarybchikfail2:
299283514Sarybchik	EFSYS_PROBE(fail2);
300283514Sarybchikfail1:
301291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
302283514Sarybchik
303283514Sarybchik	return (rc);
304283514Sarybchik}
305283514Sarybchik
306291436Sarybchik	__checkReturn		efx_rc_t
307293755Sarybchikef10_vpd_get(
308283514Sarybchik	__in			efx_nic_t *enp,
309283514Sarybchik	__in_bcount(size)	caddr_t data,
310283514Sarybchik	__in			size_t size,
311283514Sarybchik	__inout			efx_vpd_value_t *evvp)
312283514Sarybchik{
313283514Sarybchik	unsigned int offset;
314283514Sarybchik	uint8_t length;
315291436Sarybchik	efx_rc_t rc;
316283514Sarybchik
317293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
318293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
319283514Sarybchik
320283514Sarybchik	/* Attempt to satisfy the request from svpd first */
321293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length > 0) {
322293748Sarybchik		if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
323293748Sarybchik		    enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
324283514Sarybchik		    evvp->evv_keyword, &offset, &length)) == 0) {
325283514Sarybchik			evvp->evv_length = length;
326283514Sarybchik			memcpy(evvp->evv_value,
327293748Sarybchik			    enp->en_arch.ef10.ena_svpd + offset, length);
328283514Sarybchik			return (0);
329283514Sarybchik		} else if (rc != ENOENT)
330283514Sarybchik			goto fail1;
331283514Sarybchik	}
332283514Sarybchik
333283514Sarybchik	/* And then from the provided data buffer */
334283514Sarybchik	if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
335299901Sarybchik	    evvp->evv_keyword, &offset, &length)) != 0) {
336299901Sarybchik		if (rc == ENOENT)
337299901Sarybchik			return (rc);
338283514Sarybchik		goto fail2;
339299901Sarybchik	}
340283514Sarybchik
341283514Sarybchik	evvp->evv_length = length;
342283514Sarybchik	memcpy(evvp->evv_value, data + offset, length);
343283514Sarybchik
344283514Sarybchik	return (0);
345283514Sarybchik
346283514Sarybchikfail2:
347283514Sarybchik	EFSYS_PROBE(fail2);
348283514Sarybchikfail1:
349291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
350283514Sarybchik
351283514Sarybchik	return (rc);
352283514Sarybchik}
353283514Sarybchik
354291436Sarybchik	__checkReturn		efx_rc_t
355293755Sarybchikef10_vpd_set(
356283514Sarybchik	__in			efx_nic_t *enp,
357283514Sarybchik	__in_bcount(size)	caddr_t data,
358283514Sarybchik	__in			size_t size,
359283514Sarybchik	__in			efx_vpd_value_t *evvp)
360283514Sarybchik{
361291436Sarybchik	efx_rc_t rc;
362283514Sarybchik
363293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
364293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
365283514Sarybchik
366283514Sarybchik	/* If the provided (tag,keyword) exists in svpd, then it is readonly */
367293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length > 0) {
368283514Sarybchik		unsigned int offset;
369283514Sarybchik		uint8_t length;
370283514Sarybchik
371293748Sarybchik		if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd,
372293748Sarybchik		    enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag,
373283514Sarybchik		    evvp->evv_keyword, &offset, &length)) == 0) {
374283514Sarybchik			rc = EACCES;
375283514Sarybchik			goto fail1;
376283514Sarybchik		}
377283514Sarybchik	}
378283514Sarybchik
379283514Sarybchik	if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
380283514Sarybchik		goto fail2;
381283514Sarybchik
382283514Sarybchik	return (0);
383283514Sarybchik
384283514Sarybchikfail2:
385283514Sarybchik	EFSYS_PROBE(fail2);
386283514Sarybchikfail1:
387291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
388283514Sarybchik
389283514Sarybchik	return (rc);
390283514Sarybchik}
391283514Sarybchik
392291436Sarybchik	__checkReturn		efx_rc_t
393293755Sarybchikef10_vpd_next(
394283514Sarybchik	__in			efx_nic_t *enp,
395283514Sarybchik	__in_bcount(size)	caddr_t data,
396283514Sarybchik	__in			size_t size,
397283514Sarybchik	__out			efx_vpd_value_t *evvp,
398283514Sarybchik	__inout			unsigned int *contp)
399283514Sarybchik{
400283514Sarybchik	_NOTE(ARGUNUSED(enp, data, size, evvp, contp))
401283514Sarybchik
402283514Sarybchik	return (ENOTSUP);
403283514Sarybchik}
404283514Sarybchik
405291436Sarybchik	__checkReturn		efx_rc_t
406293755Sarybchikef10_vpd_write(
407283514Sarybchik	__in			efx_nic_t *enp,
408283514Sarybchik	__in_bcount(size)	caddr_t data,
409283514Sarybchik	__in			size_t size)
410283514Sarybchik{
411283514Sarybchik	size_t vpd_length;
412283514Sarybchik	uint32_t pci_pf;
413294078Sarybchik	uint32_t tag;
414291436Sarybchik	efx_rc_t rc;
415283514Sarybchik
416293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
417293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
418283514Sarybchik
419294078Sarybchik	if (enp->en_nic_cfg.enc_vpd_is_global) {
420294078Sarybchik		tag = TLV_TAG_GLOBAL_DYNAMIC_VPD;
421294078Sarybchik	} else {
422294078Sarybchik		pci_pf = enp->en_nic_cfg.enc_pf;
423294078Sarybchik		tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf);
424294078Sarybchik	}
425283514Sarybchik
426283514Sarybchik	/* Determine total length of new dynamic VPD */
427283514Sarybchik	if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
428283514Sarybchik		goto fail1;
429283514Sarybchik
430291432Sarybchik	/* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */
431293756Sarybchik	if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
432283514Sarybchik		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
433294078Sarybchik		    tag, data, vpd_length, B_TRUE)) != 0) {
434283514Sarybchik		goto fail2;
435283514Sarybchik	}
436283514Sarybchik
437283514Sarybchik	return (0);
438283514Sarybchik
439283514Sarybchikfail2:
440283514Sarybchik	EFSYS_PROBE(fail2);
441283514Sarybchik
442283514Sarybchikfail1:
443291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
444283514Sarybchik
445283514Sarybchik	return (rc);
446283514Sarybchik}
447283514Sarybchik
448283514Sarybchik				void
449293755Sarybchikef10_vpd_fini(
450283514Sarybchik	__in			efx_nic_t *enp)
451283514Sarybchik{
452293755Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
453293755Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
454283514Sarybchik
455293748Sarybchik	if (enp->en_arch.ef10.ena_svpd_length > 0) {
456293748Sarybchik		EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length,
457293748Sarybchik				enp->en_arch.ef10.ena_svpd);
458283514Sarybchik
459293748Sarybchik		enp->en_arch.ef10.ena_svpd = NULL;
460293748Sarybchik		enp->en_arch.ef10.ena_svpd_length = 0;
461283514Sarybchik	}
462283514Sarybchik}
463283514Sarybchik
464299606Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
465283514Sarybchik
466283514Sarybchik#endif	/* EFSYS_OPT_VPD */
467