aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2016-09-02 10:17:31 -0400
committerRalf Baechle <ralf@linux-mips.org>2016-09-29 12:59:49 -0400
commit058effe7fdc5776b017356f690976a857eea473f (patch)
treefb493ec17acf848dcdcb2d6d4e6a09a615ef3035
parent305723ab439e14debc1d339aa04e835d488b8253 (diff)
MIPS: Fix detection of unsupported highmem with cache aliases
The paging_init() function contains code which detects that highmem is in use but unsupported due to dcache aliasing. However this code was ineffective because it was being run before the caches are probed, meaning that cpu_has_dc_aliases would always evaluate to false (unless a platform overrides it to a compile-time constant) and the detection of the unsupported case is never triggered. The kernel would then go on to attempt to use highmem & either hit coherency issues or trigger the BUG_ON in flush_kernel_dcache_page(). Fix this by running paging_init() later than cpu_cache_init(), such that the cpu_has_dc_aliases macro will evaluate correctly & the unsupported highmem case will be detected successfully. This then leads to a formerly hidden issue in that mem_init_free_highmem() will attempt to free all highmem pages, even though we're avoiding use of them & don't have valid page structs for them. This leads to an invalid pointer dereference & a TLB exception. Avoid this by skipping the loop in mem_init_free_highmem() if cpu_has_dc_aliases evaluates true. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: Rabin Vincent <rabinv@axis.com> Cc: Matt Redfearn <matt.redfearn@imgtec.com> Cc: Jerome Marchand <jmarchan@redhat.com> Cc: Alexander Sverdlin <alexander.sverdlin@gmail.com> Cc: Aurelien Jarno <aurelien@aurel32.net> Cc: Jaedon Shin <jaedon.shin@gmail.com> Cc: Toshi Kani <toshi.kani@hpe.com> Cc: James Hogan <james.hogan@imgtec.com> Cc: Sergey Ryazanov <ryazanov.s.a@gmail.com> Cc: Jonas Gorski <jogo@openwrt.org> Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14184/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/kernel/setup.c2
-rw-r--r--arch/mips/mm/init.c3
2 files changed, 4 insertions, 1 deletions
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 3be0e6ba2797..0d57909d9026 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -764,7 +764,6 @@ static void __init arch_mem_init(char **cmdline_p)
764 device_tree_init(); 764 device_tree_init();
765 sparse_init(); 765 sparse_init();
766 plat_swiotlb_setup(); 766 plat_swiotlb_setup();
767 paging_init();
768 767
769 dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); 768 dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
770 /* Tell bootmem about cma reserved memblock section */ 769 /* Tell bootmem about cma reserved memblock section */
@@ -877,6 +876,7 @@ void __init setup_arch(char **cmdline_p)
877 prefill_possible_map(); 876 prefill_possible_map();
878 877
879 cpu_cache_init(); 878 cpu_cache_init();
879 paging_init();
880} 880}
881 881
882unsigned long kernelsp[NR_CPUS]; 882unsigned long kernelsp[NR_CPUS];
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 2c3749d98f04..72f7478ee068 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -440,6 +440,9 @@ static inline void mem_init_free_highmem(void)
440#ifdef CONFIG_HIGHMEM 440#ifdef CONFIG_HIGHMEM
441 unsigned long tmp; 441 unsigned long tmp;
442 442
443 if (cpu_has_dc_aliases)
444 return;
445
443 for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { 446 for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
444 struct page *page = pfn_to_page(tmp); 447 struct page *page = pfn_to_page(tmp);
445 448