optimize the menuconfig redrawing
[lunaix-os.git] / lunaix-os / kernel / mm / pmalloc_simple.c
1 #include <lunaix/spike.h>
2 #include "pmm_internal.h"
3
4 #ifdef CONFIG_PMALLOC_METHOD_SIMPLE
5
6 // Simple PM Allocator (segregated next fit)
7
8 #define INIT_FLAG   0b10
9
10 static const int po_limit[] = {
11     CONFIG_PMALLOC_SIMPLE_MAX_PO0,
12     CONFIG_PMALLOC_SIMPLE_MAX_PO1,
13     CONFIG_PMALLOC_SIMPLE_MAX_PO2,
14     CONFIG_PMALLOC_SIMPLE_MAX_PO3,
15     CONFIG_PMALLOC_SIMPLE_MAX_PO4,
16     CONFIG_PMALLOC_SIMPLE_MAX_PO5,
17     CONFIG_PMALLOC_SIMPLE_MAX_PO6,
18     CONFIG_PMALLOC_SIMPLE_MAX_PO7,
19     CONFIG_PMALLOC_SIMPLE_MAX_PO8,
20     CONFIG_PMALLOC_SIMPLE_MAX_PO9,
21 };
22
23 static inline bool
24 __uninitialized_page(struct ppage* page)
25 {
26     return !(page->flags & INIT_FLAG);
27 }
28
29 static inline void
30 __set_page_initialized(struct ppage* page)
31 {
32     page->flags |= INIT_FLAG;
33 }
34
35 static inline void
36 __set_pages_uninitialized(struct ppage* lead)
37 {
38     for (size_t i = 0; i < (1UL << lead->order); i++)
39     {
40         lead[i].flags &= ~INIT_FLAG;
41     }
42 }
43
44 void
45 pmm_allocator_init(struct pmem* memory)
46 {
47     // nothing todo
48 }
49
50 void
51 pmm_allocator_init_pool(struct pmem_pool* pool)
52 {
53     for (int i = 0; i < MAX_PAGE_ORDERS; i++) {
54         llist_init_head(&pool->idle_order[i]);
55         pool->count[i] = 0;
56     }
57
58     struct ppage* pooled_page = pool->pool_start;
59     for (; pooled_page <= pool->pool_end; pooled_page++) {
60         *pooled_page = (struct ppage){ };
61     }
62 }
63
64 void
65 pmm_free_one(struct ppage* page, int type_mask)
66 {
67     page = leading_page(page);
68
69     assert(page->refs);
70     assert(!reserved_page(page));
71     assert(!__uninitialized_page(page));
72
73     if (--page->refs) {
74         return;
75     }
76
77     int order = page->order;
78     assert(order <= MAX_PAGE_ORDERS);
79
80     struct pmem_pool* pool = pmm_pool_lookup(page);
81     struct llist_header* bucket = &pool->idle_order[order];
82
83     if (pool->count[order] < po_limit[order]) {
84         llist_append(bucket, &page->sibs);
85         pool->count[order]++;
86         return;
87     }
88
89     __set_pages_uninitialized(page);
90 }
91
92 static pfn_t index = 0;
93
94 struct ppage*
95 pmm_looknext(struct pmem_pool* pool, size_t order)
96 {
97     struct ppage *lead, *tail = NULL;
98     pfn_t working = index;
99     size_t count, total;
100     size_t poolsz = ppfn_of(pool, pool->pool_end) + 1;
101
102     total = 1 << order;
103     count = total;
104     do
105     {
106         tail = ppage_of(pool, working);
107
108         if (__uninitialized_page(tail)) {
109             count--;
110         }
111         else {
112             count = total;
113         }
114
115         working = (working + 1) % poolsz;
116     } while (count && working != index);
117
118     index = working;
119     if (count) {
120         return NULL;
121     }
122
123     lead = tail - total + 1;
124     for (size_t i = 0; i < total; i++)
125     {
126         struct ppage* page = &lead[i];
127         page->order = order;
128         page->companion = i;
129         page->pool = pool->type;
130         llist_init_head(&page->sibs);
131         __set_page_initialized(page);
132     }
133
134     return lead;
135 }
136
137 struct ppage*
138 pmm_alloc_napot_type(int pool, size_t order, ppage_type_t type)
139 {
140     assert(order <= MAX_PAGE_ORDERS);
141
142     struct pmem_pool* _pool = pmm_pool_get(pool);
143     struct llist_header* bucket = &_pool->idle_order[order];
144
145     struct ppage* good_page = NULL;
146     if (!llist_empty(bucket)) {
147         (_pool->count[order])--;
148         good_page = list_entry(bucket->next, struct ppage, sibs);
149         llist_delete(&good_page->sibs);
150     }
151     else {
152         good_page = pmm_looknext(_pool, order);
153     }
154
155     assert(good_page);
156     assert(!good_page->refs);
157     
158     good_page->refs = 1;
159     good_page->type = type;
160
161     return good_page;
162 }
163
164 bool
165 pmm_allocator_trymark_onhold(struct pmem_pool* pool, struct ppage* start, struct ppage* end)
166 {
167     while (start <= end) {
168         if (__uninitialized_page(start)) {
169             set_reserved(start);
170             __set_page_initialized(start);
171         }
172         else if (!start->refs) {
173             struct ppage* lead = leading_page(start);
174             llist_delete(&lead->sibs);
175
176             __set_pages_uninitialized(lead);
177             
178             continue;
179         }
180         else if (!reserved_page(start)) {
181             return false;
182         }
183
184         start++;
185     }
186
187     return true;
188 }
189
190 bool
191 pmm_allocator_trymark_unhold(struct pmem_pool* pool, struct ppage* start, struct ppage* end)
192 {
193     while (start <= end) {
194         if (!__uninitialized_page(start) && reserved_page(start)) {
195             __set_pages_uninitialized(start);
196         }
197
198         start++;
199     }
200
201     return true;
202 }
203
204 #endif