1 /*
2  * Copyright 2012-15 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include <linux/slab.h>
27 
28 #include "dm_services.h"
29 #include "include/vector.h"
30 
dal_vector_construct(struct vector * vector,struct dc_context * ctx,uint32_t capacity,uint32_t struct_size)31 bool dal_vector_construct(
32 	struct vector *vector,
33 	struct dc_context *ctx,
34 	uint32_t capacity,
35 	uint32_t struct_size)
36 {
37 	vector->container = NULL;
38 
39 	if (!struct_size || !capacity) {
40 		/* Container must be non-zero size*/
41 		BREAK_TO_DEBUGGER();
42 		return false;
43 	}
44 
45 	vector->container = kcalloc(capacity, struct_size, GFP_KERNEL);
46 	if (vector->container == NULL)
47 		return false;
48 	vector->capacity = capacity;
49 	vector->struct_size = struct_size;
50 	vector->count = 0;
51 	vector->ctx = ctx;
52 	return true;
53 }
54 
dal_vector_presized_costruct(struct vector * vector,struct dc_context * ctx,uint32_t count,void * initial_value,uint32_t struct_size)55 static bool dal_vector_presized_costruct(
56 	struct vector *vector,
57 	struct dc_context *ctx,
58 	uint32_t count,
59 	void *initial_value,
60 	uint32_t struct_size)
61 {
62 	uint32_t i;
63 
64 	vector->container = NULL;
65 
66 	if (!struct_size || !count) {
67 		/* Container must be non-zero size*/
68 		BREAK_TO_DEBUGGER();
69 		return false;
70 	}
71 
72 	vector->container = kcalloc(count, struct_size, GFP_KERNEL);
73 
74 	if (vector->container == NULL)
75 		return false;
76 
77 	/* If caller didn't supply initial value then the default
78 	 * of all zeros is expected, which is exactly what dal_alloc()
79 	 * initialises the memory to. */
80 	if (NULL != initial_value) {
81 		for (i = 0; i < count; ++i)
82 			memmove(
83 				vector->container + i * struct_size,
84 				initial_value,
85 				struct_size);
86 	}
87 
88 	vector->capacity = count;
89 	vector->struct_size = struct_size;
90 	vector->count = count;
91 	return true;
92 }
93 
dal_vector_presized_create(struct dc_context * ctx,uint32_t size,void * initial_value,uint32_t struct_size)94 struct vector *dal_vector_presized_create(
95 	struct dc_context *ctx,
96 	uint32_t size,
97 	void *initial_value,
98 	uint32_t struct_size)
99 {
100 	struct vector *vector = kzalloc(sizeof(struct vector), GFP_KERNEL);
101 
102 	if (vector == NULL)
103 		return NULL;
104 
105 	if (dal_vector_presized_costruct(
106 		vector, ctx, size, initial_value, struct_size))
107 		return vector;
108 
109 	BREAK_TO_DEBUGGER();
110 	kfree(vector);
111 	return NULL;
112 }
113 
dal_vector_create(struct dc_context * ctx,uint32_t capacity,uint32_t struct_size)114 struct vector *dal_vector_create(
115 	struct dc_context *ctx,
116 	uint32_t capacity,
117 	uint32_t struct_size)
118 {
119 	struct vector *vector = kzalloc(sizeof(struct vector), GFP_KERNEL);
120 
121 	if (vector == NULL)
122 		return NULL;
123 
124 	if (dal_vector_construct(vector, ctx, capacity, struct_size))
125 		return vector;
126 
127 	BREAK_TO_DEBUGGER();
128 	kfree(vector);
129 	return NULL;
130 }
131 
dal_vector_destruct(struct vector * vector)132 void dal_vector_destruct(
133 	struct vector *vector)
134 {
135 	kfree(vector->container);
136 	vector->count = 0;
137 	vector->capacity = 0;
138 }
139 
dal_vector_destroy(struct vector ** vector)140 void dal_vector_destroy(
141 	struct vector **vector)
142 {
143 	if (vector == NULL || *vector == NULL)
144 		return;
145 	dal_vector_destruct(*vector);
146 	kfree(*vector);
147 	*vector = NULL;
148 }
149 
dal_vector_get_count(const struct vector * vector)150 uint32_t dal_vector_get_count(
151 	const struct vector *vector)
152 {
153 	return vector->count;
154 }
155 
dal_vector_at_index(const struct vector * vector,uint32_t index)156 void *dal_vector_at_index(
157 	const struct vector *vector,
158 	uint32_t index)
159 {
160 	if (vector->container == NULL || index >= vector->count)
161 		return NULL;
162 	return vector->container + (index * vector->struct_size);
163 }
164 
dal_vector_remove_at_index(struct vector * vector,uint32_t index)165 bool dal_vector_remove_at_index(
166 	struct vector *vector,
167 	uint32_t index)
168 {
169 	if (index >= vector->count)
170 		return false;
171 
172 	if (index != vector->count - 1)
173 		memmove(
174 			vector->container + (index * vector->struct_size),
175 			vector->container + ((index + 1) * vector->struct_size),
176 			(vector->count - index - 1) * vector->struct_size);
177 	vector->count -= 1;
178 
179 	return true;
180 }
181 
dal_vector_set_at_index(const struct vector * vector,const void * what,uint32_t index)182 void dal_vector_set_at_index(
183 	const struct vector *vector,
184 	const void *what,
185 	uint32_t index)
186 {
187 	void *where = dal_vector_at_index(vector, index);
188 
189 	if (!where) {
190 		BREAK_TO_DEBUGGER();
191 		return;
192 	}
193 	memmove(
194 		where,
195 		what,
196 		vector->struct_size);
197 }
198 
calc_increased_capacity(uint32_t old_capacity)199 static inline uint32_t calc_increased_capacity(
200 	uint32_t old_capacity)
201 {
202 	return old_capacity * 2;
203 }
204 
dal_vector_insert_at(struct vector * vector,const void * what,uint32_t position)205 bool dal_vector_insert_at(
206 	struct vector *vector,
207 	const void *what,
208 	uint32_t position)
209 {
210 	uint8_t *insert_address;
211 
212 	if (vector->count == vector->capacity) {
213 		if (!dal_vector_reserve(
214 			vector,
215 			calc_increased_capacity(vector->capacity)))
216 			return false;
217 	}
218 
219 	insert_address = vector->container + (vector->struct_size * position);
220 
221 	if (vector->count && position < vector->count)
222 		memmove(
223 			insert_address + vector->struct_size,
224 			insert_address,
225 			vector->struct_size * (vector->count - position));
226 
227 	memmove(
228 		insert_address,
229 		what,
230 		vector->struct_size);
231 
232 	vector->count++;
233 
234 	return true;
235 }
236 
dal_vector_append(struct vector * vector,const void * item)237 bool dal_vector_append(
238 	struct vector *vector,
239 	const void *item)
240 {
241 	return dal_vector_insert_at(vector, item, vector->count);
242 }
243 
dal_vector_clone(const struct vector * vector)244 struct vector *dal_vector_clone(
245 	const struct vector *vector)
246 {
247 	struct vector *vec_cloned;
248 	uint32_t count;
249 
250 	/* create new vector */
251 	count = dal_vector_get_count(vector);
252 
253 	if (count == 0)
254 		/* when count is 0 we still want to create clone of the vector
255 		 */
256 		vec_cloned = dal_vector_create(
257 			vector->ctx,
258 			vector->capacity,
259 			vector->struct_size);
260 	else
261 		/* Call "presized create" version, independently of how the
262 		 * original vector was created.
263 		 * The owner of original vector must know how to treat the new
264 		 * vector - as "presized" or as "regular".
265 		 * But from vector point of view it doesn't matter. */
266 		vec_cloned = dal_vector_presized_create(vector->ctx, count,
267 			NULL,/* no initial value */
268 			vector->struct_size);
269 
270 	if (NULL == vec_cloned) {
271 		BREAK_TO_DEBUGGER();
272 		return NULL;
273 	}
274 
275 	/* copy vector's data */
276 	memmove(vec_cloned->container, vector->container,
277 			vec_cloned->struct_size * vec_cloned->capacity);
278 
279 	return vec_cloned;
280 }
281 
dal_vector_capacity(const struct vector * vector)282 uint32_t dal_vector_capacity(const struct vector *vector)
283 {
284 	return vector->capacity;
285 }
286 
dal_vector_reserve(struct vector * vector,uint32_t capacity)287 bool dal_vector_reserve(struct vector *vector, uint32_t capacity)
288 {
289 	void *new_container;
290 
291 	if (capacity <= vector->capacity)
292 		return true;
293 
294 	new_container = krealloc(vector->container,
295 				 capacity * vector->struct_size, GFP_KERNEL);
296 
297 	if (new_container) {
298 		vector->container = new_container;
299 		vector->capacity = capacity;
300 		return true;
301 	}
302 
303 	return false;
304 }
305 
dal_vector_clear(struct vector * vector)306 void dal_vector_clear(struct vector *vector)
307 {
308 	vector->count = 0;
309 }
310