From b6da0ffb09ad4468e6749488909f04f1efac5de3 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sun, 30 May 2010 00:32:51 -0700 Subject: MIPS: pfn_valid() is broken on low memory HIGHMEM systems pfn_valid() compares the PFN to max_mapnr: __pfn >= min_low_pfn && __pfn < max_mapnr; On HIGHMEM kernels, highend_pfn is used to set the value of max_mapnr. Unfortunately, highend_pfn is left at zero if the system does not actually have enough RAM to reach into the HIGHMEM range. This causes pfn_valid() to always return false, and when debug checks are enabled the kernel will fail catastrophically: Memory: 22432k/32768k available (2249k kernel code, 10336k reserved, 653k data, 1352k init, 0k highmem) NR_IRQS:128 kfree_debugcheck: out of range ptr 81c02900h. Kernel bug detected[#1]: Cpu 0 $ 0 : 00000000 10008400 00000034 00000000 $ 4 : 8003e160 802a0000 8003e160 00000000 $ 8 : 00000000 0000003e 00000747 00000747 ... On such a configuration, max_low_pfn should be used to set max_mapnr. This was seen on 2.6.34. Signed-off-by: Kevin Cernekee To: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1992/ Signed-off-by: Ralf Baechle --- arch/mips/mm/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/mm/init.c') diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 1aadeb42c5a5..11689e1a2924 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -368,7 +368,7 @@ void __init mem_init(void) #ifdef CONFIG_DISCONTIGMEM #error "CONFIG_HIGHMEM and CONFIG_DISCONTIGMEM dont work together yet" #endif - max_mapnr = highend_pfn; + max_mapnr = highend_pfn ? highend_pfn : max_low_pfn; #else max_mapnr = max_low_pfn; #endif -- cgit v1.2.1 From 464fd83e841a16f4ea1325b33eb08170ef5cd1f4 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Wed, 5 Jan 2011 23:31:30 -0800 Subject: MIPS: Limit fixrange_init() to the FIXMAP region fixrange_init() allocates page tables for all addresses higher than FIXADDR_TOP. On processors that override the default FIXADDR_TOP address of 0xfffe_0000, this can consume up to 4 pages (1 page per 4MB) for pgd's that are never used. Signed-off-by: Kevin Cernekee Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1980/ Signed-off-by: Ralf Baechle --- arch/mips/mm/init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/mips/mm/init.c') diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 11689e1a2924..b7ebc4fa89bc 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -277,11 +277,11 @@ void __init fixrange_init(unsigned long start, unsigned long end, k = __pmd_offset(vaddr); pgd = pgd_base + i; - for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { + for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) { pud = (pud_t *)pgd; - for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) { + for ( ; (j < PTRS_PER_PUD) && (vaddr < end); pud++, j++) { pmd = (pmd_t *)pud; - for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { + for (; (k < PTRS_PER_PMD) && (vaddr < end); pmd++, k++) { if (pmd_none(*pmd)) { pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); set_pmd(pmd, __pmd((unsigned long)pte)); -- cgit v1.2.1