1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * arch/xtensa/mm/init.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Derived from MIPS, PPC.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
7*4882a593Smuzhiyun * License. See the file "COPYING" in the main directory of this archive
8*4882a593Smuzhiyun * for more details.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Copyright (C) 2001 - 2005 Tensilica Inc.
11*4882a593Smuzhiyun * Copyright (C) 2014 - 2016 Cadence Design Systems Inc.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * Chris Zankel <chris@zankel.net>
14*4882a593Smuzhiyun * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
15*4882a593Smuzhiyun * Marc Gauthier
16*4882a593Smuzhiyun * Kevin Chea
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <linux/kernel.h>
20*4882a593Smuzhiyun #include <linux/errno.h>
21*4882a593Smuzhiyun #include <linux/memblock.h>
22*4882a593Smuzhiyun #include <linux/gfp.h>
23*4882a593Smuzhiyun #include <linux/highmem.h>
24*4882a593Smuzhiyun #include <linux/swap.h>
25*4882a593Smuzhiyun #include <linux/mman.h>
26*4882a593Smuzhiyun #include <linux/nodemask.h>
27*4882a593Smuzhiyun #include <linux/mm.h>
28*4882a593Smuzhiyun #include <linux/of_fdt.h>
29*4882a593Smuzhiyun #include <linux/dma-map-ops.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <asm/bootparam.h>
32*4882a593Smuzhiyun #include <asm/page.h>
33*4882a593Smuzhiyun #include <asm/sections.h>
34*4882a593Smuzhiyun #include <asm/sysmem.h>
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /*
37*4882a593Smuzhiyun * Initialize the bootmem system and give it all low memory we have available.
38*4882a593Smuzhiyun */
39*4882a593Smuzhiyun
bootmem_init(void)40*4882a593Smuzhiyun void __init bootmem_init(void)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun /* Reserve all memory below PHYS_OFFSET, as memory
43*4882a593Smuzhiyun * accounting doesn't work for pages below that address.
44*4882a593Smuzhiyun *
45*4882a593Smuzhiyun * If PHYS_OFFSET is zero reserve page at address 0:
46*4882a593Smuzhiyun * successfull allocations should never return NULL.
47*4882a593Smuzhiyun */
48*4882a593Smuzhiyun memblock_reserve(0, PHYS_OFFSET ? PHYS_OFFSET : 1);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun early_init_fdt_scan_reserved_mem();
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun if (!memblock_phys_mem_size())
53*4882a593Smuzhiyun panic("No memory found!\n");
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun min_low_pfn = PFN_UP(memblock_start_of_DRAM());
56*4882a593Smuzhiyun min_low_pfn = max(min_low_pfn, PFN_UP(PHYS_OFFSET));
57*4882a593Smuzhiyun max_pfn = PFN_DOWN(memblock_end_of_DRAM());
58*4882a593Smuzhiyun max_low_pfn = min(max_pfn, MAX_LOW_PFN);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun early_memtest((phys_addr_t)min_low_pfn << PAGE_SHIFT,
61*4882a593Smuzhiyun (phys_addr_t)max_low_pfn << PAGE_SHIFT);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun memblock_set_current_limit(PFN_PHYS(max_low_pfn));
64*4882a593Smuzhiyun dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun memblock_dump_all();
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun
zones_init(void)70*4882a593Smuzhiyun void __init zones_init(void)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun /* All pages are DMA-able, so we put them all in the DMA zone. */
73*4882a593Smuzhiyun unsigned long max_zone_pfn[MAX_NR_ZONES] = {
74*4882a593Smuzhiyun [ZONE_NORMAL] = max_low_pfn,
75*4882a593Smuzhiyun #ifdef CONFIG_HIGHMEM
76*4882a593Smuzhiyun [ZONE_HIGHMEM] = max_pfn,
77*4882a593Smuzhiyun #endif
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun free_area_init(max_zone_pfn);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
free_highpages(void)82*4882a593Smuzhiyun static void __init free_highpages(void)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun #ifdef CONFIG_HIGHMEM
85*4882a593Smuzhiyun unsigned long max_low = max_low_pfn;
86*4882a593Smuzhiyun phys_addr_t range_start, range_end;
87*4882a593Smuzhiyun u64 i;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* set highmem page free */
90*4882a593Smuzhiyun for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE,
91*4882a593Smuzhiyun &range_start, &range_end, NULL) {
92*4882a593Smuzhiyun unsigned long start = PFN_UP(range_start);
93*4882a593Smuzhiyun unsigned long end = PFN_DOWN(range_end);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* Ignore complete lowmem entries */
96*4882a593Smuzhiyun if (end <= max_low)
97*4882a593Smuzhiyun continue;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* Truncate partial highmem entries */
100*4882a593Smuzhiyun if (start < max_low)
101*4882a593Smuzhiyun start = max_low;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun for (; start < end; start++)
104*4882a593Smuzhiyun free_highmem_page(pfn_to_page(start));
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun #endif
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /*
110*4882a593Smuzhiyun * Initialize memory pages.
111*4882a593Smuzhiyun */
112*4882a593Smuzhiyun
mem_init(void)113*4882a593Smuzhiyun void __init mem_init(void)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun free_highpages();
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun max_mapnr = max_pfn - ARCH_PFN_OFFSET;
118*4882a593Smuzhiyun high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun memblock_free_all();
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun mem_init_print_info(NULL);
123*4882a593Smuzhiyun pr_info("virtual kernel memory layout:\n"
124*4882a593Smuzhiyun #ifdef CONFIG_KASAN
125*4882a593Smuzhiyun " kasan : 0x%08lx - 0x%08lx (%5lu MB)\n"
126*4882a593Smuzhiyun #endif
127*4882a593Smuzhiyun #ifdef CONFIG_MMU
128*4882a593Smuzhiyun " vmalloc : 0x%08lx - 0x%08lx (%5lu MB)\n"
129*4882a593Smuzhiyun #endif
130*4882a593Smuzhiyun #ifdef CONFIG_HIGHMEM
131*4882a593Smuzhiyun " pkmap : 0x%08lx - 0x%08lx (%5lu kB)\n"
132*4882a593Smuzhiyun " fixmap : 0x%08lx - 0x%08lx (%5lu kB)\n"
133*4882a593Smuzhiyun #endif
134*4882a593Smuzhiyun " lowmem : 0x%08lx - 0x%08lx (%5lu MB)\n"
135*4882a593Smuzhiyun " .text : 0x%08lx - 0x%08lx (%5lu kB)\n"
136*4882a593Smuzhiyun " .rodata : 0x%08lx - 0x%08lx (%5lu kB)\n"
137*4882a593Smuzhiyun " .data : 0x%08lx - 0x%08lx (%5lu kB)\n"
138*4882a593Smuzhiyun " .init : 0x%08lx - 0x%08lx (%5lu kB)\n"
139*4882a593Smuzhiyun " .bss : 0x%08lx - 0x%08lx (%5lu kB)\n",
140*4882a593Smuzhiyun #ifdef CONFIG_KASAN
141*4882a593Smuzhiyun KASAN_SHADOW_START, KASAN_SHADOW_START + KASAN_SHADOW_SIZE,
142*4882a593Smuzhiyun KASAN_SHADOW_SIZE >> 20,
143*4882a593Smuzhiyun #endif
144*4882a593Smuzhiyun #ifdef CONFIG_MMU
145*4882a593Smuzhiyun VMALLOC_START, VMALLOC_END,
146*4882a593Smuzhiyun (VMALLOC_END - VMALLOC_START) >> 20,
147*4882a593Smuzhiyun #ifdef CONFIG_HIGHMEM
148*4882a593Smuzhiyun PKMAP_BASE, PKMAP_BASE + LAST_PKMAP * PAGE_SIZE,
149*4882a593Smuzhiyun (LAST_PKMAP*PAGE_SIZE) >> 10,
150*4882a593Smuzhiyun FIXADDR_START, FIXADDR_TOP,
151*4882a593Smuzhiyun (FIXADDR_TOP - FIXADDR_START) >> 10,
152*4882a593Smuzhiyun #endif
153*4882a593Smuzhiyun PAGE_OFFSET, PAGE_OFFSET +
154*4882a593Smuzhiyun (max_low_pfn - min_low_pfn) * PAGE_SIZE,
155*4882a593Smuzhiyun #else
156*4882a593Smuzhiyun min_low_pfn * PAGE_SIZE, max_low_pfn * PAGE_SIZE,
157*4882a593Smuzhiyun #endif
158*4882a593Smuzhiyun ((max_low_pfn - min_low_pfn) * PAGE_SIZE) >> 20,
159*4882a593Smuzhiyun (unsigned long)_text, (unsigned long)_etext,
160*4882a593Smuzhiyun (unsigned long)(_etext - _text) >> 10,
161*4882a593Smuzhiyun (unsigned long)__start_rodata, (unsigned long)__end_rodata,
162*4882a593Smuzhiyun (unsigned long)(__end_rodata - __start_rodata) >> 10,
163*4882a593Smuzhiyun (unsigned long)_sdata, (unsigned long)_edata,
164*4882a593Smuzhiyun (unsigned long)(_edata - _sdata) >> 10,
165*4882a593Smuzhiyun (unsigned long)__init_begin, (unsigned long)__init_end,
166*4882a593Smuzhiyun (unsigned long)(__init_end - __init_begin) >> 10,
167*4882a593Smuzhiyun (unsigned long)__bss_start, (unsigned long)__bss_stop,
168*4882a593Smuzhiyun (unsigned long)(__bss_stop - __bss_start) >> 10);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
parse_memmap_one(char * p)171*4882a593Smuzhiyun static void __init parse_memmap_one(char *p)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun char *oldp;
174*4882a593Smuzhiyun unsigned long start_at, mem_size;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun if (!p)
177*4882a593Smuzhiyun return;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun oldp = p;
180*4882a593Smuzhiyun mem_size = memparse(p, &p);
181*4882a593Smuzhiyun if (p == oldp)
182*4882a593Smuzhiyun return;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun switch (*p) {
185*4882a593Smuzhiyun case '@':
186*4882a593Smuzhiyun start_at = memparse(p + 1, &p);
187*4882a593Smuzhiyun memblock_add(start_at, mem_size);
188*4882a593Smuzhiyun break;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun case '$':
191*4882a593Smuzhiyun start_at = memparse(p + 1, &p);
192*4882a593Smuzhiyun memblock_reserve(start_at, mem_size);
193*4882a593Smuzhiyun break;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun case 0:
196*4882a593Smuzhiyun memblock_reserve(mem_size, -mem_size);
197*4882a593Smuzhiyun break;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun default:
200*4882a593Smuzhiyun pr_warn("Unrecognized memmap syntax: %s\n", p);
201*4882a593Smuzhiyun break;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
parse_memmap_opt(char * str)205*4882a593Smuzhiyun static int __init parse_memmap_opt(char *str)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun while (str) {
208*4882a593Smuzhiyun char *k = strchr(str, ',');
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (k)
211*4882a593Smuzhiyun *k++ = 0;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun parse_memmap_one(str);
214*4882a593Smuzhiyun str = k;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun early_param("memmap", parse_memmap_opt);
220