.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License version 2 as |
---|
6 | | - * published by the Free Software Foundation. |
---|
7 | 4 | */ |
---|
8 | 5 | |
---|
9 | 6 | #include <linux/kernel.h> |
---|
10 | 7 | #include <linux/mm.h> |
---|
11 | | -#include <linux/bootmem.h> |
---|
12 | 8 | #include <linux/memblock.h> |
---|
13 | 9 | #ifdef CONFIG_BLK_DEV_INITRD |
---|
14 | 10 | #include <linux/initrd.h> |
---|
.. | .. |
---|
18 | 14 | #include <linux/module.h> |
---|
19 | 15 | #include <linux/highmem.h> |
---|
20 | 16 | #include <asm/page.h> |
---|
21 | | -#include <asm/pgalloc.h> |
---|
22 | 17 | #include <asm/sections.h> |
---|
23 | 18 | #include <asm/arcregs.h> |
---|
24 | 19 | |
---|
.. | .. |
---|
31 | 26 | |
---|
32 | 27 | #ifdef CONFIG_HIGHMEM |
---|
33 | 28 | static unsigned long min_high_pfn, max_high_pfn; |
---|
34 | | -static u64 high_mem_start; |
---|
35 | | -static u64 high_mem_sz; |
---|
| 29 | +static phys_addr_t high_mem_start; |
---|
| 30 | +static phys_addr_t high_mem_sz; |
---|
36 | 31 | #endif |
---|
37 | 32 | |
---|
38 | 33 | #ifdef CONFIG_DISCONTIGMEM |
---|
.. | .. |
---|
67 | 62 | |
---|
68 | 63 | low_mem_sz = size; |
---|
69 | 64 | in_use = 1; |
---|
| 65 | + memblock_add_node(base, size, 0); |
---|
70 | 66 | } else { |
---|
71 | 67 | #ifdef CONFIG_HIGHMEM |
---|
72 | 68 | high_mem_start = base; |
---|
73 | 69 | high_mem_sz = size; |
---|
74 | 70 | in_use = 1; |
---|
| 71 | + memblock_add_node(base, size, 1); |
---|
| 72 | + memblock_reserve(base, size); |
---|
75 | 73 | #endif |
---|
76 | 74 | } |
---|
77 | 75 | |
---|
.. | .. |
---|
79 | 77 | base, TO_MB(size), !in_use ? "Not used":""); |
---|
80 | 78 | } |
---|
81 | 79 | |
---|
82 | | -#ifdef CONFIG_BLK_DEV_INITRD |
---|
83 | | -static int __init early_initrd(char *p) |
---|
| 80 | +bool arch_has_descending_max_zone_pfns(void) |
---|
84 | 81 | { |
---|
85 | | - unsigned long start, size; |
---|
86 | | - char *endp; |
---|
87 | | - |
---|
88 | | - start = memparse(p, &endp); |
---|
89 | | - if (*endp == ',') { |
---|
90 | | - size = memparse(endp + 1, NULL); |
---|
91 | | - |
---|
92 | | - initrd_start = (unsigned long)__va(start); |
---|
93 | | - initrd_end = (unsigned long)__va(start + size); |
---|
94 | | - } |
---|
95 | | - return 0; |
---|
| 82 | + return !IS_ENABLED(CONFIG_ARC_HAS_PAE40); |
---|
96 | 83 | } |
---|
97 | | -early_param("initrd", early_initrd); |
---|
98 | | -#endif |
---|
99 | 84 | |
---|
100 | 85 | /* |
---|
101 | 86 | * First memory setup routine called from setup_arch() |
---|
.. | .. |
---|
105 | 90 | */ |
---|
106 | 91 | void __init setup_arch_memory(void) |
---|
107 | 92 | { |
---|
108 | | - unsigned long zones_size[MAX_NR_ZONES]; |
---|
109 | | - unsigned long zones_holes[MAX_NR_ZONES]; |
---|
| 93 | + unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 }; |
---|
110 | 94 | |
---|
111 | 95 | init_mm.start_code = (unsigned long)_text; |
---|
112 | 96 | init_mm.end_code = (unsigned long)_etext; |
---|
.. | .. |
---|
137 | 121 | * the crash |
---|
138 | 122 | */ |
---|
139 | 123 | |
---|
140 | | - memblock_add_node(low_mem_start, low_mem_sz, 0); |
---|
141 | 124 | memblock_reserve(CONFIG_LINUX_LINK_BASE, |
---|
142 | 125 | __pa(_end) - CONFIG_LINUX_LINK_BASE); |
---|
143 | 126 | |
---|
144 | 127 | #ifdef CONFIG_BLK_DEV_INITRD |
---|
145 | | - if (initrd_start) |
---|
146 | | - memblock_reserve(__pa(initrd_start), initrd_end - initrd_start); |
---|
| 128 | + if (phys_initrd_size) { |
---|
| 129 | + memblock_reserve(phys_initrd_start, phys_initrd_size); |
---|
| 130 | + initrd_start = (unsigned long)__va(phys_initrd_start); |
---|
| 131 | + initrd_end = initrd_start + phys_initrd_size; |
---|
| 132 | + } |
---|
147 | 133 | #endif |
---|
148 | 134 | |
---|
149 | 135 | early_init_fdt_reserve_self(); |
---|
.. | .. |
---|
152 | 138 | memblock_dump_all(); |
---|
153 | 139 | |
---|
154 | 140 | /*----------------- node/zones setup --------------------------*/ |
---|
155 | | - memset(zones_size, 0, sizeof(zones_size)); |
---|
156 | | - memset(zones_holes, 0, sizeof(zones_holes)); |
---|
157 | | - |
---|
158 | | - zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn; |
---|
159 | | - zones_holes[ZONE_NORMAL] = 0; |
---|
160 | | - |
---|
161 | | - /* |
---|
162 | | - * We can't use the helper free_area_init(zones[]) because it uses |
---|
163 | | - * PAGE_OFFSET to compute the @min_low_pfn which would be wrong |
---|
164 | | - * when our kernel doesn't start at PAGE_OFFSET, i.e. |
---|
165 | | - * PAGE_OFFSET != CONFIG_LINUX_RAM_BASE |
---|
166 | | - */ |
---|
167 | | - free_area_init_node(0, /* node-id */ |
---|
168 | | - zones_size, /* num pages per zone */ |
---|
169 | | - min_low_pfn, /* first pfn of node */ |
---|
170 | | - zones_holes); /* holes */ |
---|
| 141 | + max_zone_pfn[ZONE_NORMAL] = max_low_pfn; |
---|
171 | 142 | |
---|
172 | 143 | #ifdef CONFIG_HIGHMEM |
---|
173 | 144 | /* |
---|
.. | .. |
---|
187 | 158 | min_high_pfn = PFN_DOWN(high_mem_start); |
---|
188 | 159 | max_high_pfn = PFN_DOWN(high_mem_start + high_mem_sz); |
---|
189 | 160 | |
---|
190 | | - zones_size[ZONE_NORMAL] = 0; |
---|
191 | | - zones_holes[ZONE_NORMAL] = 0; |
---|
192 | | - |
---|
193 | | - zones_size[ZONE_HIGHMEM] = max_high_pfn - min_high_pfn; |
---|
194 | | - zones_holes[ZONE_HIGHMEM] = 0; |
---|
195 | | - |
---|
196 | | - free_area_init_node(1, /* node-id */ |
---|
197 | | - zones_size, /* num pages per zone */ |
---|
198 | | - min_high_pfn, /* first pfn of node */ |
---|
199 | | - zones_holes); /* holes */ |
---|
| 161 | + /* |
---|
| 162 | + * max_high_pfn should be ok here for both HIGHMEM and HIGHMEM+PAE. |
---|
| 163 | + * For HIGHMEM without PAE max_high_pfn should be less than |
---|
| 164 | + * min_low_pfn to guarantee that these two regions don't overlap. |
---|
| 165 | + * For PAE case highmem is greater than lowmem, so it is natural |
---|
| 166 | + * to use max_high_pfn. |
---|
| 167 | + * |
---|
| 168 | + * In both cases, holes should be handled by pfn_valid(). |
---|
| 169 | + */ |
---|
| 170 | + max_zone_pfn[ZONE_HIGHMEM] = max_high_pfn; |
---|
200 | 171 | |
---|
201 | 172 | high_memory = (void *)(min_high_pfn << PAGE_SHIFT); |
---|
202 | 173 | kmap_init(); |
---|
| 174 | +#endif |
---|
| 175 | + |
---|
| 176 | + free_area_init(max_zone_pfn); |
---|
| 177 | +} |
---|
| 178 | + |
---|
| 179 | +static void __init highmem_init(void) |
---|
| 180 | +{ |
---|
| 181 | +#ifdef CONFIG_HIGHMEM |
---|
| 182 | + unsigned long tmp; |
---|
| 183 | + |
---|
| 184 | + memblock_free(high_mem_start, high_mem_sz); |
---|
| 185 | + for (tmp = min_high_pfn; tmp < max_high_pfn; tmp++) |
---|
| 186 | + free_highmem_page(pfn_to_page(tmp)); |
---|
203 | 187 | #endif |
---|
204 | 188 | } |
---|
205 | 189 | |
---|
.. | .. |
---|
211 | 195 | */ |
---|
212 | 196 | void __init mem_init(void) |
---|
213 | 197 | { |
---|
214 | | -#ifdef CONFIG_HIGHMEM |
---|
215 | | - unsigned long tmp; |
---|
216 | | - |
---|
217 | | - reset_all_zones_managed_pages(); |
---|
218 | | - for (tmp = min_high_pfn; tmp < max_high_pfn; tmp++) |
---|
219 | | - free_highmem_page(pfn_to_page(tmp)); |
---|
220 | | -#endif |
---|
221 | | - |
---|
222 | | - free_all_bootmem(); |
---|
| 198 | + memblock_free_all(); |
---|
| 199 | + highmem_init(); |
---|
223 | 200 | mem_init_print_info(NULL); |
---|
224 | 201 | } |
---|
225 | | - |
---|
226 | | -/* |
---|
227 | | - * free_initmem: Free all the __init memory. |
---|
228 | | - */ |
---|
229 | | -void __ref free_initmem(void) |
---|
230 | | -{ |
---|
231 | | - free_initmem_default(-1); |
---|
232 | | -} |
---|
233 | | - |
---|
234 | | -#ifdef CONFIG_BLK_DEV_INITRD |
---|
235 | | -void __init free_initrd_mem(unsigned long start, unsigned long end) |
---|
236 | | -{ |
---|
237 | | - free_reserved_area((void *)start, (void *)end, -1, "initrd"); |
---|
238 | | -} |
---|
239 | | -#endif |
---|