powerpc/pseries: Add page coalescing support
authorBrian King <brking@linux.vnet.ibm.com>
Wed, 4 May 2011 06:01:20 +0000 (16:01 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 4 May 2011 06:02:21 +0000 (16:02 +1000)
Adds support for page coalescing, which is a feature on IBM Power servers
which allows for coalescing identical pages between logical partitions.
Hint text pages as coalesce candidates, since they are the most likely
pages to be able to be coalesced between partitions. This patch also
exports some page coalescing statistics available from firmware via
lparcfg.

[BenH: Moved a couple of things around to fix compile problems]

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/firmware.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/pSeries_reconfig.h
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/rtas.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/setup.c

index 4ef662e4a31d32139dbcdd2bc66286271495627a..3a6c586c4e40f3ec479271dabbc2c4ccc85cd0da 100644 (file)
@@ -47,6 +47,7 @@
 #define FW_FEATURE_BEAT                ASM_CONST(0x0000000001000000)
 #define FW_FEATURE_CMO         ASM_CONST(0x0000000002000000)
 #define FW_FEATURE_VPHN                ASM_CONST(0x0000000004000000)
+#define FW_FEATURE_XCMO                ASM_CONST(0x0000000008000000)
 
 #ifndef __ASSEMBLY__
 
@@ -60,7 +61,7 @@ enum {
                FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN |
                FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR |
                FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
-               FW_FEATURE_CMO | FW_FEATURE_VPHN,
+               FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO,
        FW_FEATURE_PSERIES_ALWAYS = 0,
        FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
        FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
index 8edec710cc6dab5449750995d09a53bd08cad270..852b8c1c09db72672136347c19f181d194cb8e47 100644 (file)
 #define H_ANDCOND              (1UL<<(63-33))
 #define H_ICACHE_INVALIDATE    (1UL<<(63-40))  /* icbi, etc.  (ignored for IO pages) */
 #define H_ICACHE_SYNCHRONIZE   (1UL<<(63-41))  /* dcbst, icbi, etc (ignored for IO pages */
+#define H_COALESCE_CAND        (1UL<<(63-42))  /* page is a good candidate for coalescing */
 #define H_ZERO_PAGE            (1UL<<(63-48))  /* zero the page before mapping (ignored for IO pages) */
 #define H_COPY_PAGE            (1UL<<(63-49))
 #define H_N                    (1UL<<(63-61))
 #define H_GET_MPP              0x2D4
 #define H_HOME_NODE_ASSOCIATIVITY 0x2EC
 #define H_BEST_ENERGY          0x2F4
+#define H_GET_MPP_X            0x314
 #define MAX_HCALL_OPCODE       H_BEST_ENERGY
 
 #ifndef __ASSEMBLY__
@@ -312,6 +314,16 @@ struct hvcall_mpp_data {
 
 int h_get_mpp(struct hvcall_mpp_data *);
 
+struct hvcall_mpp_x_data {
+       unsigned long coalesced_bytes;
+       unsigned long pool_coalesced_bytes;
+       unsigned long pool_purr_cycles;
+       unsigned long pool_spurr_cycles;
+       unsigned long reserved[3];
+};
+
+int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data);
+
 #ifdef CONFIG_PPC_PSERIES
 extern int CMO_PrPSP;
 extern int CMO_SecPSP;
index d4b4bfa26fb3515f535a3fb857ad67db877641c5..89d2f99c1bf4720d98bcd0ab091d1f9ff0fadfa8 100644 (file)
 extern int pSeries_reconfig_notifier_register(struct notifier_block *);
 extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
 extern struct blocking_notifier_head pSeries_reconfig_chain;
+/* Not the best place to put this, will be fixed when we move some
+ * of the rtas suspend-me stuff to pseries */
+extern void pSeries_coalesce_init(void);
 #else /* !CONFIG_PPC_PSERIES */
 static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
 {
        return 0;
 }
 static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
+static inline void pSeries_coalesce_init(void) { }
 #endif /* CONFIG_PPC_PSERIES */
 
+
 #endif /* __KERNEL__ */
 #endif /* _PPC64_PSERIES_RECONFIG_H */
index 301db65f05a180454a775a412edb60b0bba8959c..84daabe2fcbaf305ab8387b8ff0e5db00199b4e9 100644 (file)
@@ -132,34 +132,6 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v)
 /*
  * Methods used to fetch LPAR data when running on a pSeries platform.
  */
-/**
- * h_get_mpp
- * H_GET_MPP hcall returns info in 7 parms
- */
-int h_get_mpp(struct hvcall_mpp_data *mpp_data)
-{
-       int rc;
-       unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
-
-       rc = plpar_hcall9(H_GET_MPP, retbuf);
-
-       mpp_data->entitled_mem = retbuf[0];
-       mpp_data->mapped_mem = retbuf[1];
-
-       mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
-       mpp_data->pool_num = retbuf[2] & 0xffff;
-
-       mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff;
-       mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff;
-       mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff;
-
-       mpp_data->pool_size = retbuf[4];
-       mpp_data->loan_request = retbuf[5];
-       mpp_data->backing_mem = retbuf[6];
-
-       return rc;
-}
-EXPORT_SYMBOL(h_get_mpp);
 
 struct hvcall_ppp_data {
        u64     entitlement;
@@ -345,6 +317,30 @@ static void parse_mpp_data(struct seq_file *m)
        seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem);
 }
 
