18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 1998-2003 Hewlett-Packard Co
78c2ecf20Sopenharmony_ci *	David Mosberger-Tang <davidm@hpl.hp.com>
88c2ecf20Sopenharmony_ci *	Stephane Eranian <eranian@hpl.hp.com>
98c2ecf20Sopenharmony_ci * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
108c2ecf20Sopenharmony_ci * Copyright (C) 1999 VA Linux Systems
118c2ecf20Sopenharmony_ci * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
128c2ecf20Sopenharmony_ci * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Routines used by ia64 machines with contiguous (or virtually contiguous)
158c2ecf20Sopenharmony_ci * memory.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci#include <linux/efi.h>
188c2ecf20Sopenharmony_ci#include <linux/memblock.h>
198c2ecf20Sopenharmony_ci#include <linux/mm.h>
208c2ecf20Sopenharmony_ci#include <linux/nmi.h>
218c2ecf20Sopenharmony_ci#include <linux/swap.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <asm/meminit.h>
248c2ecf20Sopenharmony_ci#include <asm/sections.h>
258c2ecf20Sopenharmony_ci#include <asm/mca.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRTUAL_MEM_MAP
288c2ecf20Sopenharmony_cistatic unsigned long max_gap;
298c2ecf20Sopenharmony_ci#endif
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* physical address where the bootmem map is located */
328c2ecf20Sopenharmony_ciunsigned long bootmap_start;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
358c2ecf20Sopenharmony_cistatic void *cpu_data;
368c2ecf20Sopenharmony_ci/**
378c2ecf20Sopenharmony_ci * per_cpu_init - setup per-cpu variables
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * Allocate and setup per-cpu data areas.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_civoid *per_cpu_init(void)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	static bool first_time = true;
448c2ecf20Sopenharmony_ci	void *cpu0_data = __cpu0_per_cpu;
458c2ecf20Sopenharmony_ci	unsigned int cpu;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (!first_time)
488c2ecf20Sopenharmony_ci		goto skip;
498c2ecf20Sopenharmony_ci	first_time = false;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/*
528c2ecf20Sopenharmony_ci	 * get_free_pages() cannot be used before cpu_init() done.
538c2ecf20Sopenharmony_ci	 * BSP allocates PERCPU_PAGE_SIZE bytes for all possible CPUs
548c2ecf20Sopenharmony_ci	 * to avoid that AP calls get_zeroed_page().
558c2ecf20Sopenharmony_ci	 */
568c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu) {
578c2ecf20Sopenharmony_ci		void *src = cpu == 0 ? cpu0_data : __phys_per_cpu_start;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		memcpy(cpu_data, src, __per_cpu_end - __per_cpu_start);
608c2ecf20Sopenharmony_ci		__per_cpu_offset[cpu] = (char *)cpu_data - __per_cpu_start;
618c2ecf20Sopenharmony_ci		per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		/*
648c2ecf20Sopenharmony_ci		 * percpu area for cpu0 is moved from the __init area
658c2ecf20Sopenharmony_ci		 * which is setup by head.S and used till this point.
668c2ecf20Sopenharmony_ci		 * Update ar.k3.  This move is ensures that percpu
678c2ecf20Sopenharmony_ci		 * area for cpu0 is on the correct node and its
688c2ecf20Sopenharmony_ci		 * virtual address isn't insanely far from other
698c2ecf20Sopenharmony_ci		 * percpu areas which is important for congruent
708c2ecf20Sopenharmony_ci		 * percpu allocator.
718c2ecf20Sopenharmony_ci		 */
728c2ecf20Sopenharmony_ci		if (cpu == 0)
738c2ecf20Sopenharmony_ci			ia64_set_kr(IA64_KR_PER_CPU_DATA, __pa(cpu_data) -
748c2ecf20Sopenharmony_ci				    (unsigned long)__per_cpu_start);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci		cpu_data += PERCPU_PAGE_SIZE;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ciskip:
798c2ecf20Sopenharmony_ci	return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic inline __init void
838c2ecf20Sopenharmony_cialloc_per_cpu_data(void)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	size_t size = PERCPU_PAGE_SIZE * num_possible_cpus();
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	cpu_data = memblock_alloc_from(size, PERCPU_PAGE_SIZE,
888c2ecf20Sopenharmony_ci				       __pa(MAX_DMA_ADDRESS));
898c2ecf20Sopenharmony_ci	if (!cpu_data)
908c2ecf20Sopenharmony_ci		panic("%s: Failed to allocate %lu bytes align=%lx from=%lx\n",
918c2ecf20Sopenharmony_ci		      __func__, size, PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/**
958c2ecf20Sopenharmony_ci * setup_per_cpu_areas - setup percpu areas
968c2ecf20Sopenharmony_ci *
978c2ecf20Sopenharmony_ci * Arch code has already allocated and initialized percpu areas.  All
988c2ecf20Sopenharmony_ci * this function has to do is to teach the determined layout to the
998c2ecf20Sopenharmony_ci * dynamic percpu allocator, which happens to be more complex than
1008c2ecf20Sopenharmony_ci * creating whole new ones using helpers.
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_civoid __init
1038c2ecf20Sopenharmony_cisetup_per_cpu_areas(void)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct pcpu_alloc_info *ai;
1068c2ecf20Sopenharmony_ci	struct pcpu_group_info *gi;
1078c2ecf20Sopenharmony_ci	unsigned int cpu;
1088c2ecf20Sopenharmony_ci	ssize_t static_size, reserved_size, dyn_size;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	ai = pcpu_alloc_alloc_info(1, num_possible_cpus());
1118c2ecf20Sopenharmony_ci	if (!ai)
1128c2ecf20Sopenharmony_ci		panic("failed to allocate pcpu_alloc_info");
1138c2ecf20Sopenharmony_ci	gi = &ai->groups[0];
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* units are assigned consecutively to possible cpus */
1168c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu)
1178c2ecf20Sopenharmony_ci		gi->cpu_map[gi->nr_units++] = cpu;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* set parameters */
1208c2ecf20Sopenharmony_ci	static_size = __per_cpu_end - __per_cpu_start;
1218c2ecf20Sopenharmony_ci	reserved_size = PERCPU_MODULE_RESERVE;
1228c2ecf20Sopenharmony_ci	dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size;
1238c2ecf20Sopenharmony_ci	if (dyn_size < 0)
1248c2ecf20Sopenharmony_ci		panic("percpu area overflow static=%zd reserved=%zd\n",
1258c2ecf20Sopenharmony_ci		      static_size, reserved_size);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	ai->static_size		= static_size;
1288c2ecf20Sopenharmony_ci	ai->reserved_size	= reserved_size;
1298c2ecf20Sopenharmony_ci	ai->dyn_size		= dyn_size;
1308c2ecf20Sopenharmony_ci	ai->unit_size		= PERCPU_PAGE_SIZE;
1318c2ecf20Sopenharmony_ci	ai->atom_size		= PAGE_SIZE;
1328c2ecf20Sopenharmony_ci	ai->alloc_size		= PERCPU_PAGE_SIZE;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	pcpu_setup_first_chunk(ai, __per_cpu_start + __per_cpu_offset[0]);
1358c2ecf20Sopenharmony_ci	pcpu_free_alloc_info(ai);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci#else
1388c2ecf20Sopenharmony_ci#define alloc_per_cpu_data() do { } while (0)
1398c2ecf20Sopenharmony_ci#endif /* CONFIG_SMP */
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/**
1428c2ecf20Sopenharmony_ci * find_memory - setup memory map
1438c2ecf20Sopenharmony_ci *
1448c2ecf20Sopenharmony_ci * Walk the EFI memory map and find usable memory for the system, taking
1458c2ecf20Sopenharmony_ci * into account reserved areas.
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_civoid __init
1488c2ecf20Sopenharmony_cifind_memory (void)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	reserve_memory();
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* first find highest page frame number */
1538c2ecf20Sopenharmony_ci	min_low_pfn = ~0UL;
1548c2ecf20Sopenharmony_ci	max_low_pfn = 0;
1558c2ecf20Sopenharmony_ci	efi_memmap_walk(find_max_min_low_pfn, NULL);
1568c2ecf20Sopenharmony_ci	max_pfn = max_low_pfn;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRTUAL_MEM_MAP
1598c2ecf20Sopenharmony_ci	efi_memmap_walk(filter_memory, register_active_ranges);
1608c2ecf20Sopenharmony_ci#else
1618c2ecf20Sopenharmony_ci	memblock_add_node(0, PFN_PHYS(max_low_pfn), 0);
1628c2ecf20Sopenharmony_ci#endif
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	find_initrd();
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	alloc_per_cpu_data();
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/*
1708c2ecf20Sopenharmony_ci * Set up the page tables.
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_civoid __init
1748c2ecf20Sopenharmony_cipaging_init (void)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	unsigned long max_dma;
1778c2ecf20Sopenharmony_ci	unsigned long max_zone_pfns[MAX_NR_ZONES];
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
1808c2ecf20Sopenharmony_ci#ifdef CONFIG_ZONE_DMA32
1818c2ecf20Sopenharmony_ci	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
1828c2ecf20Sopenharmony_ci	max_zone_pfns[ZONE_DMA32] = max_dma;
1838c2ecf20Sopenharmony_ci#endif
1848c2ecf20Sopenharmony_ci	max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRTUAL_MEM_MAP
1878c2ecf20Sopenharmony_ci	efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
1888c2ecf20Sopenharmony_ci	if (max_gap < LARGE_GAP) {
1898c2ecf20Sopenharmony_ci		vmem_map = (struct page *) 0;
1908c2ecf20Sopenharmony_ci	} else {
1918c2ecf20Sopenharmony_ci		unsigned long map_size;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		/* allocate virtual_mem_map */
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		map_size = PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
1968c2ecf20Sopenharmony_ci			sizeof(struct page));
1978c2ecf20Sopenharmony_ci		VMALLOC_END -= map_size;
1988c2ecf20Sopenharmony_ci		vmem_map = (struct page *) VMALLOC_END;
1998c2ecf20Sopenharmony_ci		efi_memmap_walk(create_mem_map_page_table, NULL);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		/*
2028c2ecf20Sopenharmony_ci		 * alloc_node_mem_map makes an adjustment for mem_map
2038c2ecf20Sopenharmony_ci		 * which isn't compatible with vmem_map.
2048c2ecf20Sopenharmony_ci		 */
2058c2ecf20Sopenharmony_ci		NODE_DATA(0)->node_mem_map = vmem_map +
2068c2ecf20Sopenharmony_ci			find_min_pfn_with_active_regions();
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		printk("Virtual mem_map starts at 0x%p\n", mem_map);
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci#endif /* !CONFIG_VIRTUAL_MEM_MAP */
2118c2ecf20Sopenharmony_ci	free_area_init(max_zone_pfns);
2128c2ecf20Sopenharmony_ci	zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
2138c2ecf20Sopenharmony_ci}
214