The upcoming XICS-KVM support will use bits of emulated XICS code. So this introduces new level of hierarchy - "xics-common" class. Both emulated XICS and XICS-KVM will inherit from it and override class callbacks when required.
The new "xics-common" class implements: 1. replaces static "nr_irqs" and "nr_servers" properties with the dynamic ones and adds callbacks to be executed when properties are set. 2. xics_cpu_setup() callback renamed to xics_common_cpu_setup() as it is a common part for both XICS'es 3. xics_reset() renamed to xics_common_reset() for the same reason. The emulated XICS changes: 1. the part of xics_realize() which creates ICPs is moved to the "nr_servers" property callback as realize() is too late to create/initialize devices and instance_init() is too early to create devices as the number of child devices comes via the "nr_servers" property. 2. added ics_initfn() which does a little part of what xics_realize() did. Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru> --- Changes: v3: * added getters for dynamic properties * fixed some indentations, added some comments * moved ICS allocation from the nr_irqs property setter to XICS initfn (where it was initially after Anthony's rework) --- hw/intc/xics.c | 213 ++++++++++++++++++++++++++++++++++++++------------ include/hw/ppc/xics.h | 11 ++- 2 files changed, 175 insertions(+), 49 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 4d08c58..f439e8d 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -30,6 +30,143 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/xics.h" #include "qemu/error-report.h" +#include "qapi/visitor.h" + +/* + * XICS Common class - parent for emulated XICS and KVM-XICS + */ + +static void xics_common_cpu_setup(XICSState *icp, PowerPCCPU *cpu) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + ICPState *ss = &icp->ss[cs->cpu_index]; + + assert(cs->cpu_index < icp->nr_servers); + + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_POWER7: + ss->output = env->irq_inputs[POWER7_INPUT_INT]; + break; + + case PPC_FLAGS_INPUT_970: + ss->output = env->irq_inputs[PPC970_INPUT_INT]; + break; + + default: + error_report("XICS interrupt controller does not support this CPU " + "bus model"); + /* Called from machine_init only so no point in Error**, just abort */ + abort(); + } +} + +static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, + void *opaque, const char *name, Error **errp) +{ + XICSState *icp = XICS_COMMON(obj); + int64_t value = icp->nr_irqs; + + visit_type_int(v, &value, name, errp); +} + +static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, + void *opaque, const char *name, Error **errp) +{ + XICSState *icp = XICS_COMMON(obj); + XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); + Error *error = NULL; + int64_t value; + + visit_type_int(v, &value, name, &error); + if (error) { + error_propagate(errp, error); + return; + } + if (icp->nr_irqs) { + error_setg(errp, "Number of interrupts is already set to %u", + icp->nr_irqs); + return; + } + + assert(info->set_nr_irqs); + assert(icp->ics); + info->set_nr_irqs(icp, value, errp); +} + +static void xics_prop_get_nr_servers(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + XICSState *icp = XICS_COMMON(obj); + int64_t value = icp->nr_servers; + + visit_type_int(v, &value, name, errp); +} + +static void xics_prop_set_nr_servers(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + XICSState *icp = XICS_COMMON(obj); + XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); + Error *error = NULL; + int64_t value; + + visit_type_int(v, &value, name, &error); + if (error) { + error_propagate(errp, error); + return; + } + if (icp->nr_servers) { + error_setg(errp, "Number of servers is already set to %u", + icp->nr_servers); + return; + } + + assert(info->set_nr_servers); + info->set_nr_servers(icp, value, errp); +} + +static void xics_common_initfn(Object *obj) +{ + object_property_add(obj, "nr_irqs", "int", + xics_prop_get_nr_irqs, xics_prop_set_nr_irqs, + NULL, NULL, NULL); + object_property_add(obj, "nr_servers", "int", + xics_prop_get_nr_servers, xics_prop_set_nr_servers, + NULL, NULL, NULL); +} + +static void xics_common_reset(DeviceState *d) +{ + XICSState *icp = XICS_COMMON(d); + int i; + + for (i = 0; i < icp->nr_servers; i++) { + device_reset(DEVICE(&icp->ss[i])); + } + + device_reset(DEVICE(icp->ics)); +} + +static void xics_common_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + XICSStateClass *xsc = XICS_COMMON_CLASS(oc); + + dc->reset = xics_common_reset; + xsc->cpu_setup = xics_common_cpu_setup; +} + +static const TypeInfo xics_common_info = { + .name = TYPE_XICS_COMMON, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XICSState), + .class_size = sizeof(XICSStateClass), + .instance_init = xics_common_initfn, + .class_init = xics_common_class_init, +}; /* * ICP: Presentation layer @@ -443,6 +580,13 @@ static const VMStateDescription vmstate_ics = { }, }; +static void ics_initfn(Object *obj) +{ + ICSState *ics = ICS(obj); + + ics->offset = XICS_IRQ_BASE; +} + static void ics_realize(DeviceState *dev, Error **errp) { ICSState *ics = ICS(dev); @@ -474,6 +618,7 @@ static const TypeInfo ics_info = { .instance_size = sizeof(ICSState), .class_init = ics_class_init, .class_size = sizeof(ICSStateClass), + .instance_init = ics_initfn, }; /* @@ -654,46 +799,31 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, * XICS */ -static void xics_reset(DeviceState *d) +static void xics_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp) +{ + icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; +} + +static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers, + Error **errp) { - XICSState *icp = XICS(d); int i; + icp->nr_servers = nr_servers; + + icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); for (i = 0; i < icp->nr_servers; i++) { - device_reset(DEVICE(&icp->ss[i])); - } - - device_reset(DEVICE(icp->ics)); -} - -static void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) -{ - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; - ICPState *ss = &icp->ss[cs->cpu_index]; - - assert(cs->cpu_index < icp->nr_servers); - - switch (PPC_INPUT(env)) { - case PPC_FLAGS_INPUT_POWER7: - ss->output = env->irq_inputs[POWER7_INPUT_INT]; - break; - - case PPC_FLAGS_INPUT_970: - ss->output = env->irq_inputs[PPC970_INPUT_INT]; - break; - - default: - error_report("XICS interrupt controller does not support this CPU " - "bus model"); - abort(); + char buffer[32]; + object_initialize(&icp->ss[i], TYPE_ICP); + snprintf(buffer, sizeof(buffer), "icp[%d]", i); + object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), + errp); } } static void xics_realize(DeviceState *dev, Error **errp) { XICSState *icp = XICS(dev); - ICSState *ics = icp->ics; Error *error = NULL; int i; @@ -713,21 +843,13 @@ static void xics_realize(DeviceState *dev, Error **errp) spapr_register_hypercall(H_XIRR, h_xirr); spapr_register_hypercall(H_EOI, h_eoi); - ics->nr_irqs = icp->nr_irqs; - ics->offset = XICS_IRQ_BASE; - ics->icp = icp; object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); if (error) { error_propagate(errp, error); return; } - icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); for (i = 0; i < icp->nr_servers; i++) { - char buffer[32]; - object_initialize(&icp->ss[i], TYPE_ICP); - snprintf(buffer, sizeof(buffer), "icp[%d]", i); - object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), NULL); object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); if (error) { error_propagate(errp, error); @@ -742,28 +864,22 @@ static void xics_initfn(Object *obj) xics->ics = ICS(object_new(TYPE_ICS)); object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); + xics->ics->icp = xics; } -static Property xics_properties[] = { - DEFINE_PROP_UINT32("nr_servers", XICSState, nr_servers, -1), - DEFINE_PROP_UINT32("nr_irqs", XICSState, nr_irqs, -1), - DEFINE_PROP_END_OF_LIST(), -}; - static void xics_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); XICSStateClass *xsc = XICS_CLASS(oc); dc->realize = xics_realize; - dc->props = xics_properties; - dc->reset = xics_reset; - xsc->cpu_setup = xics_cpu_setup; + xsc->set_nr_irqs = xics_set_nr_irqs; + xsc->set_nr_servers = xics_set_nr_servers; } static const TypeInfo xics_info = { .name = TYPE_XICS, - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_XICS_COMMON, .instance_size = sizeof(XICSState), .class_size = sizeof(XICSStateClass), .class_init = xics_class_init, @@ -772,6 +888,7 @@ static const TypeInfo xics_info = { static void xics_register_types(void) { + type_register_static(&xics_common_info); type_register_static(&xics_info); type_register_static(&ics_info); type_register_static(&icp_info); diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 3a25987..540bb81 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -29,11 +29,18 @@ #include "hw/sysbus.h" +#define TYPE_XICS_COMMON "xics-common" +#define XICS_COMMON(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS_COMMON) + #define TYPE_XICS "xics" #define XICS(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS) +#define XICS_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS_COMMON) #define XICS_CLASS(klass) \ OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS) +#define XICS_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS_COMMON) #define XICS_GET_CLASS(obj) \ OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS) @@ -58,6 +65,8 @@ struct XICSStateClass { DeviceClass parent_class; void (*cpu_setup)(XICSState *icp, PowerPCCPU *cpu); + void (*set_nr_irqs)(XICSState *icp, uint32_t nr_irqs, Error **errp); + void (*set_nr_servers)(XICSState *icp, uint32_t nr_servers, Error **errp); }; struct XICSState { @@ -138,7 +147,7 @@ void xics_set_irq_type(XICSState *icp, int irq, bool lsi); static inline void xics_dispatch_cpu_setup(XICSState *icp, PowerPCCPU *cpu) { - XICSStateClass *info = XICS_GET_CLASS(icp); + XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); assert(info->cpu_setup); info->cpu_setup(icp, cpu); -- 1.8.3.2