From b8f3b15a7ba0a91de86547de8bbd5a633db03ab1 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Fri, 15 Mar 2019 16:31:33 +0000 Subject: MIPS: entry: Remove unneeded need_resched() loop Since the enabling and disabling of IRQs within preempt_schedule_irq() is contained in a need_resched() loop, we don't need the outer arch code loop. Note that commit a18815abcdfd ("Use preempt_schedule_irq.") initially removed the existing loop, but missed the final branch to restore_all. Commit cdaed73afb61 ("Fix preemption bug.") missed that and reintroduced the loop. Signed-off-by: Valentin Schneider Cc: Ralf Baechle Cc: Paul Burton Cc: James Hogan Cc: linux-mips@vger.kernel.org Signed-off-by: Paul Burton Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/entry.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index d7de8adcfcc8..5469d43b6966 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -58,15 +58,14 @@ resume_kernel: local_irq_disable lw t0, TI_PRE_COUNT($28) bnez t0, restore_all -need_resched: LONG_L t0, TI_FLAGS($28) andi t1, t0, _TIF_NEED_RESCHED beqz t1, restore_all LONG_L t0, PT_STATUS(sp) # Interrupts off? andi t0, 1 beqz t0, restore_all - jal preempt_schedule_irq - b need_resched + PTR_LA ra, restore_all + j preempt_schedule_irq #endif FEXPORT(ret_from_kernel_thread) -- cgit v1.2.3 From 9b6584e35f407a391de39938fd0b4fb29671924f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 5 Apr 2019 22:50:36 +0000 Subject: MIPS: jump_label: Use compact branches for >= r6 MIPSr6 introduced compact branches which have no delay slots. Make use of them for jump labels in order to avoid the need for a nop to fill the branch or jump delay slot, saving 4 bytes of code for each static branch. Signed-off-by: Paul Burton Cc: linux-mips@vger.kernel.org --- arch/mips/include/asm/jump_label.h | 12 +++++++++--- arch/mips/kernel/jump_label.c | 30 +++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 8 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h index df04449b261b..3185fd3220ec 100644 --- a/arch/mips/include/asm/jump_label.h +++ b/arch/mips/include/asm/jump_label.h @@ -11,6 +11,7 @@ #ifndef __ASSEMBLY__ #include +#include #define JUMP_LABEL_NOP_SIZE 4 @@ -21,9 +22,14 @@ #endif #ifdef CONFIG_CPU_MICROMIPS -#define B_INSN "b32" +# define B_INSN "b32" +# define J_INSN "j32" +#elif MIPS_ISA_REV >= 6 +# define B_INSN "bc" +# define J_INSN "bc" #else -#define B_INSN "b" +# define B_INSN "b" +# define J_INSN "j" #endif static __always_inline bool arch_static_branch(struct static_key *key, bool branch) @@ -42,7 +48,7 @@ l_yes: static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) { - asm_volatile_goto("1:\tj %l[l_yes]\n\t" + asm_volatile_goto("1:\t" J_INSN " %l[l_yes]\n\t" ".pushsection __jump_table, \"aw\"\n\t" WORD_INSN " 1b, %l[l_yes], %0\n\t" ".popsection\n\t" diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c index ab943927f97a..662c8db9f45b 100644 --- a/arch/mips/kernel/jump_label.c +++ b/arch/mips/kernel/jump_label.c @@ -40,18 +40,38 @@ void arch_jump_label_transform(struct jump_entry *e, { union mips_instruction *insn_p; union mips_instruction insn; + long offset; insn_p = (union mips_instruction *)msk_isa16_mode(e->code); - /* Jump only works within an aligned region its delay slot is in. */ - BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK)); - /* Target must have the right alignment and ISA must be preserved. */ BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT); if (type == JUMP_LABEL_JMP) { - insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op; - insn.j_format.target = e->target >> J_RANGE_SHIFT; + if (!IS_ENABLED(CONFIG_CPU_MICROMIPS) && MIPS_ISA_REV >= 6) { + offset = e->target - ((unsigned long)insn_p + 4); + offset >>= 2; + + /* + * The branch offset must fit in the instruction's 26 + * bit field. + */ + WARN_ON((offset >= BIT(25)) || + (offset < -(long)BIT(25))); + + insn.j_format.opcode = bc6_op; + insn.j_format.target = offset; + } else { + /* + * Jump only works within an aligned region its delay + * slot is in. + */ + WARN_ON((e->target & ~J_RANGE_MASK) != + ((e->code + 4) & ~J_RANGE_MASK)); + + insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op; + insn.j_format.target = e->target >> J_RANGE_SHIFT; + } } else { insn.word = 0; /* nop */ } -- cgit v1.2.3 From a703db3d5b4b43cb7e46b65a661471015cbcba57 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2019 01:47:37 +0300 Subject: mips: Make sure kernel .bss exists in boot mem pool Current MIPS platform code makes sure the kernel text, data and init sections are added to the boot memory map pool right after the arch-specific memory setup method has been executed. But for some reason the MIPS platform code skipped the kernel .bss section, which definitely should be in the boot mem pool as well in any case. Lets fix this just be adding the space between __bss_start and __bss_stop. Reviewed-by: Matt Redfearn Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 8d1dc6c71173..0ee033c44116 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -809,6 +809,9 @@ static void __init arch_mem_init(char **cmdline_p) arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT, PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT, BOOT_MEM_INIT_RAM); + arch_mem_addpart(PFN_DOWN(__pa_symbol(&__bss_start)) << PAGE_SHIFT, + PFN_UP(__pa_symbol(&__bss_stop)) << PAGE_SHIFT, + BOOT_MEM_RAM); pr_info("Determined physical RAM map:\n"); print_memory_map(); -- cgit v1.2.3 From 6ea3ba6fac31380af86339c37be095a672dd01bb Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2019 01:47:38 +0300 Subject: mips: Discard rudiments from bootmem_init There is a pointless code left in the bootmem_init() method since the bootmem allocator removal. First part resides the PFN ranges calculation loop. The conditional expressions and continue operator are useless there, since nothing is done after them. Second part is in RAM ranges installation loop. We can simplify the conditions cascade a bit without much of the logic redefinition, so to reduce the code length. In particular the end boundary value can be verified after the possible reduction to be below max_low_pfn. Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Matt Redfearn Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 0ee033c44116..53d93a727d1a 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -394,10 +394,7 @@ static void __init bootmem_init(void) min_low_pfn = ~0UL; max_low_pfn = 0; - /* - * Find the highest page frame number we have available - * and the lowest used RAM address - */ + /* Find the highest and lowest page frame numbers we have available. */ for (i = 0; i < boot_mem_map.nr_map; i++) { unsigned long start, end; @@ -427,13 +424,6 @@ static void __init bootmem_init(void) max_low_pfn = end; if (start < min_low_pfn) min_low_pfn = start; - if (end <= reserved_end) - continue; -#ifdef CONFIG_BLK_DEV_INITRD - /* Skip zones before initrd and initrd itself */ - if (initrd_end && end <= (unsigned long)PFN_UP(__pa(initrd_end))) - continue; -#endif } if (min_low_pfn >= max_low_pfn) @@ -474,6 +464,7 @@ static void __init bootmem_init(void) max_low_pfn = PFN_DOWN(HIGHMEM_START); } + /* Install all valid RAM ranges to the memblock memory region */ for (i = 0; i < boot_mem_map.nr_map; i++) { unsigned long start, end; @@ -481,21 +472,15 @@ static void __init bootmem_init(void) end = PFN_DOWN(boot_mem_map.map[i].addr + boot_mem_map.map[i].size); - if (start <= min_low_pfn) + if (start < min_low_pfn) start = min_low_pfn; - if (start >= end) - continue; - #ifndef CONFIG_HIGHMEM + /* Ignore highmem regions if highmem is unsupported */ if (end > max_low_pfn) end = max_low_pfn; - - /* - * ... finally, is the area going away? - */ +#endif if (end <= start) continue; -#endif memblock_add_node(PFN_PHYS(start), PFN_PHYS(end - start), 0); } -- cgit v1.2.3 From cf0c4876684d287b6fe72699598517ca9b827216 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2019 01:47:39 +0300 Subject: mips: Combine memblock init and memory reservation loops Before bootmem was completely removed from the kernel, the last loop in the bootmem_init() had been used to reserve the correspondingly marked regions, initialize sparsemem sections and to free the low memory pages, which then would be used for early memory allocations. After the bootmem removing patchset had been merged the loop was left to do the first two things only. But it didn't do them quite well. First of all it leaves the BOOT_MEM_INIT_RAM memory types unreserved, which is definitely bug (although it isn't noticeable due to being used by the kernel region only, which is fully marked as reserved). Secondly the reservation is supposed to be done for any memory including the high one. (I couldn't figure out why the highmem was ignored in the first place, since platforms and dts' may declare any memory region for reservation) Thirdly the reserved_end variable had been used here to not accidentally free memory occupied by kernel. Since we already reserved the corresponding region higher in this method there is no need in using the variable here anymore. Fourthly the sparsemem should be aware of all the memory types in the system including the ROM_DATA even if it is going to be reserved for the whole system uptime. Finally after all these notes are fixed the loop of memory reservation can be freely merged into the memory installation loop as it's done in this patch. Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Matt Redfearn Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 48 +++++++----------------------------------------- 1 file changed, 7 insertions(+), 41 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 53d93a727d1a..185e0e42e009 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -483,55 +483,21 @@ static void __init bootmem_init(void) continue; memblock_add_node(PFN_PHYS(start), PFN_PHYS(end - start), 0); - } - - /* - * Register fully available low RAM pages with the bootmem allocator. - */ - for (i = 0; i < boot_mem_map.nr_map; i++) { - unsigned long start, end, size; - - start = PFN_UP(boot_mem_map.map[i].addr); - end = PFN_DOWN(boot_mem_map.map[i].addr - + boot_mem_map.map[i].size); - /* - * Reserve usable memory. - */ + /* Reserve any memory except the ordinary RAM ranges. */ switch (boot_mem_map.map[i].type) { case BOOT_MEM_RAM: break; - case BOOT_MEM_INIT_RAM: - memory_present(0, start, end); - continue; - default: - /* Not usable memory */ - if (start > min_low_pfn && end < max_low_pfn) - memblock_reserve(boot_mem_map.map[i].addr, - boot_mem_map.map[i].size); - - continue; + default: /* Reserve the rest of the memory types at boot time */ + memblock_reserve(PFN_PHYS(start), PFN_PHYS(end - start)); + break; } /* - * We are rounding up the start address of usable memory - * and at the end of the usable range downwards. - */ - if (start >= max_low_pfn) - continue; - if (start < reserved_end) - start = reserved_end; - if (end > max_low_pfn) - end = max_low_pfn; - - /* - * ... finally, is the area going away? + * In any case the added to the memblock memory regions + * (highmem/lowmem, available/reserved, etc) are considered + * as present, so inform sparsemem about them. */ - if (end <= start) - continue; - size = end - start; - - /* Register lowmem ranges */ memory_present(0, start, end); } -- cgit v1.2.3 From f995adb0ac5bcfa0d396ba7706aab420c7a6fec2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 30 Apr 2019 22:53:30 +0000 Subject: MIPS: Use memblock_phys_alloc() for exception vector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allocate the exception vector using memblock_phys_alloc() which gives us a physical address, rather than the previous convoluted setup which obtained a virtual address using memblock_alloc(), converted it to a physical address & then back to a virtual address. Signed-off-by: Paul Burton Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Serge Semin Tested-by: Serge Semin Cc: linux-mips@vger.kernel.org --- arch/mips/kernel/traps.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 98ca55d62201..00f44b16385e 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2292,9 +2292,8 @@ void __init trap_init(void) unsigned long size = 0x200 + VECTORSPACING*64; phys_addr_t ebase_pa; - ebase = (unsigned long) - memblock_alloc(size, 1 << fls(size)); - if (!ebase) + ebase_pa = memblock_phys_alloc(size, 1 << fls(size)); + if (!ebase_pa) panic("%s: Failed to allocate %lu bytes align=0x%x\n", __func__, size, 1 << fls(size)); @@ -2309,9 +2308,10 @@ void __init trap_init(void) * EVA is special though as it allows segments to be rearranged * and to become uncached during cache error handling. */ - ebase_pa = __pa(ebase); if (!IS_ENABLED(CONFIG_EVA) && !WARN_ON(ebase_pa >= 0x20000000)) ebase = CKSEG0ADDR(ebase_pa); + else + ebase = (unsigned long)phys_to_virt(ebase_pa); } else { ebase = CAC_BASE; -- cgit v1.2.3 From 172dcd935c34b022729f45a7bbaae5cc05231533 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 30 Apr 2019 22:53:30 +0000 Subject: MIPS: Always allocate exception vector for MIPSr2+ Currently we allocate the exception vector on systems which use a vectored interrupt mode, but otherwise attempt to reuse whatever exception vector the bootloader uses. This can be problematic for a number of reasons: 1) The memory isn't properly marked reserved in the memblock allocator. We've relied on the fact that EBase is generally in the memory below the kernel image which we don't free, but this is about to change. 2) Recent versions of U-Boot place their exception vector high in kseg0, in memory which isn't protected by being lower than the kernel anyway & can end up being clobbered. 3) We are unnecessarily reliant upon there being memory at the address EBase points to upon entry to the kernel. This is often the case, but if the bootloader doesn't configure EBase & leaves it with its default value then we rely upon there being memory at physical address 0 for no good reason. Improve this situation by allocating the exception vector in all cases when running on MIPSr2 or higher, and reserving the memory for MIPSr1 or lower. This ensures we don't clobber the exception vector in any configuration, and for MIPSr2 & higher removes the need for memory at physical address 0. Signed-off-by: Paul Burton Reviewed-by: Serge Semin Tested-by: Serge Semin Cc: linux-mips@vger.kernel.org --- arch/mips/kernel/traps.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 00f44b16385e..9b565ed51662 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2284,18 +2284,27 @@ void __init trap_init(void) extern char except_vec3_generic; extern char except_vec4; extern char except_vec3_r4000; - unsigned long i; + unsigned long i, vec_size; + phys_addr_t ebase_pa; check_wait(); - if (cpu_has_veic || cpu_has_vint) { - unsigned long size = 0x200 + VECTORSPACING*64; - phys_addr_t ebase_pa; + if (!cpu_has_mips_r2_r6) { + ebase = CAC_BASE; + ebase_pa = virt_to_phys((void *)ebase); + vec_size = 0x400; + + memblock_reserve(ebase_pa, vec_size); + } else { + if (cpu_has_veic || cpu_has_vint) + vec_size = 0x200 + VECTORSPACING*64; + else + vec_size = PAGE_SIZE; - ebase_pa = memblock_phys_alloc(size, 1 << fls(size)); + ebase_pa = memblock_phys_alloc(vec_size, 1 << fls(vec_size)); if (!ebase_pa) panic("%s: Failed to allocate %lu bytes align=0x%x\n", - __func__, size, 1 << fls(size)); + __func__, vec_size, 1 << fls(vec_size)); /* * Try to ensure ebase resides in KSeg0 if possible. @@ -2312,20 +2321,6 @@ void __init trap_init(void) ebase = CKSEG0ADDR(ebase_pa); else ebase = (unsigned long)phys_to_virt(ebase_pa); - } else { - ebase = CAC_BASE; - - if (cpu_has_mips_r2_r6) { - if (cpu_has_ebase_wg) { -#ifdef CONFIG_64BIT - ebase = (read_c0_ebase_64() & ~0xfff); -#else - ebase = (read_c0_ebase() & ~0xfff); -#endif - } else { - ebase += (read_c0_ebase() & 0x3ffff000); - } - } } if (cpu_has_mmips) { -- cgit v1.2.3 From 783454e2bc7ce491b5cd50154433cde993bfd849 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 30 Apr 2019 22:53:31 +0000 Subject: MIPS: Sync icache for whole exception vector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than performing cache flushing for a fixed 0x400 bytes, use the actual size of the vector in order to ensure we cover all emitted code on systems that make use of vectored interrupts. Signed-off-by: Paul Burton Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Serge Semin Tested-by: Serge Semin Cc: linux-mips@vger.kernel.org --- arch/mips/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 9b565ed51662..2775190adbe7 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2454,7 +2454,7 @@ void __init trap_init(void) else set_handler(0x080, &except_vec3_generic, 0x80); - local_flush_icache_range(ebase, ebase + 0x400); + local_flush_icache_range(ebase, ebase + vec_size); sort_extable(__start___dbe_table, __stop___dbe_table); -- cgit v1.2.3 From de56d4c1da3e68f0ca468a55f6677bef3cee6e10 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 30 Apr 2019 22:53:31 +0000 Subject: MIPS: Remove duplicate EBase configuration Clean up our configuration of the EBase register by making configure_exception_vector() write to it unconditionally on systems implementing MIPSr2 or higher, and removing the duplicate code in per_cpu_trap_init(). The latter would have duplicated work on systems with vectored interrupts, and didn't set BEV for safety like the configure_exception_vector() version of the code does. Signed-off-by: Paul Burton Reviewed-by: Serge Semin Tested-by: Serge Semin Cc: linux-mips@vger.kernel.org --- arch/mips/kernel/traps.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 2775190adbe7..c52766a5b85f 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2151,7 +2151,7 @@ static void configure_hwrena(void) static void configure_exception_vector(void) { - if (cpu_has_veic || cpu_has_vint) { + if (cpu_has_mips_r2_r6) { unsigned long sr = set_c0_status(ST0_BEV); /* If available, use WG to set top bits of EBASE */ if (cpu_has_ebase_wg) { @@ -2163,6 +2163,8 @@ static void configure_exception_vector(void) } write_c0_ebase(ebase); write_c0_status(sr); + } + if (cpu_has_veic || cpu_has_vint) { /* Setting vector spacing enables EI/VI mode */ change_c0_intctl(0x3e0, VECTORSPACING); } @@ -2193,22 +2195,6 @@ void per_cpu_trap_init(bool is_boot_cpu) * o read IntCtl.IPFDC to determine the fast debug channel interrupt */ if (cpu_has_mips_r2_r6) { - /* - * We shouldn't trust a secondary core has a sane EBASE register - * so use the one calculated by the boot CPU. - */ - if (!is_boot_cpu) { - /* If available, use WG to set top bits of EBASE */ - if (cpu_has_ebase_wg) { -#ifdef CONFIG_64BIT - write_c0_ebase_64(ebase | MIPS_EBASE_WG); -#else - write_c0_ebase(ebase | MIPS_EBASE_WG); -#endif - } - write_c0_ebase(ebase); - } - cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7; cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7; -- cgit v1.2.3 From b93ddc4f9156205eb3c8df6ad35a37be3fa4e31e Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2019 01:47:40 +0300 Subject: mips: Reserve memory for the kernel image resources The reserved_end variable had been used by the bootmem_init() code to find a lowest limit of memory available for memmap blob. The original code just tried to find a free memory space higher than kernel was placed. This limitation seems justified for the memmap ragion search process, but I can't see any obvious reason to reserve the unused space below kernel seeing some platforms place it much higher than standard 1MB. Moreover the RELOCATION config enables it to be loaded at any memory address. So lets reserve the memory occupied by the kernel only, leaving the region below being free for allocations. After doing this we can now discard the code freeing a space between kernel _text and VMLINUX_LOAD_ADDRESS symbols since it's going to be free anyway (unless marked as reserved by platforms). Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Matt Redfearn Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 185e0e42e009..f71a7d32a687 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -371,7 +371,6 @@ static void __init bootmem_init(void) static void __init bootmem_init(void) { - unsigned long reserved_end; phys_addr_t ramstart = PHYS_ADDR_MAX; int i; @@ -382,10 +381,10 @@ static void __init bootmem_init(void) * will reserve the area used for the initrd. */ init_initrd(); - reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end)); - memblock_reserve(PHYS_OFFSET, - (reserved_end << PAGE_SHIFT) - PHYS_OFFSET); + /* Reserve memory occupied by kernel. */ + memblock_reserve(__pa_symbol(&_text), + __pa_symbol(&_end) - __pa_symbol(&_text)); /* * max_low_pfn is not a number of pages. The number of pages @@ -501,29 +500,6 @@ static void __init bootmem_init(void) memory_present(0, start, end); } -#ifdef CONFIG_RELOCATABLE - /* - * The kernel reserves all memory below its _end symbol as bootmem, - * but the kernel may now be at a much higher address. The memory - * between the original and new locations may be returned to the system. - */ - if (__pa_symbol(_text) > __pa_symbol(VMLINUX_LOAD_ADDRESS)) { - unsigned long offset; - extern void show_kernel_relocation(const char *level); - - offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS); - memblock_free(__pa_symbol(VMLINUX_LOAD_ADDRESS), offset); - -#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO) - /* - * This information is necessary when debugging the kernel - * But is a security vulnerability otherwise! - */ - show_kernel_relocation(KERN_INFO); -#endif - } -#endif - /* * Reserve initrd memory if needed. */ -- cgit v1.2.3 From eadb6925efeb0c254d17e1da9bb730d2add5613d Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2019 01:47:41 +0300 Subject: mips: Discard post-CMA-init foreach loop Really the loop is pointless, since it walks over memblock-reserved memory regions and mark them as reserved in memblock. Before bootmem was removed from the kernel, this loop had been used to map the memory reserved by CMA into the legacy bootmem allocator. But now the early memory allocator is memblock, which is used by CMA for reservation, so we don't need any mapping anymore. Reviewed-by: Matt Redfearn Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f71a7d32a687..2ae6b02b948f 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -708,7 +708,6 @@ static void __init request_crashkernel(struct resource *res) */ static void __init arch_mem_init(char **cmdline_p) { - struct memblock_region *reg; extern void plat_mem_setup(void); /* @@ -814,10 +813,6 @@ static void __init arch_mem_init(char **cmdline_p) plat_swiotlb_setup(); dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); - /* Tell bootmem about cma reserved memblock section */ - for_each_memblock(reserved, reg) - if (reg->size != 0) - memblock_reserve(reg->base, reg->size); reserve_bootmem_region(__pa_symbol(&__nosave_begin), __pa_symbol(&__nosave_end)); /* Reserve for hibernation */ -- cgit v1.2.3 From 4e50a35de4ccc834dbc32c664fb068f4c24cfebf Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2019 01:47:42 +0300 Subject: mips: Use memblock to reserve the __nosave memory range Originally before legacy bootmem was removed, the memory for the range was correctly reserved by reserve_bootmem_region(). But since memblock has been selected for early memory allocation the function can be utilized only after paging is fully initialized (as it is done by memblock_free_all() function). So calling it from arch_mem_init() method is prone to errors, and at this stage we need to reserve the memory in the memblock allocator. Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Matt Redfearn Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 2ae6b02b948f..3a5140943f54 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -814,8 +814,9 @@ static void __init arch_mem_init(char **cmdline_p) dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); - reserve_bootmem_region(__pa_symbol(&__nosave_begin), - __pa_symbol(&__nosave_end)); /* Reserve for hibernation */ + /* Reserve for hibernation. */ + memblock_reserve(__pa_symbol(&__nosave_begin), + __pa_symbol(&__nosave_end) - __pa_symbol(&__nosave_begin)); } static void __init resource_init(void) -- cgit v1.2.3 From 9b9a59db84812d326af41a3802c63f1f95d81016 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Wed, 24 Apr 2019 01:47:43 +0300 Subject: mips: Add reserve-nomap memory type support It might be necessary to prevent the virtual mapping creation for a requested memory region. For instance there is a "no-map" property indicating exactly this feature. In this case we need to not only reserve the specified region by pretending it doesn't exist in the memory space, but completely remove the range from system just by removing it from memblock. The same way it's done in default early_init_dt_reserve_memory_arch() method. Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Matt Redfearn Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/include/asm/bootinfo.h | 1 + arch/mips/kernel/prom.c | 4 +++- arch/mips/kernel/setup.c | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index a301a8f4bc66..235bc2f52113 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -92,6 +92,7 @@ extern unsigned long mips_machtype; #define BOOT_MEM_ROM_DATA 2 #define BOOT_MEM_RESERVED 3 #define BOOT_MEM_INIT_RAM 4 +#define BOOT_MEM_NOMAP 5 /* * A memory map that's built upon what was determined diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 93b8e0b4332f..437a174e3ef9 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -47,7 +47,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) int __init early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size, bool nomap) { - add_memory_region(base, size, BOOT_MEM_RESERVED); + add_memory_region(base, size, + nomap ? BOOT_MEM_NOMAP : BOOT_MEM_RESERVED); + return 0; } diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 3a5140943f54..2a1b2e7a1bc9 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -178,6 +178,7 @@ static bool __init __maybe_unused memory_region_available(phys_addr_t start, in_ram = true; break; case BOOT_MEM_RESERVED: + case BOOT_MEM_NOMAP: if ((start >= start_ && start < end_) || (start < start_ && start + size >= start_)) free = false; @@ -213,6 +214,9 @@ static void __init print_memory_map(void) case BOOT_MEM_RESERVED: printk(KERN_CONT "(reserved)\n"); break; + case BOOT_MEM_NOMAP: + printk(KERN_CONT "(nomap)\n"); + break; default: printk(KERN_CONT "type %lu\n", boot_mem_map.map[i].type); break; @@ -487,6 +491,9 @@ static void __init bootmem_init(void) switch (boot_mem_map.map[i].type) { case BOOT_MEM_RAM: break; + case BOOT_MEM_NOMAP: /* Discard the range from the system. */ + memblock_remove(PFN_PHYS(start), PFN_PHYS(end - start)); + continue; default: /* Reserve the rest of the memory types at boot time */ memblock_reserve(PFN_PHYS(start), PFN_PHYS(end - start)); break; @@ -861,6 +868,7 @@ static void __init resource_init(void) res->flags |= IORESOURCE_SYSRAM; break; case BOOT_MEM_RESERVED: + case BOOT_MEM_NOMAP: default: res->name = "reserved"; } -- cgit v1.2.3 From 30c8f4e411fb76f752a193bd945d4b9ef06c2d87 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Fri, 3 May 2019 20:50:37 +0300 Subject: mips: Dump memblock regions for debugging It is useful to have the whole memblock memory space printed to console when basic memlock initializations are done. It can be performed by ready-to-use method memblock_dump_all(), which prints the available and reserved memory spaces if memblock=debug kernel parameter is specified. Lets call it at the very end of arch_mem_init() function, when all memblock memory and reserved regions are defined, but before any serious allocation is performed. Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: Serge Semin Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 2a1b2e7a1bc9..ca493fdf69b0 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -824,6 +824,8 @@ static void __init arch_mem_init(char **cmdline_p) /* Reserve for hibernation. */ memblock_reserve(__pa_symbol(&__nosave_begin), __pa_symbol(&__nosave_end) - __pa_symbol(&__nosave_begin)); + + memblock_dump_all(); } static void __init resource_init(void) -- cgit v1.2.3 From 2f5bd0367e7a9e5f5a150500e016a9cb7042803b Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Fri, 3 May 2019 20:50:38 +0300 Subject: mips: Perform early low memory test memblock subsystem provides a method to optionally test the passed memory region in case if it was requested via special kernel boot argument. Lets add the function at the bottom of the arch_mem_init() method. Testing at this point in the boot sequence should be safe since all critical areas are now reserved and a minimum of allocations have been done. Reviewed-by: Matt Redfearn Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: Serge Semin Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index ca493fdf69b0..fbd216b4e929 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -826,6 +826,8 @@ static void __init arch_mem_init(char **cmdline_p) __pa_symbol(&__nosave_end) - __pa_symbol(&__nosave_begin)); memblock_dump_all(); + + early_memtest(PFN_PHYS(min_low_pfn), PFN_PHYS(max_low_pfn)); } static void __init resource_init(void) -- cgit v1.2.3 From 93fa5b280761a4dbb14c5330f260380385ab2b49 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Fri, 3 May 2019 20:50:40 +0300 Subject: mips: Make sure dt memory regions are valid There are situations when memory regions coming from dts may be too big for the platform physical address space. This especially concerns XPA-capable systems. Bootloader may determine more than 4GB memory available and pass it to the kernel over dts memory node, while kernel is built without XPA/64BIT support. In this case the region may either simply be truncated by add_memory_region() method or by u64->phys_addr_t type casting. But in worst case the method can even drop the memory region if it exceeds PHYS_ADDR_MAX size. So lets make sure the retrieved from dts memory regions are valid, and if some of them aren't, just manually truncate them with a warning printed out. Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: Serge Semin Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/prom.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 437a174e3ef9..28bf01961bb2 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -41,7 +41,19 @@ char *mips_get_machine_name(void) #ifdef CONFIG_USE_OF void __init early_init_dt_add_memory_arch(u64 base, u64 size) { - return add_memory_region(base, size, BOOT_MEM_RAM); + if (base >= PHYS_ADDR_MAX) { + pr_warn("Trying to add an invalid memory region, skipped\n"); + return; + } + + /* Truncate the passed memory region instead of type casting */ + if (base + size - 1 >= PHYS_ADDR_MAX || base + size < base) { + pr_warn("Truncate memory region %llx @ %llx to size %llx\n", + size, base, PHYS_ADDR_MAX - base); + size = PHYS_ADDR_MAX - base; + } + + add_memory_region(base, size, BOOT_MEM_RAM); } int __init early_init_dt_reserve_memory_arch(phys_addr_t base, -- cgit v1.2.3 From 3751cbda8f223549d7ea28803cbec8ac87e43ed2 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Fri, 3 May 2019 20:50:41 +0300 Subject: mips: Manually call fdt_init_reserved_mem() method Since memblock-patchset was introduced the reserved-memory nodes are supported being declared in dt-files. So these nodes are actually parsed during the arch setup procedure when the early_init_fdt_scan_reserved_mem() method is called. But due to the arch-specific boot mem_map container utilization we need to manually call the fdt_init_reserved_mem() method after all the available and reserved memory has been moved to memblock. The first function call performed before bootmem_init() by the early_init_fdt_scan_reserved_mem() routine fails due to the lack of any memblock memory regions to allocate from at that stage. Signed-off-by: Serge Semin Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: Greg Kroah-Hartman Cc: Thomas Bogendoerfer Cc: Huacai Chen Cc: Stefan Agner Cc: Stephen Rothwell Cc: Alexandre Belloni Cc: Juergen Gross Cc: Serge Semin Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/kernel/setup.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index fbd216b4e929..ab349d2381c3 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -825,6 +826,8 @@ static void __init arch_mem_init(char **cmdline_p) memblock_reserve(__pa_symbol(&__nosave_begin), __pa_symbol(&__nosave_end) - __pa_symbol(&__nosave_begin)); + fdt_init_reserved_mem(); + memblock_dump_all(); early_memtest(PFN_PHYS(min_low_pfn), PFN_PHYS(max_low_pfn)); -- cgit v1.2.3