Merge branches 'for-next/kvm-build-fix', 'for-next/va-refactor', 'for-next/lto',...
[sfrench/cifs-2.6.git] / arch / arm64 / mm / init.c
index 095540667f0fdd7ed408202264ffd57d5c22d0da..fbd452e12397b6d8198ca0b3b6bd9385917ee328 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/kexec.h>
 #include <linux/crash_dump.h>
 #include <linux/hugetlb.h>
+#include <linux/acpi_iort.h>
 
 #include <asm/boot.h>
 #include <asm/fixmap.h>
@@ -42,8 +43,6 @@
 #include <asm/tlb.h>
 #include <asm/alternative.h>
 
-#define ARM64_ZONE_DMA_BITS    30
-
 /*
  * We need to be able to catch inadvertent references to memstart_addr
  * that occur (potentially in generic code) before arm64_memblock_init()
@@ -175,21 +174,34 @@ static void __init reserve_elfcorehdr(void)
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
- * Return the maximum physical address for a zone with a given address size
- * limit. It currently assumes that for memory starting above 4G, 32-bit
- * devices will use a DMA offset.
+ * Return the maximum physical address for a zone accessible by the given bits
+ * limit. If DRAM starts above 32-bit, expand the zone to the maximum
+ * available memory, otherwise cap it at 32-bit.
  */
 static phys_addr_t __init max_zone_phys(unsigned int zone_bits)
 {
-       phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits);
-       return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM());
+       phys_addr_t zone_mask = DMA_BIT_MASK(zone_bits);
+       phys_addr_t phys_start = memblock_start_of_DRAM();
+
+       if (phys_start > U32_MAX)
+               zone_mask = PHYS_ADDR_MAX;
+       else if (phys_start > zone_mask)
+               zone_mask = U32_MAX;
+
+       return min(zone_mask, memblock_end_of_DRAM() - 1) + 1;
 }
 
 static void __init zone_sizes_init(unsigned long min, unsigned long max)
 {
        unsigned long max_zone_pfns[MAX_NR_ZONES]  = {0};
+       unsigned int __maybe_unused acpi_zone_dma_bits;
+       unsigned int __maybe_unused dt_zone_dma_bits;
 
 #ifdef CONFIG_ZONE_DMA
+       acpi_zone_dma_bits = fls64(acpi_iort_dma_get_max_cpu_address());
+       dt_zone_dma_bits = fls64(of_dma_get_max_cpu_address(NULL));
+       zone_dma_bits = min3(32U, dt_zone_dma_bits, acpi_zone_dma_bits);
+       arm64_dma_phys_limit = max_zone_phys(zone_dma_bits);
        max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit);
 #endif
 #ifdef CONFIG_ZONE_DMA32
@@ -269,7 +281,7 @@ static void __init fdt_enforce_memory_region(void)
 
 void __init arm64_memblock_init(void)
 {
-       const s64 linear_region_size = BIT(vabits_actual - 1);
+       const s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual);
 
        /* Handle linux,usable-memory-range property */
        fdt_enforce_memory_region();
@@ -348,15 +360,18 @@ void __init arm64_memblock_init(void)
 
        if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
                extern u16 memstart_offset_seed;
-               u64 range = linear_region_size -
-                           (memblock_end_of_DRAM() - memblock_start_of_DRAM());
+               u64 mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
+               int parange = cpuid_feature_extract_unsigned_field(
+                                       mmfr0, ID_AA64MMFR0_PARANGE_SHIFT);
+               s64 range = linear_region_size -
+                           BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
 
                /*
                 * If the size of the linear region exceeds, by a sufficient
-                * margin, the size of the region that the available physical
-                * memory spans, randomize the linear region as well.
+                * margin, the size of the region that the physical memory can
+                * span, randomize the linear region as well.
                 */
-               if (memstart_offset_seed > 0 && range >= ARM64_MEMSTART_ALIGN) {
+               if (memstart_offset_seed > 0 && range >= (s64)ARM64_MEMSTART_ALIGN) {
                        range /= ARM64_MEMSTART_ALIGN;
                        memstart_addr -= ARM64_MEMSTART_ALIGN *
                                         ((range * memstart_offset_seed) >> 16);
@@ -367,7 +382,7 @@ void __init arm64_memblock_init(void)
         * Register the kernel text, kernel data, initrd, and initial
         * pagetables with memblock.
         */
-       memblock_reserve(__pa_symbol(_text), _end - _text);
+       memblock_reserve(__pa_symbol(_stext), _end - _stext);
        if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && phys_initrd_size) {
                /* the generic initrd code expects virtual addresses */
                initrd_start = __phys_to_virt(phys_initrd_start);
@@ -376,18 +391,11 @@ void __init arm64_memblock_init(void)
 
        early_init_fdt_scan_reserved_mem();
 
-       if (IS_ENABLED(CONFIG_ZONE_DMA)) {
-               zone_dma_bits = ARM64_ZONE_DMA_BITS;
-               arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS);
-       }
-
        if (IS_ENABLED(CONFIG_ZONE_DMA32))
                arm64_dma32_phys_limit = max_zone_phys(32);
        else
                arm64_dma32_phys_limit = PHYS_MASK + 1;
 
-       reserve_crashkernel();
-
        reserve_elfcorehdr();
 
        high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
@@ -427,6 +435,12 @@ void __init bootmem_init(void)
        sparse_init();
        zone_sizes_init(min, max);
 
+       /*
+        * request_standard_resources() depends on crashkernel's memory being
+        * reserved, so do it here.
+        */
+       reserve_crashkernel();
+
        memblock_dump_all();
 }