Fix allocb's alignment to 32 bytes.
[akaros.git] / kern / src / ns / allocb.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 enum
17 {
18         Hdrspc          = 64,           /* leave room for high-level headers */
19         Bdead           = 0x51494F42,   /* "QIOB" */
20         BY2V            = 32,           /* best practice learned the hard way */
21 };
22
23 struct
24 {
25         spinlock_t lock;
26         uint32_t        bytes;
27 } ialloc;
28
29 /*
30  *  allocate blocks (round data base address to 64 bit boundary).
31  *  if mallocz gives us more than we asked for, leave room at the front
32  *  for header.
33  */
34 struct block*
35 _allocb(int size)
36 {
37         struct block *b;
38         uintptr_t addr;
39         int n;
40
41         b = kzmalloc(sizeof(struct block)+size+Hdrspc+(BY2V-1), 0);
42         if(b == NULL)
43                 return NULL;
44
45         b->next = NULL;
46         b->list = NULL;
47         b->free = NULL;
48         b->flag = 0;
49
50         addr = (uintptr_t)b;
51         addr = ROUNDUP(addr + sizeof(struct block), BY2V);
52         b->base = ( uint8_t *)addr;
53         b->lim = (( uint8_t *)b) + msize(b);
54         b->rp = b->base;
55         n = b->lim - b->base - size;
56         b->rp += n & ~(BY2V-1);
57         b->wp = b->rp;
58
59         return b;
60 }
61
62 struct block*
63 allocb(int size)
64 {
65         struct block *b;
66
67         if(0 && current == NULL)
68                 panic("allocb outside process: %8.8lux", getcallerpc(&size));
69         b = _allocb(size);
70         if(b == 0)
71                 exhausted("Blocks");
72         return b;
73 }
74
75 /*
76  *  interrupt time allocation
77  */
78 struct block*
79 iallocb(int size)
80 {
81         struct block *b;
82
83 #if 0
84         /* if we ever want to limit bytes allocated in interrupts */
85         if(ialloc.bytes > conf.ialloc){
86                 //print("iallocb: limited %lud/%lud\n", ialloc.bytes, conf.ialloc);
87                 return NULL;
88         }
89 #endif
90
91         b = _allocb(size);
92         if(b == NULL){
93                 //print("iallocb: no memory %lud/%lud\n", ialloc.bytes, conf.ialloc);
94                 return NULL;
95         }
96         b->flag = BINTR;
97
98         spin_lock_irqsave(&ialloc.lock);
99         ialloc.bytes += b->lim - b->base;
100         spin_unlock_irqsave(&ialloc.lock);
101
102         return b;
103 }
104
105 void
106 freeb(struct block *b)
107 {
108         void *dead = (void*)Bdead;
109
110         if(b == NULL)
111                 return;
112
113         /*
114          * drivers which perform non cache coherent DMA manage their own buffer
115          * pool of uncached buffers and provide their own free routine.
116          */
117         if(b->free) {
118                 b->free(b);
119                 return;
120         }
121         if(b->flag & BINTR) {
122                 spin_lock_irqsave(&ialloc.lock);
123                 ialloc.bytes -= b->lim - b->base;
124                 spin_unlock_irqsave(&ialloc.lock);
125         }
126
127         /* poison the block in case someone is still holding onto it */
128         b->next = dead;
129         b->rp = dead;
130         b->wp = dead;
131         b->lim = dead;
132         b->base = dead;
133
134         kfree(b);
135 }
136
137 void
138 checkb(struct block *b, char *msg)
139 {
140         void *dead = (void*)Bdead;
141
142         if(b == dead)
143                 panic("checkb b %s %lux", msg, b);
144         if(b->base == dead || b->lim == dead || b->next == dead
145           || b->rp == dead || b->wp == dead){
146                 printd("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n",
147                         b->base, b->lim, b->next);
148                 printd("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp);
149                 panic("checkb dead: %s\n", msg);
150         }
151
152         if(b->base > b->lim)
153                 panic("checkb 0 %s %lux %lux", msg, b->base, b->lim);
154         if(b->rp < b->base)
155                 panic("checkb 1 %s %lux %lux", msg, b->base, b->rp);
156         if(b->wp < b->base)
157                 panic("checkb 2 %s %lux %lux", msg, b->base, b->wp);
158         if(b->rp > b->lim)
159                 panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim);
160         if(b->wp > b->lim)
161                 panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim);
162
163 }
164
165 void
166 iallocsummary(void)
167 {
168         printd("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc);
169 }