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                alloc = 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                                alloc = kmalloc(sizeof *alloc, GFP_ATOMIC);
  67                                alloc->status = STATUS_FREE;
  68                                alloc->size = allocation->size - size -
  69                                        alignment;
  70                                alloc->offset = allocation->offset + size +
  71                                        alignment;
  72                                list_add(&alloc->entry, &allocation->entry);
  73
  74                                if (alignment) {
  75                                        struct intmem_allocation *tmp;
  76                                        tmp = kmalloc(sizeof *tmp, GFP_ATOMIC);
  77                                        tmp->offset = allocation->offset;
  78                                        tmp->size = alignment;
  79                                        tmp->status = STATUS_FREE;
  80                                        allocation->offset += alignment;
  81                                        list_add_tail(&tmp->entry,
  82                                                &allocation->entry);
  83                                }
  84                        }
  85                        allocation->status = STATUS_ALLOCATED;
  86                        allocation->size = size;
  87                        ret = (void*)((int)intmem_virtual + allocation->offset);
  88                }
  89        }
  90        preempt_enable();
  91        return ret;
  92}
  93
  94void crisv32_intmem_free(void* addr)
  95{
  96        struct intmem_allocation* allocation;
  97        struct intmem_allocation* tmp;
  98
  99        if (addr == NULL)
 100                return;
 101
 102        preempt_disable();
 103        crisv32_intmem_init();
 104
 105        list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
 106                if (allocation->offset == (int)(addr - intmem_virtual)) {
 107                        struct intmem_allocation *prev =
 108                          list_entry(allocation->entry.prev,
 109                                     struct intmem_allocation, entry);
 110                        struct intmem_allocation *next =
 111                          list_entry(allocation->entry.next,
 112                                     struct intmem_allocation, entry);
 113
 114                        allocation->status = STATUS_FREE;
 115                        /* Join with prev and/or next if also free */
 116                        if ((prev != &intmem_allocations) &&
 117                                        (prev->status == STATUS_FREE)) {
 118                                prev->size += allocation->size;
 119                                list_del(&allocation->entry);
 120                                kfree(allocation);
 121                                allocation = prev;
 122                        }
 123                        if ((next != &intmem_allocations) &&
 124                                        (next->status == STATUS_FREE)) {
 125                                allocation->size += next->size;
 126                                list_del(&next->entry);
 127                                kfree(next);
 128                        }
 129                        preempt_enable();
 130                        return;
 131                }
 132        }
 133        preempt_enable();
 134}
 135
 136void* crisv32_intmem_phys_to_virt(unsigned long addr)
 137{
 138        return (void *)(addr - (MEM_INTMEM_START + RESERVED_SIZE) +
 139                (unsigned long)intmem_virtual);
 140}
 141
 142unsigned long crisv32_intmem_virt_to_phys(void* addr)
 143{
 144        return (unsigned long)((unsigned long )addr -
 145                (unsigned long)intmem_virtual + MEM_INTMEM_START +
 146                RESERVED_SIZE);
 147}
 148
 149module_init(crisv32_intmem_init);
 150
 151