xref: /plan9-contrib/sys/src/9k/k10/physalloc.c (revision 491cc0e56f324ad247ae84c1168a0db04fd04b41)
12c57ff9fSDavid du Colombier /*
22c57ff9fSDavid du Colombier  * Buddy allocator for physical memory allocation.
32c57ff9fSDavid du Colombier  * One per ACPI affinity domain, to color pages depending on their
42c57ff9fSDavid du Colombier  * NUMA location.
52c57ff9fSDavid du Colombier  *
62c57ff9fSDavid du Colombier  */
72c57ff9fSDavid du Colombier #include "u.h"
82c57ff9fSDavid du Colombier #include "../port/lib.h"
92c57ff9fSDavid du Colombier #include "mem.h"
102c57ff9fSDavid du Colombier #include "dat.h"
112c57ff9fSDavid du Colombier #include "fns.h"
122c57ff9fSDavid du Colombier #include "acpi.h"
132c57ff9fSDavid du Colombier 
142c57ff9fSDavid du Colombier #define ISPOWEROF2(x)	(((x) != 0) && !((x) & ((x)-1)))
152c57ff9fSDavid du Colombier #define UNO		((uintmem)1)
162c57ff9fSDavid du Colombier 
172c57ff9fSDavid du Colombier enum {
185663e489SDavid du Colombier 	BKmin		= 12,			/* Minimum lg2 */
192c57ff9fSDavid du Colombier 	BKmax		= 30,			/* Maximum lg2 */
202c57ff9fSDavid du Colombier 
212c57ff9fSDavid du Colombier 	Ndoms = 16,				/* Max # of domains */
222c57ff9fSDavid du Colombier 
232c57ff9fSDavid du Colombier 	Used = 0,
242c57ff9fSDavid du Colombier 	Avail = 1,
252c57ff9fSDavid du Colombier };
262c57ff9fSDavid du Colombier 
272c57ff9fSDavid du Colombier 
282c57ff9fSDavid du Colombier #define INDEX(b, v)	((uint)(((v))/(b)->bminsz))
292c57ff9fSDavid du Colombier #define BLOCK(b, i)	((i)-INDEX((b),(b)->memory))
302c57ff9fSDavid du Colombier 
312c57ff9fSDavid du Colombier typedef struct Buddy Buddy;
322c57ff9fSDavid du Colombier struct Buddy {
332c57ff9fSDavid du Colombier 	short	tag;		/* Used or Avail */
342c57ff9fSDavid du Colombier 	short	kval;
352c57ff9fSDavid du Colombier 	uint	next;
362c57ff9fSDavid du Colombier 	uint	prev;
372c57ff9fSDavid du Colombier 	void	*p;
382c57ff9fSDavid du Colombier };
392c57ff9fSDavid du Colombier 
402c57ff9fSDavid du Colombier /*
412c57ff9fSDavid du Colombier  * Bals should allocate using its base address as 0.
422c57ff9fSDavid du Colombier  * For now, all of them refer to the entire memory and we record
432c57ff9fSDavid du Colombier  * the base and size for each one.
442c57ff9fSDavid du Colombier  */
452c57ff9fSDavid du Colombier typedef struct Bal Bal;
462c57ff9fSDavid du Colombier struct Bal {
472c57ff9fSDavid du Colombier 	uintmem	base;
482c57ff9fSDavid du Colombier 	u64int	size;
492c57ff9fSDavid du Colombier 	usize	nfree;
502c57ff9fSDavid du Colombier 	usize	nblocks;
512c57ff9fSDavid du Colombier 	int	kmin;		/* Minimum lg2 */
522c57ff9fSDavid du Colombier 	int	kmax;		/* Maximum lg2 */
532c57ff9fSDavid du Colombier 	uintmem	bminsz;		/* minimum block sz */
542c57ff9fSDavid du Colombier 	uintmem memory;
552c57ff9fSDavid du Colombier 	uint	kspan;
562c57ff9fSDavid du Colombier 
572c57ff9fSDavid du Colombier 	Buddy* blocks;
582c57ff9fSDavid du Colombier 	Buddy* avail;
592c57ff9fSDavid du Colombier };
602c57ff9fSDavid du Colombier 
612c57ff9fSDavid du Colombier static Bal bal[Ndoms];
622c57ff9fSDavid du Colombier static int ndoms;
632c57ff9fSDavid du Colombier static Lock budlock;
642c57ff9fSDavid du Colombier 
652c57ff9fSDavid du Colombier char*
seprintphysstats(char * s,char * e)662c57ff9fSDavid du Colombier seprintphysstats(char *s,  char *e)
672c57ff9fSDavid du Colombier {
682c57ff9fSDavid du Colombier 	Bal *b;
692c57ff9fSDavid du Colombier 	int i;
702c57ff9fSDavid du Colombier 
712c57ff9fSDavid du Colombier 	lock(&budlock);
722c57ff9fSDavid du Colombier 	for(i = 0; i < Ndoms; i++){
732c57ff9fSDavid du Colombier 		b = &bal[i];
742c57ff9fSDavid du Colombier 		if(b->size > 0)
752c57ff9fSDavid du Colombier 			s = seprint(s, e, "%uld/%uld %ulldK color %d blocks avail\n",
762c57ff9fSDavid du Colombier 				b->nfree, b->nblocks, b->bminsz/KiB, i);
772c57ff9fSDavid du Colombier 	}
782c57ff9fSDavid du Colombier 	unlock(&budlock);
792c57ff9fSDavid du Colombier 	return s;
802c57ff9fSDavid du Colombier }
812c57ff9fSDavid du Colombier 
822c57ff9fSDavid du Colombier static void
xphysfree(Bal * b,uintmem data,u64int size)832c57ff9fSDavid du Colombier xphysfree(Bal *b, uintmem data, u64int size)
842c57ff9fSDavid du Colombier {
852c57ff9fSDavid du Colombier 	uint i;
862c57ff9fSDavid du Colombier 	Buddy *l, *p;
872c57ff9fSDavid du Colombier 	Buddy *blocks, *avail;
882c57ff9fSDavid du Colombier 
892c57ff9fSDavid du Colombier 	DBG("physfree\n");
902c57ff9fSDavid du Colombier 
912c57ff9fSDavid du Colombier 	/*
922c57ff9fSDavid du Colombier 	 * Knuth's Algorithm S (Buddy System Liberation).
932c57ff9fSDavid du Colombier 	 */
942c57ff9fSDavid du Colombier 	blocks = b->blocks;
952c57ff9fSDavid du Colombier 	avail = b->avail;
962c57ff9fSDavid du Colombier 
972c57ff9fSDavid du Colombier 	if(data == 0 /*|| !ALIGNED(data, b->bminsz)*/)
982c57ff9fSDavid du Colombier 		return;
992c57ff9fSDavid du Colombier 	i = INDEX(b,data);
1002c57ff9fSDavid du Colombier 
1012c57ff9fSDavid du Colombier 	lock(&budlock);
1022c57ff9fSDavid du Colombier S1:
1032c57ff9fSDavid du Colombier 	/*
1042c57ff9fSDavid du Colombier 	 * Find buddy.
1052c57ff9fSDavid du Colombier 	 */
1062c57ff9fSDavid du Colombier 	l = &blocks[BLOCK(b,i)];
1072c57ff9fSDavid du Colombier 	l->p = nil;
1082c57ff9fSDavid du Colombier 	DBG("\tbsl: BLOCK(b,i) %d index %ulld kval %d\n",
1092c57ff9fSDavid du Colombier 		BLOCK(b,i), BLOCK(b,i)/((1<<l->kval)/b->bminsz), l->kval);
1102c57ff9fSDavid du Colombier 	if((BLOCK(b,i)/((1<<l->kval)/b->bminsz)) & 1)	/* simpler test? */
1112c57ff9fSDavid du Colombier 		p = l - (1<<l->kval)/b->bminsz;
1122c57ff9fSDavid du Colombier 	else
1132c57ff9fSDavid du Colombier 		p = l + (1<<l->kval)/(b->bminsz);
1142c57ff9fSDavid du Colombier 	DBG("\tbsl: l @ %ld buddy @ %ld\n", l - blocks, p - blocks);
1152c57ff9fSDavid du Colombier 
1162c57ff9fSDavid du Colombier 	/*
1172c57ff9fSDavid du Colombier 	 * Is buddy available?
1182c57ff9fSDavid du Colombier 	 * Can't merge if:
1192c57ff9fSDavid du Colombier 	 *	this is the largest block;
1202c57ff9fSDavid du Colombier 	 *	buddy isn't free;
1212c57ff9fSDavid du Colombier 	 *	buddy has been subsequently split again.
1222c57ff9fSDavid du Colombier 	 */
1232c57ff9fSDavid du Colombier 	if(l->kval == b->kmax || p->tag == Used || (p->tag == Avail && p->kval != l->kval)){
1242c57ff9fSDavid du Colombier 		/*
1252c57ff9fSDavid du Colombier 		 * Put on list.
1262c57ff9fSDavid du Colombier 		 */
1272c57ff9fSDavid du Colombier 		l->tag = Avail;
1282c57ff9fSDavid du Colombier 		l->next = avail[l->kval].next;
1292c57ff9fSDavid du Colombier 		l->prev = 0;
1302c57ff9fSDavid du Colombier 		if(l->next != 0)
1312c57ff9fSDavid du Colombier 			blocks[BLOCK(b,l->next)].prev = i;
1322c57ff9fSDavid du Colombier 		avail[l->kval].next = i;
1332c57ff9fSDavid du Colombier 
1342c57ff9fSDavid du Colombier 		b->nfree += size/b->bminsz;
1352c57ff9fSDavid du Colombier 
1362c57ff9fSDavid du Colombier 		unlock(&budlock);
1372c57ff9fSDavid du Colombier 		DBG("bsl: free @ i %d BLOCK(b,i) %d kval %d next %d %s\n",
1382c57ff9fSDavid du Colombier 			i, BLOCK(b,i), l->kval, l->next, l->tag?"avail":"used");
1392c57ff9fSDavid du Colombier 		return;
1402c57ff9fSDavid du Colombier 	}
1412c57ff9fSDavid du Colombier 
1422c57ff9fSDavid du Colombier 	/*
1432c57ff9fSDavid du Colombier 	 * Combine with buddy.
1442c57ff9fSDavid du Colombier 	 * This removes block P from the avail list.
1452c57ff9fSDavid du Colombier 	 */
146*491cc0e5SDavid du Colombier 	if(p->prev != 0)
1472c57ff9fSDavid du Colombier 		blocks[BLOCK(b,p->prev)].next = p->next;
1482c57ff9fSDavid du Colombier 	else
149*491cc0e5SDavid du Colombier 		avail[p->kval].next = p->next;
150*491cc0e5SDavid du Colombier 	if(p->next != 0)
1512c57ff9fSDavid du Colombier 		blocks[BLOCK(b,p->next)].prev = p->prev;
152*491cc0e5SDavid du Colombier 	p->next = p->prev = 0;
1532c57ff9fSDavid du Colombier 	p->tag = Used;
1542c57ff9fSDavid du Colombier 
1552c57ff9fSDavid du Colombier 	/*
1562c57ff9fSDavid du Colombier 	 * Now can try to merge this larger block.
1572c57ff9fSDavid du Colombier 	k++;
1582c57ff9fSDavid du Colombier 	 */
1592c57ff9fSDavid du Colombier 	DBG("\tbsl: l @ %ld p @ %ld\n", l - blocks, p - blocks);
1602c57ff9fSDavid du Colombier 	if(p < l)
1612c57ff9fSDavid du Colombier 		l = p;
1622c57ff9fSDavid du Colombier 	i = l - blocks + INDEX(b,b->memory);
1632c57ff9fSDavid du Colombier 	l->kval++;
1642c57ff9fSDavid du Colombier 	DBG("bsl: merge @ i %d BLOCK(b,i) %d kval %d next %d tag %s\n",
1652c57ff9fSDavid du Colombier 		i, BLOCK(b,i), l->kval, l->next, l->tag?"avail":"used");
1662c57ff9fSDavid du Colombier 	goto S1;
1672c57ff9fSDavid du Colombier }
1682c57ff9fSDavid du Colombier 
1692c57ff9fSDavid du Colombier void
physfree(uintmem data,u64int size)1702c57ff9fSDavid du Colombier physfree(uintmem data, u64int size)
1712c57ff9fSDavid du Colombier {
1722c57ff9fSDavid du Colombier 	Bal *b;
1732c57ff9fSDavid du Colombier 	int i;
1742c57ff9fSDavid du Colombier 
1752c57ff9fSDavid du Colombier 	for(i = 0; i < Ndoms; i++){
1762c57ff9fSDavid du Colombier 		b = &bal[i];
1772c57ff9fSDavid du Colombier 		if(b->base <= data && data < b->base + b->size){
1782c57ff9fSDavid du Colombier 			xphysfree(b, data, size);
1792c57ff9fSDavid du Colombier 			return;
1802c57ff9fSDavid du Colombier 		}
1812c57ff9fSDavid du Colombier 	}
1822c57ff9fSDavid du Colombier 	panic("physfree: no bal");
1832c57ff9fSDavid du Colombier }
1842c57ff9fSDavid du Colombier 
1852c57ff9fSDavid du Colombier static void*
xphystag(Bal * b,uintmem data)1862c57ff9fSDavid du Colombier xphystag(Bal *b, uintmem data)
1872c57ff9fSDavid du Colombier {
1882c57ff9fSDavid du Colombier 	uint i;
1892c57ff9fSDavid du Colombier 	Buddy *blocks;
1902c57ff9fSDavid du Colombier 
1912c57ff9fSDavid du Colombier 	DBG("phystag\n");
1922c57ff9fSDavid du Colombier 
1932c57ff9fSDavid du Colombier 	blocks = b->blocks;
1942c57ff9fSDavid du Colombier 
1952c57ff9fSDavid du Colombier 	if(data == 0 /*|| !ALIGNED(data, b->bminsz)*/)
1962c57ff9fSDavid du Colombier 		return nil;
1972c57ff9fSDavid du Colombier 	i = INDEX(b,data);
1982c57ff9fSDavid du Colombier 	return blocks[BLOCK(b,i)].p;
1992c57ff9fSDavid du Colombier }
2002c57ff9fSDavid du Colombier 
2012c57ff9fSDavid du Colombier void*
phystag(uintmem data)2022c57ff9fSDavid du Colombier phystag(uintmem data)
2032c57ff9fSDavid du Colombier {
2042c57ff9fSDavid du Colombier 	Bal *b;
2052c57ff9fSDavid du Colombier 	int i;
2062c57ff9fSDavid du Colombier 
2072c57ff9fSDavid du Colombier 	for(i = 0; i < Ndoms; i++){
2082c57ff9fSDavid du Colombier 		b = &bal[i];
2092c57ff9fSDavid du Colombier 		if(b->base <= data && data < b->base + b->size)
2102c57ff9fSDavid du Colombier 			return xphystag(b, data);
2112c57ff9fSDavid du Colombier 	}
2122c57ff9fSDavid du Colombier 	return nil;
2132c57ff9fSDavid du Colombier }
2142c57ff9fSDavid du Colombier 
2152c57ff9fSDavid du Colombier static uchar lg2table[256] = {
2162c57ff9fSDavid du Colombier 	0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
2172c57ff9fSDavid du Colombier 	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2182c57ff9fSDavid du Colombier 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2192c57ff9fSDavid du Colombier 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2202c57ff9fSDavid du Colombier 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2212c57ff9fSDavid du Colombier 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2222c57ff9fSDavid du Colombier 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2232c57ff9fSDavid du Colombier 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2242c57ff9fSDavid du Colombier 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2252c57ff9fSDavid du Colombier 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2262c57ff9fSDavid du Colombier 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2272c57ff9fSDavid du Colombier 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2282c57ff9fSDavid du Colombier 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2292c57ff9fSDavid du Colombier 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2302c57ff9fSDavid du Colombier 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2312c57ff9fSDavid du Colombier 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2322c57ff9fSDavid du Colombier };
2332c57ff9fSDavid du Colombier 
2342c57ff9fSDavid du Colombier static int
lg2floor(u64int w)2352c57ff9fSDavid du Colombier lg2floor(u64int w)
2362c57ff9fSDavid du Colombier {
2372c57ff9fSDavid du Colombier 	u64int hi, lo;
2382c57ff9fSDavid du Colombier 
2392c57ff9fSDavid du Colombier 	if((lo = (w>>48)) != 0){
2402c57ff9fSDavid du Colombier 		if((hi = (lo>>8)) != 0)
2412c57ff9fSDavid du Colombier 			return 56+lg2table[hi];
2422c57ff9fSDavid du Colombier 		return 48+lg2table[lo];
2432c57ff9fSDavid du Colombier 	}
2442c57ff9fSDavid du Colombier 	if((lo = (w>>32)) != 0){
2452c57ff9fSDavid du Colombier 		if((hi = (lo>>8)) != 0)
2462c57ff9fSDavid du Colombier 			return 40+lg2table[hi];
2472c57ff9fSDavid du Colombier 		return 32+lg2table[lo];
2482c57ff9fSDavid du Colombier 	}
2492c57ff9fSDavid du Colombier 	if((lo = (w>>16)) != 0){
2502c57ff9fSDavid du Colombier 		if((hi = (lo>>8)) != 0)
2512c57ff9fSDavid du Colombier 			return 24+lg2table[hi];
2522c57ff9fSDavid du Colombier 		return 16+lg2table[lo];
2532c57ff9fSDavid du Colombier 	}
2542c57ff9fSDavid du Colombier 	if((hi = (w>>8)) != 0)
2552c57ff9fSDavid du Colombier 		return 8+lg2table[hi];
2562c57ff9fSDavid du Colombier 	return lg2table[w];
2572c57ff9fSDavid du Colombier }
2582c57ff9fSDavid du Colombier 
2592c57ff9fSDavid du Colombier static uintmem
xphysalloc(Bal * b,u64int size,void * tag)2602c57ff9fSDavid du Colombier xphysalloc(Bal *b, u64int size, void *tag)
2612c57ff9fSDavid du Colombier {
2622c57ff9fSDavid du Colombier 	uint i, j, k;
2632c57ff9fSDavid du Colombier 	Buddy *l, *p;
2642c57ff9fSDavid du Colombier 	Buddy *avail, *blocks;
2652c57ff9fSDavid du Colombier 	uintmem m;
2662c57ff9fSDavid du Colombier 
2672c57ff9fSDavid du Colombier 	DBG("physalloc\n");
2682c57ff9fSDavid du Colombier 	assert(b->size > 0);
2692c57ff9fSDavid du Colombier 
2702c57ff9fSDavid du Colombier 	avail = b->avail;
2712c57ff9fSDavid du Colombier 	blocks = b->blocks;
2722c57ff9fSDavid du Colombier 
2732c57ff9fSDavid du Colombier 	/*
2742c57ff9fSDavid du Colombier 	 * Knuth's Algorithm R (Buddy System Reservation).
2752c57ff9fSDavid du Colombier 	 */
2762c57ff9fSDavid du Colombier 	if(size < b->bminsz)
2772c57ff9fSDavid du Colombier 		size = b->bminsz;
2782c57ff9fSDavid du Colombier 
2792c57ff9fSDavid du Colombier 	/*
2802c57ff9fSDavid du Colombier 	 * Find block.
2812c57ff9fSDavid du Colombier 	 */
2822c57ff9fSDavid du Colombier 	if(!ISPOWEROF2(size))
2832c57ff9fSDavid du Colombier 		return 0;
2842c57ff9fSDavid du Colombier 	k = lg2floor(size);
2852c57ff9fSDavid du Colombier 
2862c57ff9fSDavid du Colombier 	lock(&budlock);
2872c57ff9fSDavid du Colombier 	for(j = k; j <= b->kmax; j++){
2882c57ff9fSDavid du Colombier 		if(avail[j].next != 0)
2892c57ff9fSDavid du Colombier 			break;
2902c57ff9fSDavid du Colombier 	}
2912c57ff9fSDavid du Colombier 	DBG("bsr: size %#llud k %d j %d\n", size, k, j);
2922c57ff9fSDavid du Colombier 	if(j > b->kmax){
2932c57ff9fSDavid du Colombier 		unlock(&budlock);
2942c57ff9fSDavid du Colombier 		return 0;
2952c57ff9fSDavid du Colombier 	}
2962c57ff9fSDavid du Colombier 
2972c57ff9fSDavid du Colombier 	/*
2982c57ff9fSDavid du Colombier 	 * Remove from list.
2992c57ff9fSDavid du Colombier 	 */
3002c57ff9fSDavid du Colombier 	i = avail[j].next;
3012c57ff9fSDavid du Colombier 	l = &blocks[BLOCK(b,i)];
3022c57ff9fSDavid du Colombier 	DBG("bsr: block @ i %d BLOCK(b,i) %d kval %d next %d %s\n",
3032c57ff9fSDavid du Colombier 		i, BLOCK(b,i), l->kval, l->next, l->tag?"avail":"used");
3042c57ff9fSDavid du Colombier 	avail[j].next = l->next;
305*491cc0e5SDavid du Colombier 	if(avail[j].next != 0)
306*491cc0e5SDavid du Colombier 		blocks[BLOCK(b,avail[j].next)].prev = 0;
3072c57ff9fSDavid du Colombier 	l->prev = l->next = 0;
3082c57ff9fSDavid du Colombier 	l->tag = Used;
3092c57ff9fSDavid du Colombier 	l->kval = k;
3102c57ff9fSDavid du Colombier 
3112c57ff9fSDavid du Colombier 	/*
3122c57ff9fSDavid du Colombier 	 * Split required?
3132c57ff9fSDavid du Colombier 	 */
3142c57ff9fSDavid du Colombier 	while(j > k){
3152c57ff9fSDavid du Colombier 		/*
3162c57ff9fSDavid du Colombier 		 * Split.
3172c57ff9fSDavid du Colombier 		 */
3182c57ff9fSDavid du Colombier 		j--;
3192c57ff9fSDavid du Colombier 		p = &blocks[BLOCK(b,i) + (UNO<<j)/(b->bminsz)];
3202c57ff9fSDavid du Colombier 		p->tag = Avail;
3212c57ff9fSDavid du Colombier 		p->kval = j;
3222c57ff9fSDavid du Colombier 		p->next = avail[j].next;
3232c57ff9fSDavid du Colombier 		p->prev = 0;
3242c57ff9fSDavid du Colombier 		if(p->next != 0)
3252c57ff9fSDavid du Colombier 			blocks[BLOCK(b,p->next)].prev = i + (UNO<<j)/(b->bminsz);
3262c57ff9fSDavid du Colombier 		avail[j].next = i + (UNO<<j)/(b->bminsz);
3272c57ff9fSDavid du Colombier 		DBG("bsr: split @ i %d BLOCK(b,i) %ld j %d next %d (%d) %s\n",
3282c57ff9fSDavid du Colombier 			i, p - blocks, j, p->next, BLOCK(b,p->next),
3292c57ff9fSDavid du Colombier 			p->tag?"avail":"used");
3302c57ff9fSDavid du Colombier 	}
3312c57ff9fSDavid du Colombier 	b->nfree -= size/b->bminsz;
3322c57ff9fSDavid du Colombier 	unlock(&budlock);
3332c57ff9fSDavid du Colombier 
3342c57ff9fSDavid du Colombier 	m = b->memory + b->bminsz*BLOCK(b,i);
3352c57ff9fSDavid du Colombier 	assert(m >= b->base && m < b->base + b->size);
3362c57ff9fSDavid du Colombier 	blocks[BLOCK(b,i)].p = tag;
3372c57ff9fSDavid du Colombier 
3382c57ff9fSDavid du Colombier 	return m;
3392c57ff9fSDavid du Colombier }
3402c57ff9fSDavid du Colombier 
3412c57ff9fSDavid du Colombier uintmem
physalloc(u64int size,int * colorp,void * tag)3422c57ff9fSDavid du Colombier physalloc(u64int size, int *colorp, void *tag)
3432c57ff9fSDavid du Colombier {
3442c57ff9fSDavid du Colombier 	int i, color;
3452c57ff9fSDavid du Colombier 	uintmem m;
3462c57ff9fSDavid du Colombier 
3472c57ff9fSDavid du Colombier 	m = 0;
3482c57ff9fSDavid du Colombier 
3492c57ff9fSDavid du Colombier 	color = *colorp;
3502c57ff9fSDavid du Colombier 	if(color >= 0){
3512c57ff9fSDavid du Colombier 		color %= ndoms;
3522c57ff9fSDavid du Colombier 		if(bal[color].kmin > 0){
3532c57ff9fSDavid du Colombier 			*colorp = color;
3542c57ff9fSDavid du Colombier 			m = xphysalloc(&bal[color], size, tag);
3552c57ff9fSDavid du Colombier 		}
3562c57ff9fSDavid du Colombier 	}
3572c57ff9fSDavid du Colombier 	if(m == 0)
3582c57ff9fSDavid du Colombier 		for(i = 0; i < ndoms; i++)
3592c57ff9fSDavid du Colombier 			if(bal[i].kmin > 0)
3602c57ff9fSDavid du Colombier 				if((m = xphysalloc(&bal[i], size, tag)) != 0){
3612c57ff9fSDavid du Colombier 					*colorp = i;
3622c57ff9fSDavid du Colombier 					return m;
3632c57ff9fSDavid du Colombier 				}
3642c57ff9fSDavid du Colombier 	return m;
3652c57ff9fSDavid du Colombier }
3662c57ff9fSDavid du Colombier 
3672c57ff9fSDavid du Colombier static void
dump(Bal * b)3682c57ff9fSDavid du Colombier dump(Bal *b)
3692c57ff9fSDavid du Colombier {
3702c57ff9fSDavid du Colombier 	uint bi, i, k;
3712c57ff9fSDavid du Colombier 	Buddy *blocks;
3722c57ff9fSDavid du Colombier 
3732c57ff9fSDavid du Colombier 	blocks = b->blocks;
3742c57ff9fSDavid du Colombier 	for(i = 0; i < (UNO<<(b->kmax-b->kmin+1)); i++){
3752c57ff9fSDavid du Colombier 		if(blocks[i].tag == Used)
3762c57ff9fSDavid du Colombier 			continue;
3772c57ff9fSDavid du Colombier 		print("blocks[%d]: size %d prev %d next %d\n",
3782c57ff9fSDavid du Colombier 			i, 1<<b->blocks[i].kval, blocks[i].prev, blocks[i].next);
3792c57ff9fSDavid du Colombier 		//i += (1<<blocks[i].kval)/b->bminsz-1;
3802c57ff9fSDavid du Colombier 	}
3812c57ff9fSDavid du Colombier 
3822c57ff9fSDavid du Colombier 	for(k = 0; k <= b->kmax; k++){
3832c57ff9fSDavid du Colombier 		print("a[%d]:", k);
3842c57ff9fSDavid du Colombier 		for(bi = b->avail[k].next; bi != 0; bi = blocks[BLOCK(b,bi)].next){
3852c57ff9fSDavid du Colombier 			print(" %d", bi);
3862c57ff9fSDavid du Colombier 		}
3872c57ff9fSDavid du Colombier 		print("\n");
3882c57ff9fSDavid du Colombier 	}
3892c57ff9fSDavid du Colombier }
3902c57ff9fSDavid du Colombier 
3912c57ff9fSDavid du Colombier void
physallocdump(void)3922c57ff9fSDavid du Colombier physallocdump(void)
3932c57ff9fSDavid du Colombier {
3942c57ff9fSDavid du Colombier 	int n;
3952c57ff9fSDavid du Colombier 
3962c57ff9fSDavid du Colombier 	for(n = 0; n < Ndoms; n++)
3972c57ff9fSDavid du Colombier 		if(bal[n].size > 0)
3982c57ff9fSDavid du Colombier 			print("physalloc color=%d base=%#ullx size=%#ullx\n",
3992c57ff9fSDavid du Colombier 				n, bal[n].base, bal[n].size);
4002c57ff9fSDavid du Colombier }
4012c57ff9fSDavid du Colombier 
4022c57ff9fSDavid du Colombier static int
plop(Bal * b,uintmem a,int k,int type)4032c57ff9fSDavid du Colombier plop(Bal *b, uintmem a, int k, int type)
4042c57ff9fSDavid du Colombier {
4052c57ff9fSDavid du Colombier 	uint i;
4062c57ff9fSDavid du Colombier 	Buddy *l;
4072c57ff9fSDavid du Colombier 
4082c57ff9fSDavid du Colombier 
4092c57ff9fSDavid du Colombier 	DBG("plop(a %#p k %d type %d)\n", a, k, type);
4102c57ff9fSDavid du Colombier 
4112c57ff9fSDavid du Colombier 	i = INDEX(b,a);
4122c57ff9fSDavid du Colombier 	l = &b->blocks[BLOCK(b,i)];
4132c57ff9fSDavid du Colombier 
4142c57ff9fSDavid du Colombier 	l->kval = k;
4152c57ff9fSDavid du Colombier 	xphysfree(b, a, 1<<k);
4162c57ff9fSDavid du Colombier 
4172c57ff9fSDavid du Colombier 	return 1;
4182c57ff9fSDavid du Colombier }
4192c57ff9fSDavid du Colombier 
4202c57ff9fSDavid du Colombier static int
iimbchunk(Bal * b,uintmem a,uintmem e,int type)4212c57ff9fSDavid du Colombier iimbchunk(Bal *b, uintmem a, uintmem e, int type)
4222c57ff9fSDavid du Colombier {
4232c57ff9fSDavid du Colombier 	int k;
4242c57ff9fSDavid du Colombier 	uint s;
4252c57ff9fSDavid du Colombier 
4262c57ff9fSDavid du Colombier 	a = ROUNDUP(a, b->bminsz);
4272c57ff9fSDavid du Colombier 	e = ROUNDDN(e, b->bminsz);
4282c57ff9fSDavid du Colombier 	DBG("iimbchunk: start a %#P e %#P\n", a, e);
4292c57ff9fSDavid du Colombier 
4302c57ff9fSDavid du Colombier 	b->nblocks += (e-a)/b->bminsz;
4312c57ff9fSDavid du Colombier 
4322c57ff9fSDavid du Colombier 	for(k = b->kmin, s = b->bminsz; a+s < e && k < b->kmax; s <<= 1, k += 1){
4332c57ff9fSDavid du Colombier 		if(a & s){
4342c57ff9fSDavid du Colombier 			plop(b, a, k, type);
4352c57ff9fSDavid du Colombier 			a += s;
4362c57ff9fSDavid du Colombier 		}
4372c57ff9fSDavid du Colombier 	}
4382c57ff9fSDavid du Colombier 	DBG("done1 a %#P e %#P s %#ux %d\n", a, e, s, k);
4392c57ff9fSDavid du Colombier 
4402c57ff9fSDavid du Colombier 	while(a+s <= e){
4412c57ff9fSDavid du Colombier 		plop(b, a, k, type);
4422c57ff9fSDavid du Colombier 		a += s;
4432c57ff9fSDavid du Colombier 	}
4442c57ff9fSDavid du Colombier 	DBG("done2 a %#P e %#P s %#ux %d\n", a, e, s, k);
4452c57ff9fSDavid du Colombier 
4462c57ff9fSDavid du Colombier 	for(k -= 1, s >>= 1; a < e; s >>= 1, k -= 1){
4472c57ff9fSDavid du Colombier 		if(a+s <= e){
4482c57ff9fSDavid du Colombier 			plop(b, a, k, type);
4492c57ff9fSDavid du Colombier 			a += s;
4502c57ff9fSDavid du Colombier 		}
4512c57ff9fSDavid du Colombier 	}
4522c57ff9fSDavid du Colombier 	DBG("done3 a %#P e %#P s %#ux %d\n", a, e, s, k);
4532c57ff9fSDavid du Colombier 
4542c57ff9fSDavid du Colombier 	return 0;
4552c57ff9fSDavid du Colombier }
4562c57ff9fSDavid du Colombier 
4572c57ff9fSDavid du Colombier /*
4582c57ff9fSDavid du Colombier  * Called from umeminit to initialize user memory allocators.
4592c57ff9fSDavid du Colombier  */
4602c57ff9fSDavid du Colombier void
physinit(uintmem a,u64int size)4612c57ff9fSDavid du Colombier physinit(uintmem a, u64int size)
4622c57ff9fSDavid du Colombier {
4632c57ff9fSDavid du Colombier 	uintmem dtsz;
4642c57ff9fSDavid du Colombier 	Bal *b;
4652c57ff9fSDavid du Colombier 	int i, dom;
4662c57ff9fSDavid du Colombier 	uintmem addr, len;
4672c57ff9fSDavid du Colombier 
4682c57ff9fSDavid du Colombier 	DBG("physinit %#ullx %#ullx\n", a, size);
4692c57ff9fSDavid du Colombier 
4702c57ff9fSDavid du Colombier 	for(addr = a; addr < a+size; addr += len){
4712c57ff9fSDavid du Colombier 		dom = 0;
4722c57ff9fSDavid du Colombier 		len = acpimblocksize(addr, &dom);
4732c57ff9fSDavid du Colombier 		/* len can be zero if there's no acpi information about addr */
4742c57ff9fSDavid du Colombier 		if(len == 0 || addr + len > a + size)
4752c57ff9fSDavid du Colombier 			len = a + size - addr;
4762c57ff9fSDavid du Colombier 		/*
4772c57ff9fSDavid du Colombier 		 * Each block belongs to a different domain (ie. cpu/mem socket)
4782c57ff9fSDavid du Colombier 		 * We must create a buddy allocator for each block, so we could
4792c57ff9fSDavid du Colombier 		 * allocate memory from different domains.
4802c57ff9fSDavid du Colombier 		 *
4812c57ff9fSDavid du Colombier 		 * This code assumes that a domain may be extended later and
4822c57ff9fSDavid du Colombier 		 * that there is no interleaving of domains. Ok by now.
4832c57ff9fSDavid du Colombier 		 */
4842c57ff9fSDavid du Colombier 		DBG("physmem block dom %d addr %#ullx size %#ullx\n",
4852c57ff9fSDavid du Colombier 			dom, addr, len);
4862c57ff9fSDavid du Colombier 		if(dom < 0 || dom >= Ndoms){
4872c57ff9fSDavid du Colombier 			print("physinit: invalid dom %d\n", dom);
4882c57ff9fSDavid du Colombier 			dom = 0;
4892c57ff9fSDavid du Colombier 		}
4902c57ff9fSDavid du Colombier 		b = &bal[dom];
4912c57ff9fSDavid du Colombier 		if(dom >= ndoms)
4922c57ff9fSDavid du Colombier 			ndoms = dom+1;
4932c57ff9fSDavid du Colombier 		if(b->kmin == 0){
4942c57ff9fSDavid du Colombier 			b->base = addr;
4952c57ff9fSDavid du Colombier 			b->size = len;
4962c57ff9fSDavid du Colombier 			b->kmin = BKmin;
4972c57ff9fSDavid du Colombier 			b->kmax = BKmax;
4982c57ff9fSDavid du Colombier 			b->bminsz = (UNO<<b->kmin);
4992c57ff9fSDavid du Colombier 			b->memory = sys->pmstart;
5002c57ff9fSDavid du Colombier 			b->kspan = lg2floor(sys->pmend);
5012c57ff9fSDavid du Colombier 			if(!ISPOWEROF2(sys->pmend))
5022c57ff9fSDavid du Colombier 				b->kspan++;
5032c57ff9fSDavid du Colombier 			dtsz = sizeof(Buddy)*(UNO<<(b->kspan-b->kmin+1));
5042c57ff9fSDavid du Colombier 			DBG("kspan %ud (arrysz = %llud)\n", b->kspan, dtsz);
5052c57ff9fSDavid du Colombier 			b->blocks = malloc(dtsz);
5062c57ff9fSDavid du Colombier 			if(b->blocks == nil)
5072c57ff9fSDavid du Colombier 				panic("physinit: no blocks");
5082c57ff9fSDavid du Colombier 			memset(b->blocks, 0, dtsz);
5092c57ff9fSDavid du Colombier 			b->avail = malloc(sizeof(Buddy)*(b->kmax+1));
5102c57ff9fSDavid du Colombier 			if(b->avail == nil)
5112c57ff9fSDavid du Colombier 				panic("physinit: no avail");
5122c57ff9fSDavid du Colombier 			memset(b->avail, 0, sizeof(Buddy)*(b->kmax+1));
5132c57ff9fSDavid du Colombier 		}else{
5142c57ff9fSDavid du Colombier 			if(addr < b->base)
5152c57ff9fSDavid du Colombier 				panic("physinit: decreasing base");
5162c57ff9fSDavid du Colombier 			if(b->base+b->size < addr + len)
5172c57ff9fSDavid du Colombier 				b->size = (addr-b->base) + len;
5182c57ff9fSDavid du Colombier 			for(i = 0; i < Ndoms; i++)
5192c57ff9fSDavid du Colombier 				if(bal[i].kmin && &bal[i] != b)
5202c57ff9fSDavid du Colombier 				if(bal[i].base < b->base + b->size &&
5212c57ff9fSDavid du Colombier 				   bal[i].base + bal[i].size > b->base + b->size)
5222c57ff9fSDavid du Colombier 					panic("physinit: doms overlap");
5232c57ff9fSDavid du Colombier 		}
5242c57ff9fSDavid du Colombier 		assert(addr >= b->base && addr+len <= b->base + b->size);
5252c57ff9fSDavid du Colombier 
5262c57ff9fSDavid du Colombier 		iimbchunk(b, addr, addr+len, 0);
5272c57ff9fSDavid du Colombier 	}
5282c57ff9fSDavid du Colombier 
5292c57ff9fSDavid du Colombier 
5302c57ff9fSDavid du Colombier }
531