When CONFIG_FLATMEM enabled, STD/Hiberation will fail on YeeLoong
laptop, This patch fixes it:
if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will
return TRUE, but if the memory is not continuous, 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, and at last make STD/Hibernate fail when shrinking a too large
number of invalid memory.
the "invalid" memory here include the memory space we never used.
10000000-3fffffff
80000000-8fffffff
and also include the meory space we have mapped into pci space.
40000000-7fffffff : pci memory space
Here, we fix it via checking pfn is in the "System RAM" or not. and
Seems pfn_valid() is not called in assembly code, we move it to
"!__ASSEMBLY__" to ensure we can simply declare it via "extern int
pfn_valid(unsigned long)" without Compiling Error.
(This -v1 version incorporates feedback from Pavel Machek <pavel@ucw.cz>
and Sergei Shtylyov <sshtylyov@ru.mvista.com> and Ralf)
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
arch/mips/include/asm/page.h | 50 ++++++++++++++++++-----------------------
arch/mips/mm/page.c | 18 +++++++++++++++
2 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index f266295..dc28d0a 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -146,36 +146,9 @@ typedef struct { unsigned long pgprot; } pgprot_t;
*/
#define ptep_buddy(x) ((pte_t *)((unsigned long)(x) ^ sizeof(pte_t)))
-#endif /* !__ASSEMBLY__ */
-
-/*
- * __pa()/__va() should be used only during mem init.
- */
-#ifdef CONFIG_64BIT
-#define __pa(x)
\
-({ \
- unsigned long __x = (unsigned long)(x); \
- __x < CKSEG0 ? XPHYSADDR(__x) : CPHYSADDR(__x); \
-})
-#else
-#define __pa(x)
\
- ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
-#endif
-#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET -
PHYS_OFFSET))
-#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0))
-
-#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
-
#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; \
-})
+extern int pfn_valid(unsigned long);
#elif defined(CONFIG_SPARSEMEM)
@@ -194,6 +167,27 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#endif
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * __pa()/__va() should be used only during mem init.
+ */
+#ifdef CONFIG_64BIT
+#define __pa(x)
\
+({ \
+ unsigned long __x = (unsigned long)(x); \
+ __x < CKSEG0 ? XPHYSADDR(__x) : CPHYSADDR(__x); \
+})
+#else
+#define __pa(x)
\
+ ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
+#endif
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET -
PHYS_OFFSET))
+#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0))
+
+#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
+
#define virt_to_page(kaddr) pfn_to_page(PFN_DOWN(virt_to_phys(kaddr)))
#define virt_addr_valid(kaddr) pfn_valid(PFN_DOWN(virt_to_phys(kaddr)))
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
index f5c7375..203d805 100644
--- a/arch/mips/mm/page.c
+++ b/arch/mips/mm/page.c
@@ -689,3 +689,21 @@ void copy_page(void *to, void *from)
}
#endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
+
+#ifdef CONFIG_FLATMEM
+int 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) ||
+ (boot_mem_map.map[i].type == BOOT_MEM_ROM_DATA)) {
+ 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
|