aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2011-05-04 02:01:20 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-05-04 02:02:21 -0400
commit9ee820fa005254dfc816330f6654f14dcb2beee1 (patch)
tree1d36b17ec6a4c56dd24f9be2f7f31e6321040ed0 /arch/powerpc
parent7707e4110e5692fe85e7e6c471c9bb2a9254d313 (diff)
powerpc/pseries: Add page coalescing support
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>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/firmware.h3
-rw-r--r--arch/powerpc/include/asm/hvcall.h12
-rw-r--r--arch/powerpc/include/asm/pSeries_reconfig.h5
-rw-r--r--arch/powerpc/kernel/lparcfg.c53
-rw-r--r--arch/powerpc/kernel/prom_init.c4
-rw-r--r--arch/powerpc/kernel/rtas.c2
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c46
-rw-r--r--arch/powerpc/platforms/pseries/setup.c11
8 files changed, 106 insertions, 30 deletions
diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h
index 4ef662e4a31d..3a6c586c4e40 100644
--- a/arch/powerpc/include/asm/firmware.h
+++ b/arch/powerpc/include/asm/firmware.h
@@ -47,6 +47,7 @@
47#define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000) 47#define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000)
48#define FW_FEATURE_CMO ASM_CONST(0x0000000002000000) 48#define FW_FEATURE_CMO ASM_CONST(0x0000000002000000)
49#define FW_FEATURE_VPHN ASM_CONST(0x0000000004000000) 49#define FW_FEATURE_VPHN ASM_CONST(0x0000000004000000)
50#define FW_FEATURE_XCMO ASM_CONST(0x0000000008000000)
50 51
51#ifndef __ASSEMBLY__ 52#ifndef __ASSEMBLY__
52 53
@@ -60,7 +61,7 @@ enum {
60 FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN | 61 FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN |
61 FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR | 62 FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR |
62 FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | 63 FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
63 FW_FEATURE_CMO | FW_FEATURE_VPHN, 64 FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO,
64 FW_FEATURE_PSERIES_ALWAYS = 0, 65 FW_FEATURE_PSERIES_ALWAYS = 0,
65 FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, 66 FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
66 FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, 67 FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 8edec710cc6d..852b8c1c09db 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -102,6 +102,7 @@
102#define H_ANDCOND (1UL<<(63-33)) 102#define H_ANDCOND (1UL<<(63-33))
103#define H_ICACHE_INVALIDATE (1UL<<(63-40)) /* icbi, etc. (ignored for IO pages) */ 103#define H_ICACHE_INVALIDATE (1UL<<(63-40)) /* icbi, etc. (ignored for IO pages) */
104#define H_ICACHE_SYNCHRONIZE (1UL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */ 104#define H_ICACHE_SYNCHRONIZE (1UL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */
105#define H_COALESCE_CAND (1UL<<(63-42)) /* page is a good candidate for coalescing */
105#define H_ZERO_PAGE (1UL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */ 106#define H_ZERO_PAGE (1UL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */
106#define H_COPY_PAGE (1UL<<(63-49)) 107#define H_COPY_PAGE (1UL<<(63-49))
107#define H_N (1UL<<(63-61)) 108#define H_N (1UL<<(63-61))
@@ -234,6 +235,7 @@
234#define H_GET_MPP 0x2D4 235#define H_GET_MPP 0x2D4
235#define H_HOME_NODE_ASSOCIATIVITY 0x2EC 236#define H_HOME_NODE_ASSOCIATIVITY 0x2EC
236#define H_BEST_ENERGY 0x2F4 237#define H_BEST_ENERGY 0x2F4
238#define H_GET_MPP_X 0x314
237#define MAX_HCALL_OPCODE H_BEST_ENERGY 239#define MAX_HCALL_OPCODE H_BEST_ENERGY
238 240
239#ifndef __ASSEMBLY__ 241#ifndef __ASSEMBLY__
@@ -312,6 +314,16 @@ struct hvcall_mpp_data {
312 314
313int h_get_mpp(struct hvcall_mpp_data *); 315int h_get_mpp(struct hvcall_mpp_data *);
314 316
317struct hvcall_mpp_x_data {
318 unsigned long coalesced_bytes;
319 unsigned long pool_coalesced_bytes;
320 unsigned long pool_purr_cycles;
321 unsigned long pool_spurr_cycles;
322 unsigned long reserved[3];
323};
324
325int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data);
326
315#ifdef CONFIG_PPC_PSERIES 327#ifdef CONFIG_PPC_PSERIES
316extern int CMO_PrPSP; 328extern int CMO_PrPSP;
317extern int CMO_SecPSP; 329extern int CMO_SecPSP;
diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h
index d4b4bfa26fb3..89d2f99c1bf4 100644
--- a/arch/powerpc/include/asm/pSeries_reconfig.h
+++ b/arch/powerpc/include/asm/pSeries_reconfig.h
@@ -18,13 +18,18 @@
18extern int pSeries_reconfig_notifier_register(struct notifier_block *); 18extern int pSeries_reconfig_notifier_register(struct notifier_block *);
19extern void pSeries_reconfig_notifier_unregister(struct notifier_block *); 19extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
20extern struct blocking_notifier_head pSeries_reconfig_chain; 20extern struct blocking_notifier_head pSeries_reconfig_chain;
21/* Not the best place to put this, will be fixed when we move some
22 * of the rtas suspend-me stuff to pseries */
23extern void pSeries_coalesce_init(void);
21#else /* !CONFIG_PPC_PSERIES */ 24#else /* !CONFIG_PPC_PSERIES */
22static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) 25static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
23{ 26{
24 return 0; 27 return 0;
25} 28}
26static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { } 29static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
30static inline void pSeries_coalesce_init(void) { }
27#endif /* CONFIG_PPC_PSERIES */ 31#endif /* CONFIG_PPC_PSERIES */
28 32
33
29#endif /* __KERNEL__ */ 34#endif /* __KERNEL__ */
30#endif /* _PPC64_PSERIES_RECONFIG_H */ 35#endif /* _PPC64_PSERIES_RECONFIG_H */
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 301db65f05a1..84daabe2fcba 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -132,34 +132,6 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v)
132/* 132/*
133 * Methods used to fetch LPAR data when running on a pSeries platform. 133 * Methods used to fetch LPAR data when running on a pSeries platform.
134 */ 134 */
135/**
136 * h_get_mpp
137 * H_GET_MPP hcall returns info in 7 parms
138 */
139int h_get_mpp(struct hvcall_mpp_data *mpp_data)
140{
141 int rc;
142 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
143
144 rc = plpar_hcall9(H_GET_MPP, retbuf);
145
146 mpp_data->entitled_mem = retbuf[0];
147 mpp_data->mapped_mem = retbuf[1];
148
149 mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
150 mpp_data->pool_num = retbuf[2] & 0xffff;
151
152 mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff;
153 mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff;
154 mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff;
155
156 mpp_data->pool_size = retbuf[4];
157 mpp_data->loan_request = retbuf[5];
158 mpp_data->backing_mem = retbuf[6];
159
160 return rc;
161}
162EXPORT_SYMBOL(h_get_mpp);
163 135
164struct hvcall_ppp_data { 136struct hvcall_ppp_data {
165 u64 entitlement; 137 u64 entitlement;
@@ -345,6 +317,30 @@ static void parse_mpp_data(struct seq_file *m)
345 seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem); 317 seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem);
346} 318}
347 319
320/**
321 * parse_mpp_x_data
322 * Parse out data returned from h_get_mpp_x
323 */
324static void parse_mpp_x_data(struct seq_file *m)
325{
326 struct hvcall_mpp_x_data mpp_x_data;
327
328 if (!firmware_has_feature(FW_FEATURE_XCMO))
329 return;
330 if (h_get_mpp_x(&mpp_x_data))
331 return;
332
333 seq_printf(m, "coalesced_bytes=%ld\n", mpp_x_data.coalesced_bytes);
334
335 if (mpp_x_data.pool_coalesced_bytes)
336 seq_printf(m, "pool_coalesced_bytes=%ld\n",
337 mpp_x_data.pool_coalesced_bytes);
338 if (mpp_x_data.pool_purr_cycles)
339 seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles);
340 if (mpp_x_data.pool_spurr_cycles)
341 seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles);
342}
343
348#define SPLPAR_CHARACTERISTICS_TOKEN 20 344#define SPLPAR_CHARACTERISTICS_TOKEN 20
349#define SPLPAR_MAXLENGTH 1026*(sizeof(char)) 345#define SPLPAR_MAXLENGTH 1026*(sizeof(char))
350 346
@@ -520,6 +516,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
520 parse_system_parameter_string(m); 516 parse_system_parameter_string(m);
521 parse_ppp_data(m); 517 parse_ppp_data(m);
522 parse_mpp_data(m); 518 parse_mpp_data(m);
519 parse_mpp_x_data(m);
523 pseries_cmo_data(m); 520 pseries_cmo_data(m);
524 splpar_dispatch_data(m); 521 splpar_dispatch_data(m);
525 522
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 7839bd7bfd15..c016033ba78d 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -700,8 +700,10 @@ static void __init early_cmdline_parse(void)
700#endif /* CONFIG_PCI_MSI */ 700#endif /* CONFIG_PCI_MSI */
701#ifdef CONFIG_PPC_SMLPAR 701#ifdef CONFIG_PPC_SMLPAR
702#define OV5_CMO 0x80 /* Cooperative Memory Overcommitment */ 702#define OV5_CMO 0x80 /* Cooperative Memory Overcommitment */
703#define OV5_XCMO 0x40 /* Page Coalescing */
703#else 704#else
704#define OV5_CMO 0x00 705#define OV5_CMO 0x00
706#define OV5_XCMO 0x00
705#endif 707#endif
706#define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */ 708#define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */
707 709
@@ -756,7 +758,7 @@ static unsigned char ibm_architecture_vec[] = {
756 OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | 758 OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
757 OV5_DONATE_DEDICATE_CPU | OV5_MSI, 759 OV5_DONATE_DEDICATE_CPU | OV5_MSI,
758 0, 760 0,
759 OV5_CMO, 761 OV5_CMO | OV5_XCMO,
760 OV5_TYPE1_AFFINITY, 762 OV5_TYPE1_AFFINITY,
761 0, 763 0,
762 0, 764 0,
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index f48446635c89..271ff6318eda 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -42,6 +42,7 @@
42#include <asm/time.h> 42#include <asm/time.h>
43#include <asm/mmu.h> 43#include <asm/mmu.h>
44#include <asm/topology.h> 44#include <asm/topology.h>
45#include <asm/pSeries_reconfig.h>
45 46
46struct rtas_t rtas = { 47struct rtas_t rtas = {
47 .lock = __ARCH_SPIN_LOCK_UNLOCKED 48 .lock = __ARCH_SPIN_LOCK_UNLOCKED
@@ -731,6 +732,7 @@ static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_w
731 732
732 atomic_set(&data->error, rc); 733 atomic_set(&data->error, rc);
733 start_topology_update(); 734 start_topology_update();
735 pSeries_coalesce_init();
734 736
735 if (wake_when_done) { 737 if (wake_when_done) {
736 atomic_set(&data->done, 1); 738 atomic_set(&data->done, 1);
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 6f0ed3aac77f..39e6e0a7b2fa 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -329,6 +329,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
329 /* Make pHyp happy */ 329 /* Make pHyp happy */
330 if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU)) 330 if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU))
331 hpte_r &= ~_PAGE_COHERENT; 331 hpte_r &= ~_PAGE_COHERENT;
332 if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N))
333 flags |= H_COALESCE_CAND;
332 334
333 lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot); 335 lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot);
334 if (unlikely(lpar_rc == H_PTEG_FULL)) { 336 if (unlikely(lpar_rc == H_PTEG_FULL)) {
@@ -771,3 +773,47 @@ out:
771 local_irq_restore(flags); 773 local_irq_restore(flags);
772} 774}
773#endif 775#endif
776
777/**
778 * h_get_mpp
779 * H_GET_MPP hcall returns info in 7 parms
780 */
781int h_get_mpp(struct hvcall_mpp_data *mpp_data)
782{
783 int rc;
784 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
785
786 rc = plpar_hcall9(H_GET_MPP, retbuf);
787
788 mpp_data->entitled_mem = retbuf[0];
789 mpp_data->mapped_mem = retbuf[1];
790
791 mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
792 mpp_data->pool_num = retbuf[2] & 0xffff;
793
794 mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff;
795 mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff;
796 mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff;
797
798 mpp_data->pool_size = retbuf[4];
799 mpp_data->loan_request = retbuf[5];
800 mpp_data->backing_mem = retbuf[6];
801
802 return rc;
803}
804EXPORT_SYMBOL(h_get_mpp);
805
806int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data)
807{
808 int rc;
809 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 };
810
811 rc = plpar_hcall9(H_GET_MPP_X, retbuf);
812
813 mpp_x_data->coalesced_bytes = retbuf[0];
814 mpp_x_data->pool_coalesced_bytes = retbuf[1];
815 mpp_x_data->pool_purr_cycles = retbuf[2];
816 mpp_x_data->pool_spurr_cycles = retbuf[3];
817
818 return rc;
819}
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index ab73ad2ff59d..1689adccc6d7 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -405,6 +405,16 @@ static int pseries_set_xdabr(unsigned long dabr)
405#define CMO_CHARACTERISTICS_TOKEN 44 405#define CMO_CHARACTERISTICS_TOKEN 44
406#define CMO_MAXLENGTH 1026 406#define CMO_MAXLENGTH 1026
407 407
408void pSeries_coalesce_init(void)
409{
410 struct hvcall_mpp_x_data mpp_x_data;
411
412 if (firmware_has_feature(FW_FEATURE_CMO) && !h_get_mpp_x(&mpp_x_data))
413 powerpc_firmware_features |= FW_FEATURE_XCMO;
414 else
415 powerpc_firmware_features &= ~FW_FEATURE_XCMO;
416}
417
408/** 418/**
409 * fw_cmo_feature_init - FW_FEATURE_CMO is not stored in ibm,hypertas-functions, 419 * fw_cmo_feature_init - FW_FEATURE_CMO is not stored in ibm,hypertas-functions,
410 * handle that here. (Stolen from parse_system_parameter_string) 420 * handle that here. (Stolen from parse_system_parameter_string)
@@ -474,6 +484,7 @@ void pSeries_cmo_feature_init(void)
474 pr_debug("CMO enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP, 484 pr_debug("CMO enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP,
475 CMO_SecPSP); 485 CMO_SecPSP);
476 powerpc_firmware_features |= FW_FEATURE_CMO; 486 powerpc_firmware_features |= FW_FEATURE_CMO;
487 pSeries_coalesce_init();
477 } else 488 } else
478 pr_debug("CMO not enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP, 489 pr_debug("CMO not enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP,
479 CMO_SecPSP); 490 CMO_SecPSP);