xref: /rk3399_ARM-atf/drivers/io/io_storage.c (revision b10d44995eb652675863c2cc6a7726683613da0d)
1 /*
2  * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of ARM nor the names of its contributors may be used
15  * to endorse or promote products derived from this software without specific
16  * prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <assert.h>
32 #include <io_driver.h>
33 #include <io_storage.h>
34 #include <platform_def.h>
35 #include <stddef.h>
36 
37 
38 /* Storage for a fixed maximum number of IO entities, definable by platform */
39 static io_entity_t entity_pool[MAX_IO_HANDLES];
40 
41 /* Simple way of tracking used storage - each entry is NULL or a pointer to an
42  * entity */
43 static io_entity_t *entity_map[MAX_IO_HANDLES];
44 
45 /* Track number of allocated entities */
46 static unsigned int entity_count;
47 
48 /* Array of fixed maximum of registered devices, definable by platform */
49 static const io_dev_info_t *devices[MAX_IO_DEVICES];
50 
51 /* Number of currently registered devices */
52 static unsigned int dev_count;
53 
54 /* Extra validation functions only used when asserts are enabled */
55 #if ENABLE_ASSERTIONS
56 
57 /* Return a boolean value indicating whether a device connector is valid */
58 static int is_valid_dev_connector(const io_dev_connector_t *dev_con)
59 {
60 	int result = (dev_con != NULL) && (dev_con->dev_open != NULL);
61 	return result;
62 }
63 
64 
65 /* Return a boolean value indicating whether a device handle is valid */
66 static int is_valid_dev(const uintptr_t dev_handle)
67 {
68 	const io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
69 	int result = (dev != NULL) && (dev->funcs != NULL) &&
70 			(dev->funcs->type != NULL) &&
71 			(dev->funcs->type() < IO_TYPE_MAX);
72 	return result;
73 }
74 
75 
76 /* Return a boolean value indicating whether an IO entity is valid */
77 static int is_valid_entity(const uintptr_t handle)
78 {
79 	const io_entity_t *entity = (io_entity_t *)handle;
80 	int result = (entity != NULL) &&
81 			(is_valid_dev((uintptr_t)entity->dev_handle));
82 	return result;
83 }
84 
85 
86 /* Return a boolean value indicating whether a seek mode is valid */
87 static int is_valid_seek_mode(io_seek_mode_t mode)
88 {
89 	return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX));
90 }
91 
92 #endif /* ENABLE_ASSERTIONS */
93 /* End of extra validation functions only used when asserts are enabled */
94 
95 
96 /* Open a connection to a specific device */
97 static int dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
98 		io_dev_info_t **dev_info)
99 {
100 	int result;
101 	assert(dev_info != NULL);
102 	assert(is_valid_dev_connector(dev_con));
103 
104 	result = dev_con->dev_open(dev_spec, dev_info);
105 	return result;
106 }
107 
108 
109 /* Set a handle to track an entity */
110 static void set_handle(uintptr_t *handle, io_entity_t *entity)
111 {
112 	assert(handle != NULL);
113 	*handle = (uintptr_t)entity;
114 }
115 
116 
117 /* Locate an entity in the pool, specified by address */
118 static int find_first_entity(const io_entity_t *entity, unsigned int *index_out)
119 {
120 	int result = -ENOENT;
121 	for (int index = 0; index < MAX_IO_HANDLES; ++index) {
122 		if (entity_map[index] == entity) {
123 			result = 0;
124 			*index_out = index;
125 			break;
126 		}
127 	}
128 	return result;
129 }
130 
131 
132 /* Allocate an entity from the pool and return a pointer to it */
133 static int allocate_entity(io_entity_t **entity)
134 {
135 	int result = -ENOMEM;
136 	assert(entity != NULL);
137 
138 	if (entity_count < MAX_IO_HANDLES) {
139 		unsigned int index = 0;
140 		result = find_first_entity(NULL, &index);
141 		assert(result == 0);
142 		*entity = entity_map[index] = &entity_pool[index];
143 		++entity_count;
144 	}
145 
146 	return result;
147 }
148 
149 
150 /* Release an entity back to the pool */
151 static int free_entity(const io_entity_t *entity)
152 {
153 	int result;
154 	unsigned int index = 0;
155 	assert(entity != NULL);
156 
157 	result = find_first_entity(entity, &index);
158 	if (result ==  0) {
159 		entity_map[index] = NULL;
160 		--entity_count;
161 	}
162 
163 	return result;
164 }
165 
166 
167 /* Exported API */
168 
169 /* Register a device driver */
170 int io_register_device(const io_dev_info_t *dev_info)
171 {
172 	int result = -ENOMEM;
173 	assert(dev_info != NULL);
174 
175 	if (dev_count < MAX_IO_DEVICES) {
176 		devices[dev_count] = dev_info;
177 		dev_count++;
178 		result = 0;
179 	}
180 
181 	return result;
182 }
183 
184 
185 /* Open a connection to an IO device */
186 int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
187 		uintptr_t *handle)
188 {
189 	int result;
190 	assert(handle != NULL);
191 
192 	result = dev_open(dev_con, dev_spec, (io_dev_info_t **)handle);
193 	return result;
194 }
195 
196 
197 /* Initialise an IO device explicitly - to permit lazy initialisation or
198  * re-initialisation */
199 int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params)
200 {
201 	int result = 0;
202 	assert(dev_handle != (uintptr_t)NULL);
203 	assert(is_valid_dev(dev_handle));
204 
205 	io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
206 
207 	/* Absence of registered function implies NOP here */
208 	if (dev->funcs->dev_init != NULL) {
209 		result = dev->funcs->dev_init(dev, init_params);
210 	}
211 
212 	return result;
213 }
214 
215 
216 /* TODO: Consider whether an explicit "shutdown" API should be included */
217 
218 /* Close a connection to a device */
219 int io_dev_close(uintptr_t dev_handle)
220 {
221 	int result = 0;
222 	assert(dev_handle != (uintptr_t)NULL);
223 	assert(is_valid_dev(dev_handle));
224 
225 	io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
226 
227 	/* Absence of registered function implies NOP here */
228 	if (dev->funcs->dev_close != NULL) {
229 		result = dev->funcs->dev_close(dev);
230 	}
231 
232 	return result;
233 }
234 
235 
236 /* Synchronous operations */
237 
238 
239 /* Open an IO entity */
240 int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle)
241 {
242 	int result;
243 	assert((spec != (uintptr_t)NULL) && (handle != NULL));
244 	assert(is_valid_dev(dev_handle));
245 
246 	io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
247 	io_entity_t *entity;
248 
249 	result = allocate_entity(&entity);
250 
251 	if (result == 0) {
252 		assert(dev->funcs->open != NULL);
253 		result = dev->funcs->open(dev, spec, entity);
254 
255 		if (result == 0) {
256 			entity->dev_handle = dev;
257 			set_handle(handle, entity);
258 		} else
259 			free_entity(entity);
260 	}
261 	return result;
262 }
263 
264 
265 /* Seek to a specific position in an IO entity */
266 int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset)
267 {
268 	int result = -ENODEV;
269 	assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
270 
271 	io_entity_t *entity = (io_entity_t *)handle;
272 
273 	io_dev_info_t *dev = entity->dev_handle;
274 
275 	if (dev->funcs->seek != NULL)
276 		result = dev->funcs->seek(entity, mode, offset);
277 
278 	return result;
279 }
280 
281 
282 /* Determine the length of an IO entity */
283 int io_size(uintptr_t handle, size_t *length)
284 {
285 	int result = -ENODEV;
286 	assert(is_valid_entity(handle) && (length != NULL));
287 
288 	io_entity_t *entity = (io_entity_t *)handle;
289 
290 	io_dev_info_t *dev = entity->dev_handle;
291 
292 	if (dev->funcs->size != NULL)
293 		result = dev->funcs->size(entity, length);
294 
295 	return result;
296 }
297 
298 
299 /* Read data from an IO entity */
300 int io_read(uintptr_t handle,
301 		uintptr_t buffer,
302 		size_t length,
303 		size_t *length_read)
304 {
305 	int result = -ENODEV;
306 	assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL));
307 
308 	io_entity_t *entity = (io_entity_t *)handle;
309 
310 	io_dev_info_t *dev = entity->dev_handle;
311 
312 	if (dev->funcs->read != NULL)
313 		result = dev->funcs->read(entity, buffer, length, length_read);
314 
315 	return result;
316 }
317 
318 
319 /* Write data to an IO entity */
320 int io_write(uintptr_t handle,
321 		const uintptr_t buffer,
322 		size_t length,
323 		size_t *length_written)
324 {
325 	int result = -ENODEV;
326 	assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL));
327 
328 	io_entity_t *entity = (io_entity_t *)handle;
329 
330 	io_dev_info_t *dev = entity->dev_handle;
331 
332 	if (dev->funcs->write != NULL) {
333 		result = dev->funcs->write(entity, buffer, length,
334 				length_written);
335 	}
336 
337 	return result;
338 }
339 
340 
341 /* Close an IO entity */
342 int io_close(uintptr_t handle)
343 {
344 	int result = 0;
345 	assert(is_valid_entity(handle));
346 
347 	io_entity_t *entity = (io_entity_t *)handle;
348 
349 	io_dev_info_t *dev = entity->dev_handle;
350 
351 	/* Absence of registered function implies NOP here */
352 	if (dev->funcs->close != NULL)
353 		result = dev->funcs->close(entity);
354 
355 	/* Ignore improbable free_entity failure */
356 	(void)free_entity(entity);
357 
358 	return result;
359 }
360