#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" typedef struct IOMap IOMap; struct IOMap { IOMap *next; ulong start; ulong end; char reserved; char tag[13]; }; static struct { Lock; IOMap *m; IOMap *free; IOMap maps[32]; /* some initial free maps */ ulong mask; } iomap; static void insert(IOMap **l, ulong start, ulong end, char *tag, int reserved) { IOMap *m; m = iomap.free; if(m != nil) iomap.free = m->next; else m = malloc(sizeof(IOMap)); if(m == nil) panic("ioalloc: out of memory"); m->next = *l; m->start = start; m->end = end; m->reserved = reserved; strncpy(m->tag, tag, sizeof(m->tag)-1); m->tag[sizeof(m->tag)-1] = 0; *l = m; } /* * Find a free region of length "size" within the window [port, port+win) * and reserve it to be ioalloced later. */ s32 ioreservewin(u32 port, u32 win, u32 size, u32 align, char *tag) { IOMap *m, **l; if(win == 0 || port & ~iomap.mask || (~port & iomap.mask) < (win-1 & iomap.mask)) return -1; size = (size + ~iomap.mask) & iomap.mask; if(size == 0 || size > win) return -1; if(align){ if((align & (align-1)) != 0) return -1; align--; } win += port; port = (port+align) & ~align; if(port >= win || win - port < size) return -1; lock(&iomap); for(l = &iomap.m; (m = *l) != nil; l = &m->next){ if(m->end <= port) continue; if(m->start > port && m->start - port >= size) break; port = m->end; port = (port+align) & ~align; if(port >= win || win - port < size){ unlock(&iomap); return -1; } } insert(l, port, port + size, tag, 1); unlock(&iomap); return port; } /* * Reserve a range to be ioalloced later. * If port is -1, look for a free range above 0x400. */ u32 ioreserve(u32 port, u32 size, u32 align, char *tag) { if(port == -1) return ioreservewin(0x400, -0x400 & iomap.mask, size, align, tag); else return ioreservewin(port, size, size, align, tag); } /* * Alloc some io port space and remember who it was * alloced to. If port == -1, find a free region. */ s32 ioalloc(s32 port, u32 size, u32 align, char *tag) { IOMap *m, **l; if(port == -1) port = ioreserve(port, size, align, tag); size = (size + ~iomap.mask) & iomap.mask; if(size == 0 || port & ~iomap.mask || (~port & iomap.mask) < (size-1 & iomap.mask)) return -1; lock(&iomap); for(l = &iomap.m; (m = *l) != nil; l = &m->next){ if(m->end <= port) continue; if(m->start > port && m->start - port >= size) break; if(m->reserved && m->start <= port && m->end - port >= size){ if(m->end - port > size) insert(&m->next, port + size, m->end, m->tag, 1); if(m->start < port){ insert(l, m->start, port, m->tag, 1); l = &(*l)->next; } *l = m->next; m->next = iomap.free; iomap.free = m; break; } print("ioalloc: %ux - %ux %s: clashes with: %lux - %lux %s\n", port, port+size-1, tag, m->start, m->end-1, m->tag); unlock(&iomap); return -1; } insert(l, port, port + size, tag, 0); unlock(&iomap); return port; } void iofree(u32 port) { IOMap *m, **l; if(port & ~iomap.mask) return; lock(&iomap); for(l = &iomap.m; (m = *l) != nil; l = &m->next){ if(m->start == port){ *l = m->next; m->next = iomap.free; iomap.free = m; break; } if(m->start > port) break; } unlock(&iomap); } s32 iounused(u32 start, u32 end) { IOMap *m; if(start & ~iomap.mask || end < start) return 0; for(m = iomap.m; m != nil; m = m->next){ if(m->end <= start) continue; if(m->start >= end) break; if(!m->reserved) return 0; } return 1; } static s32 iomapread(Chan*, void *a, s32 n, s64 offset) { char buf[32]; IOMap *m; int i; lock(&iomap); i = 0; for(m = iomap.m; m != nil; m = m->next){ i = snprint(buf, sizeof(buf), "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag); offset -= i; if(offset < 0) break; } unlock(&iomap); if(offset >= 0) return 0; if(n > -offset) n = -offset; offset += i; memmove(a, buf+offset, n); return n; } /* * Initialize the io space port map. * The mask argument defines the valid bits of * a port address, so different architectures * might have different sizes and alignments. */ void iomapinit(u32 mask) { int i; assert(mask != 0 && (mask >> 31) == 0); for(i = 0; i < nelem(iomap.maps)-1; i++) iomap.maps[i].next = &iomap.maps[i+1]; iomap.maps[i].next = nil; iomap.free = iomap.maps; iomap.mask = mask; addarchfile("ioalloc", 0444, iomapread, nil); }