18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * arch/xtensa/mm/init.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Derived from MIPS, PPC.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
78c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
88c2ecf20Sopenharmony_ci * for more details.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2005 Tensilica Inc.
118c2ecf20Sopenharmony_ci * Copyright (C) 2014 - 2016 Cadence Design Systems Inc.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Chris Zankel	<chris@zankel.net>
148c2ecf20Sopenharmony_ci * Joe Taylor	<joe@tensilica.com, joetylr@yahoo.com>
158c2ecf20Sopenharmony_ci * Marc Gauthier
168c2ecf20Sopenharmony_ci * Kevin Chea
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/kernel.h>
208c2ecf20Sopenharmony_ci#include <linux/errno.h>
218c2ecf20Sopenharmony_ci#include <linux/memblock.h>
228c2ecf20Sopenharmony_ci#include <linux/gfp.h>
238c2ecf20Sopenharmony_ci#include <linux/highmem.h>
248c2ecf20Sopenharmony_ci#include <linux/swap.h>
258c2ecf20Sopenharmony_ci#include <linux/mman.h>
268c2ecf20Sopenharmony_ci#include <linux/nodemask.h>
278c2ecf20Sopenharmony_ci#include <linux/mm.h>
288c2ecf20Sopenharmony_ci#include <linux/of_fdt.h>
298c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <asm/bootparam.h>
328c2ecf20Sopenharmony_ci#include <asm/page.h>
338c2ecf20Sopenharmony_ci#include <asm/sections.h>
348c2ecf20Sopenharmony_ci#include <asm/sysmem.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/*
378c2ecf20Sopenharmony_ci * Initialize the bootmem system and give it all low memory we have available.
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_civoid __init bootmem_init(void)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	/* Reserve all memory below PHYS_OFFSET, as memory
438c2ecf20Sopenharmony_ci	 * accounting doesn't work for pages below that address.
448c2ecf20Sopenharmony_ci	 *
458c2ecf20Sopenharmony_ci	 * If PHYS_OFFSET is zero reserve page at address 0:
468c2ecf20Sopenharmony_ci	 * successfull allocations should never return NULL.
478c2ecf20Sopenharmony_ci	 */
488c2ecf20Sopenharmony_ci	memblock_reserve(0, PHYS_OFFSET ? PHYS_OFFSET : 1);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	early_init_fdt_scan_reserved_mem();
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (!memblock_phys_mem_size())
538c2ecf20Sopenharmony_ci		panic("No memory found!\n");
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	min_low_pfn = PFN_UP(memblock_start_of_DRAM());
568c2ecf20Sopenharmony_ci	min_low_pfn = max(min_low_pfn, PFN_UP(PHYS_OFFSET));
578c2ecf20Sopenharmony_ci	max_pfn = PFN_DOWN(memblock_end_of_DRAM());
588c2ecf20Sopenharmony_ci	max_low_pfn = min(max_pfn, MAX_LOW_PFN);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	early_memtest((phys_addr_t)min_low_pfn << PAGE_SHIFT,
618c2ecf20Sopenharmony_ci		      (phys_addr_t)max_low_pfn << PAGE_SHIFT);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	memblock_set_current_limit(PFN_PHYS(max_low_pfn));
648c2ecf20Sopenharmony_ci	dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	memblock_dump_all();
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_civoid __init zones_init(void)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	/* All pages are DMA-able, so we put them all in the DMA zone. */
738c2ecf20Sopenharmony_ci	unsigned long max_zone_pfn[MAX_NR_ZONES] = {
748c2ecf20Sopenharmony_ci		[ZONE_NORMAL] = max_low_pfn,
758c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHMEM
768c2ecf20Sopenharmony_ci		[ZONE_HIGHMEM] = max_pfn,
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci	};
798c2ecf20Sopenharmony_ci	free_area_init(max_zone_pfn);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic void __init free_highpages(void)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHMEM
858c2ecf20Sopenharmony_ci	unsigned long max_low = max_low_pfn;
868c2ecf20Sopenharmony_ci	phys_addr_t range_start, range_end;
878c2ecf20Sopenharmony_ci	u64 i;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* set highmem page free */
908c2ecf20Sopenharmony_ci	for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE,
918c2ecf20Sopenharmony_ci				&range_start, &range_end, NULL) {
928c2ecf20Sopenharmony_ci		unsigned long start = PFN_UP(range_start);
938c2ecf20Sopenharmony_ci		unsigned long end = PFN_DOWN(range_end);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		/* Ignore complete lowmem entries */
968c2ecf20Sopenharmony_ci		if (end <= max_low)
978c2ecf20Sopenharmony_ci			continue;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		/* Truncate partial highmem entries */
1008c2ecf20Sopenharmony_ci		if (start < max_low)
1018c2ecf20Sopenharmony_ci			start = max_low;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		for (; start < end; start++)
1048c2ecf20Sopenharmony_ci			free_highmem_page(pfn_to_page(start));
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci#endif
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/*
1108c2ecf20Sopenharmony_ci * Initialize memory pages.
1118c2ecf20Sopenharmony_ci */
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_civoid __init mem_init(void)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	free_highpages();
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	max_mapnr = max_pfn - ARCH_PFN_OFFSET;
1188c2ecf20Sopenharmony_ci	high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	memblock_free_all();
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	mem_init_print_info(NULL);
1238c2ecf20Sopenharmony_ci	pr_info("virtual kernel memory layout:\n"
1248c2ecf20Sopenharmony_ci#ifdef CONFIG_KASAN
1258c2ecf20Sopenharmony_ci		"    kasan   : 0x%08lx - 0x%08lx  (%5lu MB)\n"
1268c2ecf20Sopenharmony_ci#endif
1278c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU
1288c2ecf20Sopenharmony_ci		"    vmalloc : 0x%08lx - 0x%08lx  (%5lu MB)\n"
1298c2ecf20Sopenharmony_ci#endif
1308c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHMEM
1318c2ecf20Sopenharmony_ci		"    pkmap   : 0x%08lx - 0x%08lx  (%5lu kB)\n"
1328c2ecf20Sopenharmony_ci		"    fixmap  : 0x%08lx - 0x%08lx  (%5lu kB)\n"
1338c2ecf20Sopenharmony_ci#endif
1348c2ecf20Sopenharmony_ci		"    lowmem  : 0x%08lx - 0x%08lx  (%5lu MB)\n"
1358c2ecf20Sopenharmony_ci		"    .text   : 0x%08lx - 0x%08lx  (%5lu kB)\n"
1368c2ecf20Sopenharmony_ci		"    .rodata : 0x%08lx - 0x%08lx  (%5lu kB)\n"
1378c2ecf20Sopenharmony_ci		"    .data   : 0x%08lx - 0x%08lx  (%5lu kB)\n"
1388c2ecf20Sopenharmony_ci		"    .init   : 0x%08lx - 0x%08lx  (%5lu kB)\n"
1398c2ecf20Sopenharmony_ci		"    .bss    : 0x%08lx - 0x%08lx  (%5lu kB)\n",
1408c2ecf20Sopenharmony_ci#ifdef CONFIG_KASAN
1418c2ecf20Sopenharmony_ci		KASAN_SHADOW_START, KASAN_SHADOW_START + KASAN_SHADOW_SIZE,
1428c2ecf20Sopenharmony_ci		KASAN_SHADOW_SIZE >> 20,
1438c2ecf20Sopenharmony_ci#endif
1448c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU
1458c2ecf20Sopenharmony_ci		VMALLOC_START, VMALLOC_END,
1468c2ecf20Sopenharmony_ci		(VMALLOC_END - VMALLOC_START) >> 20,
1478c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHMEM
1488c2ecf20Sopenharmony_ci		PKMAP_BASE, PKMAP_BASE + LAST_PKMAP * PAGE_SIZE,
1498c2ecf20Sopenharmony_ci		(LAST_PKMAP*PAGE_SIZE) >> 10,
1508c2ecf20Sopenharmony_ci		FIXADDR_START, FIXADDR_TOP,
1518c2ecf20Sopenharmony_ci		(FIXADDR_TOP - FIXADDR_START) >> 10,
1528c2ecf20Sopenharmony_ci#endif
1538c2ecf20Sopenharmony_ci		PAGE_OFFSET, PAGE_OFFSET +
1548c2ecf20Sopenharmony_ci		(max_low_pfn - min_low_pfn) * PAGE_SIZE,
1558c2ecf20Sopenharmony_ci#else
1568c2ecf20Sopenharmony_ci		min_low_pfn * PAGE_SIZE, max_low_pfn * PAGE_SIZE,
1578c2ecf20Sopenharmony_ci#endif
1588c2ecf20Sopenharmony_ci		((max_low_pfn - min_low_pfn) * PAGE_SIZE) >> 20,
1598c2ecf20Sopenharmony_ci		(unsigned long)_text, (unsigned long)_etext,
1608c2ecf20Sopenharmony_ci		(unsigned long)(_etext - _text) >> 10,
1618c2ecf20Sopenharmony_ci		(unsigned long)__start_rodata, (unsigned long)__end_rodata,
1628c2ecf20Sopenharmony_ci		(unsigned long)(__end_rodata - __start_rodata) >> 10,
1638c2ecf20Sopenharmony_ci		(unsigned long)_sdata, (unsigned long)_edata,
1648c2ecf20Sopenharmony_ci		(unsigned long)(_edata - _sdata) >> 10,
1658c2ecf20Sopenharmony_ci		(unsigned long)__init_begin, (unsigned long)__init_end,
1668c2ecf20Sopenharmony_ci		(unsigned long)(__init_end - __init_begin) >> 10,
1678c2ecf20Sopenharmony_ci		(unsigned long)__bss_start, (unsigned long)__bss_stop,
1688c2ecf20Sopenharmony_ci		(unsigned long)(__bss_stop - __bss_start) >> 10);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void __init parse_memmap_one(char *p)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	char *oldp;
1748c2ecf20Sopenharmony_ci	unsigned long start_at, mem_size;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (!p)
1778c2ecf20Sopenharmony_ci		return;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	oldp = p;
1808c2ecf20Sopenharmony_ci	mem_size = memparse(p, &p);
1818c2ecf20Sopenharmony_ci	if (p == oldp)
1828c2ecf20Sopenharmony_ci		return;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	switch (*p) {
1858c2ecf20Sopenharmony_ci	case '@':
1868c2ecf20Sopenharmony_ci		start_at = memparse(p + 1, &p);
1878c2ecf20Sopenharmony_ci		memblock_add(start_at, mem_size);
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	case '$':
1918c2ecf20Sopenharmony_ci		start_at = memparse(p + 1, &p);
1928c2ecf20Sopenharmony_ci		memblock_reserve(start_at, mem_size);
1938c2ecf20Sopenharmony_ci		break;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	case 0:
1968c2ecf20Sopenharmony_ci		memblock_reserve(mem_size, -mem_size);
1978c2ecf20Sopenharmony_ci		break;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	default:
2008c2ecf20Sopenharmony_ci		pr_warn("Unrecognized memmap syntax: %s\n", p);
2018c2ecf20Sopenharmony_ci		break;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int __init parse_memmap_opt(char *str)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	while (str) {
2088c2ecf20Sopenharmony_ci		char *k = strchr(str, ',');
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		if (k)
2118c2ecf20Sopenharmony_ci			*k++ = 0;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		parse_memmap_one(str);
2148c2ecf20Sopenharmony_ci		str = k;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return 0;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ciearly_param("memmap", parse_memmap_opt);
220