Merge branches 'for-next/sme', 'for-next/stacktrace', 'for-next/fault-in-subpage...
[linux-2.6-microblaze.git] / arch / arm64 / mm / init.c
index 1e7b155..a141014 100644 (file)
@@ -90,6 +90,32 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;
 phys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1;
 #endif
 
+/* Current arm64 boot protocol requires 2MB alignment */
+#define CRASH_ALIGN                    SZ_2M
+
+#define CRASH_ADDR_LOW_MAX             arm64_dma_phys_limit
+#define CRASH_ADDR_HIGH_MAX            (PHYS_MASK + 1)
+
+static int __init reserve_crashkernel_low(unsigned long long low_size)
+{
+       unsigned long long low_base;
+
+       low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
+       if (!low_base) {
+               pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
+               return -ENOMEM;
+       }
+
+       pr_info("crashkernel low memory reserved: 0x%08llx - 0x%08llx (%lld MB)\n",
+               low_base, low_base + low_size, low_size >> 20);
+
+       crashk_low_res.start = low_base;
+       crashk_low_res.end   = low_base + low_size - 1;
+       insert_resource(&iomem_resource, &crashk_low_res);
+
+       return 0;
+}
+
 /*
  * reserve_crashkernel() - reserves memory for crash kernel
  *
@@ -100,17 +126,35 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1;
 static void __init reserve_crashkernel(void)
 {
        unsigned long long crash_base, crash_size;
-       unsigned long long crash_max = arm64_dma_phys_limit;
+       unsigned long long crash_low_size = 0;
+       unsigned long long crash_max = CRASH_ADDR_LOW_MAX;
+       char *cmdline = boot_command_line;
        int ret;
 
        if (!IS_ENABLED(CONFIG_KEXEC_CORE))
                return;
 
-       ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
+       /* crashkernel=X[@offset] */
+       ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
                                &crash_size, &crash_base);
-       /* no crashkernel= or invalid value specified */
-       if (ret || !crash_size)
+       if (ret == -ENOENT) {
+               ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
+               if (ret || !crash_size)
+                       return;
+
+               /*
+                * crashkernel=Y,low can be specified or not, but invalid value
+                * is not allowed.
+                */
+               ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
+               if (ret && (ret != -ENOENT))
+                       return;
+
+               crash_max = CRASH_ADDR_HIGH_MAX;
+       } else if (ret || !crash_size) {
+               /* The specified value is invalid */
                return;
+       }
 
        crash_size = PAGE_ALIGN(crash_size);
 
@@ -118,8 +162,7 @@ static void __init reserve_crashkernel(void)
        if (crash_base)
                crash_max = crash_base + crash_size;
 
-       /* Current arm64 boot protocol requires 2MB alignment */
-       crash_base = memblock_phys_alloc_range(crash_size, SZ_2M,
+       crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
                                               crash_base, crash_max);
        if (!crash_base) {
                pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
@@ -127,6 +170,12 @@ static void __init reserve_crashkernel(void)
                return;
        }
 
+       if ((crash_base >= CRASH_ADDR_LOW_MAX) &&
+            crash_low_size && reserve_crashkernel_low(crash_low_size)) {
+               memblock_phys_free(crash_base, crash_size);
+               return;
+       }
+
        pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
                crash_base, crash_base + crash_size, crash_size >> 20);
 
@@ -135,8 +184,12 @@ static void __init reserve_crashkernel(void)
         * map. Inform kmemleak so that it won't try to access it.
         */
        kmemleak_ignore_phys(crash_base);
+       if (crashk_low_res.end)
+               kmemleak_ignore_phys(crashk_low_res.start);
+
        crashk_res.start = crash_base;
        crashk_res.end = crash_base + crash_size - 1;
+       insert_resource(&iomem_resource, &crashk_res);
 }
 
 /*
@@ -157,7 +210,7 @@ static phys_addr_t __init max_zone_phys(unsigned int zone_bits)
        return min(zone_mask, memblock_end_of_DRAM() - 1) + 1;
 }
 
-static void __init zone_sizes_init(unsigned long min, unsigned long max)
+static void __init zone_sizes_init(void)
 {
        unsigned long max_zone_pfns[MAX_NR_ZONES]  = {0};
        unsigned int __maybe_unused acpi_zone_dma_bits;
@@ -176,7 +229,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
        if (!arm64_dma_phys_limit)
                arm64_dma_phys_limit = dma32_phys_limit;
 #endif
-       max_zone_pfns[ZONE_NORMAL] = max;
+       max_zone_pfns[ZONE_NORMAL] = max_pfn;
 
        free_area_init(max_zone_pfns);
 }
@@ -374,7 +427,7 @@ void __init bootmem_init(void)
         * done after the fixed reservations
         */
        sparse_init();
-       zone_sizes_init(min, max);
+       zone_sizes_init();
 
        /*
         * Reserve the CMA area after arm64_dma_phys_limit was initialised.