Commit | Line | Data |
---|---|---|
1394f032 BW |
1 | /* |
2 | * File: arch/blackfin/mm/blackfin_sram.c | |
3 | * Based on: | |
4 | * Author: | |
5 | * | |
6 | * Created: | |
7 | * Description: SRAM driver for Blackfin ADSP-BF5xx | |
8 | * | |
9 | * Modified: | |
10 | * Copyright 2004-2006 Analog Devices Inc. | |
11 | * | |
12 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License as published by | |
16 | * the Free Software Foundation; either version 2 of the License, or | |
17 | * (at your option) any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, | |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | * GNU General Public License for more details. | |
23 | * | |
24 | * You should have received a copy of the GNU General Public License | |
25 | * along with this program; if not, see the file COPYING, or write | |
26 | * to the Free Software Foundation, Inc., | |
27 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
28 | */ | |
29 | ||
30 | #include <linux/autoconf.h> | |
31 | #include <linux/module.h> | |
32 | #include <linux/kernel.h> | |
33 | #include <linux/types.h> | |
34 | #include <linux/miscdevice.h> | |
35 | #include <linux/ioport.h> | |
36 | #include <linux/fcntl.h> | |
37 | #include <linux/init.h> | |
38 | #include <linux/poll.h> | |
39 | #include <linux/proc_fs.h> | |
40 | #include <linux/spinlock.h> | |
41 | #include <linux/rtc.h> | |
42 | #include <asm/blackfin.h> | |
43 | #include "blackfin_sram.h" | |
44 | ||
45 | spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock; | |
46 | ||
47 | #if CONFIG_L1_MAX_PIECE < 16 | |
48 | #undef CONFIG_L1_MAX_PIECE | |
49 | #define CONFIG_L1_MAX_PIECE 16 | |
50 | #endif | |
51 | ||
52 | #if CONFIG_L1_MAX_PIECE > 1024 | |
53 | #undef CONFIG_L1_MAX_PIECE | |
54 | #define CONFIG_L1_MAX_PIECE 1024 | |
55 | #endif | |
56 | ||
57 | #define SRAM_SLT_NULL 0 | |
58 | #define SRAM_SLT_FREE 1 | |
59 | #define SRAM_SLT_ALLOCATED 2 | |
60 | ||
61 | /* the data structure for L1 scratchpad and DATA SRAM */ | |
62 | struct l1_sram_piece { | |
63 | void *paddr; | |
64 | int size; | |
65 | int flag; | |
66 | }; | |
67 | ||
68 | static struct l1_sram_piece l1_ssram[CONFIG_L1_MAX_PIECE]; | |
69 | ||
70 | #if L1_DATA_A_LENGTH != 0 | |
71 | static struct l1_sram_piece l1_data_A_sram[CONFIG_L1_MAX_PIECE]; | |
72 | #endif | |
73 | ||
74 | #if L1_DATA_B_LENGTH != 0 | |
75 | static struct l1_sram_piece l1_data_B_sram[CONFIG_L1_MAX_PIECE]; | |
76 | #endif | |
77 | ||
78 | #if L1_CODE_LENGTH != 0 | |
79 | static struct l1_sram_piece l1_inst_sram[CONFIG_L1_MAX_PIECE]; | |
80 | #endif | |
81 | ||
82 | /* L1 Scratchpad SRAM initialization function */ | |
83 | void l1sram_init(void) | |
84 | { | |
85 | printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n", | |
86 | L1_SCRATCH_LENGTH >> 10); | |
87 | ||
88 | memset(&l1_ssram, 0x00, sizeof(l1_ssram)); | |
89 | l1_ssram[0].paddr = (void*)L1_SCRATCH_START; | |
90 | l1_ssram[0].size = L1_SCRATCH_LENGTH; | |
91 | l1_ssram[0].flag = SRAM_SLT_FREE; | |
92 | ||
93 | /* mutex initialize */ | |
94 | spin_lock_init(&l1sram_lock); | |
95 | } | |
96 | ||
97 | void l1_data_sram_init(void) | |
98 | { | |
99 | #if L1_DATA_A_LENGTH != 0 | |
100 | printk(KERN_INFO "Blackfin DATA_A SRAM: %d KB\n", | |
101 | L1_DATA_A_LENGTH >> 10); | |
102 | ||
103 | memset(&l1_data_A_sram, 0x00, sizeof(l1_data_A_sram)); | |
104 | l1_data_A_sram[0].paddr = (void*)L1_DATA_A_START + | |
105 | (_ebss_l1 - _sdata_l1); | |
106 | l1_data_A_sram[0].size = L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1); | |
107 | l1_data_A_sram[0].flag = SRAM_SLT_FREE; | |
108 | #endif | |
109 | #if L1_DATA_B_LENGTH != 0 | |
110 | printk(KERN_INFO "Blackfin DATA_B SRAM: %d KB\n", | |
111 | L1_DATA_B_LENGTH >> 10); | |
112 | ||
113 | memset(&l1_data_B_sram, 0x00, sizeof(l1_data_B_sram)); | |
114 | l1_data_B_sram[0].paddr = (void*)L1_DATA_B_START; | |
115 | l1_data_B_sram[0].size = L1_DATA_B_LENGTH; | |
116 | l1_data_B_sram[0].flag = SRAM_SLT_FREE; | |
117 | #endif | |
118 | ||
119 | /* mutex initialize */ | |
120 | spin_lock_init(&l1_data_sram_lock); | |
121 | } | |
122 | ||
123 | void l1_inst_sram_init(void) | |
124 | { | |
125 | #if L1_CODE_LENGTH != 0 | |
126 | printk(KERN_INFO "Blackfin Instruction SRAM: %d KB\n", | |
127 | L1_CODE_LENGTH >> 10); | |
128 | ||
129 | memset(&l1_inst_sram, 0x00, sizeof(l1_inst_sram)); | |
130 | l1_inst_sram[0].paddr = (void*)L1_CODE_START + (_etext_l1 - _stext_l1); | |
131 | l1_inst_sram[0].size = L1_CODE_LENGTH - (_etext_l1 - _stext_l1); | |
132 | l1_inst_sram[0].flag = SRAM_SLT_FREE; | |
133 | #endif | |
134 | ||
135 | /* mutex initialize */ | |
136 | spin_lock_init(&l1_inst_sram_lock); | |
137 | } | |
138 | ||
139 | /* L1 memory allocate function */ | |
140 | static void *_l1_sram_alloc(size_t size, struct l1_sram_piece *pfree, int count) | |
141 | { | |
142 | int i, index = 0; | |
143 | void *addr = NULL; | |
144 | ||
145 | if (size <= 0) | |
146 | return NULL; | |
147 | ||
148 | /* Align the size */ | |
149 | size = (size + 3) & ~3; | |
150 | ||
151 | /* not use the good method to match the best slot !!! */ | |
152 | /* search an available memeory slot */ | |
153 | for (i = 0; i < count; i++) { | |
154 | if ((pfree[i].flag == SRAM_SLT_FREE) | |
155 | && (pfree[i].size >= size)) { | |
156 | addr = pfree[i].paddr; | |
157 | pfree[i].flag = SRAM_SLT_ALLOCATED; | |
158 | index = i; | |
159 | break; | |
160 | } | |
161 | } | |
162 | if (i >= count) | |
163 | return NULL; | |
164 | ||
165 | /* updated the NULL memeory slot !!! */ | |
166 | if (pfree[i].size > size) { | |
167 | for (i = 0; i < count; i++) { | |
168 | if (pfree[i].flag == SRAM_SLT_NULL) { | |
169 | pfree[i].flag = SRAM_SLT_FREE; | |
170 | pfree[i].paddr = addr + size; | |
171 | pfree[i].size = pfree[index].size - size; | |
172 | pfree[index].size = size; | |
173 | break; | |
174 | } | |
175 | } | |
176 | } | |
177 | ||
178 | return addr; | |
179 | } | |
180 | ||
181 | /* Allocate the largest available block. */ | |
182 | static void *_l1_sram_alloc_max(struct l1_sram_piece *pfree, int count, | |
183 | unsigned long *psize) | |
184 | { | |
185 | unsigned long best = 0; | |
186 | int i, index = -1; | |
187 | void *addr = NULL; | |
188 | ||
189 | /* search an available memeory slot */ | |
190 | for (i = 0; i < count; i++) { | |
191 | if (pfree[i].flag == SRAM_SLT_FREE && pfree[i].size > best) { | |
192 | addr = pfree[i].paddr; | |
193 | index = i; | |
194 | best = pfree[i].size; | |
195 | } | |
196 | } | |
197 | if (index < 0) | |
198 | return NULL; | |
199 | *psize = best; | |
200 | ||
201 | pfree[index].flag = SRAM_SLT_ALLOCATED; | |
202 | return addr; | |
203 | } | |
204 | ||
205 | /* L1 memory free function */ | |
206 | static int _l1_sram_free(const void *addr, | |
207 | struct l1_sram_piece *pfree, int count) | |
208 | { | |
209 | int i, index = 0; | |
210 | ||
211 | /* search the relevant memory slot */ | |
212 | for (i = 0; i < count; i++) { | |
213 | if (pfree[i].paddr == addr) { | |
214 | if (pfree[i].flag != SRAM_SLT_ALLOCATED) { | |
215 | /* error log */ | |
216 | return -1; | |
217 | } | |
218 | index = i; | |
219 | break; | |
220 | } | |
221 | } | |
222 | if (i >= count) | |
223 | return -1; | |
224 | ||
225 | pfree[index].flag = SRAM_SLT_FREE; | |
226 | ||
227 | /* link the next address slot */ | |
228 | for (i = 0; i < count; i++) { | |
229 | if (((pfree[index].paddr + pfree[index].size) == pfree[i].paddr) | |
230 | && (pfree[i].flag == SRAM_SLT_FREE)) { | |
231 | pfree[i].flag = SRAM_SLT_NULL; | |
232 | pfree[index].size += pfree[i].size; | |
233 | pfree[index].flag = SRAM_SLT_FREE; | |
234 | break; | |
235 | } | |
236 | } | |
237 | ||
238 | /* link the last address slot */ | |
239 | for (i = 0; i < count; i++) { | |
240 | if (((pfree[i].paddr + pfree[i].size) == pfree[index].paddr) && | |
241 | (pfree[i].flag == SRAM_SLT_FREE)) { | |
242 | pfree[index].flag = SRAM_SLT_NULL; | |
243 | pfree[i].size += pfree[index].size; | |
244 | break; | |
245 | } | |
246 | } | |
247 | ||
248 | return 0; | |
249 | } | |
250 | ||
251 | int sram_free(const void *addr) | |
252 | { | |
253 | if (0) {} | |
254 | #if L1_CODE_LENGTH != 0 | |
255 | else if (addr >= (void *)L1_CODE_START | |
256 | && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH)) | |
257 | return l1_inst_sram_free(addr); | |
258 | #endif | |
259 | #if L1_DATA_A_LENGTH != 0 | |
260 | else if (addr >= (void *)L1_DATA_A_START | |
261 | && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH)) | |
262 | return l1_data_A_sram_free(addr); | |
263 | #endif | |
264 | #if L1_DATA_B_LENGTH != 0 | |
265 | else if (addr >= (void *)L1_DATA_B_START | |
266 | && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH)) | |
267 | return l1_data_B_sram_free(addr); | |
268 | #endif | |
269 | else | |
270 | return -1; | |
271 | } | |
272 | EXPORT_SYMBOL(sram_free); | |
273 | ||
274 | void *l1_data_A_sram_alloc(size_t size) | |
275 | { | |
276 | unsigned flags; | |
277 | void *addr = NULL; | |
278 | ||
279 | /* add mutex operation */ | |
280 | spin_lock_irqsave(&l1_data_sram_lock, flags); | |
281 | ||
282 | #if L1_DATA_A_LENGTH != 0 | |
283 | addr = _l1_sram_alloc(size, l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram)); | |
284 | #endif | |
285 | ||
286 | /* add mutex operation */ | |
287 | spin_unlock_irqrestore(&l1_data_sram_lock, flags); | |
288 | ||
289 | pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n", | |
290 | (long unsigned int)addr, size); | |
291 | ||
292 | return addr; | |
293 | } | |
294 | EXPORT_SYMBOL(l1_data_A_sram_alloc); | |
295 | ||
296 | int l1_data_A_sram_free(const void *addr) | |
297 | { | |
298 | unsigned flags; | |
299 | int ret; | |
300 | ||
301 | /* add mutex operation */ | |
302 | spin_lock_irqsave(&l1_data_sram_lock, flags); | |
303 | ||
304 | #if L1_DATA_A_LENGTH != 0 | |
305 | ret = _l1_sram_free(addr, | |
306 | l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram)); | |
307 | #else | |
308 | ret = -1; | |
309 | #endif | |
310 | ||
311 | /* add mutex operation */ | |
312 | spin_unlock_irqrestore(&l1_data_sram_lock, flags); | |
313 | ||
314 | return ret; | |
315 | } | |
316 | EXPORT_SYMBOL(l1_data_A_sram_free); | |
317 | ||
318 | void *l1_data_B_sram_alloc(size_t size) | |
319 | { | |
320 | #if L1_DATA_B_LENGTH != 0 | |
321 | unsigned flags; | |
322 | void *addr; | |
323 | ||
324 | /* add mutex operation */ | |
325 | spin_lock_irqsave(&l1_data_sram_lock, flags); | |
326 | ||
327 | addr = _l1_sram_alloc(size, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram)); | |
328 | ||
329 | /* add mutex operation */ | |
330 | spin_unlock_irqrestore(&l1_data_sram_lock, flags); | |
331 | ||
332 | pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n", | |
333 | (long unsigned int)addr, size); | |
334 | ||
335 | return addr; | |
336 | #else | |
337 | return NULL; | |
338 | #endif | |
339 | } | |
340 | EXPORT_SYMBOL(l1_data_B_sram_alloc); | |
341 | ||
342 | int l1_data_B_sram_free(const void *addr) | |
343 | { | |
344 | #if L1_DATA_B_LENGTH != 0 | |
345 | unsigned flags; | |
346 | int ret; | |
347 | ||
348 | /* add mutex operation */ | |
349 | spin_lock_irqsave(&l1_data_sram_lock, flags); | |
350 | ||
351 | ret = _l1_sram_free(addr, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram)); | |
352 | ||
353 | /* add mutex operation */ | |
354 | spin_unlock_irqrestore(&l1_data_sram_lock, flags); | |
355 | ||
356 | return ret; | |
357 | #else | |
358 | return -1; | |
359 | #endif | |
360 | } | |
361 | EXPORT_SYMBOL(l1_data_B_sram_free); | |
362 | ||
363 | void *l1_data_sram_alloc(size_t size) | |
364 | { | |
365 | void *addr = l1_data_A_sram_alloc(size); | |
366 | ||
367 | if (!addr) | |
368 | addr = l1_data_B_sram_alloc(size); | |
369 | ||
370 | return addr; | |
371 | } | |
372 | EXPORT_SYMBOL(l1_data_sram_alloc); | |
373 | ||
374 | void *l1_data_sram_zalloc(size_t size) | |
375 | { | |
376 | void *addr = l1_data_sram_alloc(size); | |
377 | ||
378 | if (addr) | |
379 | memset(addr, 0x00, size); | |
380 | ||
381 | return addr; | |
382 | } | |
383 | EXPORT_SYMBOL(l1_data_sram_zalloc); | |
384 | ||
385 | int l1_data_sram_free(const void *addr) | |
386 | { | |
387 | int ret; | |
388 | ret = l1_data_A_sram_free(addr); | |
389 | if (ret == -1) | |
390 | ret = l1_data_B_sram_free(addr); | |
391 | return ret; | |
392 | } | |
393 | EXPORT_SYMBOL(l1_data_sram_free); | |
394 | ||
395 | void *l1_inst_sram_alloc(size_t size) | |
396 | { | |
397 | #if L1_DATA_A_LENGTH != 0 | |
398 | unsigned flags; | |
399 | void *addr; | |
400 | ||
401 | /* add mutex operation */ | |
402 | spin_lock_irqsave(&l1_inst_sram_lock, flags); | |
403 | ||
404 | addr = _l1_sram_alloc(size, l1_inst_sram, ARRAY_SIZE(l1_inst_sram)); | |
405 | ||
406 | /* add mutex operation */ | |
407 | spin_unlock_irqrestore(&l1_inst_sram_lock, flags); | |
408 | ||
409 | pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n", | |
410 | (long unsigned int)addr, size); | |
411 | ||
412 | return addr; | |
413 | #else | |
414 | return NULL; | |
415 | #endif | |
416 | } | |
417 | EXPORT_SYMBOL(l1_inst_sram_alloc); | |
418 | ||
419 | int l1_inst_sram_free(const void *addr) | |
420 | { | |
421 | #if L1_CODE_LENGTH != 0 | |
422 | unsigned flags; | |
423 | int ret; | |
424 | ||
425 | /* add mutex operation */ | |
426 | spin_lock_irqsave(&l1_inst_sram_lock, flags); | |
427 | ||
428 | ret = _l1_sram_free(addr, l1_inst_sram, ARRAY_SIZE(l1_inst_sram)); | |
429 | ||
430 | /* add mutex operation */ | |
431 | spin_unlock_irqrestore(&l1_inst_sram_lock, flags); | |
432 | ||
433 | return ret; | |
434 | #else | |
435 | return -1; | |
436 | #endif | |
437 | } | |
438 | EXPORT_SYMBOL(l1_inst_sram_free); | |
439 | ||
440 | /* L1 Scratchpad memory allocate function */ | |
441 | void *l1sram_alloc(size_t size) | |
442 | { | |
443 | unsigned flags; | |
444 | void *addr; | |
445 | ||
446 | /* add mutex operation */ | |
447 | spin_lock_irqsave(&l1sram_lock, flags); | |
448 | ||
449 | addr = _l1_sram_alloc(size, l1_ssram, ARRAY_SIZE(l1_ssram)); | |
450 | ||
451 | /* add mutex operation */ | |
452 | spin_unlock_irqrestore(&l1sram_lock, flags); | |
453 | ||
454 | return addr; | |
455 | } | |
456 | ||
457 | /* L1 Scratchpad memory allocate function */ | |
458 | void *l1sram_alloc_max(size_t *psize) | |
459 | { | |
460 | unsigned flags; | |
461 | void *addr; | |
462 | ||
463 | /* add mutex operation */ | |
464 | spin_lock_irqsave(&l1sram_lock, flags); | |
465 | ||
466 | addr = _l1_sram_alloc_max(l1_ssram, ARRAY_SIZE(l1_ssram), psize); | |
467 | ||
468 | /* add mutex operation */ | |
469 | spin_unlock_irqrestore(&l1sram_lock, flags); | |
470 | ||
471 | return addr; | |
472 | } | |
473 | ||
474 | /* L1 Scratchpad memory free function */ | |
475 | int l1sram_free(const void *addr) | |
476 | { | |
477 | unsigned flags; | |
478 | int ret; | |
479 | ||
480 | /* add mutex operation */ | |
481 | spin_lock_irqsave(&l1sram_lock, flags); | |
482 | ||
483 | ret = _l1_sram_free(addr, l1_ssram, ARRAY_SIZE(l1_ssram)); | |
484 | ||
485 | /* add mutex operation */ | |
486 | spin_unlock_irqrestore(&l1sram_lock, flags); | |
487 | ||
488 | return ret; | |
489 | } | |
490 | ||
491 | int sram_free_with_lsl(const void *addr) | |
492 | { | |
493 | struct sram_list_struct *lsl, **tmp; | |
494 | struct mm_struct *mm = current->mm; | |
495 | ||
496 | for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next) | |
497 | if ((*tmp)->addr == addr) | |
498 | goto found; | |
499 | return -1; | |
500 | found: | |
501 | lsl = *tmp; | |
502 | sram_free(addr); | |
503 | *tmp = lsl->next; | |
504 | kfree(lsl); | |
505 | ||
506 | return 0; | |
507 | } | |
508 | EXPORT_SYMBOL(sram_free_with_lsl); | |
509 | ||
510 | void *sram_alloc_with_lsl(size_t size, unsigned long flags) | |
511 | { | |
512 | void *addr = NULL; | |
513 | struct sram_list_struct *lsl = NULL; | |
514 | struct mm_struct *mm = current->mm; | |
515 | ||
516 | lsl = kmalloc(sizeof(struct sram_list_struct), GFP_KERNEL); | |
517 | if (!lsl) | |
518 | return NULL; | |
519 | memset(lsl, 0, sizeof(*lsl)); | |
520 | ||
521 | if (flags & L1_INST_SRAM) | |
522 | addr = l1_inst_sram_alloc(size); | |
523 | ||
524 | if (addr == NULL && (flags & L1_DATA_A_SRAM)) | |
525 | addr = l1_data_A_sram_alloc(size); | |
526 | ||
527 | if (addr == NULL && (flags & L1_DATA_B_SRAM)) | |
528 | addr = l1_data_B_sram_alloc(size); | |
529 | ||
530 | if (addr == NULL) { | |
531 | kfree(lsl); | |
532 | return NULL; | |
533 | } | |
534 | lsl->addr = addr; | |
535 | lsl->length = size; | |
536 | lsl->next = mm->context.sram_list; | |
537 | mm->context.sram_list = lsl; | |
538 | return addr; | |
539 | } | |
540 | EXPORT_SYMBOL(sram_alloc_with_lsl); |