aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/init.c38
-rw-r--r--hdata/cpu-common.c2
-rw-r--r--hdata/test/hdata_to_dt.c2
-rw-r--r--include/skiboot.h2
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 */