|
@@ -289,3 +289,187 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
|
|
arm_adjust_dma_zone(zone_size, zhole_size,
|
|
arm_adjust_dma_zone(zone_size, zhole_size,
|
|
arm_dma_zone_size >> PAGE_SHIFT);
|
|
arm_dma_zone_size >> PAGE_SHIFT);
|
|
#endif
|
|
#endif
|
|
|
|
+
|
|
|
|
+ free_area_init_node(0, zone_size, min, zhole_size);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_HAVE_ARCH_PFN_VALID
|
|
|
|
+int pfn_valid(unsigned long pfn)
|
|
|
|
+{
|
|
|
|
+ return memblock_is_memory(__pfn_to_phys(pfn));
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(pfn_valid);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#ifndef CONFIG_SPARSEMEM
|
|
|
|
+static void __init arm_memory_present(void)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+#else
|
|
|
|
+static void __init arm_memory_present(void)
|
|
|
|
+{
|
|
|
|
+ struct memblock_region *reg;
|
|
|
|
+
|
|
|
|
+ for_each_memblock(memory, reg)
|
|
|
|
+ memory_present(0, memblock_region_memory_base_pfn(reg),
|
|
|
|
+ memblock_region_memory_end_pfn(reg));
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+static bool arm_memblock_steal_permitted = true;
|
|
|
|
+
|
|
|
|
+phys_addr_t __init arm_memblock_steal(phys_addr_t size, phys_addr_t align)
|
|
|
|
+{
|
|
|
|
+ phys_addr_t phys;
|
|
|
|
+
|
|
|
|
+ BUG_ON(!arm_memblock_steal_permitted);
|
|
|
|
+
|
|
|
|
+ phys = memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ANYWHERE);
|
|
|
|
+ memblock_free(phys, size);
|
|
|
|
+ memblock_remove(phys, size);
|
|
|
|
+
|
|
|
|
+ return phys;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < mi->nr_banks; i++)
|
|
|
|
+ memblock_add(mi->bank[i].start, mi->bank[i].size);
|
|
|
|
+
|
|
|
|
+ /* Register the kernel text, kernel data and initrd with memblock. */
|
|
|
|
+#ifdef CONFIG_XIP_KERNEL
|
|
|
|
+ memblock_reserve(__pa(_sdata), _end - _sdata);
|
|
|
|
+#else
|
|
|
|
+ memblock_reserve(__pa(_stext), _end - _stext);
|
|
|
|
+#endif
|
|
|
|
+#ifdef CONFIG_BLK_DEV_INITRD
|
|
|
|
+ if (phys_initrd_size &&
|
|
|
|
+ !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
|
|
|
|
+ pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd\n",
|
|
|
|
+ phys_initrd_start, phys_initrd_size);
|
|
|
|
+ phys_initrd_start = phys_initrd_size = 0;
|
|
|
|
+ }
|
|
|
|
+ if (phys_initrd_size &&
|
|
|
|
+ memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
|
|
|
|
+ pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
|
|
|
|
+ phys_initrd_start, phys_initrd_size);
|
|
|
|
+ phys_initrd_start = phys_initrd_size = 0;
|
|
|
|
+ }
|
|
|
|
+ if (phys_initrd_size) {
|
|
|
|
+ memblock_reserve(phys_initrd_start, phys_initrd_size);
|
|
|
|
+
|
|
|
|
+ /* Now convert initrd to virtual addresses */
|
|
|
|
+ initrd_start = __phys_to_virt(phys_initrd_start);
|
|
|
|
+ initrd_end = initrd_start + phys_initrd_size;
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ arm_mm_memblock_reserve();
|
|
|
|
+ arm_dt_memblock_reserve();
|
|
|
|
+
|
|
|
|
+ /* reserve any platform specific memblock areas */
|
|
|
|
+ if (mdesc->reserve)
|
|
|
|
+ mdesc->reserve();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * reserve memory for DMA contigouos allocations,
|
|
|
|
+ * must come from DMA area inside low memory
|
|
|
|
+ */
|
|
|
|
+ dma_contiguous_reserve(min(arm_dma_limit, arm_lowmem_limit));
|
|
|
|
+
|
|
|
|
+ arm_memblock_steal_permitted = false;
|
|
|
|
+ memblock_allow_resize();
|
|
|
|
+ memblock_dump_all();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void __init bootmem_init(void)
|
|
|
|
+{
|
|
|
|
+ unsigned long min, max_low, max_high;
|
|
|
|
+
|
|
|
|
+ max_low = max_high = 0;
|
|
|
|
+
|
|
|
|
+ find_limits(&min, &max_low, &max_high);
|
|
|
|
+
|
|
|
|
+ arm_bootmem_init(min, max_low);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Sparsemem tries to allocate bootmem in memory_present(),
|
|
|
|
+ * so must be done after the fixed reservations
|
|
|
|
+ */
|
|
|
|
+ arm_memory_present();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * sparse_init() needs the bootmem allocator up and running.
|
|
|
|
+ */
|
|
|
|
+ sparse_init();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Now free the memory - free_area_init_node needs
|
|
|
|
+ * the sparse mem_map arrays initialized by sparse_init()
|
|
|
|
+ * for memmap_init_zone(), otherwise all PFNs are invalid.
|
|
|
|
+ */
|
|
|
|
+ arm_bootmem_free(min, max_low, max_high);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * This doesn't seem to be used by the Linux memory manager any
|
|
|
|
+ * more, but is used by ll_rw_block. If we can get rid of it, we
|
|
|
|
+ * also get rid of some of the stuff above as well.
|
|
|
|
+ *
|
|
|
|
+ * Note: max_low_pfn and max_pfn reflect the number of _pages_ in
|
|
|
|
+ * the system, not the maximum PFN.
|
|
|
|
+ */
|
|
|
|
+ max_low_pfn = max_low - PHYS_PFN_OFFSET;
|
|
|
|
+ max_pfn = max_high - PHYS_PFN_OFFSET;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline int free_area(unsigned long pfn, unsigned long end, char *s)
|
|
|
|
+{
|
|
|
|
+ unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
|
|
|
|
+
|
|
|
|
+ for (; pfn < end; pfn++) {
|
|
|
|
+ struct page *page = pfn_to_page(pfn);
|
|
|
|
+ ClearPageReserved(page);
|
|
|
|
+ init_page_count(page);
|
|
|
|
+ __free_page(page);
|
|
|
|
+ pages++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (size && s)
|
|
|
|
+ printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
|
|
|
|
+
|
|
|
|
+ return pages;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Poison init memory with an undefined instruction (ARM) or a branch to an
|
|
|
|
+ * undefined instruction (Thumb).
|
|
|
|
+ */
|
|
|
|
+static inline void poison_init_mem(void *s, size_t count)
|
|
|
|
+{
|
|
|
|
+ u32 *p = (u32 *)s;
|
|
|
|
+ for (; count != 0; count -= 4)
|
|
|
|
+ *p++ = 0xe7fddef0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void
|
|
|
|
+free_memmap(unsigned long start_pfn, unsigned long end_pfn)
|
|
|
|
+{
|
|
|
|
+ struct page *start_pg, *end_pg;
|
|
|
|
+ unsigned long pg, pgend;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Convert start_pfn/end_pfn to a struct page pointer.
|
|
|
|
+ */
|
|
|
|
+ start_pg = pfn_to_page(start_pfn - 1) + 1;
|
|
|
|
+ end_pg = pfn_to_page(end_pfn - 1) + 1;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Convert to physical addresses, and
|
|
|
|
+ * round start upwards and end downwards.
|
|
|
|
+ */
|
|
|
|
+ pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
|
|
|
|
+ pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
|
|
|
|
+
|
|
|
|
+ /*
|