~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/xtensa/mm/init.c

Version: ~ [ linux-5.6-rc1 ] ~ [ linux-5.5.2 ] ~ [ linux-5.4.17 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.102 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.170 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.213 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.213 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * arch/xtensa/mm/init.c
  3  *
  4  * Derived from MIPS, PPC.
  5  *
  6  * This file is subject to the terms and conditions of the GNU General Public
  7  * License.  See the file "COPYING" in the main directory of this archive
  8  * for more details.
  9  *
 10  * Copyright (C) 2001 - 2005 Tensilica Inc.
 11  * Copyright (C) 2014 Cadence Design Systems Inc.
 12  *
 13  * Chris Zankel <chris@zankel.net>
 14  * Joe Taylor   <joe@tensilica.com, joetylr@yahoo.com>
 15  * Marc Gauthier
 16  * Kevin Chea
 17  */
 18 
 19 #include <linux/kernel.h>
 20 #include <linux/errno.h>
 21 #include <linux/bootmem.h>
 22 #include <linux/gfp.h>
 23 #include <linux/highmem.h>
 24 #include <linux/swap.h>
 25 #include <linux/mman.h>
 26 #include <linux/nodemask.h>
 27 #include <linux/mm.h>
 28 
 29 #include <asm/bootparam.h>
 30 #include <asm/page.h>
 31 #include <asm/sections.h>
 32 #include <asm/sysmem.h>
 33 
 34 struct sysmem_info sysmem __initdata;
 35 
 36 static void __init sysmem_dump(void)
 37 {
 38         unsigned i;
 39 
 40         pr_debug("Sysmem:\n");
 41         for (i = 0; i < sysmem.nr_banks; ++i)
 42                 pr_debug("  0x%08lx - 0x%08lx (%ldK)\n",
 43                          sysmem.bank[i].start, sysmem.bank[i].end,
 44                          (sysmem.bank[i].end - sysmem.bank[i].start) >> 10);
 45 }
 46 
 47 /*
 48  * Find bank with maximal .start such that bank.start <= start
 49  */
 50 static inline struct meminfo * __init find_bank(unsigned long start)
 51 {
 52         unsigned i;
 53         struct meminfo *it = NULL;
 54 
 55         for (i = 0; i < sysmem.nr_banks; ++i)
 56                 if (sysmem.bank[i].start <= start)
 57                         it = sysmem.bank + i;
 58                 else
 59                         break;
 60         return it;
 61 }
 62 
 63 /*
 64  * Move all memory banks starting at 'from' to a new place at 'to',
 65  * adjust nr_banks accordingly.
 66  * Both 'from' and 'to' must be inside the sysmem.bank.
 67  *
 68  * Returns: 0 (success), -ENOMEM (not enough space in the sysmem.bank).
 69  */
 70 static int __init move_banks(struct meminfo *to, struct meminfo *from)
 71 {
 72         unsigned n = sysmem.nr_banks - (from - sysmem.bank);
 73 
 74         if (to > from && to - from + sysmem.nr_banks > SYSMEM_BANKS_MAX)
 75                 return -ENOMEM;
 76         if (to != from)
 77                 memmove(to, from, n * sizeof(struct meminfo));
 78         sysmem.nr_banks += to - from;
 79         return 0;
 80 }
 81 
 82 /*
 83  * Add new bank to sysmem. Resulting sysmem is the union of bytes of the
 84  * original sysmem and the new bank.
 85  *
 86  * Returns: 0 (success), < 0 (error)
 87  */
 88 int __init add_sysmem_bank(unsigned long start, unsigned long end)
 89 {
 90         unsigned i;
 91         struct meminfo *it = NULL;
 92         unsigned long sz;
 93         unsigned long bank_sz = 0;
 94 
 95         if (start == end ||
 96             (start < end) != (PAGE_ALIGN(start) < (end & PAGE_MASK))) {
 97                 pr_warn("Ignoring small memory bank 0x%08lx size: %ld bytes\n",
 98                         start, end - start);
 99                 return -EINVAL;
100         }
101 
102         start = PAGE_ALIGN(start);
103         end &= PAGE_MASK;
104         sz = end - start;
105 
106         it = find_bank(start);
107 
108         if (it)
109                 bank_sz = it->end - it->start;
110 
111         if (it && bank_sz >= start - it->start) {
112                 if (end - it->start > bank_sz)
113                         it->end = end;
114                 else
115                         return 0;
116         } else {
117                 if (!it)
118                         it = sysmem.bank;
119                 else
120                         ++it;
121 
122                 if (it - sysmem.bank < sysmem.nr_banks &&
123                     it->start - start <= sz) {
124                         it->start = start;
125                         if (it->end - it->start < sz)
126                                 it->end = end;
127                         else
128                                 return 0;
129                 } else {
130                         if (move_banks(it + 1, it) < 0) {
131                                 pr_warn("Ignoring memory bank 0x%08lx size %ld bytes\n",
132                                         start, end - start);
133                                 return -EINVAL;
134                         }
135                         it->start = start;
136                         it->end = end;
137                         return 0;
138                 }
139         }
140         sz = it->end - it->start;
141         for (i = it + 1 - sysmem.bank; i < sysmem.nr_banks; ++i)
142                 if (sysmem.bank[i].start - it->start <= sz) {
143                         if (sz < sysmem.bank[i].end - it->start)
144                                 it->end = sysmem.bank[i].end;
145                 } else {
146                         break;
147                 }
148 
149         move_banks(it + 1, sysmem.bank + i);
150         return 0;
151 }
152 
153 /*
154  * mem_reserve(start, end, must_exist)
155  *
156  * Reserve some memory from the memory pool.
157  * If must_exist is set and a part of the region being reserved does not exist
158  * memory map is not altered.
159  *
160  * Parameters:
161  *  start       Start of region,
162  *  end         End of region,
163  *  must_exist  Must exist in memory pool.
164  *
165  * Returns:
166  *  0 (success)
167  *  < 0 (error)
168  */
169 
170 int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
171 {
172         struct meminfo *it;
173         struct meminfo *rm = NULL;
174         unsigned long sz;
175         unsigned long bank_sz = 0;
176 
177         start = start & PAGE_MASK;
178         end = PAGE_ALIGN(end);
179         sz = end - start;
180         if (!sz)
181                 return -EINVAL;
182 
183         it = find_bank(start);
184 
185         if (it)
186                 bank_sz = it->end - it->start;
187 
188         if ((!it || end - it->start > bank_sz) && must_exist) {
189                 pr_warn("mem_reserve: [0x%0lx, 0x%0lx) not in any region!\n",
190                         start, end);
191                 return -EINVAL;
192         }
193 
194         if (it && start - it->start <= bank_sz) {
195                 if (start == it->start) {
196                         if (end - it->start < bank_sz) {
197                                 it->start = end;
198                                 return 0;
199                         } else {
200                                 rm = it;
201                         }
202                 } else {
203                         it->end = start;
204                         if (end - it->start < bank_sz)
205                                 return add_sysmem_bank(end,
206                                                        it->start + bank_sz);
207                         ++it;
208                 }
209         }
210 
211         if (!it)
212                 it = sysmem.bank;
213 
214         for (; it < sysmem.bank + sysmem.nr_banks; ++it) {
215                 if (it->end - start <= sz) {
216                         if (!rm)
217                                 rm = it;
218                 } else {
219                         if (it->start - start < sz)
220                                 it->start = end;
221                         break;
222                 }
223         }
224 
225         if (rm)
226                 move_banks(rm, it);
227 
228         return 0;
229 }
230 
231 
232 /*
233  * Initialize the bootmem system and give it all low memory we have available.
234  */
235 
236 void __init bootmem_init(void)
237 {
238         unsigned long pfn;
239         unsigned long bootmap_start, bootmap_size;
240         int i;
241 
242         /* Reserve all memory below PLATFORM_DEFAULT_MEM_START, as memory
243          * accounting doesn't work for pages below that address.
244          *
245          * If PLATFORM_DEFAULT_MEM_START is zero reserve page at address 0:
246          * successfull allocations should never return NULL.
247          */
248         if (PLATFORM_DEFAULT_MEM_START)
249                 mem_reserve(0, PLATFORM_DEFAULT_MEM_START, 0);
250         else
251                 mem_reserve(0, 1, 0);
252 
253         sysmem_dump();
254         max_low_pfn = max_pfn = 0;
255         min_low_pfn = ~0;
256 
257         for (i=0; i < sysmem.nr_banks; i++) {
258                 pfn = PAGE_ALIGN(sysmem.bank[i].start) >> PAGE_SHIFT;
259                 if (pfn < min_low_pfn)
260                         min_low_pfn = pfn;
261                 pfn = PAGE_ALIGN(sysmem.bank[i].end - 1) >> PAGE_SHIFT;
262                 if (pfn > max_pfn)
263                         max_pfn = pfn;
264         }
265 
266         if (min_low_pfn > max_pfn)
267                 panic("No memory found!\n");
268 
269         max_low_pfn = max_pfn < MAX_MEM_PFN >> PAGE_SHIFT ?
270                 max_pfn : MAX_MEM_PFN >> PAGE_SHIFT;
271 
272         /* Find an area to use for the bootmem bitmap. */
273 
274         bootmap_size = bootmem_bootmap_pages(max_low_pfn - min_low_pfn);
275         bootmap_size <<= PAGE_SHIFT;
276         bootmap_start = ~0;
277 
278         for (i=0; i<sysmem.nr_banks; i++)
279                 if (sysmem.bank[i].end - sysmem.bank[i].start >= bootmap_size) {
280                         bootmap_start = sysmem.bank[i].start;
281                         break;
282                 }
283 
284         if (bootmap_start == ~0UL)
285                 panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
286 
287         /* Reserve the bootmem bitmap area */
288 
289         mem_reserve(bootmap_start, bootmap_start + bootmap_size, 1);
290         bootmap_size = init_bootmem_node(NODE_DATA(0),
291                                          bootmap_start >> PAGE_SHIFT,
292                                          min_low_pfn,
293                                          max_low_pfn);
294 
295         /* Add all remaining memory pieces into the bootmem map */
296 
297         for (i = 0; i < sysmem.nr_banks; i++) {
298                 if (sysmem.bank[i].start >> PAGE_SHIFT < max_low_pfn) {
299                         unsigned long end = min(max_low_pfn << PAGE_SHIFT,
300                                                 sysmem.bank[i].end);
301                         free_bootmem(sysmem.bank[i].start,
302                                      end - sysmem.bank[i].start);
303                 }
304         }
305 
306 }
307 
308 
309 void __init zones_init(void)
310 {
311         /* All pages are DMA-able, so we put them all in the DMA zone. */
312         unsigned long zones_size[MAX_NR_ZONES] = {
313                 [ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET,
314 #ifdef CONFIG_HIGHMEM
315                 [ZONE_HIGHMEM] = max_pfn - max_low_pfn,
316 #endif
317         };
318         free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL);
319 }
320 
321 /*
322  * Initialize memory pages.
323  */
324 
325 void __init mem_init(void)
326 {
327 #ifdef CONFIG_HIGHMEM
328         unsigned long tmp;
329 
330         reset_all_zones_managed_pages();
331         for (tmp = max_low_pfn; tmp < max_pfn; tmp++)
332                 free_highmem_page(pfn_to_page(tmp));
333 #endif
334 
335         max_mapnr = max_pfn - ARCH_PFN_OFFSET;
336         high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT);
337 
338         free_all_bootmem();
339 
340         mem_init_print_info(NULL);
341         pr_info("virtual kernel memory layout:\n"
342 #ifdef CONFIG_HIGHMEM
343                 "    pkmap   : 0x%08lx - 0x%08lx  (%5lu kB)\n"
344                 "    fixmap  : 0x%08lx - 0x%08lx  (%5lu kB)\n"
345 #endif
346 #ifdef CONFIG_MMU
347                 "    vmalloc : 0x%08x - 0x%08x  (%5u MB)\n"
348 #endif
349                 "    lowmem  : 0x%08lx - 0x%08lx  (%5lu MB)\n",
350 #ifdef CONFIG_HIGHMEM
351                 PKMAP_BASE, PKMAP_BASE + LAST_PKMAP * PAGE_SIZE,
352                 (LAST_PKMAP*PAGE_SIZE) >> 10,
353                 FIXADDR_START, FIXADDR_TOP,
354                 (FIXADDR_TOP - FIXADDR_START) >> 10,
355 #endif
356 #ifdef CONFIG_MMU
357                 VMALLOC_START, VMALLOC_END,
358                 (VMALLOC_END - VMALLOC_START) >> 20,
359                 PAGE_OFFSET, PAGE_OFFSET +
360                 (max_low_pfn - min_low_pfn) * PAGE_SIZE,
361 #else
362                 min_low_pfn * PAGE_SIZE, max_low_pfn * PAGE_SIZE,
363 #endif
364                 ((max_low_pfn - min_low_pfn) * PAGE_SIZE) >> 20);
365 }
366 
367 #ifdef CONFIG_BLK_DEV_INITRD
368 extern int initrd_is_mapped;
369 
370 void free_initrd_mem(unsigned long start, unsigned long end)
371 {
372         if (initrd_is_mapped)
373                 free_reserved_area((void *)start, (void *)end, -1, "initrd");
374 }
375 #endif
376 
377 void free_initmem(void)
378 {
379         free_initmem_default(-1);
380 }
381 
382 static void __init parse_memmap_one(char *p)
383 {
384         char *oldp;
385         unsigned long start_at, mem_size;
386 
387         if (!p)
388                 return;
389 
390         oldp = p;
391         mem_size = memparse(p, &p);
392         if (p == oldp)
393                 return;
394 
395         switch (*p) {
396         case '@':
397                 start_at = memparse(p + 1, &p);
398                 add_sysmem_bank(start_at, start_at + mem_size);
399                 break;
400 
401         case '$':
402                 start_at = memparse(p + 1, &p);
403                 mem_reserve(start_at, start_at + mem_size, 0);
404                 break;
405 
406         case 0:
407                 mem_reserve(mem_size, 0, 0);
408                 break;
409 
410         default:
411                 pr_warn("Unrecognized memmap syntax: %s\n", p);
412                 break;
413         }
414 }
415 
416 static int __init parse_memmap_opt(char *str)
417 {
418         while (str) {
419                 char *k = strchr(str, ',');
420 
421                 if (k)
422                         *k++ = 0;
423 
424                 parse_memmap_one(str);
425                 str = k;
426         }
427 
428         return 0;
429 }
430 early_param("memmap", parse_memmap_opt);
431 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp