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);