1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
6 #include <linux/kernel.h>
8 #include <linux/memblock.h>
9 #ifdef CONFIG_BLK_DEV_INITRD
10 #include <linux/initrd.h>
12 #include <linux/of_fdt.h>
13 #include <linux/swap.h>
14 #include <linux/module.h>
15 #include <linux/highmem.h>
17 #include <asm/sections.h>
18 #include <asm/setup.h>
19 #include <asm/arcregs.h>
21 pgd_t swapper_pg_dir
[PTRS_PER_PGD
] __aligned(PAGE_SIZE
);
22 char empty_zero_page
[PAGE_SIZE
] __aligned(PAGE_SIZE
);
23 EXPORT_SYMBOL(empty_zero_page
);
25 static const unsigned long low_mem_start
= CONFIG_LINUX_RAM_BASE
;
26 static unsigned long low_mem_sz
;
29 static unsigned long min_high_pfn
, max_high_pfn
;
30 static phys_addr_t high_mem_start
;
31 static phys_addr_t high_mem_sz
;
32 unsigned long arch_pfn_offset
;
33 EXPORT_SYMBOL(arch_pfn_offset
);
36 long __init
arc_get_mem_sz(void)
41 /* User can over-ride above with "mem=nnn[KkMm]" in cmdline */
42 static int __init
setup_mem_sz(char *str
)
44 low_mem_sz
= memparse(str
, NULL
) & PAGE_MASK
;
46 /* early console might not be setup yet - it will show up later */
47 pr_info("\"mem=%s\": mem sz set to %ldM\n", str
, TO_MB(low_mem_sz
));
51 early_param("mem", setup_mem_sz
);
53 void __init
early_init_dt_add_memory_arch(u64 base
, u64 size
)
58 if (base
!= low_mem_start
)
59 panic("CONFIG_LINUX_RAM_BASE != DT memory { }");
63 memblock_add_node(base
, size
, 0, MEMBLOCK_NONE
);
66 high_mem_start
= base
;
69 memblock_add_node(base
, size
, 1, MEMBLOCK_NONE
);
70 memblock_reserve(base
, size
);
74 pr_info("Memory @ %llx [%lldM] %s\n",
75 base
, TO_MB(size
), !in_use
? "Not used":"");
79 * First memory setup routine called from setup_arch()
80 * 1. setup swapper's mm @init_mm
81 * 2. Count the pages we have and setup bootmem allocator
84 void __init
setup_arch_memory(void)
86 unsigned long max_zone_pfn
[MAX_NR_ZONES
] = { 0 };
88 setup_initial_init_mm(_text
, _etext
, _edata
, _end
);
90 /* first page of system - kernel .vector starts here */
91 min_low_pfn
= virt_to_pfn((void *)CONFIG_LINUX_RAM_BASE
);
93 /* Last usable page of low mem */
94 max_low_pfn
= max_pfn
= PFN_DOWN(low_mem_start
+ low_mem_sz
);
96 /*------------- bootmem allocator setup -----------------------*/
99 * seed the bootmem allocator after any DT memory node parsing or
100 * "mem=xxx" cmdline overrides have potentially updated @arc_mem_sz
102 * Only low mem is added, otherwise we have crashes when allocating
103 * mem_map[] itself. NO_BOOTMEM allocates mem_map[] at the end of
104 * avail memory, ending in highmem with a > 32-bit address. However
105 * it then tries to memset it with a truncaed 32-bit handle, causing
109 memblock_reserve(CONFIG_LINUX_LINK_BASE
,
110 __pa(_end
) - CONFIG_LINUX_LINK_BASE
);
112 #ifdef CONFIG_BLK_DEV_INITRD
113 if (phys_initrd_size
) {
114 memblock_reserve(phys_initrd_start
, phys_initrd_size
);
115 initrd_start
= (unsigned long)__va(phys_initrd_start
);
116 initrd_end
= initrd_start
+ phys_initrd_size
;
120 early_init_fdt_reserve_self();
121 early_init_fdt_scan_reserved_mem();
125 /*----------------- node/zones setup --------------------------*/
126 max_zone_pfn
[ZONE_NORMAL
] = max_low_pfn
;
128 #ifdef CONFIG_HIGHMEM
130 * On ARC (w/o PAE) HIGHMEM addresses are actually smaller (0 based)
131 * than addresses in normal aka low memory (0x8000_0000 based).
132 * Even with PAE, the huge peripheral space hole would waste a lot of
133 * mem with single contiguous mem_map[].
134 * Thus when HIGHMEM on ARC is enabled the memory map corresponding
135 * to the hole is freed and ARC specific version of pfn_valid()
136 * handles the hole in the memory map.
139 min_high_pfn
= PFN_DOWN(high_mem_start
);
140 max_high_pfn
= PFN_DOWN(high_mem_start
+ high_mem_sz
);
143 * max_high_pfn should be ok here for both HIGHMEM and HIGHMEM+PAE.
144 * For HIGHMEM without PAE max_high_pfn should be less than
145 * min_low_pfn to guarantee that these two regions don't overlap.
146 * For PAE case highmem is greater than lowmem, so it is natural
147 * to use max_high_pfn.
149 * In both cases, holes should be handled by pfn_valid().
151 max_zone_pfn
[ZONE_HIGHMEM
] = max_high_pfn
;
153 high_memory
= (void *)(min_high_pfn
<< PAGE_SHIFT
);
155 arch_pfn_offset
= min(min_low_pfn
, min_high_pfn
);
158 #else /* CONFIG_HIGHMEM */
159 /* pfn_valid() uses this when FLATMEM=y and HIGHMEM=n */
160 max_mapnr
= max_low_pfn
- min_low_pfn
;
162 #endif /* CONFIG_HIGHMEM */
164 free_area_init(max_zone_pfn
);
167 static void __init
highmem_init(void)
169 #ifdef CONFIG_HIGHMEM
172 memblock_phys_free(high_mem_start
, high_mem_sz
);
173 for (tmp
= min_high_pfn
; tmp
< max_high_pfn
; tmp
++)
174 free_highmem_page(pfn_to_page(tmp
));
179 * mem_init - initializes memory
182 * Calculates and displays memory available/used
184 void __init
mem_init(void)
189 BUILD_BUG_ON((PTRS_PER_PGD
* sizeof(pgd_t
)) > PAGE_SIZE
);
190 BUILD_BUG_ON((PTRS_PER_PUD
* sizeof(pud_t
)) > PAGE_SIZE
);
191 BUILD_BUG_ON((PTRS_PER_PMD
* sizeof(pmd_t
)) > PAGE_SIZE
);
192 BUILD_BUG_ON((PTRS_PER_PTE
* sizeof(pte_t
)) > PAGE_SIZE
);
195 #ifdef CONFIG_HIGHMEM
196 int pfn_valid(unsigned long pfn
)
198 return (pfn
>= min_high_pfn
&& pfn
<= max_high_pfn
) ||
199 (pfn
>= min_low_pfn
&& pfn
<= max_low_pfn
);
201 EXPORT_SYMBOL(pfn_valid
);