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
---
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(