Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/mm.h>
0008 #include <linux/memblock.h>
0009 #ifdef CONFIG_BLK_DEV_INITRD
0010 #include <linux/initrd.h>
0011 #endif
0012 #include <linux/of_fdt.h>
0013 #include <linux/swap.h>
0014 #include <linux/module.h>
0015 #include <linux/highmem.h>
0016 #include <asm/page.h>
0017 #include <asm/sections.h>
0018 #include <asm/arcregs.h>
0019 
0020 pgd_t swapper_pg_dir[PTRS_PER_PGD] __aligned(PAGE_SIZE);
0021 char empty_zero_page[PAGE_SIZE] __aligned(PAGE_SIZE);
0022 EXPORT_SYMBOL(empty_zero_page);
0023 
0024 static const unsigned long low_mem_start = CONFIG_LINUX_RAM_BASE;
0025 static unsigned long low_mem_sz;
0026 
0027 #ifdef CONFIG_HIGHMEM
0028 static unsigned long min_high_pfn, max_high_pfn;
0029 static phys_addr_t high_mem_start;
0030 static phys_addr_t high_mem_sz;
0031 unsigned long arch_pfn_offset;
0032 EXPORT_SYMBOL(arch_pfn_offset);
0033 #endif
0034 
0035 long __init arc_get_mem_sz(void)
0036 {
0037     return low_mem_sz;
0038 }
0039 
0040 /* User can over-ride above with "mem=nnn[KkMm]" in cmdline */
0041 static int __init setup_mem_sz(char *str)
0042 {
0043     low_mem_sz = memparse(str, NULL) & PAGE_MASK;
0044 
0045     /* early console might not be setup yet - it will show up later */
0046     pr_info("\"mem=%s\": mem sz set to %ldM\n", str, TO_MB(low_mem_sz));
0047 
0048     return 0;
0049 }
0050 early_param("mem", setup_mem_sz);
0051 
0052 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
0053 {
0054     int in_use = 0;
0055 
0056     if (!low_mem_sz) {
0057         if (base != low_mem_start)
0058             panic("CONFIG_LINUX_RAM_BASE != DT memory { }");
0059 
0060         low_mem_sz = size;
0061         in_use = 1;
0062         memblock_add_node(base, size, 0, MEMBLOCK_NONE);
0063     } else {
0064 #ifdef CONFIG_HIGHMEM
0065         high_mem_start = base;
0066         high_mem_sz = size;
0067         in_use = 1;
0068         memblock_add_node(base, size, 1, MEMBLOCK_NONE);
0069         memblock_reserve(base, size);
0070 #endif
0071     }
0072 
0073     pr_info("Memory @ %llx [%lldM] %s\n",
0074         base, TO_MB(size), !in_use ? "Not used":"");
0075 }
0076 
0077 bool arch_has_descending_max_zone_pfns(void)
0078 {
0079     return !IS_ENABLED(CONFIG_ARC_HAS_PAE40);
0080 }
0081 
0082 /*
0083  * First memory setup routine called from setup_arch()
0084  * 1. setup swapper's mm @init_mm
0085  * 2. Count the pages we have and setup bootmem allocator
0086  * 3. zone setup
0087  */
0088 void __init setup_arch_memory(void)
0089 {
0090     unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 };
0091 
0092     setup_initial_init_mm(_text, _etext, _edata, _end);
0093 
0094     /* first page of system - kernel .vector starts here */
0095     min_low_pfn = virt_to_pfn(CONFIG_LINUX_RAM_BASE);
0096 
0097     /* Last usable page of low mem */
0098     max_low_pfn = max_pfn = PFN_DOWN(low_mem_start + low_mem_sz);
0099 
0100     /*------------- bootmem allocator setup -----------------------*/
0101 
0102     /*
0103      * seed the bootmem allocator after any DT memory node parsing or
0104      * "mem=xxx" cmdline overrides have potentially updated @arc_mem_sz
0105      *
0106      * Only low mem is added, otherwise we have crashes when allocating
0107      * mem_map[] itself. NO_BOOTMEM allocates mem_map[] at the end of
0108      * avail memory, ending in highmem with a > 32-bit address. However
0109      * it then tries to memset it with a truncaed 32-bit handle, causing
0110      * the crash
0111      */
0112 
0113     memblock_reserve(CONFIG_LINUX_LINK_BASE,
0114              __pa(_end) - CONFIG_LINUX_LINK_BASE);
0115 
0116 #ifdef CONFIG_BLK_DEV_INITRD
0117     if (phys_initrd_size) {
0118         memblock_reserve(phys_initrd_start, phys_initrd_size);
0119         initrd_start = (unsigned long)__va(phys_initrd_start);
0120         initrd_end = initrd_start + phys_initrd_size;
0121     }
0122 #endif
0123 
0124     early_init_fdt_reserve_self();
0125     early_init_fdt_scan_reserved_mem();
0126 
0127     memblock_dump_all();
0128 
0129     /*----------------- node/zones setup --------------------------*/
0130     max_zone_pfn[ZONE_NORMAL] = max_low_pfn;
0131 
0132 #ifdef CONFIG_HIGHMEM
0133     /*
0134      * On ARC (w/o PAE) HIGHMEM addresses are actually smaller (0 based)
0135      * than addresses in normal aka low memory (0x8000_0000 based).
0136      * Even with PAE, the huge peripheral space hole would waste a lot of
0137      * mem with single contiguous mem_map[].
0138      * Thus when HIGHMEM on ARC is enabled the memory map corresponding
0139      * to the hole is freed and ARC specific version of pfn_valid()
0140      * handles the hole in the memory map.
0141      */
0142 
0143     min_high_pfn = PFN_DOWN(high_mem_start);
0144     max_high_pfn = PFN_DOWN(high_mem_start + high_mem_sz);
0145 
0146     /*
0147      * max_high_pfn should be ok here for both HIGHMEM and HIGHMEM+PAE.
0148      * For HIGHMEM without PAE max_high_pfn should be less than
0149      * min_low_pfn to guarantee that these two regions don't overlap.
0150      * For PAE case highmem is greater than lowmem, so it is natural
0151      * to use max_high_pfn.
0152      *
0153      * In both cases, holes should be handled by pfn_valid().
0154      */
0155     max_zone_pfn[ZONE_HIGHMEM] = max_high_pfn;
0156 
0157     high_memory = (void *)(min_high_pfn << PAGE_SHIFT);
0158 
0159     arch_pfn_offset = min(min_low_pfn, min_high_pfn);
0160     kmap_init();
0161 
0162 #else /* CONFIG_HIGHMEM */
0163     /* pfn_valid() uses this when FLATMEM=y and HIGHMEM=n */
0164     max_mapnr = max_low_pfn - min_low_pfn;
0165 
0166 #endif /* CONFIG_HIGHMEM */
0167 
0168     free_area_init(max_zone_pfn);
0169 }
0170 
0171 static void __init highmem_init(void)
0172 {
0173 #ifdef CONFIG_HIGHMEM
0174     unsigned long tmp;
0175 
0176     memblock_phys_free(high_mem_start, high_mem_sz);
0177     for (tmp = min_high_pfn; tmp < max_high_pfn; tmp++)
0178         free_highmem_page(pfn_to_page(tmp));
0179 #endif
0180 }
0181 
0182 /*
0183  * mem_init - initializes memory
0184  *
0185  * Frees up bootmem
0186  * Calculates and displays memory available/used
0187  */
0188 void __init mem_init(void)
0189 {
0190     memblock_free_all();
0191     highmem_init();
0192 
0193     BUILD_BUG_ON((PTRS_PER_PGD * sizeof(pgd_t)) > PAGE_SIZE);
0194     BUILD_BUG_ON((PTRS_PER_PUD * sizeof(pud_t)) > PAGE_SIZE);
0195     BUILD_BUG_ON((PTRS_PER_PMD * sizeof(pmd_t)) > PAGE_SIZE);
0196     BUILD_BUG_ON((PTRS_PER_PTE * sizeof(pte_t)) > PAGE_SIZE);
0197 }
0198 
0199 #ifdef CONFIG_HIGHMEM
0200 int pfn_valid(unsigned long pfn)
0201 {
0202     return (pfn >= min_high_pfn && pfn <= max_high_pfn) ||
0203         (pfn >= min_low_pfn && pfn <= max_low_pfn);
0204 }
0205 EXPORT_SYMBOL(pfn_valid);
0206 #endif