diff --git a/core/cpu.c b/core/cpu.c index 31f5c928bb67..75c700833d76 100644 --- a/core/cpu.c +++ b/core/cpu.c @@ -49,10 +49,12 @@ unsigned int cpu_max_pir; struct cpu_thread *boot_cpu; static struct lock reinit_lock = LOCK_UNLOCKED; static bool hile_supported; +static bool radix_supported; static unsigned long hid0_hile; static unsigned long hid0_attn; static bool pm_enabled; static bool current_hile_mode; +static bool current_radix_mode; unsigned long cpu_secondary_start __force_data = 0; @@ -700,6 +702,7 @@ void init_boot_cpu(void) case PVR_TYPE_P9: proc_gen = proc_gen_p9; hile_supported = true; + radix_supported = true; hid0_hile = SPR_HID0_POWER9_HILE; hid0_attn = SPR_HID0_POWER9_ENABLE_ATTN; break; @@ -1060,11 +1063,27 @@ static int64_t cpu_change_all_hid0(struct hid0_change_req *req) return OPAL_SUCCESS; } +void cpu_set_radix_mode(void) +{ + struct hid0_change_req req; + + if (!radix_supported) + return; + + req.clr_bits = 0; + req.set_bits = SPR_HID0_POWER9_RADIX; + cleanup_global_tlb(); + current_radix_mode = true; + cpu_change_all_hid0(&req); +} + void cpu_fast_reboot_complete(void) { /* Fast reboot will have cleared HID0:HILE */ current_hile_mode = false; + /* On P9, restore radix mode */ + cpu_set_radix_mode(); } static int64_t opal_reinit_cpus(uint64_t flags) @@ -1129,6 +1148,25 @@ static int64_t opal_reinit_cpus(uint64_t flags) } } + /* If MMU mode change is supported */ + if (radix_supported && + (flags & (OPAL_REINIT_CPUS_MMU_HASH | + OPAL_REINIT_CPUS_MMU_RADIX))) { + bool radix = !!(flags & OPAL_REINIT_CPUS_MMU_RADIX); + + flags &= ~(OPAL_REINIT_CPUS_MMU_HASH | + OPAL_REINIT_CPUS_MMU_RADIX); + if (radix != current_radix_mode) { + if (radix) + req.set_bits |= SPR_HID0_POWER9_RADIX; + else + req.clr_bits |= SPR_HID0_POWER9_RADIX; + + cleanup_global_tlb(); + current_radix_mode = radix; + } + } + /* Apply HID bits changes if any */ if (req.set_bits || req.clr_bits) cpu_change_all_hid0(&req); diff --git a/core/init.c b/core/init.c index 244a78f4cac4..9ffbc72fbe66 100644 --- a/core/init.c +++ b/core/init.c @@ -1045,6 +1045,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) prd_register_reserved_memory(); + /* On P9, switch to radix mode by default */ + cpu_set_radix_mode(); + load_and_boot_kernel(false); } diff --git a/include/cpu.h b/include/cpu.h index 1d19c200cd18..fd3acf779446 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -270,6 +270,7 @@ extern unsigned long __attrconst cpu_stack_top(unsigned int pir); extern void cpu_idle_job(void); extern void cpu_idle_delay(unsigned long delay, unsigned long min_pm); +extern void cpu_set_radix_mode(void); extern void cpu_fast_reboot_complete(void); #endif /* __CPU_H */ diff --git a/include/opal-api.h b/include/opal-api.h index 27134908fb91..8ffdd4b181cc 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -1014,6 +1014,15 @@ struct OpalIoPhb4ErrorData { enum { OPAL_REINIT_CPUS_HILE_BE = (1 << 0), OPAL_REINIT_CPUS_HILE_LE = (1 << 1), + + /* These two define the base MMU mode of the host on P9 + * + * On P9 Nimbus DD2.0 and Cumlus (and later), KVM can still + * create hash guests in "radix" mode with care (full core + * switch only). + */ + OPAL_REINIT_CPUS_MMU_HASH = (1 << 2), + OPAL_REINIT_CPUS_MMU_RADIX = (1 << 3), }; typedef struct oppanel_line { diff --git a/include/processor.h b/include/processor.h index 5906b8657c1b..af3fd2b6d3d5 100644 --- a/include/processor.h +++ b/include/processor.h @@ -169,6 +169,7 @@ #define SPR_HID0_POWER9_HILE PPC_BIT(4) #define SPR_HID0_POWER8_ENABLE_ATTN PPC_BIT(31) #define SPR_HID0_POWER9_ENABLE_ATTN PPC_BIT(3) +#define SPR_HID0_POWER9_RADIX PPC_BIT(8) /* PVR bits */ #define SPR_PVR_TYPE 0xffff0000