xref: /openbmc/linux/arch/arc/mm/init.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c121c506SVineet Gupta /*
3c121c506SVineet Gupta  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
4c121c506SVineet Gupta  */
5c121c506SVineet Gupta 
6c121c506SVineet Gupta #include <linux/kernel.h>
7c121c506SVineet Gupta #include <linux/mm.h>
8c121c506SVineet Gupta #include <linux/memblock.h>
9d6579e99SNoam Camus #ifdef CONFIG_BLK_DEV_INITRD
10d6579e99SNoam Camus #include <linux/initrd.h>
11d6579e99SNoam Camus #endif
121b10cb21SAlexey Brodkin #include <linux/of_fdt.h>
13c121c506SVineet Gupta #include <linux/swap.h>
14c121c506SVineet Gupta #include <linux/module.h>
1529e33226SVineet Gupta #include <linux/highmem.h>
16c121c506SVineet Gupta #include <asm/page.h>
17c121c506SVineet Gupta #include <asm/sections.h>
18*4d369680SVineet Gupta #include <asm/setup.h>
19c121c506SVineet Gupta #include <asm/arcregs.h>
20c121c506SVineet Gupta 
21c121c506SVineet Gupta pgd_t swapper_pg_dir[PTRS_PER_PGD] __aligned(PAGE_SIZE);
22c121c506SVineet Gupta char empty_zero_page[PAGE_SIZE] __aligned(PAGE_SIZE);
23c121c506SVineet Gupta EXPORT_SYMBOL(empty_zero_page);
24c121c506SVineet Gupta 
259ed68785SEugeniy Paltsev static const unsigned long low_mem_start = CONFIG_LINUX_RAM_BASE;
266101be5aSVineet Gupta static unsigned long low_mem_sz;
27c121c506SVineet Gupta 
2829e33226SVineet Gupta #ifdef CONFIG_HIGHMEM
2926f9d5fdSVineet Gupta static unsigned long min_high_pfn, max_high_pfn;
304af22dedSMike Rapoport static phys_addr_t high_mem_start;
314af22dedSMike Rapoport static phys_addr_t high_mem_sz;
32050b2da2SMike Rapoport unsigned long arch_pfn_offset;
33050b2da2SMike Rapoport EXPORT_SYMBOL(arch_pfn_offset);
3429e33226SVineet Gupta #endif
3529e33226SVineet Gupta 
arc_get_mem_sz(void)36e497c8e5SVineet Gupta long __init arc_get_mem_sz(void)
37e497c8e5SVineet Gupta {
38e497c8e5SVineet Gupta 	return low_mem_sz;
39e497c8e5SVineet Gupta }
40e497c8e5SVineet Gupta 
41c121c506SVineet Gupta /* User can over-ride above with "mem=nnn[KkMm]" in cmdline */
setup_mem_sz(char * str)42c121c506SVineet Gupta static int __init setup_mem_sz(char *str)
43c121c506SVineet Gupta {
446101be5aSVineet Gupta 	low_mem_sz = memparse(str, NULL) & PAGE_MASK;
45c121c506SVineet Gupta 
46c121c506SVineet Gupta 	/* early console might not be setup yet - it will show up later */
476101be5aSVineet Gupta 	pr_info("\"mem=%s\": mem sz set to %ldM\n", str, TO_MB(low_mem_sz));
48c121c506SVineet Gupta 
49c121c506SVineet Gupta 	return 0;
50c121c506SVineet Gupta }
51c121c506SVineet Gupta early_param("mem", setup_mem_sz);
52c121c506SVineet Gupta 
early_init_dt_add_memory_arch(u64 base,u64 size)53999159a5SVineet Gupta void __init early_init_dt_add_memory_arch(u64 base, u64 size)
54999159a5SVineet Gupta {
5529e33226SVineet Gupta 	int in_use = 0;
56f759ee57SVineet Gupta 
5729e33226SVineet Gupta 	if (!low_mem_sz) {
58ff1c0b6aSVineet Gupta 		if (base != low_mem_start)
599ed68785SEugeniy Paltsev 			panic("CONFIG_LINUX_RAM_BASE != DT memory { }");
60ff1c0b6aSVineet Gupta 
6129e33226SVineet Gupta 		low_mem_sz = size;
6229e33226SVineet Gupta 		in_use = 1;
63952eea9bSDavid Hildenbrand 		memblock_add_node(base, size, 0, MEMBLOCK_NONE);
6429e33226SVineet Gupta 	} else {
6529e33226SVineet Gupta #ifdef CONFIG_HIGHMEM
6629e33226SVineet Gupta 		high_mem_start = base;
6729e33226SVineet Gupta 		high_mem_sz = size;
6829e33226SVineet Gupta 		in_use = 1;
69952eea9bSDavid Hildenbrand 		memblock_add_node(base, size, 1, MEMBLOCK_NONE);
704af22dedSMike Rapoport 		memblock_reserve(base, size);
7129e33226SVineet Gupta #endif
7229e33226SVineet Gupta 	}
7329e33226SVineet Gupta 
7429e33226SVineet Gupta 	pr_info("Memory @ %llx [%lldM] %s\n",
7529e33226SVineet Gupta 		base, TO_MB(size), !in_use ? "Not used":"");
76999159a5SVineet Gupta }
77999159a5SVineet Gupta 
78c121c506SVineet Gupta /*
79c121c506SVineet Gupta  * First memory setup routine called from setup_arch()
80c121c506SVineet Gupta  * 1. setup swapper's mm @init_mm
81c121c506SVineet Gupta  * 2. Count the pages we have and setup bootmem allocator
82c121c506SVineet Gupta  * 3. zone setup
83c121c506SVineet Gupta  */
setup_arch_memory(void)84c121c506SVineet Gupta void __init setup_arch_memory(void)
85c121c506SVineet Gupta {
8651930df5SMike Rapoport 	unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 };
87c121c506SVineet Gupta 
888e339d50SKefeng Wang 	setup_initial_init_mm(_text, _etext, _edata, _end);
89c121c506SVineet Gupta 
90c121c506SVineet Gupta 	/* first page of system - kernel .vector starts here */
91c8092025SLinus Walleij 	min_low_pfn = virt_to_pfn((void *)CONFIG_LINUX_RAM_BASE);
92c121c506SVineet Gupta 
936101be5aSVineet Gupta 	/* Last usable page of low mem */
946101be5aSVineet Gupta 	max_low_pfn = max_pfn = PFN_DOWN(low_mem_start + low_mem_sz);
95c121c506SVineet Gupta 
966101be5aSVineet Gupta 	/*------------- bootmem allocator setup -----------------------*/
9729e33226SVineet Gupta 
9829e33226SVineet Gupta 	/*
9929e33226SVineet Gupta 	 * seed the bootmem allocator after any DT memory node parsing or
10029e33226SVineet Gupta 	 * "mem=xxx" cmdline overrides have potentially updated @arc_mem_sz
10129e33226SVineet Gupta 	 *
10229e33226SVineet Gupta 	 * Only low mem is added, otherwise we have crashes when allocating
10329e33226SVineet Gupta 	 * mem_map[] itself. NO_BOOTMEM allocates mem_map[] at the end of
10429e33226SVineet Gupta 	 * avail memory, ending in highmem with a > 32-bit address. However
10529e33226SVineet Gupta 	 * it then tries to memset it with a truncaed 32-bit handle, causing
10629e33226SVineet Gupta 	 * the crash
10729e33226SVineet Gupta 	 */
10829e33226SVineet Gupta 
109a3010a04SEugeniy Paltsev 	memblock_reserve(CONFIG_LINUX_LINK_BASE,
110a3010a04SEugeniy Paltsev 			 __pa(_end) - CONFIG_LINUX_LINK_BASE);
111c121c506SVineet Gupta 
112d6579e99SNoam Camus #ifdef CONFIG_BLK_DEV_INITRD
113229c55ccSFlorian Fainelli 	if (phys_initrd_size) {
114229c55ccSFlorian Fainelli 		memblock_reserve(phys_initrd_start, phys_initrd_size);
115229c55ccSFlorian Fainelli 		initrd_start = (unsigned long)__va(phys_initrd_start);
116229c55ccSFlorian Fainelli 		initrd_end = initrd_start + phys_initrd_size;
117229c55ccSFlorian Fainelli 	}
118d6579e99SNoam Camus #endif
119d6579e99SNoam Camus 
1201b10cb21SAlexey Brodkin 	early_init_fdt_reserve_self();
1211b10cb21SAlexey Brodkin 	early_init_fdt_scan_reserved_mem();
1221b10cb21SAlexey Brodkin 
123c121c506SVineet Gupta 	memblock_dump_all();
124c121c506SVineet Gupta 
1256101be5aSVineet Gupta 	/*----------------- node/zones setup --------------------------*/
12651930df5SMike Rapoport 	max_zone_pfn[ZONE_NORMAL] = max_low_pfn;
127f2e2013fSVineet Gupta 
12829e33226SVineet Gupta #ifdef CONFIG_HIGHMEM
12926f9d5fdSVineet Gupta 	/*
13026f9d5fdSVineet Gupta 	 * On ARC (w/o PAE) HIGHMEM addresses are actually smaller (0 based)
131e7793e53SMike Rapoport 	 * than addresses in normal aka low memory (0x8000_0000 based).
13226f9d5fdSVineet Gupta 	 * Even with PAE, the huge peripheral space hole would waste a lot of
133e7793e53SMike Rapoport 	 * mem with single contiguous mem_map[].
134e7793e53SMike Rapoport 	 * Thus when HIGHMEM on ARC is enabled the memory map corresponding
135e7793e53SMike Rapoport 	 * to the hole is freed and ARC specific version of pfn_valid()
136e7793e53SMike Rapoport 	 * handles the hole in the memory map.
13726f9d5fdSVineet Gupta 	 */
13826f9d5fdSVineet Gupta 
13926f9d5fdSVineet Gupta 	min_high_pfn = PFN_DOWN(high_mem_start);
14026f9d5fdSVineet Gupta 	max_high_pfn = PFN_DOWN(high_mem_start + high_mem_sz);
14126f9d5fdSVineet Gupta 
1421d5e4640SVladimir Isaev 	/*
1431d5e4640SVladimir Isaev 	 * max_high_pfn should be ok here for both HIGHMEM and HIGHMEM+PAE.
1441d5e4640SVladimir Isaev 	 * For HIGHMEM without PAE max_high_pfn should be less than
1451d5e4640SVladimir Isaev 	 * min_low_pfn to guarantee that these two regions don't overlap.
1461d5e4640SVladimir Isaev 	 * For PAE case highmem is greater than lowmem, so it is natural
1471d5e4640SVladimir Isaev 	 * to use max_high_pfn.
1481d5e4640SVladimir Isaev 	 *
1491d5e4640SVladimir Isaev 	 * In both cases, holes should be handled by pfn_valid().
1501d5e4640SVladimir Isaev 	 */
1511d5e4640SVladimir Isaev 	max_zone_pfn[ZONE_HIGHMEM] = max_high_pfn;
15226f9d5fdSVineet Gupta 
15329e33226SVineet Gupta 	high_memory = (void *)(min_high_pfn << PAGE_SHIFT);
154050b2da2SMike Rapoport 
155050b2da2SMike Rapoport 	arch_pfn_offset = min(min_low_pfn, min_high_pfn);
15629e33226SVineet Gupta 	kmap_init();
157050b2da2SMike Rapoport 
158050b2da2SMike Rapoport #else /* CONFIG_HIGHMEM */
159050b2da2SMike Rapoport 	/* pfn_valid() uses this when FLATMEM=y and HIGHMEM=n */
160050b2da2SMike Rapoport 	max_mapnr = max_low_pfn - min_low_pfn;
161050b2da2SMike Rapoport 
162050b2da2SMike Rapoport #endif /* CONFIG_HIGHMEM */
16351930df5SMike Rapoport 
16451930df5SMike Rapoport 	free_area_init(max_zone_pfn);
165c121c506SVineet Gupta }
166c121c506SVineet Gupta 
highmem_init(void)1674af22dedSMike Rapoport static void __init highmem_init(void)
1684af22dedSMike Rapoport {
1694af22dedSMike Rapoport #ifdef CONFIG_HIGHMEM
1704af22dedSMike Rapoport 	unsigned long tmp;
1714af22dedSMike Rapoport 
1723ecc6834SMike Rapoport 	memblock_phys_free(high_mem_start, high_mem_sz);
1734af22dedSMike Rapoport 	for (tmp = min_high_pfn; tmp < max_high_pfn; tmp++)
1744af22dedSMike Rapoport 		free_highmem_page(pfn_to_page(tmp));
1754af22dedSMike Rapoport #endif
1764af22dedSMike Rapoport }
1774af22dedSMike Rapoport 
178c121c506SVineet Gupta /*
179c121c506SVineet Gupta  * mem_init - initializes memory
180c121c506SVineet Gupta  *
181c121c506SVineet Gupta  * Frees up bootmem
182c121c506SVineet Gupta  * Calculates and displays memory available/used
183c121c506SVineet Gupta  */
mem_init(void)184c121c506SVineet Gupta void __init mem_init(void)
185c121c506SVineet Gupta {
186c6ffc5caSMike Rapoport 	memblock_free_all();
1874af22dedSMike Rapoport 	highmem_init();
188d9820ff7SVineet Gupta 
189d9820ff7SVineet Gupta 	BUILD_BUG_ON((PTRS_PER_PGD * sizeof(pgd_t)) > PAGE_SIZE);
1908747ff70SVineet Gupta 	BUILD_BUG_ON((PTRS_PER_PUD * sizeof(pud_t)) > PAGE_SIZE);
1912dde02abSVineet Gupta 	BUILD_BUG_ON((PTRS_PER_PMD * sizeof(pmd_t)) > PAGE_SIZE);
192d9820ff7SVineet Gupta 	BUILD_BUG_ON((PTRS_PER_PTE * sizeof(pte_t)) > PAGE_SIZE);
193c121c506SVineet Gupta }
194050b2da2SMike Rapoport 
195050b2da2SMike Rapoport #ifdef CONFIG_HIGHMEM
pfn_valid(unsigned long pfn)196050b2da2SMike Rapoport int pfn_valid(unsigned long pfn)
197050b2da2SMike Rapoport {
198050b2da2SMike Rapoport 	return (pfn >= min_high_pfn && pfn <= max_high_pfn) ||
199050b2da2SMike Rapoport 		(pfn >= min_low_pfn && pfn <= max_low_pfn);
200050b2da2SMike Rapoport }
201050b2da2SMike Rapoport EXPORT_SYMBOL(pfn_valid);
202050b2da2SMike Rapoport #endif
203