Commit | Line | Data |
---|---|---|
1394f032 | 1 | /* |
96f1050d | 2 | * SRAM allocator for Blackfin on-chip memory |
1394f032 | 3 | * |
96f1050d | 4 | * Copyright 2004-2009 Analog Devices Inc. |
1394f032 | 5 | * |
96f1050d | 6 | * Licensed under the GPL-2 or later. |
1394f032 BW |
7 | */ |
8 | ||
1394f032 BW |
9 | #include <linux/module.h> |
10 | #include <linux/kernel.h> | |
11 | #include <linux/types.h> | |
12 | #include <linux/miscdevice.h> | |
13 | #include <linux/ioport.h> | |
14 | #include <linux/fcntl.h> | |
15 | #include <linux/init.h> | |
16 | #include <linux/poll.h> | |
17 | #include <linux/proc_fs.h> | |
18 | #include <linux/spinlock.h> | |
19 | #include <linux/rtc.h> | |
20 | #include <asm/blackfin.h> | |
dbc895f9 | 21 | #include <asm/mem_map.h> |
1394f032 BW |
22 | #include "blackfin_sram.h" |
23 | ||
1394f032 | 24 | /* the data structure for L1 scratchpad and DATA SRAM */ |
5d481f49 | 25 | struct sram_piece { |
1394f032 BW |
26 | void *paddr; |
27 | int size; | |
bc61b4e6 | 28 | pid_t pid; |
5d481f49 | 29 | struct sram_piece *next; |
1394f032 BW |
30 | }; |
31 | ||
81c969a8 | 32 | static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1sram_lock); |
8f65873e GY |
33 | static DEFINE_PER_CPU(struct sram_piece, free_l1_ssram_head); |
34 | static DEFINE_PER_CPU(struct sram_piece, used_l1_ssram_head); | |
1394f032 BW |
35 | |
36 | #if L1_DATA_A_LENGTH != 0 | |
8f65873e GY |
37 | static DEFINE_PER_CPU(struct sram_piece, free_l1_data_A_sram_head); |
38 | static DEFINE_PER_CPU(struct sram_piece, used_l1_data_A_sram_head); | |
1394f032 BW |
39 | #endif |
40 | ||
41 | #if L1_DATA_B_LENGTH != 0 | |
8f65873e GY |
42 | static DEFINE_PER_CPU(struct sram_piece, free_l1_data_B_sram_head); |
43 | static DEFINE_PER_CPU(struct sram_piece, used_l1_data_B_sram_head); | |
1394f032 BW |
44 | #endif |
45 | ||
81c969a8 MF |
46 | #if L1_DATA_A_LENGTH || L1_DATA_B_LENGTH |
47 | static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_data_sram_lock); | |
48 | #endif | |
49 | ||
1394f032 | 50 | #if L1_CODE_LENGTH != 0 |
81c969a8 | 51 | static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_inst_sram_lock); |
8f65873e GY |
52 | static DEFINE_PER_CPU(struct sram_piece, free_l1_inst_sram_head); |
53 | static DEFINE_PER_CPU(struct sram_piece, used_l1_inst_sram_head); | |
1394f032 BW |
54 | #endif |
55 | ||
07aa7be5 | 56 | #if L2_LENGTH != 0 |
81c969a8 | 57 | static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp; |
262c3825 SZ |
58 | static struct sram_piece free_l2_sram_head, used_l2_sram_head; |
59 | #endif | |
60 | ||
5d481f49 SZ |
61 | static struct kmem_cache *sram_piece_cache; |
62 | ||
1394f032 | 63 | /* L1 Scratchpad SRAM initialization function */ |
5d481f49 | 64 | static void __init l1sram_init(void) |
1394f032 | 65 | { |
8f65873e | 66 | unsigned int cpu; |
89ecd506 GY |
67 | unsigned long reserve; |
68 | ||
69 | #ifdef CONFIG_SMP | |
70 | reserve = 0; | |
71 | #else | |
72 | reserve = sizeof(struct l1_scratch_task_info); | |
73 | #endif | |
74 | ||
8f65873e GY |
75 | for (cpu = 0; cpu < num_possible_cpus(); ++cpu) { |
76 | per_cpu(free_l1_ssram_head, cpu).next = | |
77 | kmem_cache_alloc(sram_piece_cache, GFP_KERNEL); | |
78 | if (!per_cpu(free_l1_ssram_head, cpu).next) { | |
79 | printk(KERN_INFO "Fail to initialize Scratchpad data SRAM.\n"); | |
80 | return; | |
81 | } | |
82 | ||
89ecd506 GY |
83 | per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu) + reserve; |
84 | per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH - reserve; | |
8f65873e GY |
85 | per_cpu(free_l1_ssram_head, cpu).next->pid = 0; |
86 | per_cpu(free_l1_ssram_head, cpu).next->next = NULL; | |
87 | ||
88 | per_cpu(used_l1_ssram_head, cpu).next = NULL; | |
89 | ||
90 | /* mutex initialize */ | |
91 | spin_lock_init(&per_cpu(l1sram_lock, cpu)); | |
92 | printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n", | |
93 | L1_SCRATCH_LENGTH >> 10); | |
5d481f49 | 94 | } |
1394f032 BW |
95 | } |
96 | ||
5d481f49 | 97 | static void __init l1_data_sram_init(void) |
1394f032 | 98 | { |
0b82e274 | 99 | #if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0 |
8f65873e | 100 | unsigned int cpu; |
0b82e274 | 101 | #endif |
1394f032 | 102 | #if L1_DATA_A_LENGTH != 0 |
8f65873e GY |
103 | for (cpu = 0; cpu < num_possible_cpus(); ++cpu) { |
104 | per_cpu(free_l1_data_A_sram_head, cpu).next = | |
105 | kmem_cache_alloc(sram_piece_cache, GFP_KERNEL); | |
106 | if (!per_cpu(free_l1_data_A_sram_head, cpu).next) { | |
107 | printk(KERN_INFO "Fail to initialize L1 Data A SRAM.\n"); | |
108 | return; | |
109 | } | |
110 | ||
111 | per_cpu(free_l1_data_A_sram_head, cpu).next->paddr = | |
112 | (void *)get_l1_data_a_start_cpu(cpu) + (_ebss_l1 - _sdata_l1); | |
113 | per_cpu(free_l1_data_A_sram_head, cpu).next->size = | |
114 | L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1); | |
115 | per_cpu(free_l1_data_A_sram_head, cpu).next->pid = 0; | |
116 | per_cpu(free_l1_data_A_sram_head, cpu).next->next = NULL; | |
117 | ||
118 | per_cpu(used_l1_data_A_sram_head, cpu).next = NULL; | |
119 | ||
120 | printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n", | |
121 | L1_DATA_A_LENGTH >> 10, | |
122 | per_cpu(free_l1_data_A_sram_head, cpu).next->size >> 10); | |
5d481f49 | 123 | } |
1394f032 BW |
124 | #endif |
125 | #if L1_DATA_B_LENGTH != 0 | |
8f65873e GY |
126 | for (cpu = 0; cpu < num_possible_cpus(); ++cpu) { |
127 | per_cpu(free_l1_data_B_sram_head, cpu).next = | |
128 | kmem_cache_alloc(sram_piece_cache, GFP_KERNEL); | |
129 | if (!per_cpu(free_l1_data_B_sram_head, cpu).next) { | |
130 | printk(KERN_INFO "Fail to initialize L1 Data B SRAM.\n"); | |
131 | return; | |
132 | } | |
133 | ||
134 | per_cpu(free_l1_data_B_sram_head, cpu).next->paddr = | |
135 | (void *)get_l1_data_b_start_cpu(cpu) + (_ebss_b_l1 - _sdata_b_l1); | |
136 | per_cpu(free_l1_data_B_sram_head, cpu).next->size = | |
137 | L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1); | |
138 | per_cpu(free_l1_data_B_sram_head, cpu).next->pid = 0; | |
139 | per_cpu(free_l1_data_B_sram_head, cpu).next->next = NULL; | |
140 | ||
141 | per_cpu(used_l1_data_B_sram_head, cpu).next = NULL; | |
142 | ||
143 | printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n", | |
144 | L1_DATA_B_LENGTH >> 10, | |
145 | per_cpu(free_l1_data_B_sram_head, cpu).next->size >> 10); | |
146 | /* mutex initialize */ | |
5d481f49 | 147 | } |
1394f032 BW |
148 | #endif |
149 | ||
8f65873e GY |
150 | #if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0 |
151 | for (cpu = 0; cpu < num_possible_cpus(); ++cpu) | |
152 | spin_lock_init(&per_cpu(l1_data_sram_lock, cpu)); | |
153 | #endif | |
1394f032 BW |
154 | } |
155 | ||
5d481f49 | 156 | static void __init l1_inst_sram_init(void) |
1394f032 BW |
157 | { |
158 | #if L1_CODE_LENGTH != 0 | |
8f65873e GY |
159 | unsigned int cpu; |
160 | for (cpu = 0; cpu < num_possible_cpus(); ++cpu) { | |
161 | per_cpu(free_l1_inst_sram_head, cpu).next = | |
162 | kmem_cache_alloc(sram_piece_cache, GFP_KERNEL); | |
163 | if (!per_cpu(free_l1_inst_sram_head, cpu).next) { | |
164 | printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n"); | |
165 | return; | |
166 | } | |
167 | ||
168 | per_cpu(free_l1_inst_sram_head, cpu).next->paddr = | |
169 | (void *)get_l1_code_start_cpu(cpu) + (_etext_l1 - _stext_l1); | |
170 | per_cpu(free_l1_inst_sram_head, cpu).next->size = | |
171 | L1_CODE_LENGTH - (_etext_l1 - _stext_l1); | |
172 | per_cpu(free_l1_inst_sram_head, cpu).next->pid = 0; | |
173 | per_cpu(free_l1_inst_sram_head, cpu).next->next = NULL; | |
174 | ||
175 | per_cpu(used_l1_inst_sram_head, cpu).next = NULL; | |
176 | ||
177 | printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n", | |
178 | L1_CODE_LENGTH >> 10, | |
179 | per_cpu(free_l1_inst_sram_head, cpu).next->size >> 10); | |
180 | ||
181 | /* mutex initialize */ | |
182 | spin_lock_init(&per_cpu(l1_inst_sram_lock, cpu)); | |
5d481f49 | 183 | } |
1394f032 | 184 | #endif |
1394f032 BW |
185 | } |
186 | ||
262c3825 SZ |
187 | static void __init l2_sram_init(void) |
188 | { | |
07aa7be5 | 189 | #if L2_LENGTH != 0 |
262c3825 SZ |
190 | free_l2_sram_head.next = |
191 | kmem_cache_alloc(sram_piece_cache, GFP_KERNEL); | |
192 | if (!free_l2_sram_head.next) { | |
8f65873e | 193 | printk(KERN_INFO "Fail to initialize L2 SRAM.\n"); |
262c3825 SZ |
194 | return; |
195 | } | |
196 | ||
b2c2f303 JZ |
197 | free_l2_sram_head.next->paddr = |
198 | (void *)L2_START + (_ebss_l2 - _stext_l2); | |
199 | free_l2_sram_head.next->size = | |
200 | L2_LENGTH - (_ebss_l2 - _stext_l2); | |
262c3825 SZ |
201 | free_l2_sram_head.next->pid = 0; |
202 | free_l2_sram_head.next->next = NULL; | |
203 | ||
204 | used_l2_sram_head.next = NULL; | |
205 | ||
206 | printk(KERN_INFO "Blackfin L2 SRAM: %d KB (%d KB free)\n", | |
207 | L2_LENGTH >> 10, | |
208 | free_l2_sram_head.next->size >> 10); | |
262c3825 SZ |
209 | |
210 | /* mutex initialize */ | |
211 | spin_lock_init(&l2_sram_lock); | |
81c969a8 | 212 | #endif |
262c3825 | 213 | } |
8f65873e | 214 | |
c72aa079 | 215 | static int __init bfin_sram_init(void) |
5d481f49 SZ |
216 | { |
217 | sram_piece_cache = kmem_cache_create("sram_piece_cache", | |
218 | sizeof(struct sram_piece), | |
219 | 0, SLAB_PANIC, NULL); | |
220 | ||
221 | l1sram_init(); | |
222 | l1_data_sram_init(); | |
223 | l1_inst_sram_init(); | |
262c3825 | 224 | l2_sram_init(); |
c72aa079 GY |
225 | |
226 | return 0; | |
5d481f49 | 227 | } |
c72aa079 | 228 | pure_initcall(bfin_sram_init); |
5d481f49 | 229 | |
262c3825 SZ |
230 | /* SRAM allocate function */ |
231 | static void *_sram_alloc(size_t size, struct sram_piece *pfree_head, | |
5d481f49 | 232 | struct sram_piece *pused_head) |
1394f032 | 233 | { |
5d481f49 | 234 | struct sram_piece *pslot, *plast, *pavail; |
1394f032 | 235 | |
5d481f49 | 236 | if (size <= 0 || !pfree_head || !pused_head) |
1394f032 BW |
237 | return NULL; |
238 | ||
239 | /* Align the size */ | |
240 | size = (size + 3) & ~3; | |
241 | ||
5d481f49 SZ |
242 | pslot = pfree_head->next; |
243 | plast = pfree_head; | |
244 | ||
245 | /* search an available piece slot */ | |
246 | while (pslot != NULL && size > pslot->size) { | |
247 | plast = pslot; | |
248 | pslot = pslot->next; | |
1394f032 | 249 | } |
5d481f49 SZ |
250 | |
251 | if (!pslot) | |
1394f032 BW |
252 | return NULL; |
253 | ||
5d481f49 SZ |
254 | if (pslot->size == size) { |
255 | plast->next = pslot->next; | |
256 | pavail = pslot; | |
257 | } else { | |
258 | pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL); | |
259 | ||
260 | if (!pavail) | |
261 | return NULL; | |
262 | ||
263 | pavail->paddr = pslot->paddr; | |
264 | pavail->size = size; | |
265 | pslot->paddr += size; | |
266 | pslot->size -= size; | |
1394f032 BW |
267 | } |
268 | ||
5d481f49 SZ |
269 | pavail->pid = current->pid; |
270 | ||
271 | pslot = pused_head->next; | |
272 | plast = pused_head; | |
273 | ||
274 | /* insert new piece into used piece list !!! */ | |
275 | while (pslot != NULL && pavail->paddr < pslot->paddr) { | |
276 | plast = pslot; | |
277 | pslot = pslot->next; | |
278 | } | |
279 | ||
280 | pavail->next = pslot; | |
281 | plast->next = pavail; | |
282 | ||
283 | return pavail->paddr; | |
1394f032 BW |
284 | } |
285 | ||
286 | /* Allocate the largest available block. */ | |
262c3825 | 287 | static void *_sram_alloc_max(struct sram_piece *pfree_head, |
5d481f49 | 288 | struct sram_piece *pused_head, |
1394f032 BW |
289 | unsigned long *psize) |
290 | { | |
5d481f49 SZ |
291 | struct sram_piece *pslot, *pmax; |
292 | ||
293 | if (!pfree_head || !pused_head) | |
294 | return NULL; | |
295 | ||
296 | pmax = pslot = pfree_head->next; | |
1394f032 | 297 | |
5d481f49 SZ |
298 | /* search an available piece slot */ |
299 | while (pslot != NULL) { | |
300 | if (pslot->size > pmax->size) | |
301 | pmax = pslot; | |
302 | pslot = pslot->next; | |
1394f032 | 303 | } |
5d481f49 SZ |
304 | |
305 | if (!pmax) | |
1394f032 | 306 | return NULL; |
1394f032 | 307 | |
5d481f49 SZ |
308 | *psize = pmax->size; |
309 | ||
262c3825 | 310 | return _sram_alloc(*psize, pfree_head, pused_head); |
1394f032 BW |
311 | } |
312 | ||
262c3825 SZ |
313 | /* SRAM free function */ |
314 | static int _sram_free(const void *addr, | |
5d481f49 SZ |
315 | struct sram_piece *pfree_head, |
316 | struct sram_piece *pused_head) | |
1394f032 | 317 | { |
5d481f49 SZ |
318 | struct sram_piece *pslot, *plast, *pavail; |
319 | ||
320 | if (!pfree_head || !pused_head) | |
321 | return -1; | |
1394f032 BW |
322 | |
323 | /* search the relevant memory slot */ | |
5d481f49 SZ |
324 | pslot = pused_head->next; |
325 | plast = pused_head; | |
326 | ||
327 | /* search an available piece slot */ | |
328 | while (pslot != NULL && pslot->paddr != addr) { | |
329 | plast = pslot; | |
330 | pslot = pslot->next; | |
1394f032 | 331 | } |
5d481f49 SZ |
332 | |
333 | if (!pslot) | |
1394f032 BW |
334 | return -1; |
335 | ||
5d481f49 SZ |
336 | plast->next = pslot->next; |
337 | pavail = pslot; | |
338 | pavail->pid = 0; | |
339 | ||
340 | /* insert free pieces back to the free list */ | |
341 | pslot = pfree_head->next; | |
342 | plast = pfree_head; | |
343 | ||
344 | while (pslot != NULL && addr > pslot->paddr) { | |
345 | plast = pslot; | |
346 | pslot = pslot->next; | |
347 | } | |
348 | ||
349 | if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) { | |
350 | plast->size += pavail->size; | |
351 | kmem_cache_free(sram_piece_cache, pavail); | |
352 | } else { | |
225f7e1e | 353 | pavail->next = plast->next; |
5d481f49 SZ |
354 | plast->next = pavail; |
355 | plast = pavail; | |
1394f032 BW |
356 | } |
357 | ||
5d481f49 SZ |
358 | if (pslot && plast->paddr + plast->size == pslot->paddr) { |
359 | plast->size += pslot->size; | |
360 | plast->next = pslot->next; | |
361 | kmem_cache_free(sram_piece_cache, pslot); | |
1394f032 BW |
362 | } |
363 | ||
364 | return 0; | |
365 | } | |
366 | ||
367 | int sram_free(const void *addr) | |
368 | { | |
5e95320f | 369 | |
1394f032 | 370 | #if L1_CODE_LENGTH != 0 |
8f65873e GY |
371 | if (addr >= (void *)get_l1_code_start() |
372 | && addr < (void *)(get_l1_code_start() + L1_CODE_LENGTH)) | |
1394f032 | 373 | return l1_inst_sram_free(addr); |
5e95320f | 374 | else |
1394f032 BW |
375 | #endif |
376 | #if L1_DATA_A_LENGTH != 0 | |
8f65873e GY |
377 | if (addr >= (void *)get_l1_data_a_start() |
378 | && addr < (void *)(get_l1_data_a_start() + L1_DATA_A_LENGTH)) | |
1394f032 | 379 | return l1_data_A_sram_free(addr); |
5e95320f | 380 | else |
1394f032 BW |
381 | #endif |
382 | #if L1_DATA_B_LENGTH != 0 | |
8f65873e GY |
383 | if (addr >= (void *)get_l1_data_b_start() |
384 | && addr < (void *)(get_l1_data_b_start() + L1_DATA_B_LENGTH)) | |
1394f032 | 385 | return l1_data_B_sram_free(addr); |
5e95320f | 386 | else |
262c3825 | 387 | #endif |
07aa7be5 | 388 | #if L2_LENGTH != 0 |
5e95320f | 389 | if (addr >= (void *)L2_START |
262c3825 SZ |
390 | && addr < (void *)(L2_START + L2_LENGTH)) |
391 | return l2_sram_free(addr); | |
1394f032 | 392 | else |
5e95320f | 393 | #endif |
1394f032 BW |
394 | return -1; |
395 | } | |
396 | EXPORT_SYMBOL(sram_free); | |
397 | ||
398 | void *l1_data_A_sram_alloc(size_t size) | |
399 | { | |
81c969a8 | 400 | #if L1_DATA_A_LENGTH != 0 |
226a6ec3 | 401 | unsigned long flags; |
81c969a8 | 402 | void *addr; |
8f65873e | 403 | unsigned int cpu; |
1394f032 | 404 | |
8f65873e | 405 | cpu = get_cpu(); |
1394f032 | 406 | /* add mutex operation */ |
8f65873e | 407 | spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags); |
1394f032 | 408 | |
8f65873e GY |
409 | addr = _sram_alloc(size, &per_cpu(free_l1_data_A_sram_head, cpu), |
410 | &per_cpu(used_l1_data_A_sram_head, cpu)); | |
1394f032 BW |
411 | |
412 | /* add mutex operation */ | |
8f65873e GY |
413 | spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags); |
414 | put_cpu(); | |
1394f032 BW |
415 | |
416 | pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n", | |
417 | (long unsigned int)addr, size); | |
418 | ||
419 | return addr; | |
81c969a8 MF |
420 | #else |
421 | return NULL; | |
422 | #endif | |
1394f032 BW |
423 | } |
424 | EXPORT_SYMBOL(l1_data_A_sram_alloc); | |
425 | ||
426 | int l1_data_A_sram_free(const void *addr) | |
427 | { | |
81c969a8 | 428 | #if L1_DATA_A_LENGTH != 0 |
226a6ec3 | 429 | unsigned long flags; |
1394f032 | 430 | int ret; |
8f65873e | 431 | unsigned int cpu; |
1394f032 | 432 | |
8f65873e | 433 | cpu = get_cpu(); |
1394f032 | 434 | /* add mutex operation */ |
8f65873e | 435 | spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags); |
1394f032 | 436 | |
8f65873e GY |
437 | ret = _sram_free(addr, &per_cpu(free_l1_data_A_sram_head, cpu), |
438 | &per_cpu(used_l1_data_A_sram_head, cpu)); | |
1394f032 BW |
439 | |
440 | /* add mutex operation */ | |
8f65873e GY |
441 | spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags); |
442 | put_cpu(); | |
1394f032 BW |
443 | |
444 | return ret; | |
81c969a8 MF |
445 | #else |
446 | return -1; | |
447 | #endif | |
1394f032 BW |
448 | } |
449 | EXPORT_SYMBOL(l1_data_A_sram_free); | |
450 | ||
451 | void *l1_data_B_sram_alloc(size_t size) | |
452 | { | |
453 | #if L1_DATA_B_LENGTH != 0 | |
226a6ec3 | 454 | unsigned long flags; |
1394f032 | 455 | void *addr; |
8f65873e | 456 | unsigned int cpu; |
1394f032 | 457 | |
8f65873e | 458 | cpu = get_cpu(); |
1394f032 | 459 | /* add mutex operation */ |
8f65873e | 460 | spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags); |
1394f032 | 461 | |
8f65873e GY |
462 | addr = _sram_alloc(size, &per_cpu(free_l1_data_B_sram_head, cpu), |
463 | &per_cpu(used_l1_data_B_sram_head, cpu)); | |
1394f032 BW |
464 | |
465 | /* add mutex operation */ | |
8f65873e GY |
466 | spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags); |
467 | put_cpu(); | |
1394f032 BW |
468 | |
469 | pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n", | |
470 | (long unsigned int)addr, size); | |
471 | ||
472 | return addr; | |
473 | #else | |
474 | return NULL; | |
475 | #endif | |
476 | } | |
477 | EXPORT_SYMBOL(l1_data_B_sram_alloc); | |
478 | ||
479 | int l1_data_B_sram_free(const void *addr) | |
480 | { | |
481 | #if L1_DATA_B_LENGTH != 0 | |
226a6ec3 | 482 | unsigned long flags; |
1394f032 | 483 | int ret; |
8f65873e | 484 | unsigned int cpu; |
1394f032 | 485 | |
8f65873e | 486 | cpu = get_cpu(); |
1394f032 | 487 | /* add mutex operation */ |
8f65873e | 488 | spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags); |
1394f032 | 489 | |
8f65873e GY |
490 | ret = _sram_free(addr, &per_cpu(free_l1_data_B_sram_head, cpu), |
491 | &per_cpu(used_l1_data_B_sram_head, cpu)); | |
1394f032 BW |
492 | |
493 | /* add mutex operation */ | |
8f65873e GY |
494 | spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags); |
495 | put_cpu(); | |
1394f032 BW |
496 | |
497 | return ret; | |
498 | #else | |
499 | return -1; | |
500 | #endif | |
501 | } | |
502 | EXPORT_SYMBOL(l1_data_B_sram_free); | |
503 | ||
504 | void *l1_data_sram_alloc(size_t size) | |
505 | { | |
506 | void *addr = l1_data_A_sram_alloc(size); | |
507 | ||
508 | if (!addr) | |
509 | addr = l1_data_B_sram_alloc(size); | |
510 | ||
511 | return addr; | |
512 | } | |
513 | EXPORT_SYMBOL(l1_data_sram_alloc); | |
514 | ||
515 | void *l1_data_sram_zalloc(size_t size) | |
516 | { | |
517 | void *addr = l1_data_sram_alloc(size); | |
518 | ||
519 | if (addr) | |
520 | memset(addr, 0x00, size); | |
521 | ||
522 | return addr; | |
523 | } | |
524 | EXPORT_SYMBOL(l1_data_sram_zalloc); | |
525 | ||
526 | int l1_data_sram_free(const void *addr) | |
527 | { | |
528 | int ret; | |
529 | ret = l1_data_A_sram_free(addr); | |
530 | if (ret == -1) | |
531 | ret = l1_data_B_sram_free(addr); | |
532 | return ret; | |
533 | } | |
534 | EXPORT_SYMBOL(l1_data_sram_free); | |
535 | ||
536 | void *l1_inst_sram_alloc(size_t size) | |
537 | { | |
c5b50df8 | 538 | #if L1_CODE_LENGTH != 0 |
226a6ec3 | 539 | unsigned long flags; |
1394f032 | 540 | void *addr; |
8f65873e | 541 | unsigned int cpu; |
1394f032 | 542 | |
8f65873e | 543 | cpu = get_cpu(); |
1394f032 | 544 | /* add mutex operation */ |
8f65873e | 545 | spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags); |
1394f032 | 546 | |
8f65873e GY |
547 | addr = _sram_alloc(size, &per_cpu(free_l1_inst_sram_head, cpu), |
548 | &per_cpu(used_l1_inst_sram_head, cpu)); | |
1394f032 BW |
549 | |
550 | /* add mutex operation */ | |
8f65873e GY |
551 | spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags); |
552 | put_cpu(); | |
1394f032 BW |
553 | |
554 | pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n", | |
555 | (long unsigned int)addr, size); | |
556 | ||
557 | return addr; | |
558 | #else | |
559 | return NULL; | |
560 | #endif | |
561 | } | |
562 | EXPORT_SYMBOL(l1_inst_sram_alloc); | |
563 | ||
564 | int l1_inst_sram_free(const void *addr) | |
565 | { | |
566 | #if L1_CODE_LENGTH != 0 | |
226a6ec3 | 567 | unsigned long flags; |
1394f032 | 568 | int ret; |
8f65873e | 569 | unsigned int cpu; |
1394f032 | 570 | |
8f65873e | 571 | cpu = get_cpu(); |
1394f032 | 572 | /* add mutex operation */ |
8f65873e | 573 | spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags); |
1394f032 | 574 | |
8f65873e GY |
575 | ret = _sram_free(addr, &per_cpu(free_l1_inst_sram_head, cpu), |
576 | &per_cpu(used_l1_inst_sram_head, cpu)); | |
1394f032 BW |
577 | |
578 | /* add mutex operation */ | |
8f65873e GY |
579 | spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags); |
580 | put_cpu(); | |
1394f032 BW |
581 | |
582 | return ret; | |
583 | #else | |
584 | return -1; | |
585 | #endif | |
586 | } | |
587 | EXPORT_SYMBOL(l1_inst_sram_free); | |
588 | ||
589 | /* L1 Scratchpad memory allocate function */ | |
590 | void *l1sram_alloc(size_t size) | |
591 | { | |
226a6ec3 | 592 | unsigned long flags; |
1394f032 | 593 | void *addr; |
8f65873e | 594 | unsigned int cpu; |
1394f032 | 595 | |
8f65873e | 596 | cpu = get_cpu(); |
1394f032 | 597 | /* add mutex operation */ |
8f65873e | 598 | spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags); |
1394f032 | 599 | |
8f65873e GY |
600 | addr = _sram_alloc(size, &per_cpu(free_l1_ssram_head, cpu), |
601 | &per_cpu(used_l1_ssram_head, cpu)); | |
1394f032 BW |
602 | |
603 | /* add mutex operation */ | |
8f65873e GY |
604 | spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags); |
605 | put_cpu(); | |
1394f032 BW |
606 | |
607 | return addr; | |
608 | } | |
609 | ||
610 | /* L1 Scratchpad memory allocate function */ | |
611 | void *l1sram_alloc_max(size_t *psize) | |
612 | { | |
226a6ec3 | 613 | unsigned long flags; |
1394f032 | 614 | void *addr; |
8f65873e | 615 | unsigned int cpu; |
1394f032 | 616 | |
8f65873e | 617 | cpu = get_cpu(); |
1394f032 | 618 | /* add mutex operation */ |
8f65873e | 619 | spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags); |
1394f032 | 620 | |
8f65873e GY |
621 | addr = _sram_alloc_max(&per_cpu(free_l1_ssram_head, cpu), |
622 | &per_cpu(used_l1_ssram_head, cpu), psize); | |
1394f032 BW |
623 | |
624 | /* add mutex operation */ | |
8f65873e GY |
625 | spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags); |
626 | put_cpu(); | |
1394f032 BW |
627 | |
628 | return addr; | |
629 | } | |
630 | ||
631 | /* L1 Scratchpad memory free function */ | |
632 | int l1sram_free(const void *addr) | |
633 | { | |
226a6ec3 | 634 | unsigned long flags; |
1394f032 | 635 | int ret; |
8f65873e | 636 | unsigned int cpu; |
1394f032 | 637 | |
8f65873e | 638 | cpu = get_cpu(); |
1394f032 | 639 | /* add mutex operation */ |
8f65873e | 640 | spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags); |
1394f032 | 641 | |
8f65873e GY |
642 | ret = _sram_free(addr, &per_cpu(free_l1_ssram_head, cpu), |
643 | &per_cpu(used_l1_ssram_head, cpu)); | |
1394f032 BW |
644 | |
645 | /* add mutex operation */ | |
8f65873e GY |
646 | spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags); |
647 | put_cpu(); | |
1394f032 BW |
648 | |
649 | return ret; | |
650 | } | |
651 | ||
262c3825 SZ |
652 | void *l2_sram_alloc(size_t size) |
653 | { | |
07aa7be5 | 654 | #if L2_LENGTH != 0 |
226a6ec3 | 655 | unsigned long flags; |
262c3825 SZ |
656 | void *addr; |
657 | ||
658 | /* add mutex operation */ | |
659 | spin_lock_irqsave(&l2_sram_lock, flags); | |
660 | ||
661 | addr = _sram_alloc(size, &free_l2_sram_head, | |
662 | &used_l2_sram_head); | |
663 | ||
664 | /* add mutex operation */ | |
665 | spin_unlock_irqrestore(&l2_sram_lock, flags); | |
666 | ||
667 | pr_debug("Allocated address in l2_sram_alloc is 0x%lx+0x%lx\n", | |
668 | (long unsigned int)addr, size); | |
669 | ||
670 | return addr; | |
671 | #else | |
672 | return NULL; | |
673 | #endif | |
674 | } | |
675 | EXPORT_SYMBOL(l2_sram_alloc); | |
676 | ||
677 | void *l2_sram_zalloc(size_t size) | |
678 | { | |
679 | void *addr = l2_sram_alloc(size); | |
680 | ||
681 | if (addr) | |
682 | memset(addr, 0x00, size); | |
683 | ||
684 | return addr; | |
685 | } | |
686 | EXPORT_SYMBOL(l2_sram_zalloc); | |
687 | ||
688 | int l2_sram_free(const void *addr) | |
689 | { | |
07aa7be5 | 690 | #if L2_LENGTH != 0 |
226a6ec3 | 691 | unsigned long flags; |
262c3825 SZ |
692 | int ret; |
693 | ||
694 | /* add mutex operation */ | |
695 | spin_lock_irqsave(&l2_sram_lock, flags); | |
696 | ||
697 | ret = _sram_free(addr, &free_l2_sram_head, | |
698 | &used_l2_sram_head); | |
699 | ||
700 | /* add mutex operation */ | |
701 | spin_unlock_irqrestore(&l2_sram_lock, flags); | |
702 | ||
703 | return ret; | |
704 | #else | |
705 | return -1; | |
706 | #endif | |
707 | } | |
708 | EXPORT_SYMBOL(l2_sram_free); | |
709 | ||
1394f032 BW |
710 | int sram_free_with_lsl(const void *addr) |
711 | { | |
712 | struct sram_list_struct *lsl, **tmp; | |
713 | struct mm_struct *mm = current->mm; | |
714 | ||
715 | for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next) | |
716 | if ((*tmp)->addr == addr) | |
717 | goto found; | |
718 | return -1; | |
719 | found: | |
720 | lsl = *tmp; | |
721 | sram_free(addr); | |
722 | *tmp = lsl->next; | |
723 | kfree(lsl); | |
724 | ||
725 | return 0; | |
726 | } | |
727 | EXPORT_SYMBOL(sram_free_with_lsl); | |
728 | ||
f1db88d2 MF |
729 | /* Allocate memory and keep in L1 SRAM List (lsl) so that the resources are |
730 | * tracked. These are designed for userspace so that when a process exits, | |
731 | * we can safely reap their resources. | |
732 | */ | |
1394f032 BW |
733 | void *sram_alloc_with_lsl(size_t size, unsigned long flags) |
734 | { | |
735 | void *addr = NULL; | |
736 | struct sram_list_struct *lsl = NULL; | |
737 | struct mm_struct *mm = current->mm; | |
738 | ||
dd00cc48 | 739 | lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL); |
1394f032 BW |
740 | if (!lsl) |
741 | return NULL; | |
1394f032 BW |
742 | |
743 | if (flags & L1_INST_SRAM) | |
744 | addr = l1_inst_sram_alloc(size); | |
745 | ||
746 | if (addr == NULL && (flags & L1_DATA_A_SRAM)) | |
747 | addr = l1_data_A_sram_alloc(size); | |
748 | ||
749 | if (addr == NULL && (flags & L1_DATA_B_SRAM)) | |
750 | addr = l1_data_B_sram_alloc(size); | |
751 | ||
262c3825 SZ |
752 | if (addr == NULL && (flags & L2_SRAM)) |
753 | addr = l2_sram_alloc(size); | |
754 | ||
1394f032 BW |
755 | if (addr == NULL) { |
756 | kfree(lsl); | |
757 | return NULL; | |
758 | } | |
759 | lsl->addr = addr; | |
760 | lsl->length = size; | |
761 | lsl->next = mm->context.sram_list; | |
762 | mm->context.sram_list = lsl; | |
763 | return addr; | |
764 | } | |
765 | EXPORT_SYMBOL(sram_alloc_with_lsl); | |
bc61b4e6 MF |
766 | |
767 | #ifdef CONFIG_PROC_FS | |
768 | /* Once we get a real allocator, we'll throw all of this away. | |
769 | * Until then, we need some sort of visibility into the L1 alloc. | |
770 | */ | |
260d5d35 MF |
771 | /* Need to keep line of output the same. Currently, that is 44 bytes |
772 | * (including newline). | |
773 | */ | |
262c3825 | 774 | static int _sram_proc_read(char *buf, int *len, int count, const char *desc, |
5d481f49 SZ |
775 | struct sram_piece *pfree_head, |
776 | struct sram_piece *pused_head) | |
bc61b4e6 | 777 | { |
5d481f49 SZ |
778 | struct sram_piece *pslot; |
779 | ||
780 | if (!pfree_head || !pused_head) | |
781 | return -1; | |
bc61b4e6 | 782 | |
262c3825 | 783 | *len += sprintf(&buf[*len], "--- SRAM %-14s Size PID State \n", desc); |
5d481f49 SZ |
784 | |
785 | /* search the relevant memory slot */ | |
786 | pslot = pused_head->next; | |
787 | ||
788 | while (pslot != NULL) { | |
262c3825 | 789 | *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n", |
5d481f49 SZ |
790 | pslot->paddr, pslot->paddr + pslot->size, |
791 | pslot->size, pslot->pid, "ALLOCATED"); | |
792 | ||
793 | pslot = pslot->next; | |
794 | } | |
795 | ||
796 | pslot = pfree_head->next; | |
797 | ||
798 | while (pslot != NULL) { | |
262c3825 | 799 | *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n", |
5d481f49 SZ |
800 | pslot->paddr, pslot->paddr + pslot->size, |
801 | pslot->size, pslot->pid, "FREE"); | |
802 | ||
803 | pslot = pslot->next; | |
bc61b4e6 | 804 | } |
5d481f49 SZ |
805 | |
806 | return 0; | |
bc61b4e6 | 807 | } |
262c3825 | 808 | static int sram_proc_read(char *buf, char **start, off_t offset, int count, |
bc61b4e6 MF |
809 | int *eof, void *data) |
810 | { | |
811 | int len = 0; | |
8f65873e | 812 | unsigned int cpu; |
bc61b4e6 | 813 | |
8f65873e GY |
814 | for (cpu = 0; cpu < num_possible_cpus(); ++cpu) { |
815 | if (_sram_proc_read(buf, &len, count, "Scratchpad", | |
816 | &per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu))) | |
817 | goto not_done; | |
bc61b4e6 | 818 | #if L1_DATA_A_LENGTH != 0 |
8f65873e GY |
819 | if (_sram_proc_read(buf, &len, count, "L1 Data A", |
820 | &per_cpu(free_l1_data_A_sram_head, cpu), | |
821 | &per_cpu(used_l1_data_A_sram_head, cpu))) | |
822 | goto not_done; | |
bc61b4e6 MF |
823 | #endif |
824 | #if L1_DATA_B_LENGTH != 0 | |
8f65873e GY |
825 | if (_sram_proc_read(buf, &len, count, "L1 Data B", |
826 | &per_cpu(free_l1_data_B_sram_head, cpu), | |
827 | &per_cpu(used_l1_data_B_sram_head, cpu))) | |
828 | goto not_done; | |
bc61b4e6 MF |
829 | #endif |
830 | #if L1_CODE_LENGTH != 0 | |
8f65873e GY |
831 | if (_sram_proc_read(buf, &len, count, "L1 Instruction", |
832 | &per_cpu(free_l1_inst_sram_head, cpu), | |
833 | &per_cpu(used_l1_inst_sram_head, cpu))) | |
834 | goto not_done; | |
bc61b4e6 | 835 | #endif |
8f65873e | 836 | } |
07aa7be5 | 837 | #if L2_LENGTH != 0 |
8f65873e GY |
838 | if (_sram_proc_read(buf, &len, count, "L2", &free_l2_sram_head, |
839 | &used_l2_sram_head)) | |
262c3825 SZ |
840 | goto not_done; |
841 | #endif | |
260d5d35 MF |
842 | *eof = 1; |
843 | not_done: | |
bc61b4e6 MF |
844 | return len; |
845 | } | |
846 | ||
262c3825 | 847 | static int __init sram_proc_init(void) |
bc61b4e6 MF |
848 | { |
849 | struct proc_dir_entry *ptr; | |
850 | ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL); | |
851 | if (!ptr) { | |
852 | printk(KERN_WARNING "unable to create /proc/sram\n"); | |
853 | return -1; | |
854 | } | |
262c3825 | 855 | ptr->read_proc = sram_proc_read; |
bc61b4e6 MF |
856 | return 0; |
857 | } | |
262c3825 | 858 | late_initcall(sram_proc_init); |
bc61b4e6 | 859 | #endif |