summaryrefslogtreecommitdiffstats
path: root/arch/ppc/amiga/chipram.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
commit1d67e90f19a7acfd9a05dc59678e7d0c5090bd0d (patch)
tree357efc7b93f8f5102110d20d293f41360ec212fc /arch/ppc/amiga/chipram.c
parentaea27b2e18d69af87e673972246e66657b4fa274 (diff)
Merge with Linux 2.3.21.
Diffstat (limited to 'arch/ppc/amiga/chipram.c')
-rw-r--r--arch/ppc/amiga/chipram.c176
1 files changed, 175 insertions, 1 deletions
diff --git a/arch/ppc/amiga/chipram.c b/arch/ppc/amiga/chipram.c
index e6ab3c6b2..31f91a794 100644
--- a/arch/ppc/amiga/chipram.c
+++ b/arch/ppc/amiga/chipram.c
@@ -1 +1,175 @@
-#include "../../m68k/amiga/chipram.c"
+/*
+** linux/amiga/chipram.c
+**
+** Modified 03-May-94 by Geert Uytterhoeven
+** (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+** - 64-bit aligned allocations for full AGA compatibility
+*/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.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!! */
+};
+
+#define DP(ptr) ((struct chip_desc *)(ptr))
+
+u_long amiga_chip_size;
+static unsigned long chipavail;
+
+unsigned long amiga_chip_avail( void )
+{
+#ifdef DEBUG
+ printk("chip_avail : %ld bytes\n",chipavail);
+#endif
+ return chipavail;
+}
+
+
+__init
+void amiga_chip_init (void)
+{
+ struct chip_desc *dp;
+
+ 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
+
+ /* 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*/
+
+#ifdef DEBUG
+ printk ("chipram end boundary is %p, length is %d\n", dp,
+ dp->length);
+#endif
+}
+
+void *amiga_chip_alloc (long size)
+{
+ /* last chunk */
+ struct chip_desc *dp;
+ void *ptr;
+
+ /* round off */
+ size = (size + 7) & ~7;
+
+#ifdef DEBUG
+ printk("chip_alloc: allocate %ld bytes\n", size);
+#endif
+
+ /*
+ * 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;
+ }
+
+ 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 ("chip_alloc: no split\n");
+#endif
+ } else {
+ /* split the extent; use the end part */
+ long newsize = dp->length - (2*sizeof(*dp) + size);
+
+#ifdef DEBUG
+ printk ("chip_alloc: splitting %d to %ld\n", dp->length,
+ newsize);
+#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;
+ }
+
+#ifdef DEBUG
+ printk ("chip_alloc: returning %p\n", ptr);
+#endif
+
+ if ((unsigned long)ptr & 7)
+ panic("chip_alloc: alignment violation\n");
+
+ chipavail -= size + (2*sizeof(*dp)); /*MILAN*/
+
+ return 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);
+
+ chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/
+#ifdef DEBUG
+ printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr);
+#endif
+ /* deallocate the chunk */
+ sdp->alloced = edp->alloced = 0;
+
+ /* 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;
+ }
+}