Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | /* ** 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/types.h> #include <linux/kernel.h> #include <asm/bootinfo.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)) static unsigned long chipsize; void amiga_chip_init (void) { struct chip_desc *dp; if (!AMIGAHW_PRESENT(CHIP_RAM)) return; chipsize = boot_info.bi_amiga.chip_size; /* initialize start boundary */ dp = DP(chipaddr); dp->first = 1; dp->alloced = 0; dp->length = chipsize - 2*sizeof(*dp); /* initialize end boundary */ dp = DP(chipaddr + chipsize) - 1; dp->last = 1; dp->alloced = 0; dp->length = chipsize - 2*sizeof(*dp); #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 + chipsize) - 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"); 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); /* 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; } } |