122944501Smrg/*
222944501Smrg * GLX Hardware Device Driver common code
322944501Smrg * Copyright (C) 1999 Wittawat Yamwong
422944501Smrg *
522944501Smrg * Permission is hereby granted, free of charge, to any person obtaining a
622944501Smrg * copy of this software and associated documentation files (the "Software"),
722944501Smrg * to deal in the Software without restriction, including without limitation
822944501Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
922944501Smrg * and/or sell copies of the Software, and to permit persons to whom the
1022944501Smrg * Software is furnished to do so, subject to the following conditions:
1122944501Smrg *
1222944501Smrg * The above copyright notice and this permission notice shall be included
1322944501Smrg * in all copies or substantial portions of the Software.
1422944501Smrg *
1522944501Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1622944501Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1722944501Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1822944501Smrg * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
1922944501Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2022944501Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
2122944501Smrg * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222944501Smrg *
2322944501Smrg */
2422944501Smrg
2522944501Smrg#include <stdlib.h>
2622944501Smrg#include <assert.h>
2722944501Smrg
2822944501Smrg#include "xf86drm.h"
29e6188e58Smrg#include "libdrm_macros.h"
3022944501Smrg#include "mm.h"
3122944501Smrg
32e6188e58Smrgdrm_private void mmDumpMemInfo(const struct mem_block *heap)
3322944501Smrg{
3422944501Smrg	drmMsg("Memory heap %p:\n", (void *)heap);
3522944501Smrg	if (heap == 0) {
3622944501Smrg		drmMsg("  heap == 0\n");
3722944501Smrg	} else {
3822944501Smrg		const struct mem_block *p;
3922944501Smrg
4022944501Smrg		for (p = heap->next; p != heap; p = p->next) {
4122944501Smrg			drmMsg("  Offset:%08x, Size:%08x, %c%c\n", p->ofs,
4222944501Smrg			       p->size, p->free ? 'F' : '.',
4322944501Smrg			       p->reserved ? 'R' : '.');
4422944501Smrg		}
4522944501Smrg
4622944501Smrg		drmMsg("\nFree list:\n");
4722944501Smrg
4822944501Smrg		for (p = heap->next_free; p != heap; p = p->next_free) {
4922944501Smrg			drmMsg(" FREE Offset:%08x, Size:%08x, %c%c\n", p->ofs,
5022944501Smrg			       p->size, p->free ? 'F' : '.',
5122944501Smrg			       p->reserved ? 'R' : '.');
5222944501Smrg		}
5322944501Smrg
5422944501Smrg	}
5522944501Smrg	drmMsg("End of memory blocks\n");
5622944501Smrg}
5722944501Smrg
58e6188e58Smrgdrm_private struct mem_block *mmInit(int ofs, int size)
5922944501Smrg{
6022944501Smrg	struct mem_block *heap, *block;
6122944501Smrg
6222944501Smrg	if (size <= 0)
6322944501Smrg		return NULL;
6422944501Smrg
6522944501Smrg	heap = (struct mem_block *)calloc(1, sizeof(struct mem_block));
6622944501Smrg	if (!heap)
6722944501Smrg		return NULL;
6822944501Smrg
6922944501Smrg	block = (struct mem_block *)calloc(1, sizeof(struct mem_block));
7022944501Smrg	if (!block) {
7122944501Smrg		free(heap);
7222944501Smrg		return NULL;
7322944501Smrg	}
7422944501Smrg
7522944501Smrg	heap->next = block;
7622944501Smrg	heap->prev = block;
7722944501Smrg	heap->next_free = block;
7822944501Smrg	heap->prev_free = block;
7922944501Smrg
8022944501Smrg	block->heap = heap;
8122944501Smrg	block->next = heap;
8222944501Smrg	block->prev = heap;
8322944501Smrg	block->next_free = heap;
8422944501Smrg	block->prev_free = heap;
8522944501Smrg
8622944501Smrg	block->ofs = ofs;
8722944501Smrg	block->size = size;
8822944501Smrg	block->free = 1;
8922944501Smrg
9022944501Smrg	return heap;
9122944501Smrg}
9222944501Smrg
9322944501Smrgstatic struct mem_block *SliceBlock(struct mem_block *p,
9422944501Smrg				    int startofs, int size,
9522944501Smrg				    int reserved, int alignment)
9622944501Smrg{
9722944501Smrg	struct mem_block *newblock;
9822944501Smrg
9922944501Smrg	/* break left  [p, newblock, p->next], then p = newblock */
10022944501Smrg	if (startofs > p->ofs) {
10122944501Smrg		newblock =
10222944501Smrg		    (struct mem_block *)calloc(1, sizeof(struct mem_block));
10322944501Smrg		if (!newblock)
10422944501Smrg			return NULL;
10522944501Smrg		newblock->ofs = startofs;
10622944501Smrg		newblock->size = p->size - (startofs - p->ofs);
10722944501Smrg		newblock->free = 1;
10822944501Smrg		newblock->heap = p->heap;
10922944501Smrg
11022944501Smrg		newblock->next = p->next;
11122944501Smrg		newblock->prev = p;
11222944501Smrg		p->next->prev = newblock;
11322944501Smrg		p->next = newblock;
11422944501Smrg
11522944501Smrg		newblock->next_free = p->next_free;
11622944501Smrg		newblock->prev_free = p;
11722944501Smrg		p->next_free->prev_free = newblock;
11822944501Smrg		p->next_free = newblock;
11922944501Smrg
12022944501Smrg		p->size -= newblock->size;
12122944501Smrg		p = newblock;
12222944501Smrg	}
12322944501Smrg
12422944501Smrg	/* break right, also [p, newblock, p->next] */
12522944501Smrg	if (size < p->size) {
12622944501Smrg		newblock =
12722944501Smrg		    (struct mem_block *)calloc(1, sizeof(struct mem_block));
12822944501Smrg		if (!newblock)
12922944501Smrg			return NULL;
13022944501Smrg		newblock->ofs = startofs + size;
13122944501Smrg		newblock->size = p->size - size;
13222944501Smrg		newblock->free = 1;
13322944501Smrg		newblock->heap = p->heap;
13422944501Smrg
13522944501Smrg		newblock->next = p->next;
13622944501Smrg		newblock->prev = p;
13722944501Smrg		p->next->prev = newblock;
13822944501Smrg		p->next = newblock;
13922944501Smrg
14022944501Smrg		newblock->next_free = p->next_free;
14122944501Smrg		newblock->prev_free = p;
14222944501Smrg		p->next_free->prev_free = newblock;
14322944501Smrg		p->next_free = newblock;
14422944501Smrg
14522944501Smrg		p->size = size;
14622944501Smrg	}
14722944501Smrg
14822944501Smrg	/* p = middle block */
14922944501Smrg	p->free = 0;
15022944501Smrg
15122944501Smrg	/* Remove p from the free list:
15222944501Smrg	 */
15322944501Smrg	p->next_free->prev_free = p->prev_free;
15422944501Smrg	p->prev_free->next_free = p->next_free;
15522944501Smrg
15622944501Smrg	p->next_free = 0;
15722944501Smrg	p->prev_free = 0;
15822944501Smrg
15922944501Smrg	p->reserved = reserved;
16022944501Smrg	return p;
16122944501Smrg}
16222944501Smrg
163e6188e58Smrgdrm_private struct mem_block *mmAllocMem(struct mem_block *heap, int size,
164e6188e58Smrg					 int align2, int startSearch)
16522944501Smrg{
16622944501Smrg	struct mem_block *p;
16722944501Smrg	const int mask = (1 << align2) - 1;
16822944501Smrg	int startofs = 0;
16922944501Smrg	int endofs;
17022944501Smrg
17122944501Smrg	if (!heap || align2 < 0 || size <= 0)
17222944501Smrg		return NULL;
17322944501Smrg
17422944501Smrg	for (p = heap->next_free; p != heap; p = p->next_free) {
17522944501Smrg		assert(p->free);
17622944501Smrg
17722944501Smrg		startofs = (p->ofs + mask) & ~mask;
17822944501Smrg		if (startofs < startSearch) {
17922944501Smrg			startofs = startSearch;
18022944501Smrg		}
18122944501Smrg		endofs = startofs + size;
18222944501Smrg		if (endofs <= (p->ofs + p->size))
18322944501Smrg			break;
18422944501Smrg	}
18522944501Smrg
18622944501Smrg	if (p == heap)
18722944501Smrg		return NULL;
18822944501Smrg
18922944501Smrg	assert(p->free);
19022944501Smrg	p = SliceBlock(p, startofs, size, 0, mask + 1);
19122944501Smrg
19222944501Smrg	return p;
19322944501Smrg}
19422944501Smrg
19522944501Smrgstatic int Join2Blocks(struct mem_block *p)
19622944501Smrg{
19722944501Smrg	/* XXX there should be some assertions here */
19822944501Smrg
19922944501Smrg	/* NOTE: heap->free == 0 */
20022944501Smrg
20122944501Smrg	if (p->free && p->next->free) {
20222944501Smrg		struct mem_block *q = p->next;
20322944501Smrg
20422944501Smrg		assert(p->ofs + p->size == q->ofs);
20522944501Smrg		p->size += q->size;
20622944501Smrg
20722944501Smrg		p->next = q->next;
20822944501Smrg		q->next->prev = p;
20922944501Smrg
21022944501Smrg		q->next_free->prev_free = q->prev_free;
21122944501Smrg		q->prev_free->next_free = q->next_free;
21222944501Smrg
21322944501Smrg		free(q);
21422944501Smrg		return 1;
21522944501Smrg	}
21622944501Smrg	return 0;
21722944501Smrg}
21822944501Smrg
219e6188e58Smrgdrm_private int mmFreeMem(struct mem_block *b)
22022944501Smrg{
22122944501Smrg	if (!b)
22222944501Smrg		return 0;
22322944501Smrg
22422944501Smrg	if (b->free) {
22522944501Smrg		drmMsg("block already free\n");
22622944501Smrg		return -1;
22722944501Smrg	}
22822944501Smrg	if (b->reserved) {
22922944501Smrg		drmMsg("block is reserved\n");
23022944501Smrg		return -1;
23122944501Smrg	}
23222944501Smrg
23322944501Smrg	b->free = 1;
23422944501Smrg	b->next_free = b->heap->next_free;
23522944501Smrg	b->prev_free = b->heap;
23622944501Smrg	b->next_free->prev_free = b;
23722944501Smrg	b->prev_free->next_free = b;
23822944501Smrg
23922944501Smrg	Join2Blocks(b);
24022944501Smrg	if (b->prev != b->heap)
24122944501Smrg		Join2Blocks(b->prev);
24222944501Smrg
24322944501Smrg	return 0;
24422944501Smrg}
24522944501Smrg
246e6188e58Smrgdrm_private void mmDestroy(struct mem_block *heap)
24722944501Smrg{
24822944501Smrg	struct mem_block *p;
24922944501Smrg
25022944501Smrg	if (!heap)
25122944501Smrg		return;
25222944501Smrg
25322944501Smrg	for (p = heap->next; p != heap;) {
25422944501Smrg		struct mem_block *next = p->next;
25522944501Smrg		free(p);
25622944501Smrg		p = next;
25722944501Smrg	}
25822944501Smrg
25922944501Smrg	free(heap);
26022944501Smrg}
261