aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@ozlabs.org>2017-01-30 05:21:36 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2017-01-31 03:11:44 -0500
commitcc3d2940133d24000e2866b21e03ce32adfead0a (patch)
tree964b1a961e180ecd57ed96f3d3234d1472532090
parent3f4ab2f83b4e443c66549206eb88a9fa5a85d647 (diff)
powerpc/64: Enable use of radix MMU under hypervisor on POWER9
To use radix as a guest, we first need to tell the hypervisor via the ibm,client-architecture call first that we support POWER9 and architecture v3.00, and that we can do either radix or hash and that we would like to choose later using an hcall (the H_REGISTER_PROC_TBL hcall). Then we need to check whether the hypervisor agreed to us using radix. We need to do this very early on in the kernel boot process before any of the MMU initialization is done. If the hypervisor doesn't agree, we can't use radix and therefore clear the radix MMU feature bit. Later, when we have set up our process table, which points to the radix tree for each process, we need to install that using the H_REGISTER_PROC_TBL hcall. Signed-off-by: Paul Mackerras <paulus@ozlabs.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/book3s/64/mmu.h6
-rw-r--r--arch/powerpc/include/asm/hvcall.h11
-rw-r--r--arch/powerpc/include/asm/prom.h9
-rw-r--r--arch/powerpc/kernel/prom_init.c18
-rw-r--r--arch/powerpc/mm/init_64.c12
-rw-r--r--arch/powerpc/mm/pgtable-radix.c2
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c29
7 files changed, 81 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
index 8afb0e00f7d9..cea522c3bcae 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -138,5 +138,11 @@ static inline void setup_initial_memory_limit(phys_addr_t first_memblock_base,
138extern int (*register_process_table)(unsigned long base, unsigned long page_size, 138extern int (*register_process_table)(unsigned long base, unsigned long page_size,
139 unsigned long tbl_size); 139 unsigned long tbl_size);
140 140
141#ifdef CONFIG_PPC_PSERIES
142extern void radix_init_pseries(void);
143#else
144static inline void radix_init_pseries(void) { };
145#endif
146
141#endif /* __ASSEMBLY__ */ 147#endif /* __ASSEMBLY__ */
142#endif /* _ASM_POWERPC_BOOK3S_64_MMU_H_ */ 148#endif /* _ASM_POWERPC_BOOK3S_64_MMU_H_ */
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 77ff1ba99d1f..54d11b3a6bf7 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -276,6 +276,7 @@
276#define H_GET_MPP_X 0x314 276#define H_GET_MPP_X 0x314
277#define H_SET_MODE 0x31C 277#define H_SET_MODE 0x31C
278#define H_CLEAR_HPT 0x358 278#define H_CLEAR_HPT 0x358
279#define H_REGISTER_PROC_TBL 0x37C
279#define H_SIGNAL_SYS_RESET 0x380 280#define H_SIGNAL_SYS_RESET 0x380
280#define MAX_HCALL_OPCODE H_SIGNAL_SYS_RESET 281#define MAX_HCALL_OPCODE H_SIGNAL_SYS_RESET
281 282
@@ -313,6 +314,16 @@
313#define H_SIGNAL_SYS_RESET_ALL_OTHERS -2 314#define H_SIGNAL_SYS_RESET_ALL_OTHERS -2
314/* >= 0 values are CPU number */ 315/* >= 0 values are CPU number */
315 316
317/* Flag values used in H_REGISTER_PROC_TBL hcall */
318#define PROC_TABLE_OP_MASK 0x18
319#define PROC_TABLE_DEREG 0x10
320#define PROC_TABLE_NEW 0x18
321#define PROC_TABLE_TYPE_MASK 0x06
322#define PROC_TABLE_HPT_SLB 0x00
323#define PROC_TABLE_HPT_PT 0x02
324#define PROC_TABLE_RADIX 0x04
325#define PROC_TABLE_GTSE 0x01
326
316#ifndef __ASSEMBLY__ 327#ifndef __ASSEMBLY__
317 328
318/** 329/**
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index e6d83d0fada7..8af2546ea593 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -121,6 +121,8 @@ struct of_drconf_cell {
121#define OV1_PPC_2_06 0x02 /* set if we support PowerPC 2.06 */ 121#define OV1_PPC_2_06 0x02 /* set if we support PowerPC 2.06 */
122#define OV1_PPC_2_07 0x01 /* set if we support PowerPC 2.07 */ 122#define OV1_PPC_2_07 0x01 /* set if we support PowerPC 2.07 */
123 123
124#define OV1_PPC_3_00 0x80 /* set if we support PowerPC 3.00 */
125
124/* Option vector 2: Open Firmware options supported */ 126/* Option vector 2: Open Firmware options supported */
125#define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */ 127#define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */
126 128
@@ -155,6 +157,13 @@ struct of_drconf_cell {
155#define OV5_PFO_HW_842 0x1140 /* PFO Compression Accelerator */ 157#define OV5_PFO_HW_842 0x1140 /* PFO Compression Accelerator */
156#define OV5_PFO_HW_ENCR 0x1120 /* PFO Encryption Accelerator */ 158#define OV5_PFO_HW_ENCR 0x1120 /* PFO Encryption Accelerator */
157#define OV5_SUB_PROCESSORS 0x1501 /* 1,2,or 4 Sub-Processors supported */ 159#define OV5_SUB_PROCESSORS 0x1501 /* 1,2,or 4 Sub-Processors supported */
160#define OV5_XIVE_EXPLOIT 0x1701 /* XIVE exploitation supported */
161#define OV5_MMU_RADIX_300 0x1880 /* ISA v3.00 radix MMU supported */
162#define OV5_MMU_HASH_300 0x1840 /* ISA v3.00 hash MMU supported */
163#define OV5_MMU_SEGM_RADIX 0x1820 /* radix mode (no segmentation) */
164#define OV5_MMU_PROC_TBL 0x1810 /* hcall selects SLB or proc table */
165#define OV5_MMU_SLB 0x1800 /* always use SLB */
166#define OV5_MMU_GTSE 0x1808 /* Guest translation shootdown */
158 167
159/* Option Vector 6: IBM PAPR hints */ 168/* Option Vector 6: IBM PAPR hints */
160#define OV6_LINUX 0x02 /* Linux is our OS */ 169#define OV6_LINUX 0x02 /* Linux is our OS */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index ec47a939cbdd..358d43f8f84f 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -649,6 +649,7 @@ static void __init early_cmdline_parse(void)
649struct option_vector1 { 649struct option_vector1 {
650 u8 byte1; 650 u8 byte1;
651 u8 arch_versions; 651 u8 arch_versions;
652 u8 arch_versions3;
652} __packed; 653} __packed;
653 654
654struct option_vector2 { 655struct option_vector2 {
@@ -691,6 +692,9 @@ struct option_vector5 {
691 u8 reserved2; 692 u8 reserved2;
692 __be16 reserved3; 693 __be16 reserved3;
693 u8 subprocessors; 694 u8 subprocessors;
695 u8 byte22;
696 u8 intarch;
697 u8 mmu;
694} __packed; 698} __packed;
695 699
696struct option_vector6 { 700struct option_vector6 {
@@ -700,7 +704,7 @@ struct option_vector6 {
700} __packed; 704} __packed;
701 705
702struct ibm_arch_vec { 706struct ibm_arch_vec {
703 struct { u32 mask, val; } pvrs[10]; 707 struct { u32 mask, val; } pvrs[12];
704 708
705 u8 num_vectors; 709 u8 num_vectors;
706 710
@@ -750,6 +754,14 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = {
750 .val = cpu_to_be32(0x004d0000), 754 .val = cpu_to_be32(0x004d0000),
751 }, 755 },
752 { 756 {
757 .mask = cpu_to_be32(0xffff0000), /* POWER9 */
758 .val = cpu_to_be32(0x004e0000),
759 },
760 {
761 .mask = cpu_to_be32(0xffffffff), /* all 3.00-compliant */
762 .val = cpu_to_be32(0x0f000005),
763 },
764 {
753 .mask = cpu_to_be32(0xffffffff), /* all 2.07-compliant */ 765 .mask = cpu_to_be32(0xffffffff), /* all 2.07-compliant */
754 .val = cpu_to_be32(0x0f000004), 766 .val = cpu_to_be32(0x0f000004),
755 }, 767 },
@@ -774,6 +786,7 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = {
774 .byte1 = 0, 786 .byte1 = 0,
775 .arch_versions = OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 | 787 .arch_versions = OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
776 OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07, 788 OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07,
789 .arch_versions3 = OV1_PPC_3_00,
777 }, 790 },
778 791
779 .vec2_len = VECTOR_LENGTH(sizeof(struct option_vector2)), 792 .vec2_len = VECTOR_LENGTH(sizeof(struct option_vector2)),
@@ -836,6 +849,9 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = {
836 .reserved2 = 0, 849 .reserved2 = 0,
837 .reserved3 = 0, 850 .reserved3 = 0,
838 .subprocessors = 1, 851 .subprocessors = 1,
852 .intarch = 0,
853 .mmu = OV5_FEAT(OV5_MMU_RADIX_300) | OV5_FEAT(OV5_MMU_HASH_300) |
854 OV5_FEAT(OV5_MMU_PROC_TBL) | OV5_FEAT(OV5_MMU_GTSE),
839 }, 855 },
840 856
841 /* option vector 6: IBM PAPR hints */ 857 /* option vector 6: IBM PAPR hints */
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 4d9481ec2468..10c9a545a646 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -347,10 +347,9 @@ static int __init parse_disable_radix(char *p)
347early_param("disable_radix", parse_disable_radix); 347early_param("disable_radix", parse_disable_radix);
348 348
349/* 349/*
350 * If we're running under a hypervisor, we currently can't do radix 350 * If we're running under a hypervisor, we need to check the contents of
351 * since we don't have the code to do the H_REGISTER_PROC_TBL hcall. 351 * /chosen/ibm,architecture-vec-5 to see if the hypervisor is willing to do
352 * We tell that we're running under a hypervisor by looking for the 352 * radix. If not, we clear the radix feature bit so we fall back to hash.
353 * /chosen/ibm,architecture-vec-5 property.
354 */ 353 */
355static void early_check_vec5(void) 354static void early_check_vec5(void)
356{ 355{
@@ -365,7 +364,10 @@ static void early_check_vec5(void)
365 vec5 = of_get_flat_dt_prop(chosen, "ibm,architecture-vec-5", &size); 364 vec5 = of_get_flat_dt_prop(chosen, "ibm,architecture-vec-5", &size);
366 if (!vec5) 365 if (!vec5)
367 return; 366 return;
368 cur_cpu_spec->mmu_features &= ~MMU_FTR_TYPE_RADIX; 367 if (size <= OV5_INDX(OV5_MMU_RADIX_300) ||
368 !(vec5[OV5_INDX(OV5_MMU_RADIX_300)] & OV5_FEAT(OV5_MMU_RADIX_300)))
369 /* Hypervisor doesn't support radix */
370 cur_cpu_spec->mmu_features &= ~MMU_FTR_TYPE_RADIX;
369} 371}
370 372
371void __init mmu_early_init_devtree(void) 373void __init mmu_early_init_devtree(void)
diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c
index cfa53ccc8baf..94323c4ececc 100644
--- a/arch/powerpc/mm/pgtable-radix.c
+++ b/arch/powerpc/mm/pgtable-radix.c
@@ -401,6 +401,8 @@ void __init radix__early_init_mmu(void)
401 mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR); 401 mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR);
402 radix_init_partition_table(); 402 radix_init_partition_table();
403 radix_init_amor(); 403 radix_init_amor();
404 } else {
405 radix_init_pseries();
404 } 406 }
405 407
406 memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE); 408 memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 5dc1c3c6e716..0587655aea69 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -609,6 +609,29 @@ static int __init disable_bulk_remove(char *str)
609 609
610__setup("bulk_remove=", disable_bulk_remove); 610__setup("bulk_remove=", disable_bulk_remove);
611 611
612/* Actually only used for radix, so far */
613static int pseries_lpar_register_process_table(unsigned long base,
614 unsigned long page_size, unsigned long table_size)
615{
616 long rc;
617 unsigned long flags = PROC_TABLE_NEW;
618
619 if (radix_enabled())
620 flags |= PROC_TABLE_RADIX | PROC_TABLE_GTSE;
621 for (;;) {
622 rc = plpar_hcall_norets(H_REGISTER_PROC_TBL, flags, base,
623 page_size, table_size);
624 if (!H_IS_LONG_BUSY(rc))
625 break;
626 mdelay(get_longbusy_msecs(rc));
627 }
628 if (rc != H_SUCCESS) {
629 pr_err("Failed to register process table (rc=%ld)\n", rc);
630 BUG();
631 }
632 return rc;
633}
634
612void __init hpte_init_pseries(void) 635void __init hpte_init_pseries(void)
613{ 636{
614 mmu_hash_ops.hpte_invalidate = pSeries_lpar_hpte_invalidate; 637 mmu_hash_ops.hpte_invalidate = pSeries_lpar_hpte_invalidate;
@@ -622,6 +645,12 @@ void __init hpte_init_pseries(void)
622 mmu_hash_ops.hugepage_invalidate = pSeries_lpar_hugepage_invalidate; 645 mmu_hash_ops.hugepage_invalidate = pSeries_lpar_hugepage_invalidate;
623} 646}
624 647
648void radix_init_pseries(void)
649{
650 pr_info("Using radix MMU under hypervisor\n");
651 register_process_table = pseries_lpar_register_process_table;
652}
653
625#ifdef CONFIG_PPC_SMLPAR 654#ifdef CONFIG_PPC_SMLPAR
626#define CMO_FREE_HINT_DEFAULT 1 655#define CMO_FREE_HINT_DEFAULT 1
627static int cmo_free_hint_flag = CMO_FREE_HINT_DEFAULT; 656static int cmo_free_hint_flag = CMO_FREE_HINT_DEFAULT;