xref: /freebsd/sys/dev/bhnd/nvram/bhnd_sprom.c (revision ca942ab4b2b665e5375cc72afc4930d3b33b14f9)
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
3  * Copyright (c) 2017 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Landon Fuller
7  * under sponsorship from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer,
14  *    without modification.
15  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17  *    redistribution must be conditioned upon including a substantially
18  *    similar Disclaimer requirement for further binary redistribution.
19  *
20  * NO WARRANTY
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGES.
32  */
33 
34 #include <sys/cdefs.h>
35 /*
36  * BHND SPROM driver.
37  *
38  * Abstract driver for memory-mapped SPROM devices.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/bus.h>
44 #include <sys/limits.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/systm.h>
48 
49 #include <machine/bus.h>
50 #include <sys/rman.h>
51 #include <machine/resource.h>
52 
53 #include <dev/bhnd/bhnd.h>
54 
55 #include "bhnd_nvram_if.h"
56 
57 #include "bhnd_nvram_io.h"
58 
59 #include "bhnd_spromvar.h"
60 
61 /**
62  * Default bhnd sprom driver implementation of DEVICE_PROBE().
63  */
64 int
bhnd_sprom_probe(device_t dev)65 bhnd_sprom_probe(device_t dev)
66 {
67 	device_set_desc(dev, "SPROM/OTP");
68 
69 	/* Refuse wildcard attachments */
70 	return (BUS_PROBE_NOWILDCARD);
71 }
72 
73 /* Default DEVICE_ATTACH() implementation; assumes a zero offset to the
74  * SPROM data */
75 static int
bhnd_sprom_attach_meth(device_t dev)76 bhnd_sprom_attach_meth(device_t dev)
77 {
78 	return (bhnd_sprom_attach(dev, 0));
79 }
80 
81 /**
82  * BHND SPROM device attach.
83  *
84  * This should be called from DEVICE_ATTACH() with the @p offset to the
85  * SPROM data.
86  *
87  * Assumes SPROM is mapped via SYS_RES_MEMORY resource with RID 0.
88  *
89  * @param dev BHND SPROM device.
90  * @param offset Offset to the SPROM data.
91  */
92 int
bhnd_sprom_attach(device_t dev,bus_size_t offset)93 bhnd_sprom_attach(device_t dev, bus_size_t offset)
94 {
95 	struct bhnd_sprom_softc	*sc;
96 	struct bhnd_nvram_io	*io;
97 	struct bhnd_resource	*r;
98 	bus_size_t		 r_size, sprom_size;
99 	int			 error;
100 
101 	sc = device_get_softc(dev);
102 	sc->dev = dev;
103 	sc->store = NULL;
104 
105 	io = NULL;
106 	r = NULL;
107 
108 	/* Allocate SPROM resource */
109 	r = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE);
110 	if (r == NULL) {
111 		device_printf(dev, "failed to allocate resources\n");
112 		return (ENXIO);
113 	}
114 
115 	/* Determine SPROM size */
116 	r_size = rman_get_size(r->res);
117 	if (r_size <= offset || (r_size - offset) > BUS_SPACE_MAXSIZE) {
118 		device_printf(dev, "invalid sprom offset\n");
119 		error = ENXIO;
120 		goto failed;
121 	}
122 
123 	sprom_size = r_size - offset;
124 
125 	/* Allocate an I/O context for the SPROM parser. All SPROM reads
126 	 * must be 16-bit aligned */
127 	io = bhnd_nvram_iores_new(r, offset, sprom_size, sizeof(uint16_t));
128 	if (io == NULL) {
129 		error = ENXIO;
130 		goto failed;
131 	}
132 
133 	/* Initialize NVRAM data store */
134 	error = bhnd_nvram_store_parse_new(&sc->store, io,
135 	    &bhnd_nvram_sprom_class);
136 	if (error)
137 		goto failed;
138 
139 	/* Clean up our temporary I/O context and its backing resource */
140 	bhnd_nvram_io_free(io);
141 	bhnd_release_resource(dev, r);
142 
143 	io = NULL;
144 	r = NULL;
145 
146 	/* Register ourselves with the bus */
147 	if ((error = bhnd_register_provider(dev, BHND_SERVICE_NVRAM))) {
148 		device_printf(dev, "failed to register NVRAM provider: %d\n",
149 		    error);
150 		goto failed;
151 	}
152 
153 	return (0);
154 
155 failed:
156 	/* Clean up I/O context before releasing its backing resource */
157 	if (io != NULL)
158 		bhnd_nvram_io_free(io);
159 
160 	if (r != NULL)
161 		bhnd_release_resource(dev, r);
162 
163 	if (sc->store != NULL)
164 		bhnd_nvram_store_free(sc->store);
165 
166 	return (error);
167 }
168 
169 /**
170  * Default bhnd_sprom implementation of DEVICE_RESUME().
171  */
172 int
bhnd_sprom_resume(device_t dev)173 bhnd_sprom_resume(device_t dev)
174 {
175 	return (0);
176 }
177 
178 /**
179  * Default bhnd sprom driver implementation of DEVICE_SUSPEND().
180  */
181 int
bhnd_sprom_suspend(device_t dev)182 bhnd_sprom_suspend(device_t dev)
183 {
184 	return (0);
185 }
186 
187 /**
188  * Default bhnd sprom driver implementation of DEVICE_DETACH().
189  */
190 int
bhnd_sprom_detach(device_t dev)191 bhnd_sprom_detach(device_t dev)
192 {
193 	struct bhnd_sprom_softc	*sc;
194 	int			 error;
195 
196 	sc = device_get_softc(dev);
197 
198 	if ((error = bhnd_deregister_provider(dev, BHND_SERVICE_ANY)))
199 		return (error);
200 
201 	bhnd_nvram_store_free(sc->store);
202 
203 	return (0);
204 }
205 
206 /**
207  * Default bhnd sprom driver implementation of BHND_NVRAM_GETVAR().
208  */
209 static int
bhnd_sprom_getvar_method(device_t dev,const char * name,void * buf,size_t * len,bhnd_nvram_type type)210 bhnd_sprom_getvar_method(device_t dev, const char *name, void *buf, size_t *len,
211     bhnd_nvram_type type)
212 {
213 	struct bhnd_sprom_softc	*sc = device_get_softc(dev);
214 
215 	return (bhnd_nvram_store_getvar(sc->store, name, buf, len, type));
216 }
217 
218 /**
219  * Default bhnd sprom driver implementation of BHND_NVRAM_SETVAR().
220  */
221 static int
bhnd_sprom_setvar_method(device_t dev,const char * name,const void * buf,size_t len,bhnd_nvram_type type)222 bhnd_sprom_setvar_method(device_t dev, const char *name, const void *buf,
223     size_t len, bhnd_nvram_type type)
224 {
225 	struct bhnd_sprom_softc	*sc = device_get_softc(dev);
226 
227 	return (bhnd_nvram_store_setvar(sc->store, name, buf, len, type));
228 }
229 
230 static device_method_t bhnd_sprom_methods[] = {
231 	/* Device interface */
232 	DEVMETHOD(device_probe,			bhnd_sprom_probe),
233 	DEVMETHOD(device_attach,		bhnd_sprom_attach_meth),
234 	DEVMETHOD(device_resume,		bhnd_sprom_resume),
235 	DEVMETHOD(device_suspend,		bhnd_sprom_suspend),
236 	DEVMETHOD(device_detach,		bhnd_sprom_detach),
237 
238 	/* NVRAM interface */
239 	DEVMETHOD(bhnd_nvram_getvar,		bhnd_sprom_getvar_method),
240 	DEVMETHOD(bhnd_nvram_setvar,		bhnd_sprom_setvar_method),
241 
242 	DEVMETHOD_END
243 };
244 
245 DEFINE_CLASS_0(bhnd_nvram_store, bhnd_sprom_driver, bhnd_sprom_methods, sizeof(struct bhnd_sprom_softc));
246 MODULE_VERSION(bhnd_sprom, 1);
247