+/**
+ * parse_mpp_x_data
+ * Parse out data returned from h_get_mpp_x
+ */
+static void parse_mpp_x_data(struct seq_file *m)
+{
+       struct hvcall_mpp_x_data mpp_x_data;
+
+       if (!firmware_has_feature(FW_FEATURE_XCMO))
+               return;
+       if (h_get_mpp_x(&mpp_x_data))
+               return;
+
+       seq_printf(m, "coalesced_bytes=%ld\n", mpp_x_data.coalesced_bytes);
+
+       if (mpp_x_data.pool_coalesced_bytes)
+               seq_printf(m, "pool_coalesced_bytes=%ld\n",
+                          mpp_x_data.pool_coalesced_bytes);
+       if (mpp_x_data.pool_purr_cycles)
+               seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles);
+       if (mpp_x_data.pool_spurr_cycles)
+               seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles);
+}
+
 #define SPLPAR_CHARACTERISTICS_TOKEN 20
 #define SPLPAR_MAXLENGTH 1026*(sizeof(char))
 
@@ -520,6 +516,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
                parse_system_parameter_string(m);
                parse_ppp_data(m);
                parse_mpp_data(m);
+               parse_mpp_x_data(m);
                pseries_cmo_data(m);
                splpar_dispatch_data(m);
 
index 7839bd7bfd1587f9a621d3fe8dc876e3a0f0af19..c016033ba78dc30166ce6f7d8d41ad828075d87c 100644 (file)
@@ -700,8 +700,10 @@ static void __init early_cmdline_parse(void)
 #endif /* CONFIG_PCI_MSI */
 #ifdef CONFIG_PPC_SMLPAR
 #define OV5_CMO                        0x80    /* Cooperative Memory Overcommitment */
+#define OV5_XCMO                       0x40    /* Page Coalescing */
 #else
 #define OV5_CMO                        0x00
+#define OV5_XCMO                       0x00
 #endif
 #define OV5_TYPE1_AFFINITY     0x80    /* Type 1 NUMA affinity */
 
@@ -756,7 +758,7 @@ static unsigned char ibm_architecture_vec[] = {
        OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
        OV5_DONATE_DEDICATE_CPU | OV5_MSI,
        0,
-       OV5_CMO,
+       OV5_CMO | OV5_XCMO,
        OV5_TYPE1_AFFINITY,
        0,
        0,
index f48446635c8945290e1c44db800250039ca999a3..271ff6318eda483cb7ee2f77fce128fb86fe5a8e 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/time.h>
 #include <asm/mmu.h>
 #include <asm/topology.h>
+#include <asm/pSeries_reconfig.h>
 
 struct rtas_t rtas = {
        .lock = __ARCH_SPIN_LOCK_UNLOCKED
@@ -731,6 +732,7 @@ static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_w
 
        atomic_set(&data->error, rc);
        start_topology_update();
+       pSeries_coalesce_init();
 
        if (wake_when_done) {
                atomic_set(&data->done, 1);
index 6f0ed3aac77f1562b2dc0a72c4263db82ec096a1..39e6e0a7b2faf259db0f59e169f2fce9ab6fb1a0 100644 (file)
@@ -329,6 +329,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
        /* Make pHyp happy */
        if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU))
                hpte_r &= ~_PAGE_COHERENT;
+       if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N))
+               flags |= H_COALESCE_CAND;
 
        lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot);
        if (unlikely(lpar_rc == H_PTEG_FULL)) {
@@ -771,3 +773,47 @@ out:
        local_irq_restore(flags);
 }
 #endif
+
+/**
+ * h_get_mpp
+ * H_GET_MPP hcall returns info in 7 parms
+ */
+int h_get_mpp(struct hvcall_mpp_data *mpp_data)
+{
+       int rc;
+       unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+       rc = plpar_hcall9(H_GET_MPP, retbuf);
+
+       mpp_data->entitled_mem = retbuf[0];
+       mpp_data->mapped_mem = retbuf[1];
+
+       mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
+       mpp_data->pool_num = retbuf[2] & 0xffff;
+
+       mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff;
+       mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff;
+       mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff;
+
+       mpp_data->pool_size = retbuf[4];
+       mpp_data->loan_request = retbuf[5];
+       mpp_data->backing_mem = retbuf[6];
+
+       return rc;
+}
+EXPORT_SYMBOL(h_get_mpp);
+
+int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data)
+{
+       int rc;
+       unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 };
+
+       rc = plpar_hcall9(H_GET_MPP_X, retbuf);
+
+       mpp_x_data->coalesced_bytes = retbuf[0];
+       mpp_x_data->pool_coalesced_bytes = retbuf[1];
+       mpp_x_data->pool_purr_cycles = retbuf[2];
+       mpp_x_data->pool_spurr_cycles = retbuf[3];
+
+       return rc;
+}
index ab73ad2ff59dbc0d627fb8e9610397461ce1e7f4..1689adccc6d73402cccc5c27e7ee0d1c4446456c 100644 (file)
@@ -405,6 +405,16 @@ static int pseries_set_xdabr(unsigned long dabr)
 #define CMO_CHARACTERISTICS_TOKEN 44
 #define CMO_MAXLENGTH 1026
 
+void pSeries_coalesce_init(void)
+{
+       struct hvcall_mpp_x_data mpp_x_data;
+
+       if (firmware_has_feature(FW_FEATURE_CMO) && !h_get_mpp_x(&mpp_x_data))
+               powerpc_firmware_features |= FW_FEATURE_XCMO;
+       else
+               powerpc_firmware_features &= ~FW_FEATURE_XCMO;
+}
+
 /**
  * fw_cmo_feature_init - FW_FEATURE_CMO is not stored in ibm,hypertas-functions,
  * handle that here. (Stolen from parse_system_parameter_string)
@@ -474,6 +484,7 @@ void pSeries_cmo_feature_init(void)
                pr_debug("CMO enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP,
                         CMO_SecPSP);
                powerpc_firmware_features |= FW_FEATURE_CMO;
+               pSeries_coalesce_init();
        } else
                pr_debug("CMO not enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP,
                         CMO_SecPSP);