patch-2.4.0-test12 linux/arch/m68k/amiga/chipram.c

Next file: linux/arch/m68k/amiga/cia.c
Previous file: linux/arch/m68k/amiga/amisound.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test11/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c
@@ -3,173 +3,127 @@
 **
 **      Modified 03-May-94 by Geert Uytterhoeven <geert@linux-m68k.org>
 **          - 64-bit aligned allocations for full AGA compatibility
+**
+**	Rewritten 15/9/2000 by Geert to use resource management
 */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/slab.h>
 #include <asm/amigahw.h>
 
-struct chip_desc {
-	unsigned first   :  1;
-	unsigned last    :  1;
-	unsigned alloced :  1;
-	unsigned length  : 24;
-	long pad;					/* We suppose this makes this struct 64 bits long!! */
-};
+unsigned long amiga_chip_size;
 
-#define DP(ptr) ((struct chip_desc *)(ptr))
-
-u_long amiga_chip_size;
+static struct resource chipram_res = { "Chip RAM", CHIP_PHYSADDR };
 static unsigned long chipavail;
 
-static struct resource chipram = { "Chip RAM", 0 };
 
-unsigned long amiga_chip_avail( void )
+void __init amiga_chip_init(void)
 {
-#ifdef DEBUG
-	printk("chip_avail : %ld bytes\n",chipavail);
+    if (!AMIGAHW_PRESENT(CHIP_RAM))
+	return;
+
+#ifndef CONFIG_APUS_FAST_EXCEPT
+    /*
+     *  Remove the first 4 pages where PPC exception handlers will be located
+     */
+    amiga_chip_size -= 0x4000;
 #endif
-	return chipavail;
-}
+    chipram_res.end = amiga_chip_size-1;
+    request_resource(&iomem_resource, &chipram_res);
 
+    chipavail = amiga_chip_size;
+}
 
-void __init amiga_chip_init (void)
+    
+void *amiga_chip_alloc(unsigned long size, const char *name)
 {
-  struct chip_desc *dp;
-
-  if (!AMIGAHW_PRESENT(CHIP_RAM))
-    return;
-
-  chipram.end = amiga_chip_size-1;
-  request_resource(&iomem_resource, &chipram);
+    struct resource *res;
 
-  /* initialize start boundary */
-
-  dp = DP(chipaddr);
-  dp->first = 1;
-
-  dp->alloced = 0;
-  dp->length = amiga_chip_size - 2*sizeof(*dp);
-
-  /* initialize end boundary */
-  dp = DP(chipaddr + amiga_chip_size) - 1;
-  dp->last = 1;
-  
-  dp->alloced = 0;
-  dp->length = amiga_chip_size - 2*sizeof(*dp);
-  chipavail = dp->length;  /*MILAN*/
+    /* round up */
+    size = PAGE_ALIGN(size);
 
 #ifdef DEBUG
-  printk ("chipram end boundary is %p, length is %d\n", dp,
-	  dp->length);
+    printk("amiga_chip_alloc: allocate %ld bytes\n", size);
 #endif
-}
-
-void *amiga_chip_alloc(long size, const char *name)
-{
-	/* last chunk */
-	struct chip_desc *dp;
-	void *ptr;
-
-	/* round off */
-	size = (size + 7) & ~7;
+    res = kmalloc(sizeof(struct resource), GFP_KERNEL);
+    if (!res)
+	return NULL;
+    memset(res, 0, sizeof(struct resource));
+    res->name = name;
 
+    if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) {
+	kfree(res);
+	return NULL;
+    }
+    chipavail -= size;
 #ifdef DEBUG
-   printk("amiga_chip_alloc: allocate %ld bytes\n", size);
+    printk("amiga_chip_alloc: returning %lx\n", res->start);
 #endif
+    return (void *)ZTWO_VADDR(res->start);
+}
 
-	/*
-	 * get pointer to descriptor for last chunk by 
-	 * going backwards from end chunk
-	 */
-	dp = DP(chipaddr + amiga_chip_size) - 1;
-	dp = DP((unsigned long)dp - dp->length) - 1;
-	
-	while ((dp->alloced || dp->length < size)
-	       && !dp->first)
-		dp = DP ((unsigned long)dp - dp[-1].length) - 2;
 
-	if (dp->alloced || dp->length < size) {
-		printk ("no chipmem available for %ld allocation\n", size);
-		return NULL;
-	}
+    /*
+     *  Warning:
+     *  amiga_chip_alloc_res is meant only for drivers that need to allocate
+     *  Chip RAM before kmalloc() is functional. As a consequence, those
+     *  drivers must not free that Chip RAM afterwards.
+     */
 
