* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / arch / m68k / amiga / chipram.c
blob80bc3c408e710d0179551db17c96dd31d188d23f
1 /*
2 ** linux/amiga/chipram.c
3 **
4 ** Modified 03-May-94 by Geert Uytterhoeven <geert@linux-m68k.org>
5 ** - 64-bit aligned allocations for full AGA compatibility
6 */
8 #include <linux/types.h>
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <asm/amigahw.h>
13 struct chip_desc {
14 unsigned first : 1;
15 unsigned last : 1;
16 unsigned alloced : 1;
17 unsigned length : 24;
18 long pad; /* We suppose this makes this struct 64 bits long!! */
21 #define DP(ptr) ((struct chip_desc *)(ptr))
23 u_long amiga_chip_size;
24 static unsigned long chipavail;
26 unsigned long amiga_chip_avail( void )
28 #ifdef DEBUG
29 printk("chip_avail : %ld bytes\n",chipavail);
30 #endif
31 return chipavail;
35 void __init amiga_chip_init (void)
37 struct chip_desc *dp;
39 if (!AMIGAHW_PRESENT(CHIP_RAM))
40 return;
42 /* initialize start boundary */
44 dp = DP(chipaddr);
45 dp->first = 1;
47 dp->alloced = 0;
48 dp->length = amiga_chip_size - 2*sizeof(*dp);
50 /* initialize end boundary */
51 dp = DP(chipaddr + amiga_chip_size) - 1;
52 dp->last = 1;
54 dp->alloced = 0;
55 dp->length = amiga_chip_size - 2*sizeof(*dp);
56 chipavail = dp->length; /*MILAN*/
58 #ifdef DEBUG
59 printk ("chipram end boundary is %p, length is %d\n", dp,
60 dp->length);
61 #endif
64 void *amiga_chip_alloc (long size)
66 /* last chunk */
67 struct chip_desc *dp;
68 void *ptr;
70 /* round off */
71 size = (size + 7) & ~7;
73 #ifdef DEBUG
74 printk("chip_alloc: allocate %ld bytes\n", size);
75 #endif
78 * get pointer to descriptor for last chunk by
79 * going backwards from end chunk
81 dp = DP(chipaddr + amiga_chip_size) - 1;
82 dp = DP((unsigned long)dp - dp->length) - 1;
84 while ((dp->alloced || dp->length < size)
85 && !dp->first)
86 dp = DP ((unsigned long)dp - dp[-1].length) - 2;
88 if (dp->alloced || dp->length < size) {
89 printk ("no chipmem available for %ld allocation\n", size);
90 return NULL;
93 if (dp->length < (size + 2*sizeof(*dp))) {
94 /* length too small to split; allocate the whole thing */
95 dp->alloced = 1;
96 ptr = (void *)(dp+1);
97 dp = DP((unsigned long)ptr + dp->length);
98 dp->alloced = 1;
99 #ifdef DEBUG
100 printk ("chip_alloc: no split\n");
101 #endif
102 } else {
103 /* split the extent; use the end part */
104 long newsize = dp->length - (2*sizeof(*dp) + size);
106 #ifdef DEBUG
107 printk ("chip_alloc: splitting %d to %ld\n", dp->length,
108 newsize);
109 #endif
110 dp->length = newsize;
111 dp = DP((unsigned long)(dp+1) + newsize);
112 dp->first = dp->last = 0;
113 dp->alloced = 0;
114 dp->length = newsize;
115 dp++;
116 dp->first = dp->last = 0;
117 dp->alloced = 1;
118 dp->length = size;
119 ptr = (void *)(dp+1);
120 dp = DP((unsigned long)ptr + size);
121 dp->alloced = 1;
122 dp->length = size;
125 #ifdef DEBUG
126 printk ("chip_alloc: returning %p\n", ptr);
127 #endif
129 if ((unsigned long)ptr & 7)
130 panic("chip_alloc: alignment violation\n");
132 chipavail -= size + (2*sizeof(*dp)); /*MILAN*/
134 return ptr;
137 void amiga_chip_free (void *ptr)
139 struct chip_desc *sdp = DP(ptr) - 1, *dp2;
140 struct chip_desc *edp = DP((unsigned long)ptr + sdp->length);
142 chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/
143 #ifdef DEBUG
144 printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr);
145 #endif
146 /* deallocate the chunk */
147 sdp->alloced = edp->alloced = 0;
149 /* check if we should merge with the previous chunk */
150 if (!sdp->first && !sdp[-1].alloced) {
151 dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2;
152 dp2->length += sdp->length + 2*sizeof(*sdp);
153 edp->length = dp2->length;
154 sdp = dp2;
157 /* check if we should merge with the following chunk */
158 if (!edp->last && !edp[1].alloced) {
159 dp2 = DP((unsigned long)edp + edp[1].length) + 2;
160 dp2->length += edp->length + 2*sizeof(*sdp);
161 sdp->length = dp2->length;
162 edp = dp2;