Root/target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c

1/*
2 * arch/ubicom32/mm/ocm-alloc.c
3 * OCM allocator for Uibcom32 On-Chip memory
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 * Copyright 2004-2008 Analog Devices Inc.
7 *
8 * Based on:
9 *
10 * arch/blackfin/mm/sram-alloc.c
11 *
12 *
13 * This file is part of the Ubicom32 Linux Kernel Port.
14 *
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.
19 *
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.
24 *
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/>.
28 *
29 * Ubicom32 implementation derived from (with many thanks):
30 * arch/m68knommu
31 * arch/blackfin
32 * arch/parisc
33 */
34
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>
47
48#if 0
49#define DEBUGP printk
50#else
51#define DEBUGP(fmt, a...)
52#endif
53/*
54 * the data structure for OCM heap pieces
55 */
56struct ocm_piece {
57    void *paddr;
58    int size;
59    pid_t pid;
60    struct ocm_piece *next;
61};
62
63/*
64 * struct ocm_heap
65 */
66struct ocm_heap {
67    struct ocm_piece free_head;
68    struct ocm_piece used_head;
69    struct mutex lock;
70};
71
72static struct ocm_heap ocm_inst_heap;
73int ubi32_ocm_skbuf_max = 21, ubi32_ocm_skbuf, ubi32_ddr_skbuf;
74
75/*
76 * OCM area for storing code
77 */
78extern asmlinkage void *__ocm_free_begin;
79extern asmlinkage void *__ocm_free_end;
80extern asmlinkage void *__ocm_inst_heap_begin;
81extern 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)
85
86static struct kmem_cache *ocm_piece_cache;
87
88/*
89 * _ocm_heap_init()
90 */
91static int __init _ocm_heap_init(struct ocm_heap *ocmh,
92                  unsigned int start,
93                  unsigned int size)
94{
95    ocmh->free_head.next = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL);
96
97    if (!ocmh->free_head.next)
98        return -1;
99
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;
104
105    ocmh->used_head.next = NULL;
106
107    /* mutex initialize */
108    mutex_init(&ocmh->lock);
109
110    return 0;
111}
112
113/*
114 * _ocm_alloc_init()
115 *
116 * starts the ocm heap(s)
117 */
118static int __init _ocm_alloc_init(void)
119{
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);
124
125        if (_ocm_heap_init(&ocm_inst_heap,
126                   OCM_INST_HEAP_BEGIN,
127                   OCM_INST_HEAP_LENGTH) == 0)
128            printk(KERN_INFO "OCM Instruction Heap %d KB\n",
129                   OCM_INST_HEAP_LENGTH >> 10);
130        else
131            printk(KERN_INFO "Failed to initialize OCM "
132                   "Instruction Heap\n");
133
134    } else
135        printk(KERN_INFO "No space available for OCM "
136               "Instruction Heap\n");
137
138    return 0;
139}
140pure_initcall(_ocm_alloc_init);
141
142/*
143 * _ocm_alloc()
144 * generic alloc a block in the ocm heap, if successful
145 * returns the pointer.
146 */
147static void *_ocm_alloc(size_t size, pid_t pid, struct ocm_heap *ocmheap)
148{
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;
152
153    if (size <= 0 || !pfree_head || !pused_head)
154        return NULL;
155
156    /* Align the size */
157    size = (size + 3) & ~3;
158
159    pslot = pfree_head->next;
160    plast = pfree_head;
161
162    /*
163     * search an available piece slot
164     */
165    while (pslot != NULL && size > pslot->size) {
166        plast = pslot;
167        pslot = pslot->next;
168    }
169
170    if (!pslot)
171        return NULL;
172
173    if (pslot->size == size) {
174        /*
175         * Unlink this block from the list
176         */
177        plast->next = pslot->next;
178        pavail = pslot;
179    } else {
180        /*
181         * Split this block in two.
182         */
183        pavail = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL);
184
185        if (!pavail)
186            return NULL;
187
188        pavail->paddr = pslot->paddr;
189        pavail->size = size;
190        pslot->paddr += size;
191        pslot->size -= size;
192    }
193
194    pavail->pid = pid;
195
196    pslot = pused_head->next;
197    plast = pused_head;
198
199    /*
200     * insert new piece into used piece list !!!
201     */
202    while (pslot != NULL && pavail->paddr < pslot->paddr) {
203        plast = pslot;
204        pslot = pslot->next;
205    }
206
207    pavail->next = pslot;
208    plast->next = pavail;
209
210    DEBUGP("_ocm_alloc %d bytes at %p from in %p",
211           size, pavail->paddr, ocmheap);
212
213    return pavail->paddr;
214}
215
216#if 0
217/* Allocate the largest available block. */
218static void *_ocm_alloc_max(struct ocm_heap *ocmheap,
219                 unsigned long *psize)
220{
221    struct ocm_piece *pfree_head = &ocmheap->free_head;
222    struct ocm_piece *pslot, *pmax;
223
224    pmax = pslot = pfree_head->next;
225
226    /* search an available piece slot */
227    while (pslot != NULL) {
228        if (pslot->size > pmax->size)
229            pmax = pslot;
230        pslot = pslot->next;
231    }
232
233    if (!pmax)
234        return NULL;
235
236    *psize = pmax->size;
237
238    return _ocm_alloc(*psize, ocmheap);
239}
240#endif
241
242/*
243 * _ocm_free()
244 * generic free a block in the ocm heap, if successful
245 */
246static int _ocm_free(const void *addr,
247             struct ocm_heap *ocmheap)
248{
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;
252
253    /* search the relevant memory slot */
254    pslot = pused_head->next;
255    plast = pused_head;
256
257    /* search an available piece slot */
258    while (pslot != NULL && pslot->paddr != addr) {
259        plast = pslot;
260        pslot = pslot->next;
261    }
262
263    if (!pslot) {
264        DEBUGP("_ocm_free %p not found in %p", addr, ocmheap);
265        return -1;
266    }
267    DEBUGP("_ocm_free %p from in %p", addr, ocmheap);
268
269    plast->next = pslot->next;
270    pavail = pslot;
271    pavail->pid = 0;
272
273    /* insert free pieces back to the free list */
274    pslot = pfree_head->next;
275    plast = pfree_head;
276
277    while (pslot != NULL && addr > pslot->paddr) {
278        plast = pslot;
279        pslot = pslot->next;
280    }
281
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);
286    } else {
287        pavail->next = plast->next;
288        plast->next = pavail;
289        plast = pavail;
290    }
291
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);
296    }
297
298    return 0;
299}
300
301/*
302 * ocm_inst_alloc()
303 *
304 * allocates a block of size in the ocm instrction heap, if
305 * successful returns address allocated.
306 */
307void *ocm_inst_alloc(size_t size, pid_t pid)
308{
309    void *addr;
310
311    if (!OCM_INST_HEAP_LENGTH)
312        return NULL;
313
314
315    mutex_lock(&ocm_inst_heap.lock);
316
317    addr = _ocm_alloc(size, pid, &ocm_inst_heap);
318
319    mutex_unlock(&ocm_inst_heap.lock);
320
321    return addr;
322}
323EXPORT_SYMBOL(ocm_inst_alloc);
324
325/*
326 * ocm_inst_free()
327 * free a block in the ocm instrction heap, returns 0 if successful.
328 */
329int ocm_inst_free(const void *addr)
330{
331    int ret;
332
333    if (!OCM_INST_HEAP_LENGTH)
334        return -1;
335
336    mutex_lock(&ocm_inst_heap.lock);
337
338    ret = _ocm_free(addr, &ocm_inst_heap);
339
340    mutex_unlock(&ocm_inst_heap.lock);
341
342    return ret;
343}
344EXPORT_SYMBOL(ocm_inst_free);
345
346/*
347 * ocm_free()
348 * free a block in one of the ocm heaps, returns 0 if successful.
349 */
350int ocm_free(const void *addr)
351{
352    if (addr >= (void *)OCM_INST_HEAP_BEGIN
353         && addr < (void *)(OCM_INST_HEAP_END))
354        return ocm_inst_free(addr);
355    else
356        return -1;
357}
358EXPORT_SYMBOL(ocm_free);
359
360
361#ifdef CONFIG_PROC_FS
362/* Need to keep line of output the same. Currently, that is 46 bytes
363 * (including newline).
364 */
365static int _ocm_proc_read(char *buf, int *len, int count, const char *desc,
366               struct ocm_heap *ocmheap)
367{
368    struct ocm_piece *pslot;
369    struct ocm_piece *pfree_head = &ocmheap->free_head;
370    struct ocm_piece *pused_head = &ocmheap->used_head;
371
372    /* The format is the following
373     * --- OCM 123456789012345 Size PID State \n
374     * 12345678-12345678 1234567890 12345 1234567890\n
375     */
376    int l;
377    l = sprintf(&buf[*len], "--- OCM %-15s Size PID State \n",
378            desc);
379
380    *len += l;
381    count -= l;
382
383    mutex_lock(&ocm_inst_heap.lock);
384
385    /*
386     * search the relevant memory slot
387     */
388    pslot = pused_head->next;
389
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");
394
395        *len += l;
396        count -= l;
397        pslot = pslot->next;
398    }
399
400    pslot = pfree_head->next;
401
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");
406
407        *len += l;
408        count -= l;
409        pslot = pslot->next;
410    }
411
412    mutex_unlock(&ocm_inst_heap.lock);
413
414    return 0;
415}
416
417static int ocm_proc_read(char *buf, char **start, off_t offset, int count,
418        int *eof, void *data)
419{
420    int len = 0;
421
422    len = sprintf(&buf[len], "--- OCM SKB usage (max RX buf %d)\n"
423            "(SKB in OCM) %d - (SKB in DDR) %d\n",
424            ubi32_ocm_skbuf_max,
425            ubi32_ocm_skbuf,
426            ubi32_ddr_skbuf);
427
428    len += sprintf(&buf[len], "--- OCM Data Heap Size\n"
429            "%p-%p %10i\n",
430            ((void *)&__ocm_free_begin),
431            ((void *)&__ocm_free_end),
432            ((unsigned int)&__ocm_free_end) -
433            ((unsigned int)&__ocm_free_begin));
434
435    if (_ocm_proc_read(buf, &len, count - len, "Inst Heap",
436                &ocm_inst_heap))
437        goto not_done;
438    *eof = 1;
439 not_done:
440    return len;
441}
442
443static int ocm_proc_write(struct file *file, const char __user *buffer,
444                           unsigned long count, void *data)
445{
446    int n, v;
447    char in[8];
448
449    if (count > sizeof(in))
450        return -EINVAL;
451
452    if (copy_from_user(in, buffer, count))
453        return -EFAULT;
454    in[count-1] = 0;
455
456    printk(KERN_INFO "OCM skb alloc max = %s\n", in);
457
458    n = 0;
459    v = 0;
460    while ((in[n] >= '0') && (in[n] <= '9')) {
461        v = v * 10 + (int)(in[n] - '0');
462        n++;
463    }
464
465    if (v == 0)
466        return -EINVAL;
467
468    ubi32_ocm_skbuf_max = v;
469    ubi32_ocm_skbuf = ubi32_ddr_skbuf = 0;
470
471    return count;
472}
473
474static int __init sram_proc_init(void)
475{
476    struct proc_dir_entry *ptr;
477    ptr = create_proc_entry("ocm", S_IFREG | S_IRUGO, NULL);
478    if (!ptr) {
479        printk(KERN_WARNING "unable to create /proc/ocm\n");
480        return -1;
481    }
482    ptr->read_proc = ocm_proc_read;
483    ptr->write_proc = ocm_proc_write;
484    return 0;
485}
486late_initcall(sram_proc_init);
487#endif
488

Archive Download this file



interactive