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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | /*
** 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 <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;
}
__initfunc(void amiga_chip_init (void))
{
struct chip_desc *dp;
if (!AMIGAHW_PRESENT(CHIP_RAM))
return;
/* 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;
}
}
|