-	if (dp->length < (size + 2*sizeof(*dp))) {
-		/* length too small to split; allocate the whole thing */
-		dp->alloced = 1;
-		ptr = (void *)(dp+1);
-		dp = DP((unsigned long)ptr + dp->length);
-		dp->alloced = 1;
-#ifdef DEBUG
-		printk ("amiga_chip_alloc: no split\n");
-#endif
-	} else {
-		/* split the extent; use the end part */
-		long newsize = dp->length - (2*sizeof(*dp) + size);
+void * __init amiga_chip_alloc_res(unsigned long size, struct resource *res)
+{
+    unsigned long start;
+
+    /* round up */
+    size = PAGE_ALIGN(size);
+    /* dmesg into chipmem prefers memory at the safe end */
+    start = CHIP_PHYSADDR + chipavail - size;
 
 #ifdef DEBUG
-		printk ("amiga_chip_alloc: splitting %d to %ld\n", dp->length,
-			newsize);
+    printk("amiga_chip_alloc_res: allocate %ld bytes\n", size);
 #endif
-		dp->length = newsize;
-		dp = DP((unsigned long)(dp+1) + newsize);
-		dp->first = dp->last = 0;
-		dp->alloced = 0;
-		dp->length = newsize;
-		dp++;
-		dp->first = dp->last = 0;
-		dp->alloced = 1;
-		dp->length = size;
-		ptr = (void *)(dp+1);
-		dp = DP((unsigned long)ptr + size);
-		dp->alloced = 1;
-		dp->length = size;
-	}
-
+    if (allocate_resource(&chipram_res, res, size, start, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) {
+	printk("amiga_chip_alloc_res: first alloc failed!\n");
+	if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0)
+	    return NULL;
+    }
+    chipavail -= size;
 #ifdef DEBUG
-	printk ("amiga_chip_alloc: returning %p\n", ptr);
+    printk("amiga_chip_alloc_res: returning %lx\n", res->start);
 #endif
-
-	if ((unsigned long)ptr & 7)
-		panic("amiga_chip_alloc: alignment violation\n");
-
-    chipavail -= size + (2*sizeof(*dp)); /*MILAN*/
-
-    if (!request_mem_region(ZTWO_PADDR(ptr), size, name))
-	printk(KERN_WARNING "amiga_chip_alloc: region of size %ld at 0x%08lx "
-	       "is busy\n", size, ZTWO_PADDR(ptr));
-
-    return ptr;
+    return (void *)ZTWO_VADDR(res->start);
 }
 
-void amiga_chip_free (void *ptr)
+void amiga_chip_free(void *ptr)
 {
-	struct chip_desc *sdp = DP(ptr) - 1, *dp2;
-	struct chip_desc *edp = DP((unsigned long)ptr + sdp->length);
+    unsigned long start = ZTWO_PADDR(ptr);
+    struct resource **p, *res;
+    unsigned long size;
+
+    for (p = &chipram_res.child; (res = *p); p = &res->sibling) {
+	if (res->start != start)
+	    continue;
+	*p = res->sibling;
+	size = res->end-start;
+#ifdef DEBUG
+	printk("amiga_chip_free: free %ld bytes at %p\n", size, ptr);
+#endif
+	chipavail += size;
+	kfree(res);
+	return;
+    }
+    printk("amiga_chip_free: trying to free nonexistent region at %p\n", ptr);
+}
 
-    chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/
+
+unsigned long amiga_chip_avail(void)
+{
 #ifdef DEBUG
-   printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr);
+	printk("amiga_chip_avail : %ld bytes\n", chipavail);
 #endif
-	/* deallocate the chunk */
-	sdp->alloced = edp->alloced = 0;
-	release_mem_region(ZTWO_PADDR(ptr), sdp->length);
-
-	/* check if we should merge with the previous chunk */
-	if (!sdp->first && !sdp[-1].alloced) {
-		dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2;
-		dp2->length += sdp->length + 2*sizeof(*sdp);
-		edp->length = dp2->length;
-		sdp = dp2;
-	}
-
-	/* check if we should merge with the following chunk */
-	if (!edp->last && !edp[1].alloced) {
-		dp2 = DP((unsigned long)edp + edp[1].length) + 2;
-		dp2->length += edp->length + 2*sizeof(*sdp);
-		sdp->length = dp2->length;
-		edp = dp2;
-	}
+	return chipavail;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)