#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: stalloc.c,v 1.20 2023/01/24 07:57:20 mlelstv Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <atari/atari/stalloc.h>
extern u_long st_pool_size, st_pool_virt, st_pool_phys;
#define PHYS_ADDR(virt) ((u_long)(virt) - st_pool_virt + st_pool_phys)
static TAILQ_HEAD(stlist, mem_node) st_list;
static TAILQ_HEAD(freelist, mem_node) free_list;
u_long stmem_total;
void
init_stmem(void)
{
int s;
struct mem_node *mem;
s = splhigh();
stmem_total = st_pool_size - sizeof(*mem);
mem = (struct mem_node *)st_pool_virt;
mem->size = st_pool_size - sizeof(*mem);
TAILQ_INIT(&st_list);
TAILQ_INIT(&free_list);
TAILQ_INSERT_HEAD(&st_list, mem, link);
TAILQ_INSERT_HEAD(&free_list, mem, free_link);
splx(s);
}
void *
alloc_stmem(u_long size, void **phys_addr)
{
struct mem_node *mn, *new, *bfit;
int s;
if (size == 0)
return NULL;
s = splhigh();
if ((size & ~(ST_BLOCKMASK)) != 0)
size = (size & ST_BLOCKMASK) + ST_BLOCKSIZE;
bfit = NULL;
TAILQ_FOREACH(mn, &free_list, free_link) {
if (size <= mn->size) {
if ((bfit != NULL) &&
(bfit->size < mn->size))
continue;
bfit = mn;
}
}
if (bfit != NULL)
mn = bfit;
if (mn == NULL) {
printf("St-mem pool exhausted, binpatch 'st_pool_size'"
"to get more\n");
splx(s);
return NULL;
}
if ((mn->size - size) <= sizeof(*mn)) {
TAILQ_REMOVE(&free_list, mn, free_link);
mn->type = MNODE_USED;
size = mn->size;
stmem_total -= mn->size;
splx(s);
*phys_addr = (void*)PHYS_ADDR(&mn[1]);
return (void *)&mn[1];
}
new = mn;
new->size -= size + sizeof(*mn);
mn = (struct mem_node *)(MNODES_MEM(new) + new->size);
mn->size = size;
TAILQ_INSERT_AFTER(&st_list, new, mn, link);
mn->type = MNODE_USED;
stmem_total -= size + sizeof(*mn);
splx(s);
*phys_addr = (void*)PHYS_ADDR(&mn[1]);
return (void *)&mn[1];
}
void
free_stmem(void *mem)
{
struct mem_node *mn, *next, *prev;
int s;
if (mem == NULL)
return;
s = splhigh();
mn = (struct mem_node *)mem - 1;
next = TAILQ_NEXT(mn, link);
prev = TAILQ_PREV(mn, stlist, link);
if (next != NULL && next->type == MNODE_FREE) {
TAILQ_INSERT_BEFORE(next, mn, free_link);
mn->type = MNODE_FREE;
TAILQ_REMOVE(&st_list, next, link);
TAILQ_REMOVE(&free_list, next, free_link);
stmem_total += mn->size + sizeof(*mn);
mn->size += next->size + sizeof(*mn);
}
if (prev != NULL && prev->type == MNODE_FREE) {
if (mn->type != MNODE_FREE)
stmem_total += mn->size + sizeof(*mn);
else {
TAILQ_REMOVE(&free_list, mn, free_link);
mn->type = MNODE_USED;
stmem_total += sizeof(*mn);
}
TAILQ_REMOVE(&st_list, mn, link);
prev->size += mn->size + sizeof(*mn);
} else if (mn->type != MNODE_FREE) {
while (next != NULL && prev != NULL) {
if (next->type == MNODE_FREE) {
TAILQ_INSERT_BEFORE(next, mn, free_link);
mn->type = MNODE_FREE;
break;
}
if (prev->type == MNODE_FREE) {
TAILQ_INSERT_AFTER(&free_list, prev, mn,
free_link);
mn->type = MNODE_FREE;
break;
}
prev = TAILQ_PREV(prev, stlist, link);
next = TAILQ_NEXT(next, link);
}
if (mn->type != MNODE_FREE) {
if (next == NULL) {
TAILQ_INSERT_TAIL(&free_list,mn,free_link);
} else {
TAILQ_INSERT_HEAD(&free_list,mn,free_link);
}
mn->type = MNODE_FREE;
}
stmem_total += mn->size;
}
splx(s);
}