1227569Sphilip/*-
2227569Sphilip * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
3227569Sphilip *
4227569Sphilip * Redistribution and use in source and binary forms, with or without
5227569Sphilip * modification, are permitted provided that the following conditions
6227569Sphilip * are met:
7227569Sphilip * 1. Redistributions of source code must retain the above copyright
8227569Sphilip *    notice, this list of conditions and the following disclaimer.
9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
10227569Sphilip *    notice, this list of conditions and the following disclaimer in the
11227569Sphilip *    documentation and/or other materials provided with the distribution.
12227569Sphilip *
13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227569Sphilip * SUCH DAMAGE.
24227569Sphilip */
25227569Sphilip
26228100Sphilip#include <sys/cdefs.h>
27228100Sphilip__FBSDID("$FreeBSD$");
28228100Sphilip
29227569Sphilip#include "efsys.h"
30227569Sphilip#include "efx.h"
31227569Sphilip#include "efx_types.h"
32227569Sphilip#include "efx_regs.h"
33227569Sphilip#include "efx_impl.h"
34227569Sphilip
35227569Sphilip#if EFSYS_OPT_NVRAM
36227569Sphilip
37227569Sphilip#if EFSYS_OPT_FALCON
38227569Sphilip
39227569Sphilipstatic efx_nvram_ops_t	__cs	__efx_nvram_falcon_ops = {
40227569Sphilip#if EFSYS_OPT_DIAG
41227569Sphilip	falcon_nvram_test,		/* envo_test */
42227569Sphilip#endif	/* EFSYS_OPT_DIAG */
43227569Sphilip	falcon_nvram_size,		/* envo_size */
44227569Sphilip	falcon_nvram_get_version,	/* envo_get_version */
45227569Sphilip	falcon_nvram_rw_start,		/* envo_rw_start */
46227569Sphilip	falcon_nvram_read_chunk,	/* envo_read_chunk */
47227569Sphilip	falcon_nvram_erase,		/* envo_erase */
48227569Sphilip	falcon_nvram_write_chunk,	/* envo_write_chunk */
49227569Sphilip	falcon_nvram_rw_finish,		/* envo_rw_finish */
50227569Sphilip	falcon_nvram_set_version,	/* envo_set_version */
51227569Sphilip};
52227569Sphilip
53227569Sphilip#endif	/* EFSYS_OPT_FALCON */
54227569Sphilip
55227569Sphilip#if EFSYS_OPT_SIENA
56227569Sphilip
57227569Sphilipstatic efx_nvram_ops_t	__cs	__efx_nvram_siena_ops = {
58227569Sphilip#if EFSYS_OPT_DIAG
59227569Sphilip	siena_nvram_test,		/* envo_test */
60227569Sphilip#endif	/* EFSYS_OPT_DIAG */
61227569Sphilip	siena_nvram_size,		/* envo_size */
62227569Sphilip	siena_nvram_get_version,	/* envo_get_version */
63227569Sphilip	siena_nvram_rw_start,		/* envo_rw_start */
64227569Sphilip	siena_nvram_read_chunk,		/* envo_read_chunk */
65227569Sphilip	siena_nvram_erase,		/* envo_erase */
66227569Sphilip	siena_nvram_write_chunk,	/* envo_write_chunk */
67227569Sphilip	siena_nvram_rw_finish,		/* envo_rw_finish */
68227569Sphilip	siena_nvram_set_version,	/* envo_set_version */
69227569Sphilip};
70227569Sphilip
71227569Sphilip#endif	/* EFSYS_OPT_SIENA */
72227569Sphilip
73227569Sphilip	__checkReturn	int
74227569Sphilipefx_nvram_init(
75227569Sphilip	__in		efx_nic_t *enp)
76227569Sphilip{
77227569Sphilip	efx_nvram_ops_t *envop;
78227569Sphilip	int rc;
79227569Sphilip
80227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
81227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
82227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
83227569Sphilip
84227569Sphilip	switch (enp->en_family) {
85227569Sphilip#if EFSYS_OPT_FALCON
86227569Sphilip	case EFX_FAMILY_FALCON:
87227569Sphilip		envop = (efx_nvram_ops_t *)&__efx_nvram_falcon_ops;
88227569Sphilip		break;
89227569Sphilip#endif	/* EFSYS_OPT_FALCON */
90227569Sphilip
91227569Sphilip#if EFSYS_OPT_SIENA
92227569Sphilip	case EFX_FAMILY_SIENA:
93227569Sphilip		envop = (efx_nvram_ops_t *)&__efx_nvram_siena_ops;
94227569Sphilip		break;
95227569Sphilip#endif	/* EFSYS_OPT_SIENA */
96227569Sphilip
97227569Sphilip	default:
98227569Sphilip		EFSYS_ASSERT(0);
99227569Sphilip		rc = ENOTSUP;
100227569Sphilip		goto fail1;
101227569Sphilip	}
102227569Sphilip
103227569Sphilip	enp->en_envop = envop;
104227569Sphilip	enp->en_mod_flags |= EFX_MOD_NVRAM;
105227569Sphilip
106227569Sphilip	return (0);
107227569Sphilip
108227569Sphilipfail1:
109227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
110227569Sphilip
111227569Sphilip	return (rc);
112227569Sphilip}
113227569Sphilip
114227569Sphilip#if EFSYS_OPT_DIAG
115227569Sphilip
116227569Sphilip	__checkReturn		int
117227569Sphilipefx_nvram_test(
118227569Sphilip	__in			efx_nic_t *enp)
119227569Sphilip{
120227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
121227569Sphilip	int rc;
122227569Sphilip
123227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
124227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
125227569Sphilip
126227569Sphilip	if ((rc = envop->envo_test(enp)) != 0)
127227569Sphilip		goto fail1;
128227569Sphilip
129227569Sphilip	return (0);
130227569Sphilip
131227569Sphilipfail1:
132227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
133227569Sphilip
134227569Sphilip	return (rc);
135227569Sphilip}
136227569Sphilip
137227569Sphilip#endif	/* EFSYS_OPT_DIAG */
138227569Sphilip
139227569Sphilip	__checkReturn		int
140227569Sphilipefx_nvram_size(
141227569Sphilip	__in			efx_nic_t *enp,
142227569Sphilip	__in			efx_nvram_type_t type,
143227569Sphilip	__out			size_t *sizep)
144227569Sphilip{
145227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
146227569Sphilip	int rc;
147227569Sphilip
148227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
149227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
150227569Sphilip
151227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
152227569Sphilip
153227569Sphilip	if ((rc = envop->envo_size(enp, type, sizep)) != 0)
154227569Sphilip		goto fail1;
155227569Sphilip
156227569Sphilip	return (0);
157227569Sphilip
158227569Sphilipfail1:
159227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
160227569Sphilip
161227569Sphilip	return (rc);
162227569Sphilip}
163227569Sphilip
164227569Sphilip	__checkReturn		int
165227569Sphilipefx_nvram_get_version(
166227569Sphilip	__in			efx_nic_t *enp,
167227569Sphilip	__in			efx_nvram_type_t type,
168227569Sphilip	__out			uint32_t *subtypep,
169227569Sphilip	__out_ecount(4)		uint16_t version[4])
170227569Sphilip{
171227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
172227569Sphilip	int rc;
173227569Sphilip
174227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
175227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
176227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
177227569Sphilip
178227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
179227569Sphilip
180227569Sphilip	if ((rc = envop->envo_get_version(enp, type, subtypep, version)) != 0)
181227569Sphilip		goto fail1;
182227569Sphilip
183227569Sphilip	return (0);
184227569Sphilip
185227569Sphilipfail1:
186227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
187227569Sphilip
188227569Sphilip	return (rc);
189227569Sphilip}
190227569Sphilip
191227569Sphilip	__checkReturn		int
192227569Sphilipefx_nvram_rw_start(
193227569Sphilip	__in			efx_nic_t *enp,
194227569Sphilip	__in			efx_nvram_type_t type,
195227569Sphilip	__out_opt		size_t *chunk_sizep)
196227569Sphilip{
197227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
198227569Sphilip	int rc;
199227569Sphilip
200227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
201227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
202227569Sphilip
203227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
204227569Sphilip	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
205227569Sphilip
206227569Sphilip	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
207227569Sphilip
208227569Sphilip	if ((rc = envop->envo_rw_start(enp, type, chunk_sizep)) != 0)
209227569Sphilip		goto fail1;
210227569Sphilip
211227569Sphilip	enp->en_nvram_locked = type;
212227569Sphilip
213227569Sphilip	return (0);
214227569Sphilip
215227569Sphilipfail1:
216227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
217227569Sphilip
218227569Sphilip	return (rc);
219227569Sphilip}
220227569Sphilip
221227569Sphilip	__checkReturn		int
222227569Sphilipefx_nvram_read_chunk(
223227569Sphilip	__in			efx_nic_t *enp,
224227569Sphilip	__in			efx_nvram_type_t type,
225227569Sphilip	__in			unsigned int offset,
226227569Sphilip	__out_bcount(size)	caddr_t data,
227227569Sphilip	__in			size_t size)
228227569Sphilip{
229227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
230227569Sphilip	int rc;
231227569Sphilip
232227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
233227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
234227569Sphilip
235227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
236227569Sphilip	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
237227569Sphilip
238227569Sphilip	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
239227569Sphilip
240227569Sphilip	if ((rc = envop->envo_read_chunk(enp, type, offset, data, size)) != 0)
241227569Sphilip		goto fail1;
242227569Sphilip
243227569Sphilip	return (0);
244227569Sphilip
245227569Sphilipfail1:
246227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
247227569Sphilip
248227569Sphilip	return (rc);
249227569Sphilip}
250227569Sphilip
251227569Sphilip	__checkReturn		int
252227569Sphilipefx_nvram_erase(
253227569Sphilip	__in			efx_nic_t *enp,
254227569Sphilip	__in			efx_nvram_type_t type)
255227569Sphilip{
256227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
257227569Sphilip	int rc;
258227569Sphilip
259227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
260227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
261227569Sphilip
262227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
263227569Sphilip	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
264227569Sphilip
265227569Sphilip	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
266227569Sphilip
267227569Sphilip	if ((rc = envop->envo_erase(enp, type)) != 0)
268227569Sphilip		goto fail1;
269227569Sphilip
270227569Sphilip	return (0);
271227569Sphilip
272227569Sphilipfail1:
273227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
274227569Sphilip
275227569Sphilip	return (rc);
276227569Sphilip}
277227569Sphilip
278227569Sphilip	__checkReturn		int
279227569Sphilipefx_nvram_write_chunk(
280227569Sphilip	__in			efx_nic_t *enp,
281227569Sphilip	__in			efx_nvram_type_t type,
282227569Sphilip	__in			unsigned int offset,
283227569Sphilip	__in_bcount(size)	caddr_t data,
284227569Sphilip	__in			size_t size)
285227569Sphilip{
286227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
287227569Sphilip	int rc;
288227569Sphilip
289227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
290227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
291227569Sphilip
292227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
293227569Sphilip	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
294227569Sphilip
295227569Sphilip	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
296227569Sphilip
297227569Sphilip	if ((rc = envop->envo_write_chunk(enp, type, offset, data, size)) != 0)
298227569Sphilip		goto fail1;
299227569Sphilip
300227569Sphilip	return (0);
301227569Sphilip
302227569Sphilipfail1:
303227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
304227569Sphilip
305227569Sphilip	return (rc);
306227569Sphilip}
307227569Sphilip
308227569Sphilip				void
309227569Sphilipefx_nvram_rw_finish(
310227569Sphilip	__in			efx_nic_t *enp,
311227569Sphilip	__in			efx_nvram_type_t type)
312227569Sphilip{
313227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
314227569Sphilip
315227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
316227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
317227569Sphilip
318227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
319227569Sphilip	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
320227569Sphilip
321227569Sphilip	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
322227569Sphilip
323227569Sphilip	envop->envo_rw_finish(enp, type);
324227569Sphilip
325227569Sphilip	enp->en_nvram_locked = EFX_NVRAM_INVALID;
326227569Sphilip}
327227569Sphilip
328227569Sphilip	__checkReturn		int
329227569Sphilipefx_nvram_set_version(
330227569Sphilip	__in			efx_nic_t *enp,
331227569Sphilip	__in			efx_nvram_type_t type,
332227569Sphilip	__out			uint16_t version[4])
333227569Sphilip{
334227569Sphilip	efx_nvram_ops_t *envop = enp->en_envop;
335227569Sphilip	int rc;
336227569Sphilip
337227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
338227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
339227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
340227569Sphilip
341227569Sphilip	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
342227569Sphilip
343227569Sphilip	/*
344227569Sphilip	 * The Siena implementation of envo_set_version() will attempt to
345227569Sphilip	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
346227569Sphilip	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
347227569Sphilip	 */
348227569Sphilip	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
349227569Sphilip
350227569Sphilip	if ((rc = envop->envo_set_version(enp, type, version)) != 0)
351227569Sphilip		goto fail1;
352227569Sphilip
353227569Sphilip	return (0);
354227569Sphilip
355227569Sphilipfail1:
356227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
357227569Sphilip
358227569Sphilip	return (rc);
359227569Sphilip}
360227569Sphilip
361227569Sphilipvoid
362227569Sphilipefx_nvram_fini(
363227569Sphilip	__in		efx_nic_t *enp)
364227569Sphilip{
365227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
366227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
367227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
368227569Sphilip
369227569Sphilip	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
370227569Sphilip
371227569Sphilip	enp->en_envop = NULL;
372227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
373227569Sphilip}
374227569Sphilip
375227569Sphilip#endif	/* EFSYS_OPT_NVRAM */
376