[PATCH] CRIS update: new subarchitecture v32

New CRIS sub architecture named v32.

From: Dave Jones <davej@redhat.com>

	Fix swapped kmalloc args

Signed-off-by: Mikael Starvik <starvik@axis.com>
Signed-off-by: Dave Jones <davej@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/arch/cris/arch-v32/mm/intmem.c b/arch/cris/arch-v32/mm/intmem.c
new file mode 100644
index 0000000..41ee7f7
--- /dev/null
+++ b/arch/cris/arch-v32/mm/intmem.c
@@ -0,0 +1,139 @@
+/*
+ * 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 <asm/arch/memmap.h>
+
+#define STATUS_FREE 0
+#define STATUS_ALLOCATED 1
+
+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 =
+		  (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL);
+		INIT_LIST_HEAD(&intmem_allocations);
+		intmem_virtual = ioremap(MEM_INTMEM_START, MEM_INTMEM_SIZE);
+		initiated = 1;
+		alloc->size = MEM_INTMEM_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 =
+					(struct intmem_allocation*)
+					kmalloc(sizeof *alloc, GFP_ATOMIC);
+				alloc->status = STATUS_FREE;
+				alloc->size = allocation->size - size - alignment;
+				alloc->offset = allocation->offset + size;
+				list_add(&alloc->entry, &allocation->entry);
+
+				if (alignment) {
+					struct intmem_allocation* tmp;
+					tmp = (struct intmem_allocation*)
+						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->status == STATUS_FREE) {
+				prev->size += allocation->size;
+				list_del(&allocation->entry);
+				kfree(allocation);
+				allocation = prev;
+			}
+			if (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+
+	               (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);
+}
+
+
+