@@ -88,6 +88,25 @@ static void xive_eq_push(XiveEQ *eq, uint32_t data)
* XIVE Interrupt Presenter
*/
+Object *xive_nvt_create(Object *cpu, const char *type, Error **errp)
+{
+ Error *local_err = NULL;
+ Object *obj;
+
+ obj = object_new(type);
+ object_property_add_child(cpu, type, obj, &error_abort);
+ object_unref(obj);
+ object_property_add_const_link(obj, ICP_PROP_CPU, cpu, &error_abort);
+ object_property_set_bool(obj, true, "realized", &local_err);
+ if (local_err) {
+ object_unparent(obj);
+ error_propagate(errp, local_err);
+ obj = NULL;
+ }
+
+ return obj;
+}
+
/* Convert a priority number to an Interrupt Pending Buffer (IPB)
* register, which indicates a pending interrupt at the priority
* corresponding to the bit number
@@ -251,6 +251,7 @@ static void xive_system_init(MachineState *machine, int nr_irqs, Error **errp)
spapr->xive = spapr_xive_create(spapr, TYPE_SPAPR_XIVE, nr_irqs, errp);
if (spapr->xive) {
+ spapr->nvt_type = TYPE_XIVE_NVT;
spapr_xive_hcall_init(spapr);
}
}
@@ -1522,13 +1523,32 @@ static int spapr_reset_drcs(Object *child, void *opaque)
/* Setup XIVE exploitation or legacy mode as required by CAS */
static void spapr_reset_interrupt(sPAPRMachineState *spapr, Error **errp)
{
+ Error *local_err = NULL;
+ const char *intc_type;
+
/* Reset XIVE if enabled */
if (spapr->xive_exploitation) {
spapr_xive_mmio_unmap(spapr->xive);
}
+ /* Reset CPU ICPs */
+ spapr_cpu_core_reset_icp(&local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
spapr_xive_mmio_map(spapr->xive);
+ intc_type = spapr->nvt_type;
+ } else {
+ intc_type = spapr->icp_type;
+ }
+
+ spapr_cpu_core_set_icp(intc_type, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
}
}
@@ -3963,6 +3983,26 @@ Object *spapr_icp_create(sPAPRMachineState *spapr, Object *cpu, Error **errp)
return NULL;
}
+ if (spapr->xive_exploitation) {
+ Object *obj_xive;
+
+ /* Add a XIVE interrupt presenter. The machine will switch
+ * the CPU ICP depending on the interrupt model negotiated
+ * at CAS time.
+ */
+ obj_xive = xive_nvt_create(cpu, spapr->nvt_type, &local_err);
+ if (local_err) {
+ object_unparent(obj);
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ /* when hotplugged, the CPU should have the correct ICP */
+ if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return obj_xive;
+ }
+ }
+
return obj;
}
@@ -256,3 +256,47 @@ static const TypeInfo spapr_cpu_core_type_infos[] = {
};
DEFINE_TYPES(spapr_cpu_core_type_infos)
+
+void spapr_cpu_core_reset_icp(Error **errp)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ cpu->intc = NULL;
+ }
+}
+
+typedef struct ForeachFindICPArgs {
+ const char *icp_type;
+ Object *icp;
+} ForeachFindICPArgs;
+
+static int spapr_cpu_core_find_icp(Object *child, void *opaque)
+{
+ ForeachFindICPArgs *args = opaque;
+
+ if (object_dynamic_cast(child, args->icp_type)) {
+ args->icp = child;
+ }
+
+ return args->icp != NULL;
+}
+
+void spapr_cpu_core_set_icp(const char *icp_type, Error **errp)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ ForeachFindICPArgs args = { icp_type, NULL };
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ object_child_foreach(OBJECT(cs), spapr_cpu_core_find_icp, &args);
+ if (!args.icp) {
+ error_setg(errp, "Couldn't find a '%s' icp", icp_type);
+ return;
+ }
+
+ cpu->intc = args.icp;
+ }
+}
@@ -168,6 +168,7 @@ struct sPAPRMachineState {
const char *icp_type;
uint8_t xive_exploitation;
sPAPRXive *xive;
+ const char *nvt_type;
bool cmd_line_caps[SPAPR_CAP_NUM];
sPAPRCapabilities def, eff, mig;
@@ -38,4 +38,6 @@ typedef struct sPAPRCPUCoreClass {
} sPAPRCPUCoreClass;
const char *spapr_get_cpu_core_type(const char *cpu_type);
+void spapr_cpu_core_set_icp(const char *icp_type, Error **errp);
+void spapr_cpu_core_reset_icp(Error **errp);
#endif
@@ -191,6 +191,7 @@ extern const MemoryRegionOps xive_tm_os_ops;
void xive_nvt_pic_print_info(XiveNVT *nvt, Monitor *mon);
XiveEQ *xive_nvt_eq_get(XiveNVT *nvt, uint8_t priority);
+Object *xive_nvt_create(Object *cpu, const char *type, Error **errp);
void xive_eq_reset(XiveEQ *eq);
void xive_eq_pic_print_info(XiveEQ *eq, Monitor *mon);
Each interrupt mode has its own specific interrupt presenter object, that we store under the CPU object, one for XICS and one for XIVE. The active presenter, corresponding to the current interrupt mode, is simply selected with a lookup on the children of the CPU. Migration and CPU hotplug also need to reflect the current interrupt mode in use. Signed-off-by: Cédric Le Goater <clg@kaod.org> --- hw/intc/xive.c | 19 ++++++++++++++++++ hw/ppc/spapr.c | 40 +++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_cpu_core.c | 44 +++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 1 + include/hw/ppc/spapr_cpu_core.h | 2 ++ include/hw/ppc/xive.h | 1 + 6 files changed, 107 insertions(+)