linux/arch/cris/arch-v32/mm/intmem.c
Paul Gortmaker 73de14e8cd cris: don't use module_init for non-modular core intmem.c code
The intmem.c code is always built in.  It will never be modular,
so using module_init as an alias for __initcall is rather
misleading.

Fix this up now, so that we can relocate module_init from
init.h into module.h in the future.  If we don't do this, we'd
have to add module.h to obviously non-modular code, and that
would be a worse thing.

Direct use of __initcall is discouraged, vs prioritized ones.
Use of device_initcall is consistent with what __initcall
maps onto, and hence does not change the init order, making the
impact of this change zero.   Should someone with real hardware
for boot testing want to change it later to arch_initcall or
something different, they can do that at a later date.

Reported-by: kbuild test robot <fengguang.wu@intel.com>
Cc: Mikael Starvik <starvik@axis.com>
Cc: Jesper Nilsson <jesper.nilsson@axis.com>
Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>
Cc: linux-cris-kernel@axis.com
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
2015-06-16 14:12:30 -04:00

150 lines
3.6 KiB
C

/*
* Simple allocator for internal RAM in ETRAX FS
*
* Copyright (c) 2004 Axis Communications AB.
*/
#include <linux/list.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <memmap.h>
#define STATUS_FREE 0
#define STATUS_ALLOCATED 1
#ifdef CONFIG_ETRAX_L2CACHE
#define RESERVED_SIZE 66*1024
#else
#define RESERVED_SIZE 0
#endif
struct intmem_allocation {
struct list_head entry;
unsigned int size;
unsigned offset;
char status;
};
static struct list_head intmem_allocations;
static void* intmem_virtual;
static void crisv32_intmem_init(void)
{
static int initiated = 0;
if (!initiated) {
struct intmem_allocation* alloc;
alloc = kmalloc(sizeof *alloc, GFP_KERNEL);
INIT_LIST_HEAD(&intmem_allocations);
intmem_virtual = ioremap(MEM_INTMEM_START + RESERVED_SIZE,
MEM_INTMEM_SIZE - RESERVED_SIZE);
initiated = 1;
alloc->size = MEM_INTMEM_SIZE - RESERVED_SIZE;
alloc->offset = 0;
alloc->status = STATUS_FREE;
list_add_tail(&alloc->entry, &intmem_allocations);
}
}
void* crisv32_intmem_alloc(unsigned size, unsigned align)
{
struct intmem_allocation* allocation;
struct intmem_allocation* tmp;
void* ret = NULL;
preempt_disable();
crisv32_intmem_init();
list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
int alignment = allocation->offset % align;
alignment = alignment ? align - alignment : alignment;
if (allocation->status == STATUS_FREE &&
allocation->size >= size + alignment) {
if (allocation->size > size + alignment) {
struct intmem_allocation* alloc;
alloc = kmalloc(sizeof *alloc, GFP_ATOMIC);
alloc->status = STATUS_FREE;
alloc->size = allocation->size - size -
alignment;
alloc->offset = allocation->offset + size +
alignment;
list_add(&alloc->entry, &allocation->entry);
if (alignment) {
struct intmem_allocation *tmp;
tmp = kmalloc(sizeof *tmp, GFP_ATOMIC);
tmp->offset = allocation->offset;
tmp->size = alignment;
tmp->status = STATUS_FREE;
allocation->offset += alignment;
list_add_tail(&tmp->entry,
&allocation->entry);
}
}
allocation->status = STATUS_ALLOCATED;
allocation->size = size;
ret = (void*)((int)intmem_virtual + allocation->offset);
}
}
preempt_enable();
return ret;
}
void crisv32_intmem_free(void* addr)
{
struct intmem_allocation* allocation;
struct intmem_allocation* tmp;
if (addr == NULL)
return;
preempt_disable();
crisv32_intmem_init();
list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
if (allocation->offset == (int)(addr - intmem_virtual)) {
struct intmem_allocation *prev =
list_entry(allocation->entry.prev,
struct intmem_allocation, entry);
struct intmem_allocation *next =
list_entry(allocation->entry.next,
struct intmem_allocation, entry);
allocation->status = STATUS_FREE;
/* Join with prev and/or next if also free */
if ((prev != &intmem_allocations) &&
(prev->status == STATUS_FREE)) {
prev->size += allocation->size;
list_del(&allocation->entry);
kfree(allocation);
allocation = prev;
}
if ((next != &intmem_allocations) &&
(next->status == STATUS_FREE)) {
allocation->size += next->size;
list_del(&next->entry);
kfree(next);
}
preempt_enable();
return;
}
}
preempt_enable();
}
void* crisv32_intmem_phys_to_virt(unsigned long addr)
{
return (void *)(addr - (MEM_INTMEM_START + RESERVED_SIZE) +
(unsigned long)intmem_virtual);
}
unsigned long crisv32_intmem_virt_to_phys(void* addr)
{
return (unsigned long)((unsigned long )addr -
(unsigned long)intmem_virtual + MEM_INTMEM_START +
RESERVED_SIZE);
}
device_initcall(crisv32_intmem_init);