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 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | /*
** linux/amiga/chipram.c
**
** Modified 03-May-94 by Geert Uytterhoeven <geert@linux-m68k.org>
** - 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 <linux/zorro.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;
static struct resource chipram = { "Chip RAM", 0 };
unsigned long amiga_chip_avail( void )
{
#ifdef DEBUG
printk("chip_avail : %ld bytes\n",chipavail);
#endif
return chipavail;
}
void __init 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
chipram.end = amiga_chip_size-1;
request_resource(&iomem_resource, &chipram);
/* 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, const char *name)
{
/* last chunk */
struct chip_desc *dp;
void *ptr;
/* round off */
size = (size + 7) & ~7;
#ifdef DEBUG
printk("amiga_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 ("amiga_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 ("amiga_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 ("amiga_chip_alloc: returning %p\n", ptr);
#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;
}
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;
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;
}
}
|