00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <agnix/agnix.h>
00015 #include <asm/bitops.h>
00016 #include <agnix/memory.h>
00017 #include <agnix/panic.h>
00018 #include <agnix/console.h>
00019
00020 #define MOD_NAME "MEM: "
00021 #define NO_PAGE 0
00022
00023 struct buddy_allocator_s buddy_alloc_normal = {
00024 .buddy_name = "Normal area buddy allocator",
00025 .buddy_alloc_req_areas = BUDDY_ALLOC_NORMAL_AREAS
00026 };
00027
00028 struct buddy_allocator_s buddy_alloc_dma = {
00029 .buddy_name = "DMA area buddy allocator",
00030 .buddy_alloc_req_areas = BUDDY_ALLOC_DMA_AREAS
00031 };
00032
00033 extern struct allocator_s main_alloc;
00034 extern void (*put_free_pages_fn)(u32 addr, u8 order);
00035 extern u32 (*get_free_pages_fn)(u8 order);
00036 extern void (*put_free_dma_pages_fn)(u32 addr, u8 order);
00037 extern u32 (*get_free_dma_pages_fn)(u8 order);
00038 struct page_desc_s *system_pages;
00039
00040 void buddy_put_free_pages(struct buddy_allocator_s *buddy_alloc, u32 addr, u8 order)
00041 {
00042 u8 start_order;
00043 u32 bitmap_idx;
00044 struct buddy_area_s *area = &buddy_alloc->buddy_area[order];
00045 struct page_desc_s *page_desc;
00046 struct page_desc_s *page_buddy_desc;
00047 u32 page_idx = virt_to_page(addr);
00048 u32 page_buddy_idx;
00049 u32 page_mask;
00050 u32 flags;
00051
00052 spin_lock_irqsave(&buddy_alloc->buddy_lock, flags);
00053
00054 page_mask = (~0UL) << order;
00055 for (start_order = order; start_order < buddy_alloc->buddy_alloc_req_areas; start_order++) {
00056 bitmap_idx = page_idx >> (start_order + 1);
00057
00058 if (!test_and_change_bit(bitmap_idx, area->area_bitmap)) {
00059 break;
00060 }
00061
00062 page_buddy_idx = page_idx ^ (1 + ~page_mask);
00063 page_buddy_desc = &system_pages[page_buddy_idx];
00064 list_del(&page_buddy_desc->page_list);
00065 area->free_units--;
00066
00067 area++;
00068 page_mask <<= 1;
00069 page_idx &= page_mask;
00070 }
00071
00072 page_desc = &system_pages[page_idx];
00073 list_add(&page_desc->page_list, &area->area_list);
00074 area->free_units++;
00075
00076 spin_unlock_irqrestore(&buddy_alloc->buddy_lock, flags);
00077 }
00078
00079 struct page_desc_s *buddy_get_free_pages_back(struct buddy_allocator_s *buddy_alloc, u32 order, u32 cur_order)
00080 {
00081 struct buddy_area_s *area = &buddy_alloc->buddy_area[cur_order];
00082 struct page_desc_s *page_desc = NULL;
00083 u32 page_idx;
00084 u32 page_half_idx;
00085 u32 back_order;
00086 u32 area_size;
00087
00088 page_desc = list_entry(area->area_list.next, struct page_desc_s, page_list);
00089 page_idx = virt_to_page(page_desc->address_virt);
00090 list_del(area->area_list.next);
00091 change_bit(page_idx >> (cur_order + 1), area->area_bitmap);
00092 area->free_units--;
00093
00094 for (back_order = cur_order - 1; back_order >= order; back_order--) {
00095 area = &buddy_alloc->buddy_area[back_order];
00096 area_size = 1 << back_order;
00097 page_idx = virt_to_page(page_desc->address_virt);
00098 page_half_idx = page_idx + area_size;
00099 list_add(&page_desc->page_list, &area->area_list);
00100 area->free_units++;
00101
00102 change_bit(page_idx >> (back_order + 1), area->area_bitmap);
00103 page_desc = &system_pages[page_half_idx];
00104
00105 if (back_order == order)
00106 break;
00107 }
00108
00109 return page_desc;
00110 }
00111
00112 u32 buddy_get_free_pages(struct buddy_allocator_s *buddy_alloc, u8 order)
00113 {
00114 struct buddy_area_s *area = &buddy_alloc->buddy_area[order];
00115 struct page_desc_s *page_desc = NULL;
00116 u32 cur_order;
00117 u32 flags;
00118 u8 *ptr;
00119 int i;
00120
00121 spin_lock_irqsave(&buddy_alloc->buddy_lock, flags);
00122
00123 for (cur_order = order; cur_order < buddy_alloc->buddy_alloc_req_areas; cur_order++) {
00124
00125 if (!list_empty(&area->area_list)) {
00126 if (cur_order == order) {
00127 page_desc = list_entry(area->area_list.next, struct page_desc_s, page_list);
00128 change_bit(virt_to_page(page_desc->address_virt) >> (order + 1), area->area_bitmap);
00129 list_del(area->area_list.next);
00130 area->free_units--;
00131 } else {
00132 page_desc = buddy_get_free_pages_back(buddy_alloc, order, cur_order);
00133 }
00134
00135 break;
00136 }
00137 area++;
00138 }
00139
00140 spin_unlock_irqrestore(&buddy_alloc->buddy_lock, flags);
00141
00142 if (cur_order == buddy_alloc->buddy_alloc_req_areas)
00143 return 0;
00144
00145 if (page_desc->address_virt < 0xc0000000) {
00146 printk("address < 0xc0000000\n");
00147 for (i = 0; i < 1000000000; i++);
00148 }
00149
00150 ptr = (u8 *)page_desc->address_virt;
00151
00152 for (i = 0; i < PAGE_SIZE; i++) {
00153 ptr[i] = 0;
00154 }
00155
00156 return page_desc->address_virt;
00157 }
00158
00159 u32 buddy_get_free_pages_wrapper(u8 order)
00160 {
00161 return buddy_get_free_pages(&buddy_alloc_normal, order);
00162 }
00163
00164 void buddy_put_free_pages_wrapper(u32 address, u8 order)
00165 {
00166 return buddy_put_free_pages(&buddy_alloc_normal, address, order);
00167 }
00168
00169 u32 buddy_get_free_dma_pages_wrapper(u8 order)
00170 {
00171 return buddy_get_free_pages(&buddy_alloc_dma, order);
00172 }
00173
00174 void buddy_put_free_dma_pages_wrapper(u32 address, u8 order)
00175 {
00176 return buddy_put_free_pages(&buddy_alloc_dma, address, order);
00177 }
00178
00179 void buddy_alloc_fn_init(void)
00180 {
00181 get_free_pages_fn = buddy_get_free_pages_wrapper;
00182 put_free_pages_fn = buddy_put_free_pages_wrapper;
00183 get_free_dma_pages_fn = buddy_get_free_dma_pages_wrapper;
00184 put_free_dma_pages_fn = buddy_put_free_dma_pages_wrapper;
00185 }
00186
00187 int buddy_alloc_areas_init(struct allocator_s *main_alloc, struct buddy_allocator_s *buddy_alloc)
00188 {
00189 int i;
00190 int area_size_pages = 0;
00191
00192 for (i = 0; i < buddy_alloc->buddy_alloc_req_areas; i++) {
00193
00194 area_size_pages = (((main_alloc->mem_size_pages + (1 << 3) - 1) >> 4) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
00195 if ((buddy_alloc->buddy_area[i].area_bitmap = (u32 *)bin_get_free_pages(area_size_pages)) == NULL) {
00196 kernel_panic(MOD_NAME "buddy_alloc_init() failed\n");
00197 }
00198
00199 INIT_LIST_HEAD(&buddy_alloc->buddy_area[i].area_list);
00200 buddy_alloc->buddy_area[i].free_units = 0;
00201 }
00202
00203 return 0;
00204 }
00205
00206 void buddy_alloc_pages_init(struct allocator_s *main_alloc)
00207 {
00208 int system_pages_size;
00209 int i;
00210
00211 system_pages_size = ((main_alloc->mem_size_pages * sizeof(struct page_desc_s)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
00212
00213 if ((system_pages = (struct page_desc_s *)bin_get_free_pages(system_pages_size)) == NULL) {
00214 kernel_panic(MOD_NAME "buddy_alloc_pages_init() failed\n");
00215 }
00216
00217 for (i = 0; i < main_alloc->mem_size_pages; i++) {
00218 system_pages[i].address_phys = (u32)(i << PAGE_SHIFT);
00219 system_pages[i].address_virt = phys_to_virt(system_pages[i].address_phys);
00220
00221 INIT_LIST_HEAD(&system_pages[i].page_list);
00222 }
00223 }
00224
00225 void buddy_alloc_print_units(struct buddy_allocator_s *buddy_alloc, int broadcast)
00226 {
00227 struct buddy_area_s *area;
00228 int i;
00229 u32 flags;
00230
00231 if (broadcast)
00232 printk("\n" MOD_NAME "%s free units\n", buddy_alloc->buddy_name);
00233 else
00234 printf("\n" MOD_NAME "%s free units\n", buddy_alloc->buddy_name);
00235
00236 spin_lock_irqsave(&buddy_alloc->buddy_lock, flags);
00237
00238 for (i = 0; i < buddy_alloc->buddy_alloc_req_areas; i++) {
00239 area = &buddy_alloc->buddy_area[i];
00240 if (broadcast)
00241 printk(MOD_NAME "\torder %02d -> %d free units\n", i, area->free_units);
00242 else
00243 printf(MOD_NAME "\torder %02d -> %d free units\n", i, area->free_units);
00244 }
00245
00246 if (broadcast)
00247 printk("\n");
00248 else
00249 printf("\n");
00250
00251 spin_unlock_irqrestore(&buddy_alloc->buddy_lock, flags);
00252 }
00253
00254 u32 buddy_alloc_free(struct buddy_allocator_s *buddy_alloc)
00255 {
00256 struct buddy_area_s *area;
00257 u32 page_order;
00258 u32 free;
00259 u32 flags;
00260 int i;
00261
00262 spin_lock_irqsave(&buddy_alloc->buddy_lock, flags);
00263
00264 free = 0;
00265 page_order = 1;
00266 for (i = 0; i < buddy_alloc->buddy_alloc_req_areas; i++) {
00267 area = &buddy_alloc->buddy_area[i];
00268 free += area->free_units * page_order;
00269 page_order <<= 1;
00270 }
00271
00272 spin_unlock_irqrestore(&buddy_alloc->buddy_lock, flags);
00273
00274 return free;
00275 }
00276
00277 void __init buddy_alloc_init(void)
00278 {
00279 spin_lock_init(&buddy_alloc->buddy_lock);
00280
00281 buddy_alloc_areas_init(&main_alloc, &buddy_alloc_dma);
00282 buddy_alloc_areas_init(&main_alloc, &buddy_alloc_normal);
00283 buddy_alloc_pages_init(&main_alloc);
00284 buddy_alloc_fn_init();
00285 bin_put_all_free_pages();
00286 buddy_alloc_print_units(&buddy_alloc_dma, 1);
00287 buddy_alloc_print_units(&buddy_alloc_normal, 1);
00288 }
00289
00290 void buddy_alloc_print_stats(void)
00291 {
00292 buddy_alloc_print_units(&buddy_alloc_dma, 0);
00293 buddy_alloc_print_units(&buddy_alloc_normal, 0);
00294 }
00295
00296 void buddy_alloc_print_free(void)
00297 {
00298 u32 free_dma, free_normal;
00299
00300 free_dma = buddy_alloc_free(&buddy_alloc_dma);
00301 printf("DMA free: %d KB\n", free_dma << (PAGE_SHIFT - 10));
00302
00303 free_normal = buddy_alloc_free(&buddy_alloc_normal);
00304 printf("Normal free: %d KB\n", free_normal << (PAGE_SHIFT - 10));
00305
00306 printf("Total free: %d KB\n", (free_normal + free_dma) << (PAGE_SHIFT - 10));
00307 }