summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/intc/xics.c156
-rw-r--r--hw/ppc/spapr.c2
-rw-r--r--include/hw/ppc/xics.h20
3 files changed, 157 insertions, 21 deletions
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index c90eb0aa12..5ed2618769 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -30,6 +30,7 @@
#include "hw/ppc/spapr.h"
#include "hw/ppc/xics.h"
#include "qemu/error-report.h"
+#include "qapi/visitor.h"
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
{
@@ -55,9 +56,12 @@ void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
}
}
-static void xics_reset(DeviceState *d)
+/*
+ * XICS Common class - parent for emulated XICS and KVM-XICS
+ */
+static void xics_common_reset(DeviceState *d)
{
- XICSState *icp = XICS(d);
+ XICSState *icp = XICS_COMMON(d);
int i;
for (i = 0; i < icp->nr_servers; i++) {
@@ -67,6 +71,99 @@ static void xics_reset(DeviceState *d)
device_reset(DEVICE(icp->ics));
}
+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_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->reset = xics_common_reset;
+}
+
+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
*/
@@ -479,6 +576,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);
@@ -509,6 +613,7 @@ static const TypeInfo ics_info = {
.instance_size = sizeof(ICSState),
.class_init = ics_class_init,
.class_size = sizeof(ICSStateClass),
+ .instance_init = ics_initfn,
};
/*
@@ -689,10 +794,31 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr,
* XICS
*/
+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)
+{
+ int i;
+
+ icp->nr_servers = nr_servers;
+
+ 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], sizeof(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;
@@ -712,21 +838,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], sizeof(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);
@@ -741,33 +859,31 @@ 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->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,
.instance_init = xics_initfn,
};
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/hw/ppc/spapr.c b/hw/ppc/spapr.c
index a276377496..f65dadc356 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -161,7 +161,7 @@ static XICSState *try_create_xics(const char *type, int nr_servers,
return NULL;
}
- return XICS(dev);
+ return XICS_COMMON(dev);
}
static XICSState *xics_system_init(int nr_servers, int nr_irqs)
diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h
index 6e3b605550..7e702a0068 100644
--- a/include/hw/ppc/xics.h
+++ b/include/hw/ppc/xics.h
@@ -29,9 +29,21 @@
#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)
+
#define XICS_IPI 0x2
#define XICS_BUID 0x1
#define XICS_IRQ_BASE (XICS_BUID << 12)
@@ -41,6 +53,7 @@
* (the kernel implementation supports more but we don't exploit
* that yet)
*/
+typedef struct XICSStateClass XICSStateClass;
typedef struct XICSState XICSState;
typedef struct ICPStateClass ICPStateClass;
typedef struct ICPState ICPState;
@@ -48,6 +61,13 @@ typedef struct ICSStateClass ICSStateClass;
typedef struct ICSState ICSState;
typedef struct ICSIRQState ICSIRQState;
+struct XICSStateClass {
+ DeviceClass parent_class;
+
+ 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 {
/*< private >*/
SysBusDevice parent_obj;