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
- Lines: 259
- Date:
Mon Nov 27 17:57:34 2000
- Orig file:
v2.4.0-test11/linux/arch/m68k/amiga/chipram.c
- Orig date:
Tue Oct 31 12:42:26 2000
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)