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 <memmap.h>
  11
  12#define STATUS_FREE 0
  13#define STATUS_ALLOCATED 1
  14
  15#ifdef CONFIG_ETRAX_L2CACHE
  16#define RESERVED_SIZE 66*1024
  17#else
  18#define RESERVED_SIZE 0
  19#endif
  20
  21struct intmem_allocation {
  22        struct list_head entry;
  23        unsigned int size;
  24        unsigned offset;
  25        char status;
  26};
  27
  28
  29static struct list_head intmem_allocations;
  30static void* intmem_virtual;
  31
  32static void crisv32_intmem_init(void)
  33{
  34        static int initiated = 0;
  35        if (!initiated) {
  36                struct intmem_allocation* alloc =
  37                  (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL);
  38                INIT_LIST_HEAD(&intmem_allocations);
  39                intmem_virtual = ioremap(MEM_INTMEM_START + RESERVED_SIZE,
  40                                         MEM_INTMEM_SIZE - RESERVED_SIZE);
  41                initiated = 1;
  42                alloc->size = MEM_INTMEM_SIZE - RESERVED_SIZE;
  43                alloc->offset = 0;
  44                alloc->status = STATUS_FREE;
  45                list_add_tail(&alloc->entry, &intmem_allocations);
  46        }
  47}
  48
  49void* crisv32_intmem_alloc(unsigned size, unsigned align)
  50{
  51        struct intmem_allocation* allocation;
  52        struct intmem_allocation* tmp;
  53        void* ret = NULL;
  54
  55        preempt_disable();
  56        crisv32_intmem_init();
  57
  58        list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
  59                int alignment = allocation->offset % align;
  60                alignment = alignment ? align - alignment : alignment;
  61
  62                if (allocation->status == STATUS_FREE &&
  63                    allocation->size >= size + alignment) {
  64                        if (allocation->size > size + alignment) {
  65                                struct intmem_allocation* alloc =
  66                                        (struct intmem_allocation*)
  67                                        kmalloc(sizeof *alloc, GFP_ATOMIC);
  68                                alloc->status = STATUS_FREE;
  69                                alloc->size = allocation->size - size -
  70                                        alignment;
  71                                alloc->offset = allocation->offset + size +
  72                                        alignment;
  73                                list_add(&alloc->entry, &allocation->entry);
  74
  75                                if (alignment) {
  76                                        struct intmem_allocation *tmp;
  77                                        tmp = (struct intmem_allocation *)
  78                                                kmalloc(sizeof *tmp,
  79                                                        GFP_ATOMIC);
  80                                        tmp->offset = allocation->offset;
  81                                        tmp->size = alignment;
  82                                        tmp->status = STATUS_FREE;
  83                                        allocation->offset += alignment;
  84                                        list_add_tail(&tmp->entry,
  85                                                &allocation->entry);
  86                                }
  87                        }
  88                        allocation->status = STATUS_ALLOCATED;
  89                        allocation->size = size;
  90                        ret = (void*)((int)intmem_virtual + allocation->offset);
  91                }
  92        }
  93        preempt_enable();
  94        return ret;
  95}
  96
  97void crisv32_intmem_free(void* addr)
  98{
  99        struct intmem_allocation* allocation;
 100        struct intmem_allocation* tmp;
 101
 102        if (addr == NULL)
 103                return;
 104
 105        preempt_disable();
 106        crisv32_intmem_init();
 107
 108        list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
 109                if (allocation->offset == (int)(addr - intmem_virtual)) {
 110                        struct intmem_allocation *prev =
 111                          list_entry(allocation->entry.prev,
 112                                     struct intmem_allocation, entry);
 113                        struct intmem_allocation *next =
 114                          list_entry(allocation->entry.next,
 115                                     struct intmem_allocation, entry);
 116
 117                        allocation->status = STATUS_FREE;
 118                        /* Join with prev and/or next if also free */
 119                        if ((prev != &intmem_allocations) &&
 120                                        (prev->status == STATUS_FREE)) {
 121                                prev->size += allocation->size;
 122                                list_del(&allocation->entry);
 123                                kfree(allocation);
 124                                allocation = prev;
 125                        }
 126                        if ((next != &intmem_allocations) &&
 127                                        (next->status == STATUS_FREE)) {
 128                                allocation->size += next->size;
 129                                list_del(&next->entry);
 130                                kfree(next);
 131                        }
 132                        preempt_enable();
 133                        return;
 134                }
 135        }
 136        preempt_enable();
 137}
 138
 139void* crisv32_intmem_phys_to_virt(unsigned long addr)
 140{
 141        return (void *)(addr - (MEM_INTMEM_START + RESERVED_SIZE) +
 142                (unsigned long)intmem_virtual);
 143}
 144
 145unsigned long crisv32_intmem_virt_to_phys(void* addr)
 146{
 147        return (unsigned long)((unsigned long )addr -
 148                (unsigned long)intmem_virtual + MEM_INTMEM_START +
 149                RESERVED_SIZE);
 150}
 151
 152module_init(crisv32_intmem_init);
 153
 154