linux/arch/cris/arch-v32/mm/intmem.c
<<
>>
Prefs
   1/*
   2 * Simple allocator for internal RAM in ETRAX FS
   3 *
   4 * Copyright (c) 2004 Axis Communications AB.
   5 */
   6
   7#include <linux/list.h>
   8#include <linux/slab.h>
   9#include <asm/io.h>
  10#include <asm/arch/memmap.h>
  11
  12#define STATUS_FREE 0
  13#define STATUS_ALLOCATED 1
  14
  15struct intmem_allocation {
  16        struct list_head entry;
  17        unsigned int size;
  18        unsigned offset;
  19        char status;
  20};
  21
  22
  23static struct list_head intmem_allocations;
  24static void* intmem_virtual;
  25
  26static void crisv32_intmem_init(void)
  27{
  28        static int initiated = 0;
  29        if (!initiated) {
  30                struct intmem_allocation* alloc =
  31                  (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL);
  32                INIT_LIST_HEAD(&intmem_allocations);
  33                intmem_virtual = ioremap(MEM_INTMEM_START, MEM_INTMEM_SIZE);
  34                initiated = 1;
  35                alloc->size = MEM_INTMEM_SIZE;
  36                alloc->offset = 0;
  37                alloc->status = STATUS_FREE;
  38                list_add_tail(&alloc->entry, &intmem_allocations);
  39        }
  40}
  41
  42void* crisv32_intmem_alloc(unsigned size, unsigned align)
  43{
  44        struct intmem_allocation* allocation;
  45        struct intmem_allocation* tmp;
  46        void* ret = NULL;
  47
  48        preempt_disable();
  49        crisv32_intmem_init();
  50
  51        list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
  52                int alignment = allocation->offset % align;
  53                alignment = alignment ? align - alignment : alignment;
  54
  55                if (allocation->status == STATUS_FREE &&
  56                    allocation->size >= size + alignment) {
  57                        if (allocation->size > size + alignment) {
  58                                struct intmem_allocation* alloc =
  59                                        (struct intmem_allocation*)
  60                                        kmalloc(sizeof *alloc, GFP_ATOMIC);
  61                                alloc->status = STATUS_FREE;
  62                                alloc->size = allocation->size - size - alignment;
  63                                alloc->offset = allocation->offset + size;
  64                                list_add(&alloc->entry, &allocation->entry);
  65
  66                                if (alignment) {
  67                                        struct intmem_allocation* tmp;
  68                                        tmp = (struct intmem_allocation*)
  69                                                kmalloc(sizeof *tmp, GFP_ATOMIC);
  70                                        tmp->offset = allocation->offset;
  71                                        tmp->size = alignment;
  72                                        tmp->status = STATUS_FREE;
  73                                        allocation->offset += alignment;
  74                                        list_add_tail(&tmp->entry, &allocation->entry);
  75                                }
  76                        }
  77                        allocation->status = STATUS_ALLOCATED;
  78                        allocation->size = size;
  79                        ret = (void*)((int)intmem_virtual + allocation->offset);
  80                }
  81        }
  82        preempt_enable();
  83        return ret;
  84}
  85
  86void crisv32_intmem_free(void* addr)
  87{
  88        struct intmem_allocation* allocation;
  89        struct intmem_allocation* tmp;
  90
  91        if (addr == NULL)
  92                return;
  93
  94        preempt_disable();
  95        crisv32_intmem_init();
  96
  97        list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
  98                if (allocation->offset == (int)(addr - intmem_virtual)) {
  99                        struct intmem_allocation* prev =
 100                          list_entry(allocation->entry.prev,
 101                                     struct intmem_allocation, entry);
 102                        struct intmem_allocation* next =
 103                          list_entry(allocation->entry.next,
 104                                     struct intmem_allocation, entry);
 105
 106                        allocation->status = STATUS_FREE;
 107                        /* Join with prev and/or next if also free */
 108                        if (prev->status == STATUS_FREE) {
 109                                prev->size += allocation->size;
 110                                list_del(&allocation->entry);
 111                                kfree(allocation);
 112                                allocation = prev;
 113                        }
 114                        if (next->status == STATUS_FREE) {
 115                                allocation->size += next->size;
 116                                list_del(&next->entry);
 117                                kfree(next);
 118                        }
 119                        preempt_enable();
 120                        return;
 121                }
 122        }
 123        preempt_enable();
 124}
 125
 126void* crisv32_intmem_phys_to_virt(unsigned long addr)
 127{
 128        return (void*)(addr - MEM_INTMEM_START+
 129                       (unsigned long)intmem_virtual);
 130}
 131
 132unsigned long crisv32_intmem_virt_to_phys(void* addr)
 133{
 134        return (unsigned long)((unsigned long )addr -
 135          (unsigned long)intmem_virtual + MEM_INTMEM_START);
 136}
 137
 138
 139
 140
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.