When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong laptop, This patch fix it: if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will return TRUE, but in reality, if the memory is not continuous, it should be false. for example: $ cat /proc/iomem | grep "System RAM" 00000000-0fffffff : System RAM 90000000-bfffffff : System RAM as we can see, it is not continuous, so, some of the memory is not valid but regarded as valid by pfn_valid(), and at last make STD/Hibernate fail when shrinking a too large number of invalid memory. Here, we fix it via checking pfn is in the "System RAM" or not, if yes, return TRUE. Signed-off-by: Wu Zhangjin <wuzhangjin@xxxxxxxxx> --- arch/mips/include/asm/page.h | 11 ++++------- arch/mips/mm/page.c | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index f266295..16903a6 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -168,13 +168,10 @@ typedef struct { unsigned long pgprot; } pgprot_t; #ifdef CONFIG_FLATMEM -#define pfn_valid(pfn) \ -({ \ - unsigned long __pfn = (pfn); \ - /* avoid <linux/bootmem.h> include hell */ \ - extern unsigned long min_low_pfn; \ - \ - __pfn >= min_low_pfn && __pfn < max_mapnr; \ +#define pfn_valid(pfn) \ +({ \ + extern int is_pfn_valid(unsigned long); \ + is_pfn_valid(pfn); \ }) #elif defined(CONFIG_SPARSEMEM) diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index f5c7375..48a4d2a 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -689,3 +689,20 @@ void copy_page(void *to, void *from) } #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */ + +#ifdef CONFIG_FLATMEM +int is_pfn_valid(unsigned long pfn) +{ + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type == BOOT_MEM_RAM) { + if ((pfn >= PFN_DOWN(boot_mem_map.map[i].addr)) && + ((pfn) <= (PFN_UP(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size)))) + return 1; + } + } + return 0; +} +#endif -- 1.6.2.1