b58cf196d7cce26d09b6487235c574293fa5a53f
[linux-2.6.git] / arch / blackfin / mm / blackfin_sram.c
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-2007 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/module.h>
31 #include <linux/kernel.h>
32 #include <linux/types.h>
33 #include <linux/miscdevice.h>
34 #include <linux/ioport.h>
35 #include <linux/fcntl.h>
36 #include <linux/init.h>
37 #include <linux/poll.h>
38 #include <linux/proc_fs.h>
39 #include <linux/spinlock.h>
40 #include <linux/rtc.h>
41 #include <asm/blackfin.h>
42 #include "blackfin_sram.h"
43
44 static spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
45
46 /* the data structure for L1 scratchpad and DATA SRAM */
47 struct sram_piece {
48         void *paddr;
49         int size;
50         pid_t pid;
51         struct sram_piece *next;
52 };
53
54 static struct sram_piece free_l1_ssram_head, used_l1_ssram_head;
55
56 #if L1_DATA_A_LENGTH != 0
57 static struct sram_piece free_l1_data_A_sram_head, used_l1_data_A_sram_head;
58 #endif
59
60 #if L1_DATA_B_LENGTH != 0
61 static struct sram_piece free_l1_data_B_sram_head, used_l1_data_B_sram_head;
62 #endif
63
64 #if L1_CODE_LENGTH != 0
65 static struct sram_piece free_l1_inst_sram_head, used_l1_inst_sram_head;
66 #endif
67
68 static struct kmem_cache *sram_piece_cache;
69
70 /* L1 Scratchpad SRAM initialization function */
71 static void __init l1sram_init(void)
72 {
73         free_l1_ssram_head.next =
74                 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
75         if (!free_l1_ssram_head.next) {
76                 printk(KERN_INFO"Fail to initialize Scratchpad data SRAM.\n");
77                 return;
78         }
79
80         free_l1_ssram_head.next->paddr = (void *)L1_SCRATCH_START;
81         free_l1_ssram_head.next->size = L1_SCRATCH_LENGTH;
82         free_l1_ssram_head.next->pid = 0;
83         free_l1_ssram_head.next->next = NULL;
84
85         used_l1_ssram_head.next = NULL;
86
87         /* mutex initialize */
88         spin_lock_init(&l1sram_lock);
89
90         printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
91                L1_SCRATCH_LENGTH >> 10);
92 }
93
94 static void __init l1_data_sram_init(void)
95 {
96 #if L1_DATA_A_LENGTH != 0
97         free_l1_data_A_sram_head.next =
98                 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
99         if (!free_l1_data_A_sram_head.next) {
100                 printk(KERN_INFO"Fail to initialize Data A SRAM.\n");
101                 return;
102         }
103
104         free_l1_data_A_sram_head.next->paddr =
105                 (void *)L1_DATA_A_START + (_ebss_l1 - _sdata_l1);
106         free_l1_data_A_sram_head.next->size =
107                 L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
108         free_l1_data_A_sram_head.next->pid = 0;
109         free_l1_data_A_sram_head.next->next = NULL;
110
111         used_l1_data_A_sram_head.next = NULL;
112
113         printk(KERN_INFO "Blackfin Data A SRAM: %d KB (%d KB free)\n",
114                 L1_DATA_A_LENGTH >> 10,
115                 free_l1_data_A_sram_head.next->size >> 10);
116 #endif
117 #if L1_DATA_B_LENGTH != 0
118         free_l1_data_B_sram_head.next =
119                 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
120         if (!free_l1_data_B_sram_head.next) {
121                 printk(KERN_INFO"Fail to initialize Data B SRAM.\n");
122                 return;
123         }
124
125         free_l1_data_B_sram_head.next->paddr =
126                 (void *)L1_DATA_B_START + (_ebss_b_l1 - _sdata_b_l1);
127         free_l1_data_B_sram_head.next->size =
128                 L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1);
129         free_l1_data_B_sram_head.next->pid = 0;
130         free_l1_data_B_sram_head.next->next = NULL;
131
132         used_l1_data_B_sram_head.next = NULL;
133
134         printk(KERN_INFO "Blackfin Data B SRAM: %d KB (%d KB free)\n",
135                 L1_DATA_B_LENGTH >> 10,
136                 free_l1_data_B_sram_head.next->size >> 10);
137 #endif
138
139         /* mutex initialize */
140         spin_lock_init(&l1_data_sram_lock);
141 }
142
143 static void __init l1_inst_sram_init(void)
144 {
145 #if L1_CODE_LENGTH != 0
146         free_l1_inst_sram_head.next =
147                 kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
148         if (!free_l1_inst_sram_head.next) {
149                 printk(KERN_INFO"Fail to initialize Instruction SRAM.\n");
150                 return;
151         }
152
153         free_l1_inst_sram_head.next->paddr =
154                 (void *)L1_CODE_START + (_etext_l1 - _stext_l1);
155         free_l1_inst_sram_head.next->size =
156                 L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
157         free_l1_inst_sram_head.next->pid = 0;
158         free_l1_inst_sram_head.next->next = NULL;
159
160         used_l1_inst_sram_head.next = NULL;
161
162         printk(KERN_INFO "Blackfin Instruction SRAM: %d KB (%d KB free)\n",
163                 L1_CODE_LENGTH >> 10,
164                 free_l1_inst_sram_head.next->size >> 10);
165 #endif
166
167         /* mutex initialize */
168         spin_lock_init(&l1_inst_sram_lock);
169 }
170
171 void __init bfin_sram_init(void)
172 {
173         sram_piece_cache = kmem_cache_create("sram_piece_cache",
174                                 sizeof(struct sram_piece),
175                                 0, SLAB_PANIC, NULL);
176
177         l1sram_init();
178         l1_data_sram_init();
179         l1_inst_sram_init();
180 }
181
182 /* L1 memory allocate function */
183 static void *_l1_sram_alloc(size_t size, struct sram_piece *pfree_head,
184                 struct sram_piece *pused_head)
185 {
186         struct sram_piece *pslot, *plast, *pavail;
187
188         if (size <= 0 || !pfree_head || !pused_head)
189                 return NULL;
190
191         /* Align the size */
192         size = (size + 3) & ~3;
193
194         pslot = pfree_head->next;
195         plast = pfree_head;
196
197         /* search an available piece slot */
198         while (pslot != NULL && size > pslot->size) {
199                 plast = pslot;
200                 pslot = pslot->next;
201         }
202
203         if (!pslot)
204                 return NULL;
205
206         if (pslot->size == size) {
207                 plast->next = pslot->next;
208                 pavail = pslot;
209         } else {
210                 pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
211
212                 if (!pavail)
213                         return NULL;
214
215                 pavail->paddr = pslot->paddr;
216                 pavail->size = size;
217                 pslot->paddr += size;
218                 pslot->size -= size;
219         }
220
221         pavail->pid = current->pid;
222
223         pslot = pused_head->next;
224         plast = pused_head;
225
226         /* insert new piece into used piece list !!! */
227         while (pslot != NULL && pavail->paddr < pslot->paddr) {
228                 plast = pslot;
229                 pslot = pslot->next;
230         }
231
232         pavail->next = pslot;
233         plast->next = pavail;
234
235         return pavail->paddr;
236 }
237
238 /* Allocate the largest available block.  */
239 static void *_l1_sram_alloc_max(struct sram_piece *pfree_head,
240                                 struct sram_piece *pused_head,
241                                 unsigned long *psize)
242 {
243         struct sram_piece *pslot, *pmax;
244
245         if (!pfree_head || !pused_head)
246                 return NULL;
247
248         pmax = pslot = pfree_head->next;
249
250         /* search an available piece slot */
251         while (pslot != NULL) {
252                 if (pslot->size > pmax->size)
253                         pmax = pslot;
254                 pslot = pslot->next;
255         }
256
257         if (!pmax)
258                 return NULL;
259
260         *psize = pmax->size;
261
262         return _l1_sram_alloc(*psize, pfree_head, pused_head);
263 }
264
265 /* L1 memory free function */
266 static int _l1_sram_free(const void *addr,
267                         struct sram_piece *pfree_head,
268                         struct sram_piece *pused_head)
269 {
270         struct sram_piece *pslot, *plast, *pavail;
271
272         if (!pfree_head || !pused_head)
273                 return -1;
274
275         /* search the relevant memory slot */
276         pslot = pused_head->next;
277         plast = pused_head;
278
279         /* search an available piece slot */
280         while (pslot != NULL && pslot->paddr != addr) {
281                 plast = pslot;
282                 pslot = pslot->next;
283         }
284
285         if (!pslot)
286                 return -1;
287
288         plast->next = pslot->next;
289         pavail = pslot;
290         pavail->pid = 0;
291
292         /* insert free pieces back to the free list */
293         pslot = pfree_head->next;
294         plast = pfree_head;
295
296         while (pslot != NULL && addr > pslot->paddr) {
297                 plast = pslot;
298                 pslot = pslot->next;
299         }
300
301         if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) {
302                 plast->size += pavail->size;
303                 kmem_cache_free(sram_piece_cache, pavail);
304         } else {
305                 pavail->next = plast;
306                 plast->next = pavail;
307                 plast = pavail;
308         }
309
310         if (pslot && plast->paddr + plast->size == pslot->paddr) {
311                 plast->size += pslot->size;
312                 plast->next = pslot->next;
313                 kmem_cache_free(sram_piece_cache, pslot);
314         }
315
316         return 0;
317 }
318
319 int sram_free(const void *addr)
320 {
321         if (0) {}
322 #if L1_CODE_LENGTH != 0
323         else if (addr >= (void *)L1_CODE_START
324                  && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
325                 return l1_inst_sram_free(addr);
326 #endif
327 #if L1_DATA_A_LENGTH != 0
328         else if (addr >= (void *)L1_DATA_A_START
329                  && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
330                 return l1_data_A_sram_free(addr);
331 #endif
332 #if L1_DATA_B_LENGTH != 0
333         else if (addr >= (void *)L1_DATA_B_START
334                  && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
335                 return l1_data_B_sram_free(addr);
336 #endif
337         else
338                 return -1;
339 }
340 EXPORT_SYMBOL(sram_free);
341
342 void *l1_data_A_sram_alloc(size_t size)
343 {
344         unsigned flags;
345         void *addr = NULL;
346
347         /* add mutex operation */
348         spin_lock_irqsave(&l1_data_sram_lock, flags);
349
350 #if L1_DATA_A_LENGTH != 0
351         addr = _l1_sram_alloc(size, &free_l1_data_A_sram_head,
352                         &used_l1_data_A_sram_head);
353 #endif
354
355         /* add mutex operation */
356         spin_unlock_irqrestore(&l1_data_sram_lock, flags);
357
358         pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
359                  (long unsigned int)addr, size);
360
361         return addr;
362 }
363 EXPORT_SYMBOL(l1_data_A_sram_alloc);
364
365 int l1_data_A_sram_free(const void *addr)
366 {
367         unsigned flags;
368         int ret;
369
370         /* add mutex operation */
371         spin_lock_irqsave(&l1_data_sram_lock, flags);
372
373 #if L1_DATA_A_LENGTH != 0
374         ret = _l1_sram_free(addr, &free_l1_data_A_sram_head,
375                         &used_l1_data_A_sram_head);
376 #else
377         ret = -1;
378 #endif
379
380         /* add mutex operation */
381         spin_unlock_irqrestore(&l1_data_sram_lock, flags);
382
383         return ret;
384 }
385 EXPORT_SYMBOL(l1_data_A_sram_free);
386
387 void *l1_data_B_sram_alloc(size_t size)
388 {
389 #if L1_DATA_B_LENGTH != 0
390         unsigned flags;
391         void *addr;
392
393         /* add mutex operation */
394         spin_lock_irqsave(&l1_data_sram_lock, flags);
395
396         addr = _l1_sram_alloc(size, &free_l1_data_B_sram_head,
397                         &used_l1_data_B_sram_head);
398
399         /* add mutex operation */
400         spin_unlock_irqrestore(&l1_data_sram_lock, flags);
401
402         pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
403                  (long unsigned int)addr, size);
404
405         return addr;
406 #else
407         return NULL;
408 #endif
409 }
410 EXPORT_SYMBOL(l1_data_B_sram_alloc);
411
412 int l1_data_B_sram_free(const void *addr)
413 {
414 #if L1_DATA_B_LENGTH != 0
415         unsigned flags;
416         int ret;
417
418         /* add mutex operation */
419         spin_lock_irqsave(&l1_data_sram_lock, flags);
420
421         ret = _l1_sram_free(addr, &free_l1_data_B_sram_head,
422                         &used_l1_data_B_sram_head);
423
424         /* add mutex operation */
425         spin_unlock_irqrestore(&l1_data_sram_lock, flags);
426
427         return ret;
428 #else
429         return -1;
430 #endif
431 }
432 EXPORT_SYMBOL(l1_data_B_sram_free);
433
434 void *l1_data_sram_alloc(size_t size)
435 {
436         void *addr = l1_data_A_sram_alloc(size);
437
438         if (!addr)
439                 addr = l1_data_B_sram_alloc(size);
440
441         return addr;
442 }
443 EXPORT_SYMBOL(l1_data_sram_alloc);
444
445 void *l1_data_sram_zalloc(size_t size)
446 {
447         void *addr = l1_data_sram_alloc(size);
448
449         if (addr)
450                 memset(addr, 0x00, size);
451
452         return addr;
453 }
454 EXPORT_SYMBOL(l1_data_sram_zalloc);
455
456 int l1_data_sram_free(const void *addr)
457 {
458         int ret;
459         ret = l1_data_A_sram_free(addr);
460         if (ret == -1)
461                 ret = l1_data_B_sram_free(addr);
462         return ret;
463 }
464 EXPORT_SYMBOL(l1_data_sram_free);
465
466 void *l1_inst_sram_alloc(size_t size)
467 {
468 #if L1_CODE_LENGTH != 0
469         unsigned flags;
470         void *addr;
471
472         /* add mutex operation */
473         spin_lock_irqsave(&l1_inst_sram_lock, flags);
474
475         addr = _l1_sram_alloc(size, &free_l1_inst_sram_head,
476                         &used_l1_inst_sram_head);
477
478         /* add mutex operation */
479         spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
480
481         pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
482                  (long unsigned int)addr, size);
483
484         return addr;
485 #else
486         return NULL;
487 #endif
488 }
489 EXPORT_SYMBOL(l1_inst_sram_alloc);
490
491 int l1_inst_sram_free(const void *addr)
492 {
493 #if L1_CODE_LENGTH != 0
494         unsigned flags;
495         int ret;
496
497         /* add mutex operation */
498         spin_lock_irqsave(&l1_inst_sram_lock, flags);
499
500         ret = _l1_sram_free(addr, &free_l1_inst_sram_head,
501                         &used_l1_inst_sram_head);
502
503         /* add mutex operation */
504         spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
505
506         return ret;
507 #else
508         return -1;
509 #endif
510 }
511 EXPORT_SYMBOL(l1_inst_sram_free);
512
513 /* L1 Scratchpad memory allocate function */
514 void *l1sram_alloc(size_t size)
515 {
516         unsigned flags;
517         void *addr;
518
519         /* add mutex operation */
520         spin_lock_irqsave(&l1sram_lock, flags);
521
522         addr = _l1_sram_alloc(size, &free_l1_ssram_head,
523                         &used_l1_ssram_head);
524
525         /* add mutex operation */
526         spin_unlock_irqrestore(&l1sram_lock, flags);
527
528         return addr;
529 }
530
531 /* L1 Scratchpad memory allocate function */
532 void *l1sram_alloc_max(size_t *psize)
533 {
534         unsigned flags;
535         void *addr;
536
537         /* add mutex operation */
538         spin_lock_irqsave(&l1sram_lock, flags);
539
540         addr = _l1_sram_alloc_max(&free_l1_ssram_head,
541                         &used_l1_ssram_head, psize);
542
543         /* add mutex operation */
544         spin_unlock_irqrestore(&l1sram_lock, flags);
545
546         return addr;
547 }
548
549 /* L1 Scratchpad memory free function */
550 int l1sram_free(const void *addr)
551 {
552         unsigned flags;
553         int ret;
554
555         /* add mutex operation */
556         spin_lock_irqsave(&l1sram_lock, flags);
557
558         ret = _l1_sram_free(addr, &free_l1_ssram_head,
559                         &used_l1_ssram_head);
560
561         /* add mutex operation */
562         spin_unlock_irqrestore(&l1sram_lock, flags);
563
564         return ret;
565 }
566
567 int sram_free_with_lsl(const void *addr)
568 {
569         struct sram_list_struct *lsl, **tmp;
570         struct mm_struct *mm = current->mm;
571
572         for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
573                 if ((*tmp)->addr == addr)
574                         goto found;
575         return -1;
576 found:
577         lsl = *tmp;
578         sram_free(addr);
579         *tmp = lsl->next;
580         kfree(lsl);
581
582         return 0;
583 }
584 EXPORT_SYMBOL(sram_free_with_lsl);
585
586 void *sram_alloc_with_lsl(size_t size, unsigned long flags)
587 {
588         void *addr = NULL;
589         struct sram_list_struct *lsl = NULL;
590         struct mm_struct *mm = current->mm;
591
592         lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
593         if (!lsl)
594                 return NULL;
595
596         if (flags & L1_INST_SRAM)
597                 addr = l1_inst_sram_alloc(size);
598
599         if (addr == NULL && (flags & L1_DATA_A_SRAM))
600                 addr = l1_data_A_sram_alloc(size);
601
602         if (addr == NULL && (flags & L1_DATA_B_SRAM))
603                 addr = l1_data_B_sram_alloc(size);
604
605         if (addr == NULL) {
606                 kfree(lsl);
607                 return NULL;
608         }
609         lsl->addr = addr;
610         lsl->length = size;
611         lsl->next = mm->context.sram_list;
612         mm->context.sram_list = lsl;
613         return addr;
614 }
615 EXPORT_SYMBOL(sram_alloc_with_lsl);
616
617 #ifdef CONFIG_PROC_FS
618 /* Once we get a real allocator, we'll throw all of this away.
619  * Until then, we need some sort of visibility into the L1 alloc.
620  */
621 /* Need to keep line of output the same.  Currently, that is 44 bytes
622  * (including newline).
623  */
624 static int _l1sram_proc_read(char *buf, int *len, int count, const char *desc,
625                 struct sram_piece *pfree_head,
626                 struct sram_piece *pused_head)
627 {
628         struct sram_piece *pslot;
629
630         if (!pfree_head || !pused_head)
631                 return -1;
632
633         *len += sprintf(&buf[*len], "--- L1 %-14s Size   PID State     \n", desc);
634
635         /* search the relevant memory slot */
636         pslot = pused_head->next;
637
638         while (pslot != NULL) {
639                 *len += sprintf(&buf[*len], "%p-%p %8i %5i %-10s\n",
640                         pslot->paddr, pslot->paddr + pslot->size,
641                         pslot->size, pslot->pid, "ALLOCATED");
642
643                 pslot = pslot->next;
644         }
645
646         pslot = pfree_head->next;
647
648         while (pslot != NULL) {
649                 *len += sprintf(&buf[*len], "%p-%p %8i %5i %-10s\n",
650                         pslot->paddr, pslot->paddr + pslot->size,
651                         pslot->size, pslot->pid, "FREE");
652
653                 pslot = pslot->next;
654         }
655
656         return 0;
657 }
658 static int l1sram_proc_read(char *buf, char **start, off_t offset, int count,
659                 int *eof, void *data)
660 {
661         int len = 0;
662
663         if (_l1sram_proc_read(buf, &len, count, "Scratchpad",
664                         &free_l1_ssram_head, &used_l1_ssram_head))
665                 goto not_done;
666 #if L1_DATA_A_LENGTH != 0
667         if (_l1sram_proc_read(buf, &len, count, "Data A",
668                         &free_l1_data_A_sram_head,
669                         &used_l1_data_A_sram_head))
670                 goto not_done;
671 #endif
672 #if L1_DATA_B_LENGTH != 0
673         if (_l1sram_proc_read(buf, &len, count, "Data B",
674                         &free_l1_data_B_sram_head,
675                         &used_l1_data_B_sram_head))
676                 goto not_done;
677 #endif
678 #if L1_CODE_LENGTH != 0
679         if (_l1sram_proc_read(buf, &len, count, "Instruction",
680                         &free_l1_inst_sram_head, &used_l1_inst_sram_head))
681                 goto not_done;
682 #endif
683
684         *eof = 1;
685  not_done:
686         return len;
687 }
688
689 static int __init l1sram_proc_init(void)
690 {
691         struct proc_dir_entry *ptr;
692         ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
693         if (!ptr) {
694                 printk(KERN_WARNING "unable to create /proc/sram\n");
695                 return -1;
696         }
697         ptr->owner = THIS_MODULE;
698         ptr->read_proc = l1sram_proc_read;
699         return 0;
700 }
701 late_initcall(l1sram_proc_init);
702 #endif