--- /dev/null
+From 14f966e79445015cd89d0fa0ceb6b33702e951b6 Mon Sep 17 00:00:00 2001
+From: Robert Jennings <rcj@linux.vnet.ibm.com>
+Date: Wed, 15 Apr 2009 05:55:32 +0000
+Subject: powerpc/pseries: CMO unused page hinting
+Patch-mainline: 2.6.31
+References: bnc#495091
+
+From: Robert Jennings <rcj@linux.vnet.ibm.com>
+
+commit 14f966e79445015cd89d0fa0ceb6b33702e951b6 upstream.
+
+Adds support for the "unused" page hint which can be used in shared
+memory partitions to flag pages not in use, which will then be stolen
+before active pages by the hypervisor when memory needs to be moved to
+LPARs in need of additional memory. Failure to mark pages as 'unused'
+makes the LPAR slower to give up unused memory to other partitions.
+
+This adds the kernel parameter 'cmo_free_hint' to disable this
+functionality.
+
+Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
+Signed-off-by: Robert Jennings <rcj@linux.vnet.ibm.com>
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/kernel-parameters.txt | 7 ++++
+ arch/powerpc/include/asm/page.h | 5 +++
+ arch/powerpc/platforms/pseries/lpar.c | 52 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 64 insertions(+)
+
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -458,6 +458,13 @@ and is between 256 and 4096 characters.
+ Also note the kernel might malfunction if you disable
+ some critical bits.
+
++ cmo_free_hint= [PPC] Format: { yes | no }
++ Specify whether pages are marked as being inactive
++ when they are freed. This is used in CMO environments
++ to determine OS memory pressure for page stealing by
++ a hypervisor.
++ Default: yes
++
+ code_bytes [IA32/X86_64] How many bytes of object code to print
+ in an oops report.
+ Range: 0 - 8192
+--- a/arch/powerpc/include/asm/page.h
++++ b/arch/powerpc/include/asm/page.h
+@@ -215,6 +215,11 @@ extern void copy_user_page(void *to, voi
+ struct page *p);
+ extern int page_is_ram(unsigned long pfn);
+
++#ifdef CONFIG_PPC_SMLPAR
++void arch_free_page(struct page *page, int order);
++#define HAVE_ARCH_FREE_PAGE
++#endif
++
+ struct vm_area_struct;
+
+ typedef struct page *pgtable_t;
+--- a/arch/powerpc/platforms/pseries/lpar.c
++++ b/arch/powerpc/platforms/pseries/lpar.c
+@@ -609,3 +609,55 @@ void __init hpte_init_lpar(void)
+ ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range;
+ ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear;
+ }
++
++#ifdef CONFIG_PPC_SMLPAR
++#define CMO_FREE_HINT_DEFAULT 1
++static int cmo_free_hint_flag = CMO_FREE_HINT_DEFAULT;
++
++static int __init cmo_free_hint(char *str)
++{
++ char *parm;
++ parm = strstrip(str);
++
++ if (strcasecmp(parm, "no") == 0 || strcasecmp(parm, "off") == 0) {
++ printk(KERN_INFO "cmo_free_hint: CMO free page hinting is not active.\n");
++ cmo_free_hint_flag = 0;
++ return 1;
++ }
++
++ cmo_free_hint_flag = 1;
++ printk(KERN_INFO "cmo_free_hint: CMO free page hinting is active.\n");
++
++ if (strcasecmp(parm, "yes") == 0 || strcasecmp(parm, "on") == 0)
++ return 1;
++
++ return 0;
++}
++
++__setup("cmo_free_hint=", cmo_free_hint);
++
++static void pSeries_set_page_state(struct page *page, int order,
++ unsigned long state)
++{
++ int i, j;
++ unsigned long cmo_page_sz, addr;
++
++ cmo_page_sz = cmo_get_page_size();
++ addr = __pa((unsigned long)page_address(page));
++
++ for (i = 0; i < (1 << order); i++, addr += PAGE_SIZE) {
++ for (j = 0; j < PAGE_SIZE; j += cmo_page_sz)
++ plpar_hcall_norets(H_PAGE_INIT, state, addr + j, 0);
++ }
++}
++
++void arch_free_page(struct page *page, int order)
++{
++ if (!cmo_free_hint_flag || !firmware_has_feature(FW_FEATURE_CMO))
++ return;
++
++ pSeries_set_page_state(page, order, H_PAGE_SET_UNUSED);
++}
++EXPORT_SYMBOL(arch_free_page);
++
++#endif