diff options
-rw-r--r-- | core/init.c | 38 | ||||
-rw-r--r-- | hdata/cpu-common.c | 2 | ||||
-rw-r--r-- | hdata/test/hdata_to_dt.c | 2 | ||||
-rw-r--r-- | include/skiboot.h | 2 |
4 files changed, 44 insertions, 0 deletions
diff --git a/core/init.c b/core/init.c index a1fd5f2..005ecf3 100644 --- a/core/init.c +++ b/core/init.c @@ -48,6 +48,7 @@ #include <debug_descriptor.h> #include <occ.h> #include <opal-dump.h> +#include <xscom-p9-regs.h> #include <xscom-p10-regs.h> enum proc_gen proc_gen; @@ -1026,6 +1027,40 @@ static void mask_pc_system_xstop(void) } } +bool lpar_per_core = false; + +static void probe_lpar_per_core(void) +{ + struct cpu_thread *cpu = this_cpu(); + uint32_t chip_id = pir_to_chip_id(cpu->pir); + uint32_t core_id = pir_to_core_id(cpu->pir); + uint64_t addr; + uint64_t core_thread_state; + int rc; + + if (chip_quirk(QUIRK_MAMBO_CALLOUTS) || chip_quirk(QUIRK_AWAN)) + return; + + if (proc_gen == proc_gen_p9) + addr = XSCOM_ADDR_P9_EC(core_id, P9_CORE_THREAD_STATE); + else if (proc_gen == proc_gen_p10) + addr = XSCOM_ADDR_P10_EC(core_id, P10_EC_CORE_THREAD_STATE); + else + return; + + rc = xscom_read(chip_id, addr, &core_thread_state); + if (rc) { + prerror("Error reading CORE_THREAD_STATE rc:%d on PIR:%x\n", + rc, cpu->pir); + return; + } + + if (core_thread_state & PPC_BIT(62)) { + lpar_per_core = true; + prlog(PR_WARNING, "LPAR-per-core mode detected. KVM may not be usable."); + } +} + /* Called from head.S, thus no prototype. */ void __noreturn __nomcount main_cpu_entry(const void *fdt); @@ -1211,6 +1246,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) /* Once all CPU are up apply this workaround */ mask_pc_system_xstop(); + /* P9/10 may be in LPAR-per-core mode, which is incompatible with KVM */ + probe_lpar_per_core(); + /* Add the /opal node to the device-tree */ add_opal_node(); diff --git a/hdata/cpu-common.c b/hdata/cpu-common.c index 2248f9b..4ba1430 100644 --- a/hdata/cpu-common.c +++ b/hdata/cpu-common.c @@ -127,6 +127,8 @@ struct dt_node * add_core_common(struct dt_node *cpus, dt_add_property_cells(cpu, "ibm,mmu-pid-bits", 20); dt_add_property_cells(cpu, "ibm,mmu-lpid-bits", 12); } + if (lpar_per_core) + dt_add_property(cpu, "ibm,mmu-lpar-per-core", NULL, 0); /* HPT segment page size encodings, common to all supported CPUs */ dt_add_property_cells(cpu, "ibm,segment-page-sizes", diff --git a/hdata/test/hdata_to_dt.c b/hdata/test/hdata_to_dt.c index 1729f1c..ead6e3c 100644 --- a/hdata/test/hdata_to_dt.c +++ b/hdata/test/hdata_to_dt.c @@ -104,6 +104,8 @@ static unsigned long fake_pvr = PVR_P8; unsigned int cpu_thread_count = 8; +bool lpar_per_core; + static inline unsigned long mfspr(unsigned int spr) { assert(spr == SPR_PVR); diff --git a/include/skiboot.h b/include/skiboot.h index db08f45..b0b75a4 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -103,6 +103,8 @@ enum proc_gen { }; extern enum proc_gen proc_gen; +extern bool lpar_per_core; + extern unsigned int pcie_max_link_speed; /* Convert a 4-bit number to a hex char */ |