1 /* 2 * allocate Blocks from uncached memory 3 */ 4 #include "u.h" 5 #include "../port/lib.h" 6 #include "mem.h" 7 #include "dat.h" 8 #include "fns.h" 9 #include "error.h" 10 11 enum 12 { 13 Hdrspc = 64, /* leave room for high-level headers */ 14 Bdead = 0x51494F42, /* "QIOB" */ 15 }; 16 17 struct 18 { 19 Lock; 20 ulong bytes; 21 } ucialloc; 22 23 static Block* 24 _ucallocb(int size) 25 { 26 Block *b; 27 ulong addr; 28 29 if((b = ucalloc(sizeof(Block)+size+Hdrspc)) == nil) 30 return nil; 31 32 b->next = nil; 33 b->list = nil; 34 b->free = 0; 35 b->flag = 0; 36 b->ref = 0; 37 _xinc(&b->ref); 38 39 /* align start of data portion by rounding up */ 40 addr = (ulong)b; 41 addr = ROUND(addr + sizeof(Block), BLOCKALIGN); 42 b->base = (uchar*)addr; 43 44 /* align end of data portion by rounding down */ 45 b->lim = ((uchar*)b) + msize(b); 46 addr = (ulong)(b->lim); 47 addr = addr & ~(BLOCKALIGN-1); 48 b->lim = (uchar*)addr; 49 50 /* leave sluff at beginning for added headers */ 51 b->rp = b->lim - ROUND(size, BLOCKALIGN); 52 if(b->rp < b->base) 53 panic("_ucallocb"); 54 b->wp = b->rp; 55 56 return b; 57 } 58 59 Block* 60 ucallocb(int size) 61 { 62 Block *b; 63 64 /* 65 * Check in a process and wait until successful. 66 * Can still error out of here, though. 67 */ 68 if(up == nil) 69 panic("ucallocb without up: %#p", getcallerpc(&size)); 70 if((b = _ucallocb(size)) == nil) 71 panic("ucallocb: no memory for %d bytes", size); 72 setmalloctag(b, getcallerpc(&size)); 73 74 return b; 75 } 76 77 Block* 78 uciallocb(int size) 79 { 80 Block *b; 81 static int m1, m2, mp; 82 83 if(0 && ucialloc.bytes > conf.ialloc){ 84 if((m1++%10000)==0){ 85 if(mp++ > 1000){ 86 active.exiting = 1; 87 exit(0); 88 } 89 iprint("uciallocb: limited %lud/%lud\n", 90 ucialloc.bytes, conf.ialloc); 91 } 92 return nil; 93 } 94 95 if((b = _ucallocb(size)) == nil){ 96 if(0 && (m2++%10000)==0){ 97 if(mp++ > 1000){ 98 active.exiting = 1; 99 exit(0); 100 } 101 iprint("uciallocb: no memory %lud/%lud\n", 102 ucialloc.bytes, conf.ialloc); 103 } 104 return nil; 105 } 106 setmalloctag(b, getcallerpc(&size)); 107 b->flag = BINTR; 108 109 ilock(&ucialloc); 110 ucialloc.bytes += b->lim - b->base; 111 iunlock(&ucialloc); 112 113 return b; 114 } 115 116 void 117 ucfreeb(Block *b) 118 { 119 void *dead = (void*)Bdead; 120 long ref; 121 122 if(b == nil || (ref = _xdec(&b->ref)) > 0) 123 return; 124 125 if(ref < 0){ 126 dumpstack(); 127 panic("ucfreeb: ref %ld; caller pc %#p", ref, getcallerpc(&b)); 128 } 129 130 /* 131 * drivers which perform non cache coherent DMA manage their own buffer 132 * pool of uncached buffers and provide their own free routine. 133 */ 134 if(b->free) { 135 b->free(b); 136 return; 137 } 138 if(b->flag & BINTR) { 139 ilock(&ucialloc); 140 ucialloc.bytes -= b->lim - b->base; 141 iunlock(&ucialloc); 142 } 143 144 /* poison the block in case someone is still holding onto it */ 145 b->next = dead; 146 b->rp = dead; 147 b->wp = dead; 148 b->lim = dead; 149 b->base = dead; 150 151 ucfree(b); 152 } 153