xref: /aosp_15_r20/external/libdrm/intel/mm.c (revision 7688df22e49036ff52a766b7101da3a49edadb8c)
1*7688df22SAndroid Build Coastguard Worker /*
2*7688df22SAndroid Build Coastguard Worker  * GLX Hardware Device Driver common code
3*7688df22SAndroid Build Coastguard Worker  * Copyright (C) 1999 Wittawat Yamwong
4*7688df22SAndroid Build Coastguard Worker  *
5*7688df22SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
6*7688df22SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
7*7688df22SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
8*7688df22SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*7688df22SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
10*7688df22SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
11*7688df22SAndroid Build Coastguard Worker  *
12*7688df22SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included
13*7688df22SAndroid Build Coastguard Worker  * in all copies or substantial portions of the Software.
14*7688df22SAndroid Build Coastguard Worker  *
15*7688df22SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16*7688df22SAndroid Build Coastguard Worker  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*7688df22SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*7688df22SAndroid Build Coastguard Worker  * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
19*7688df22SAndroid Build Coastguard Worker  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20*7688df22SAndroid Build Coastguard Worker  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
21*7688df22SAndroid Build Coastguard Worker  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*7688df22SAndroid Build Coastguard Worker  *
23*7688df22SAndroid Build Coastguard Worker  */
24*7688df22SAndroid Build Coastguard Worker 
25*7688df22SAndroid Build Coastguard Worker #include <stdlib.h>
26*7688df22SAndroid Build Coastguard Worker #include <assert.h>
27*7688df22SAndroid Build Coastguard Worker 
28*7688df22SAndroid Build Coastguard Worker #include "xf86drm.h"
29*7688df22SAndroid Build Coastguard Worker #include "libdrm_macros.h"
30*7688df22SAndroid Build Coastguard Worker #include "mm.h"
31*7688df22SAndroid Build Coastguard Worker 
mmDumpMemInfo(const struct mem_block * heap)32*7688df22SAndroid Build Coastguard Worker drm_private void mmDumpMemInfo(const struct mem_block *heap)
33*7688df22SAndroid Build Coastguard Worker {
34*7688df22SAndroid Build Coastguard Worker 	drmMsg("Memory heap %p:\n", (void *)heap);
35*7688df22SAndroid Build Coastguard Worker 	if (heap == 0) {
36*7688df22SAndroid Build Coastguard Worker 		drmMsg("  heap == 0\n");
37*7688df22SAndroid Build Coastguard Worker 	} else {
38*7688df22SAndroid Build Coastguard Worker 		const struct mem_block *p;
39*7688df22SAndroid Build Coastguard Worker 
40*7688df22SAndroid Build Coastguard Worker 		for (p = heap->next; p != heap; p = p->next) {
41*7688df22SAndroid Build Coastguard Worker 			drmMsg("  Offset:%08x, Size:%08x, %c%c\n", p->ofs,
42*7688df22SAndroid Build Coastguard Worker 			       p->size, p->free ? 'F' : '.',
43*7688df22SAndroid Build Coastguard Worker 			       p->reserved ? 'R' : '.');
44*7688df22SAndroid Build Coastguard Worker 		}
45*7688df22SAndroid Build Coastguard Worker 
46*7688df22SAndroid Build Coastguard Worker 		drmMsg("\nFree list:\n");
47*7688df22SAndroid Build Coastguard Worker 
48*7688df22SAndroid Build Coastguard Worker 		for (p = heap->next_free; p != heap; p = p->next_free) {
49*7688df22SAndroid Build Coastguard Worker 			drmMsg(" FREE Offset:%08x, Size:%08x, %c%c\n", p->ofs,
50*7688df22SAndroid Build Coastguard Worker 			       p->size, p->free ? 'F' : '.',
51*7688df22SAndroid Build Coastguard Worker 			       p->reserved ? 'R' : '.');
52*7688df22SAndroid Build Coastguard Worker 		}
53*7688df22SAndroid Build Coastguard Worker 
54*7688df22SAndroid Build Coastguard Worker 	}
55*7688df22SAndroid Build Coastguard Worker 	drmMsg("End of memory blocks\n");
56*7688df22SAndroid Build Coastguard Worker }
57*7688df22SAndroid Build Coastguard Worker 
mmInit(int ofs,int size)58*7688df22SAndroid Build Coastguard Worker drm_private struct mem_block *mmInit(int ofs, int size)
59*7688df22SAndroid Build Coastguard Worker {
60*7688df22SAndroid Build Coastguard Worker 	struct mem_block *heap, *block;
61*7688df22SAndroid Build Coastguard Worker 
62*7688df22SAndroid Build Coastguard Worker 	if (size <= 0)
63*7688df22SAndroid Build Coastguard Worker 		return NULL;
64*7688df22SAndroid Build Coastguard Worker 
65*7688df22SAndroid Build Coastguard Worker 	heap = (struct mem_block *)calloc(1, sizeof(struct mem_block));
66*7688df22SAndroid Build Coastguard Worker 	if (!heap)
67*7688df22SAndroid Build Coastguard Worker 		return NULL;
68*7688df22SAndroid Build Coastguard Worker 
69*7688df22SAndroid Build Coastguard Worker 	block = (struct mem_block *)calloc(1, sizeof(struct mem_block));
70*7688df22SAndroid Build Coastguard Worker 	if (!block) {
71*7688df22SAndroid Build Coastguard Worker 		free(heap);
72*7688df22SAndroid Build Coastguard Worker 		return NULL;
73*7688df22SAndroid Build Coastguard Worker 	}
74*7688df22SAndroid Build Coastguard Worker 
75*7688df22SAndroid Build Coastguard Worker 	heap->next = block;
76*7688df22SAndroid Build Coastguard Worker 	heap->prev = block;
77*7688df22SAndroid Build Coastguard Worker 	heap->next_free = block;
78*7688df22SAndroid Build Coastguard Worker 	heap->prev_free = block;
79*7688df22SAndroid Build Coastguard Worker 
80*7688df22SAndroid Build Coastguard Worker 	block->heap = heap;
81*7688df22SAndroid Build Coastguard Worker 	block->next = heap;
82*7688df22SAndroid Build Coastguard Worker 	block->prev = heap;
83*7688df22SAndroid Build Coastguard Worker 	block->next_free = heap;
84*7688df22SAndroid Build Coastguard Worker 	block->prev_free = heap;
85*7688df22SAndroid Build Coastguard Worker 
86*7688df22SAndroid Build Coastguard Worker 	block->ofs = ofs;
87*7688df22SAndroid Build Coastguard Worker 	block->size = size;
88*7688df22SAndroid Build Coastguard Worker 	block->free = 1;
89*7688df22SAndroid Build Coastguard Worker 
90*7688df22SAndroid Build Coastguard Worker 	return heap;
91*7688df22SAndroid Build Coastguard Worker }
92*7688df22SAndroid Build Coastguard Worker 
SliceBlock(struct mem_block * p,int startofs,int size,int reserved,int alignment)93*7688df22SAndroid Build Coastguard Worker static struct mem_block *SliceBlock(struct mem_block *p,
94*7688df22SAndroid Build Coastguard Worker 				    int startofs, int size,
95*7688df22SAndroid Build Coastguard Worker 				    int reserved, int alignment)
96*7688df22SAndroid Build Coastguard Worker {
97*7688df22SAndroid Build Coastguard Worker 	struct mem_block *newblock;
98*7688df22SAndroid Build Coastguard Worker 
99*7688df22SAndroid Build Coastguard Worker 	/* break left  [p, newblock, p->next], then p = newblock */
100*7688df22SAndroid Build Coastguard Worker 	if (startofs > p->ofs) {
101*7688df22SAndroid Build Coastguard Worker 		newblock =
102*7688df22SAndroid Build Coastguard Worker 		    (struct mem_block *)calloc(1, sizeof(struct mem_block));
103*7688df22SAndroid Build Coastguard Worker 		if (!newblock)
104*7688df22SAndroid Build Coastguard Worker 			return NULL;
105*7688df22SAndroid Build Coastguard Worker 		newblock->ofs = startofs;
106*7688df22SAndroid Build Coastguard Worker 		newblock->size = p->size - (startofs - p->ofs);
107*7688df22SAndroid Build Coastguard Worker 		newblock->free = 1;
108*7688df22SAndroid Build Coastguard Worker 		newblock->heap = p->heap;
109*7688df22SAndroid Build Coastguard Worker 
110*7688df22SAndroid Build Coastguard Worker 		newblock->next = p->next;
111*7688df22SAndroid Build Coastguard Worker 		newblock->prev = p;
112*7688df22SAndroid Build Coastguard Worker 		p->next->prev = newblock;
113*7688df22SAndroid Build Coastguard Worker 		p->next = newblock;
114*7688df22SAndroid Build Coastguard Worker 
115*7688df22SAndroid Build Coastguard Worker 		newblock->next_free = p->next_free;
116*7688df22SAndroid Build Coastguard Worker 		newblock->prev_free = p;
117*7688df22SAndroid Build Coastguard Worker 		p->next_free->prev_free = newblock;
118*7688df22SAndroid Build Coastguard Worker 		p->next_free = newblock;
119*7688df22SAndroid Build Coastguard Worker 
120*7688df22SAndroid Build Coastguard Worker 		p->size -= newblock->size;
121*7688df22SAndroid Build Coastguard Worker 		p = newblock;
122*7688df22SAndroid Build Coastguard Worker 	}
123*7688df22SAndroid Build Coastguard Worker 
124*7688df22SAndroid Build Coastguard Worker 	/* break right, also [p, newblock, p->next] */
125*7688df22SAndroid Build Coastguard Worker 	if (size < p->size) {
126*7688df22SAndroid Build Coastguard Worker 		newblock =
127*7688df22SAndroid Build Coastguard Worker 		    (struct mem_block *)calloc(1, sizeof(struct mem_block));
128*7688df22SAndroid Build Coastguard Worker 		if (!newblock)
129*7688df22SAndroid Build Coastguard Worker 			return NULL;
130*7688df22SAndroid Build Coastguard Worker 		newblock->ofs = startofs + size;
131*7688df22SAndroid Build Coastguard Worker 		newblock->size = p->size - size;
132*7688df22SAndroid Build Coastguard Worker 		newblock->free = 1;
133*7688df22SAndroid Build Coastguard Worker 		newblock->heap = p->heap;
134*7688df22SAndroid Build Coastguard Worker 
135*7688df22SAndroid Build Coastguard Worker 		newblock->next = p->next;
136*7688df22SAndroid Build Coastguard Worker 		newblock->prev = p;
137*7688df22SAndroid Build Coastguard Worker 		p->next->prev = newblock;
138*7688df22SAndroid Build Coastguard Worker 		p->next = newblock;
139*7688df22SAndroid Build Coastguard Worker 
140*7688df22SAndroid Build Coastguard Worker 		newblock->next_free = p->next_free;
141*7688df22SAndroid Build Coastguard Worker 		newblock->prev_free = p;
142*7688df22SAndroid Build Coastguard Worker 		p->next_free->prev_free = newblock;
143*7688df22SAndroid Build Coastguard Worker 		p->next_free = newblock;
144*7688df22SAndroid Build Coastguard Worker 
145*7688df22SAndroid Build Coastguard Worker 		p->size = size;
146*7688df22SAndroid Build Coastguard Worker 	}
147*7688df22SAndroid Build Coastguard Worker 
148*7688df22SAndroid Build Coastguard Worker 	/* p = middle block */
149*7688df22SAndroid Build Coastguard Worker 	p->free = 0;
150*7688df22SAndroid Build Coastguard Worker 
151*7688df22SAndroid Build Coastguard Worker 	/* Remove p from the free list:
152*7688df22SAndroid Build Coastguard Worker 	 */
153*7688df22SAndroid Build Coastguard Worker 	p->next_free->prev_free = p->prev_free;
154*7688df22SAndroid Build Coastguard Worker 	p->prev_free->next_free = p->next_free;
155*7688df22SAndroid Build Coastguard Worker 
156*7688df22SAndroid Build Coastguard Worker 	p->next_free = 0;
157*7688df22SAndroid Build Coastguard Worker 	p->prev_free = 0;
158*7688df22SAndroid Build Coastguard Worker 
159*7688df22SAndroid Build Coastguard Worker 	p->reserved = reserved;
160*7688df22SAndroid Build Coastguard Worker 	return p;
161*7688df22SAndroid Build Coastguard Worker }
162*7688df22SAndroid Build Coastguard Worker 
mmAllocMem(struct mem_block * heap,int size,int align2,int startSearch)163*7688df22SAndroid Build Coastguard Worker drm_private struct mem_block *mmAllocMem(struct mem_block *heap, int size,
164*7688df22SAndroid Build Coastguard Worker 					 int align2, int startSearch)
165*7688df22SAndroid Build Coastguard Worker {
166*7688df22SAndroid Build Coastguard Worker 	struct mem_block *p;
167*7688df22SAndroid Build Coastguard Worker 	const int mask = (1 << align2) - 1;
168*7688df22SAndroid Build Coastguard Worker 	int startofs = 0;
169*7688df22SAndroid Build Coastguard Worker 	int endofs;
170*7688df22SAndroid Build Coastguard Worker 
171*7688df22SAndroid Build Coastguard Worker 	if (!heap || align2 < 0 || size <= 0)
172*7688df22SAndroid Build Coastguard Worker 		return NULL;
173*7688df22SAndroid Build Coastguard Worker 
174*7688df22SAndroid Build Coastguard Worker 	for (p = heap->next_free; p != heap; p = p->next_free) {
175*7688df22SAndroid Build Coastguard Worker 		assert(p->free);
176*7688df22SAndroid Build Coastguard Worker 
177*7688df22SAndroid Build Coastguard Worker 		startofs = (p->ofs + mask) & ~mask;
178*7688df22SAndroid Build Coastguard Worker 		if (startofs < startSearch) {
179*7688df22SAndroid Build Coastguard Worker 			startofs = startSearch;
180*7688df22SAndroid Build Coastguard Worker 		}
181*7688df22SAndroid Build Coastguard Worker 		endofs = startofs + size;
182*7688df22SAndroid Build Coastguard Worker 		if (endofs <= (p->ofs + p->size))
183*7688df22SAndroid Build Coastguard Worker 			break;
184*7688df22SAndroid Build Coastguard Worker 	}
185*7688df22SAndroid Build Coastguard Worker 
186*7688df22SAndroid Build Coastguard Worker 	if (p == heap)
187*7688df22SAndroid Build Coastguard Worker 		return NULL;
188*7688df22SAndroid Build Coastguard Worker 
189*7688df22SAndroid Build Coastguard Worker 	assert(p->free);
190*7688df22SAndroid Build Coastguard Worker 	p = SliceBlock(p, startofs, size, 0, mask + 1);
191*7688df22SAndroid Build Coastguard Worker 
192*7688df22SAndroid Build Coastguard Worker 	return p;
193*7688df22SAndroid Build Coastguard Worker }
194*7688df22SAndroid Build Coastguard Worker 
Join2Blocks(struct mem_block * p)195*7688df22SAndroid Build Coastguard Worker static int Join2Blocks(struct mem_block *p)
196*7688df22SAndroid Build Coastguard Worker {
197*7688df22SAndroid Build Coastguard Worker 	/* XXX there should be some assertions here */
198*7688df22SAndroid Build Coastguard Worker 
199*7688df22SAndroid Build Coastguard Worker 	/* NOTE: heap->free == 0 */
200*7688df22SAndroid Build Coastguard Worker 
201*7688df22SAndroid Build Coastguard Worker 	if (p->free && p->next->free) {
202*7688df22SAndroid Build Coastguard Worker 		struct mem_block *q = p->next;
203*7688df22SAndroid Build Coastguard Worker 
204*7688df22SAndroid Build Coastguard Worker 		assert(p->ofs + p->size == q->ofs);
205*7688df22SAndroid Build Coastguard Worker 		p->size += q->size;
206*7688df22SAndroid Build Coastguard Worker 
207*7688df22SAndroid Build Coastguard Worker 		p->next = q->next;
208*7688df22SAndroid Build Coastguard Worker 		q->next->prev = p;
209*7688df22SAndroid Build Coastguard Worker 
210*7688df22SAndroid Build Coastguard Worker 		q->next_free->prev_free = q->prev_free;
211*7688df22SAndroid Build Coastguard Worker 		q->prev_free->next_free = q->next_free;
212*7688df22SAndroid Build Coastguard Worker 
213*7688df22SAndroid Build Coastguard Worker 		free(q);
214*7688df22SAndroid Build Coastguard Worker 		return 1;
215*7688df22SAndroid Build Coastguard Worker 	}
216*7688df22SAndroid Build Coastguard Worker 	return 0;
217*7688df22SAndroid Build Coastguard Worker }
218*7688df22SAndroid Build Coastguard Worker 
mmFreeMem(struct mem_block * b)219*7688df22SAndroid Build Coastguard Worker drm_private int mmFreeMem(struct mem_block *b)
220*7688df22SAndroid Build Coastguard Worker {
221*7688df22SAndroid Build Coastguard Worker 	if (!b)
222*7688df22SAndroid Build Coastguard Worker 		return 0;
223*7688df22SAndroid Build Coastguard Worker 
224*7688df22SAndroid Build Coastguard Worker 	if (b->free) {
225*7688df22SAndroid Build Coastguard Worker 		drmMsg("block already free\n");
226*7688df22SAndroid Build Coastguard Worker 		return -1;
227*7688df22SAndroid Build Coastguard Worker 	}
228*7688df22SAndroid Build Coastguard Worker 	if (b->reserved) {
229*7688df22SAndroid Build Coastguard Worker 		drmMsg("block is reserved\n");
230*7688df22SAndroid Build Coastguard Worker 		return -1;
231*7688df22SAndroid Build Coastguard Worker 	}
232*7688df22SAndroid Build Coastguard Worker 
233*7688df22SAndroid Build Coastguard Worker 	b->free = 1;
234*7688df22SAndroid Build Coastguard Worker 	b->next_free = b->heap->next_free;
235*7688df22SAndroid Build Coastguard Worker 	b->prev_free = b->heap;
236*7688df22SAndroid Build Coastguard Worker 	b->next_free->prev_free = b;
237*7688df22SAndroid Build Coastguard Worker 	b->prev_free->next_free = b;
238*7688df22SAndroid Build Coastguard Worker 
239*7688df22SAndroid Build Coastguard Worker 	Join2Blocks(b);
240*7688df22SAndroid Build Coastguard Worker 	if (b->prev != b->heap)
241*7688df22SAndroid Build Coastguard Worker 		Join2Blocks(b->prev);
242*7688df22SAndroid Build Coastguard Worker 
243*7688df22SAndroid Build Coastguard Worker 	return 0;
244*7688df22SAndroid Build Coastguard Worker }
245*7688df22SAndroid Build Coastguard Worker 
mmDestroy(struct mem_block * heap)246*7688df22SAndroid Build Coastguard Worker drm_private void mmDestroy(struct mem_block *heap)
247*7688df22SAndroid Build Coastguard Worker {
248*7688df22SAndroid Build Coastguard Worker 	struct mem_block *p;
249*7688df22SAndroid Build Coastguard Worker 
250*7688df22SAndroid Build Coastguard Worker 	if (!heap)
251*7688df22SAndroid Build Coastguard Worker 		return;
252*7688df22SAndroid Build Coastguard Worker 
253*7688df22SAndroid Build Coastguard Worker 	for (p = heap->next; p != heap;) {
254*7688df22SAndroid Build Coastguard Worker 		struct mem_block *next = p->next;
255*7688df22SAndroid Build Coastguard Worker 		free(p);
256*7688df22SAndroid Build Coastguard Worker 		p = next;
257*7688df22SAndroid Build Coastguard Worker 	}
258*7688df22SAndroid Build Coastguard Worker 
259*7688df22SAndroid Build Coastguard Worker 	free(heap);
260*7688df22SAndroid Build Coastguard Worker }
261