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*
_ucallocb(int size)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*
ucallocb(int size)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*
uciallocb(int size)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
ucfreeb(Block * b)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