5a10c2938ba86fcbb15ca61916b441ebb0bc9627
2 * arch/ubicom32/mm/ocm-alloc.c
3 * OCM allocator for Uibcom32 On-Chip memory
5 * (C) Copyright 2009, Ubicom, Inc.
6 * Copyright 2004-2008 Analog Devices Inc.
10 * arch/blackfin/mm/sram-alloc.c
13 * This file is part of the Ubicom32 Linux Kernel Port.
15 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
16 * it and/or modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, either version 2 of the
18 * License, or (at your option) any later version.
20 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
21 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
22 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
23 * the GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with the Ubicom32 Linux Kernel Port. If not,
27 * see <http://www.gnu.org/licenses/>.
29 * Ubicom32 implementation derived from (with many thanks):
35 #include <linux/module.h>
36 #include <linux/kernel.h>
37 #include <linux/types.h>
38 #include <linux/miscdevice.h>
39 #include <linux/ioport.h>
40 #include <linux/fcntl.h>
41 #include <linux/init.h>
42 #include <linux/poll.h>
43 #include <linux/proc_fs.h>
44 #include <linux/mutex.h>
45 #include <linux/rtc.h>
46 #include <asm/ocm-alloc.h>
51 #define DEBUGP(fmt, a...)
54 * the data structure for OCM heap pieces
60 struct ocm_piece
*next
;
67 struct ocm_piece free_head
;
68 struct ocm_piece used_head
;
72 static struct ocm_heap ocm_inst_heap
;
73 int ubi32_ocm_skbuf_max
= 21, ubi32_ocm_skbuf
, ubi32_ddr_skbuf
;
76 * OCM area for storing code
78 extern asmlinkage
void *__ocm_free_begin
;
79 extern asmlinkage
void *__ocm_free_end
;
80 extern asmlinkage
void *__ocm_inst_heap_begin
;
81 extern asmlinkage
void *__ocm_inst_heap_end
;
82 #define OCM_INST_HEAP_BEGIN ((unsigned int)&__ocm_inst_heap_begin)
83 #define OCM_INST_HEAP_END ((unsigned int)&__ocm_inst_heap_end)
84 #define OCM_INST_HEAP_LENGTH (OCM_INST_HEAP_END - OCM_INST_HEAP_BEGIN)
86 static struct kmem_cache
*ocm_piece_cache
;
91 static int __init
_ocm_heap_init(struct ocm_heap
*ocmh
,
95 ocmh
->free_head
.next
= kmem_cache_alloc(ocm_piece_cache
, GFP_KERNEL
);
97 if (!ocmh
->free_head
.next
)
100 ocmh
->free_head
.next
->paddr
= (void *)start
;
101 ocmh
->free_head
.next
->size
= size
;
102 ocmh
->free_head
.next
->pid
= 0;
103 ocmh
->free_head
.next
->next
= 0;
105 ocmh
->used_head
.next
= NULL
;
107 /* mutex initialize */
108 mutex_init(&ocmh
->lock
);
116 * starts the ocm heap(s)
118 static int __init
_ocm_alloc_init(void)
120 if (OCM_INST_HEAP_LENGTH
) {
121 ocm_piece_cache
= kmem_cache_create("ocm_piece_cache",
122 sizeof(struct ocm_piece
),
123 0, SLAB_PANIC
, NULL
);
125 if (_ocm_heap_init(&ocm_inst_heap
,
127 OCM_INST_HEAP_LENGTH
) == 0)
128 printk(KERN_INFO
"OCM Instruction Heap %d KB\n",
129 OCM_INST_HEAP_LENGTH
>> 10);
131 printk(KERN_INFO
"Failed to initialize OCM "
132 "Instruction Heap\n");
135 printk(KERN_INFO
"No space available for OCM "
136 "Instruction Heap\n");
140 pure_initcall(_ocm_alloc_init
);
144 * generic alloc a block in the ocm heap, if successful
145 * returns the pointer.
147 static void *_ocm_alloc(size_t size
, pid_t pid
, struct ocm_heap
*ocmheap
)
149 struct ocm_piece
*pslot
, *plast
, *pavail
;
150 struct ocm_piece
*pfree_head
= &ocmheap
->free_head
;
151 struct ocm_piece
*pused_head
= &ocmheap
->used_head
;
153 if (size
<= 0 || !pfree_head
|| !pused_head
)
157 size
= (size
+ 3) & ~3;
159 pslot
= pfree_head
->next
;
163 * search an available piece slot
165 while (pslot
!= NULL
&& size
> pslot
->size
) {
173 if (pslot
->size
== size
) {
175 * Unlink this block from the list
177 plast
->next
= pslot
->next
;
181 * Split this block in two.
183 pavail
= kmem_cache_alloc(ocm_piece_cache
, GFP_KERNEL
);
188 pavail
->paddr
= pslot
->paddr
;
190 pslot
->paddr
+= size
;
196 pslot
= pused_head
->next
;
200 * insert new piece into used piece list !!!
202 while (pslot
!= NULL
&& pavail
->paddr
< pslot
->paddr
) {
207 pavail
->next
= pslot
;
208 plast
->next
= pavail
;
210 DEBUGP("_ocm_alloc %d bytes at %p from in %p",
211 size
, pavail
->paddr
, ocmheap
);
213 return pavail
->paddr
;
217 /* Allocate the largest available block. */
218 static void *_ocm_alloc_max(struct ocm_heap
*ocmheap
,
219 unsigned long *psize
)
221 struct ocm_piece
*pfree_head
= &ocmheap
->free_head
;
222 struct ocm_piece
*pslot
, *pmax
;
224 pmax
= pslot
= pfree_head
->next
;
226 /* search an available piece slot */
227 while (pslot
!= NULL
) {
228 if (pslot
->size
> pmax
->size
)
238 return _ocm_alloc(*psize
, ocmheap
);
244 * generic free a block in the ocm heap, if successful
246 static int _ocm_free(const void *addr
,
247 struct ocm_heap
*ocmheap
)
249 struct ocm_piece
*pslot
, *plast
, *pavail
;
250 struct ocm_piece
*pfree_head
= &ocmheap
->free_head
;
251 struct ocm_piece
*pused_head
= &ocmheap
->used_head
;
253 /* search the relevant memory slot */
254 pslot
= pused_head
->next
;
257 /* search an available piece slot */
258 while (pslot
!= NULL
&& pslot
->paddr
!= addr
) {
264 DEBUGP("_ocm_free %p not found in %p", addr
, ocmheap
);
267 DEBUGP("_ocm_free %p from in %p", addr
, ocmheap
);
269 plast
->next
= pslot
->next
;
273 /* insert free pieces back to the free list */
274 pslot
= pfree_head
->next
;
277 while (pslot
!= NULL
&& addr
> pslot
->paddr
) {
282 if (plast
!= pfree_head
&&
283 plast
->paddr
+ plast
->size
== pavail
->paddr
) {
284 plast
->size
+= pavail
->size
;
285 kmem_cache_free(ocm_piece_cache
, pavail
);
287 pavail
->next
= plast
->next
;
288 plast
->next
= pavail
;
292 if (pslot
&& plast
->paddr
+ plast
->size
== pslot
->paddr
) {
293 plast
->size
+= pslot
->size
;
294 plast
->next
= pslot
->next
;
295 kmem_cache_free(ocm_piece_cache
, pslot
);
304 * allocates a block of size in the ocm instrction heap, if
305 * successful returns address allocated.
307 void *ocm_inst_alloc(size_t size
, pid_t pid
)
311 if (!OCM_INST_HEAP_LENGTH
)
315 mutex_lock(&ocm_inst_heap
.lock
);
317 addr
= _ocm_alloc(size
, pid
, &ocm_inst_heap
);
319 mutex_unlock(&ocm_inst_heap
.lock
);
323 EXPORT_SYMBOL(ocm_inst_alloc
);
327 * free a block in the ocm instrction heap, returns 0 if successful.
329 int ocm_inst_free(const void *addr
)
333 if (!OCM_INST_HEAP_LENGTH
)
336 mutex_lock(&ocm_inst_heap
.lock
);
338 ret
= _ocm_free(addr
, &ocm_inst_heap
);
340 mutex_unlock(&ocm_inst_heap
.lock
);
344 EXPORT_SYMBOL(ocm_inst_free
);
348 * free a block in one of the ocm heaps, returns 0 if successful.
350 int ocm_free(const void *addr
)
352 if (addr
>= (void *)OCM_INST_HEAP_BEGIN
353 && addr
< (void *)(OCM_INST_HEAP_END
))
354 return ocm_inst_free(addr
);
358 EXPORT_SYMBOL(ocm_free
);
361 #ifdef CONFIG_PROC_FS
362 /* Need to keep line of output the same. Currently, that is 46 bytes
363 * (including newline).
365 static int _ocm_proc_read(char *buf
, int *len
, int count
, const char *desc
,
366 struct ocm_heap
*ocmheap
)
368 struct ocm_piece
*pslot
;
369 struct ocm_piece
*pfree_head
= &ocmheap
->free_head
;
370 struct ocm_piece
*pused_head
= &ocmheap
->used_head
;
372 /* The format is the following
373 * --- OCM 123456789012345 Size PID State \n
374 * 12345678-12345678 1234567890 12345 1234567890\n
377 l
= sprintf(&buf
[*len
], "--- OCM %-15s Size PID State \n",
383 mutex_lock(&ocm_inst_heap
.lock
);
386 * search the relevant memory slot
388 pslot
= pused_head
->next
;
390 while (pslot
!= NULL
&& count
> 46) {
391 l
= sprintf(&buf
[*len
], "%p-%p %10i %5i %-10s\n",
392 pslot
->paddr
, pslot
->paddr
+ pslot
->size
,
393 pslot
->size
, pslot
->pid
, "ALLOCATED");
400 pslot
= pfree_head
->next
;
402 while (pslot
!= NULL
&& count
> 46) {
403 l
= sprintf(&buf
[*len
], "%p-%p %10i %5i %-10s\n",
404 pslot
->paddr
, pslot
->paddr
+ pslot
->size
,
405 pslot
->size
, pslot
->pid
, "FREE");
412 mutex_unlock(&ocm_inst_heap
.lock
);
417 static int ocm_proc_read(char *buf
, char **start
, off_t offset
, int count
,
418 int *eof
, void *data
)
422 len
= sprintf(&buf
[len
], "--- OCM SKB usage (max RX buf %d)\n"
423 "(SKB in OCM) %d - (SKB in DDR) %d\n",
428 len
+= sprintf(&buf
[len
], "--- OCM Data Heap Size\n"
430 ((void *)&__ocm_free_begin
),
431 ((void *)&__ocm_free_end
),
432 ((unsigned int)&__ocm_free_end
) -
433 ((unsigned int)&__ocm_free_begin
));
435 if (_ocm_proc_read(buf
, &len
, count
- len
, "Inst Heap",
443 static int ocm_proc_write(struct file
*file
, const char __user
*buffer
,
444 unsigned long count
, void *data
)
449 if (count
> sizeof(in
))
452 if (copy_from_user(in
, buffer
, count
))
456 printk(KERN_INFO
"OCM skb alloc max = %s\n", in
);
460 while ((in
[n
] >= '0') && (in
[n
] <= '9')) {
461 v
= v
* 10 + (int)(in
[n
] - '0');
468 ubi32_ocm_skbuf_max
= v
;
469 ubi32_ocm_skbuf
= ubi32_ddr_skbuf
= 0;
474 static int __init
sram_proc_init(void)
476 struct proc_dir_entry
*ptr
;
477 ptr
= create_proc_entry("ocm", S_IFREG
| S_IRUGO
, NULL
);
479 printk(KERN_WARNING
"unable to create /proc/ocm\n");
482 ptr
->read_proc
= ocm_proc_read
;
483 ptr
->write_proc
= ocm_proc_write
;
486 late_initcall(sram_proc_init
);