#include "monitor/monitor.h"
#include "hw/intc/intc.h"
-int xics_get_cpu_index_by_dt_id(int cpu_dt_id)
+void icp_pic_print_info(ICPState *icp, Monitor *mon)
{
- PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
-
- if (cpu) {
- return cpu->parent_obj.cpu_index;
- }
-
- return -1;
-}
-
-void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu)
-{
- CPUState *cs = CPU(cpu);
- ICPState *ss = &xics->ss[cs->cpu_index];
-
- assert(cs->cpu_index < xics->nr_servers);
- assert(cs == ss->cs);
-
- ss->output = NULL;
- ss->cs = NULL;
-}
-
-void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
-{
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
- ICPState *ss = &xics->ss[cs->cpu_index];
- XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
-
- assert(cs->cpu_index < xics->nr_servers);
-
- ss->cs = cs;
-
- if (info->cpu_setup) {
- info->cpu_setup(xics, cpu);
- }
-
- 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();
- }
-}
-
-static void icp_pic_print_info(InterruptStatsProvider *obj,
- Monitor *mon)
-{
- ICPState *icp = ICP(obj);
+ ICPStateClass *icpc = ICP_GET_CLASS(icp);
int cpu_index = icp->cs ? icp->cs->cpu_index : -1;
if (!icp->output) {
return;
}
+
+ if (icpc->synchronize_state) {
+ icpc->synchronize_state(icp);
+ }
+
monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n",
cpu_index, icp->xirr, icp->xirr_owner,
icp->pending_priority, icp->mfrr);
}
-static void ics_simple_pic_print_info(InterruptStatsProvider *obj,
- Monitor *mon)
+void ics_pic_print_info(ICSState *ics, Monitor *mon)
{
- ICSState *ics = ICS_SIMPLE(obj);
+ ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics);
uint32_t i;
monitor_printf(mon, "ICS %4x..%4x %p\n",
return;
}
+ if (icsc->synchronize_state) {
+ icsc->synchronize_state(ics);
+ }
+
for (i = 0; i < ics->nr_irqs; i++) {
ICSIRQState *irq = ics->irqs + i;
}
}
-/*
- * XICS Common class - parent for emulated XICS and KVM-XICS
- */
-static void xics_common_reset(DeviceState *d)
-{
- XICSState *xics = XICS_COMMON(d);
- int i;
-
- for (i = 0; i < xics->nr_servers; i++) {
- device_reset(DEVICE(&xics->ss[i]));
- }
-}
-
-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_DEVICE,
- .instance_size = sizeof(XICSState),
- .class_size = sizeof(XICSStateClass),
- .class_init = xics_common_class_init,
-};
-
/*
* ICP: Presentation layer
*/
#define XISR_MASK 0x00ffffff
#define CPPR_MASK 0xff000000
-#define XISR(ss) (((ss)->xirr) & XISR_MASK)
-#define CPPR(ss) (((ss)->xirr) >> 24)
+#define XISR(icp) (((icp)->xirr) & XISR_MASK)
+#define CPPR(icp) (((icp)->xirr) >> 24)
static void ics_reject(ICSState *ics, uint32_t nr)
{
}
}
-static void icp_check_ipi(ICPState *ss)
+static void icp_check_ipi(ICPState *icp)
{
- if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
+ if (XISR(icp) && (icp->pending_priority <= icp->mfrr)) {
return;
}
- trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr);
+ trace_xics_icp_check_ipi(icp->cs->cpu_index, icp->mfrr);
- if (XISR(ss) && ss->xirr_owner) {
- ics_reject(ss->xirr_owner, XISR(ss));
+ if (XISR(icp) && icp->xirr_owner) {
+ ics_reject(icp->xirr_owner, XISR(icp));
}
- ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
- ss->pending_priority = ss->mfrr;
- ss->xirr_owner = NULL;
- qemu_irq_raise(ss->output);
+ icp->xirr = (icp->xirr & ~XISR_MASK) | XICS_IPI;
+ icp->pending_priority = icp->mfrr;
+ icp->xirr_owner = NULL;
+ qemu_irq_raise(icp->output);
}
-static void icp_resend(ICPState *ss)
+void icp_resend(ICPState *icp)
{
- XICSFabric *xi = ss->xics;
+ XICSFabric *xi = icp->xics;
XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
- if (ss->mfrr < CPPR(ss)) {
- icp_check_ipi(ss);
+ if (icp->mfrr < CPPR(icp)) {
+ icp_check_ipi(icp);
}
xic->ics_resend(xi);
}
-void icp_set_cppr(ICPState *ss, uint8_t cppr)
+void icp_set_cppr(ICPState *icp, uint8_t cppr)
{
uint8_t old_cppr;
uint32_t old_xisr;
- old_cppr = CPPR(ss);
- ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
+ old_cppr = CPPR(icp);
+ icp->xirr = (icp->xirr & ~CPPR_MASK) | (cppr << 24);
if (cppr < old_cppr) {
- if (XISR(ss) && (cppr <= ss->pending_priority)) {
- old_xisr = XISR(ss);
- ss->xirr &= ~XISR_MASK; /* Clear XISR */
- ss->pending_priority = 0xff;
- qemu_irq_lower(ss->output);
- if (ss->xirr_owner) {
- ics_reject(ss->xirr_owner, old_xisr);
- ss->xirr_owner = NULL;
+ if (XISR(icp) && (cppr <= icp->pending_priority)) {
+ old_xisr = XISR(icp);
+ icp->xirr &= ~XISR_MASK; /* Clear XISR */
+ icp->pending_priority = 0xff;
+ qemu_irq_lower(icp->output);
+ if (icp->xirr_owner) {
+ ics_reject(icp->xirr_owner, old_xisr);
+ icp->xirr_owner = NULL;
}
}
} else {
- if (!XISR(ss)) {
- icp_resend(ss);
+ if (!XISR(icp)) {
+ icp_resend(icp);
}
}
}
-void icp_set_mfrr(ICPState *ss, uint8_t mfrr)
+void icp_set_mfrr(ICPState *icp, uint8_t mfrr)
{
- ss->mfrr = mfrr;
- if (mfrr < CPPR(ss)) {
- icp_check_ipi(ss);
+ icp->mfrr = mfrr;
+ if (mfrr < CPPR(icp)) {
+ icp_check_ipi(icp);
}
}
-uint32_t icp_accept(ICPState *ss)
+uint32_t icp_accept(ICPState *icp)
{
- uint32_t xirr = ss->xirr;
+ uint32_t xirr = icp->xirr;
- qemu_irq_lower(ss->output);
- ss->xirr = ss->pending_priority << 24;
- ss->pending_priority = 0xff;
- ss->xirr_owner = NULL;
+ qemu_irq_lower(icp->output);
+ icp->xirr = icp->pending_priority << 24;
+ icp->pending_priority = 0xff;
+ icp->xirr_owner = NULL;
- trace_xics_icp_accept(xirr, ss->xirr);
+ trace_xics_icp_accept(xirr, icp->xirr);
return xirr;
}
-uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)
+uint32_t icp_ipoll(ICPState *icp, uint32_t *mfrr)
{
if (mfrr) {
- *mfrr = ss->mfrr;
+ *mfrr = icp->mfrr;
}
- return ss->xirr;
+ return icp->xirr;
}
-void icp_eoi(ICPState *ss, uint32_t xirr)
+void icp_eoi(ICPState *icp, uint32_t xirr)
{
- XICSFabric *xi = ss->xics;
+ XICSFabric *xi = icp->xics;
XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
ICSState *ics;
uint32_t irq;
/* Send EOI -> ICS */
- ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
- trace_xics_icp_eoi(ss->cs->cpu_index, xirr, ss->xirr);
+ icp->xirr = (icp->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
+ trace_xics_icp_eoi(icp->cs->cpu_index, xirr, icp->xirr);
irq = xirr & XISR_MASK;
ics = xic->ics_get(xi, irq);
if (ics) {
ics_eoi(ics, irq);
}
- if (!XISR(ss)) {
- icp_resend(ss);
+ if (!XISR(icp)) {
+ icp_resend(icp);
}
}
static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority)
{
- XICSState *xics = ics->xics;
- ICPState *ss = xics->ss + server;
+ ICPState *icp = xics_icp_get(ics->xics, server);
trace_xics_icp_irq(server, nr, priority);
- if ((priority >= CPPR(ss))
- || (XISR(ss) && (ss->pending_priority <= priority))) {
+ if ((priority >= CPPR(icp))
+ || (XISR(icp) && (icp->pending_priority <= priority))) {
ics_reject(ics, nr);
} else {
- if (XISR(ss) && ss->xirr_owner) {
- ics_reject(ss->xirr_owner, XISR(ss));
- ss->xirr_owner = NULL;
+ if (XISR(icp) && icp->xirr_owner) {
+ ics_reject(icp->xirr_owner, XISR(icp));
+ icp->xirr_owner = NULL;
}
- ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
- ss->xirr_owner = ics;
- ss->pending_priority = priority;
- trace_xics_icp_raise(ss->xirr, ss->pending_priority);
- qemu_irq_raise(ss->output);
+ icp->xirr = (icp->xirr & ~XISR_MASK) | (nr & XISR_MASK);
+ icp->xirr_owner = ics;
+ icp->pending_priority = priority;
+ trace_xics_icp_raise(icp->xirr, icp->pending_priority);
+ qemu_irq_raise(icp->output);
}
}
-static void icp_dispatch_pre_save(void *opaque)
+static int icp_dispatch_pre_save(void *opaque)
{
- ICPState *ss = opaque;
- ICPStateClass *info = ICP_GET_CLASS(ss);
+ ICPState *icp = opaque;
+ ICPStateClass *info = ICP_GET_CLASS(icp);
if (info->pre_save) {
- info->pre_save(ss);
+ info->pre_save(icp);
}
+
+ return 0;
}
static int icp_dispatch_post_load(void *opaque, int version_id)
{
- ICPState *ss = opaque;
- ICPStateClass *info = ICP_GET_CLASS(ss);
+ ICPState *icp = opaque;
+ ICPStateClass *info = ICP_GET_CLASS(icp);
if (info->post_load) {
- return info->post_load(ss, version_id);
+ return info->post_load(icp, version_id);
}
return 0;
},
};
-static void icp_reset(DeviceState *dev)
+static void icp_reset(void *dev)
{
ICPState *icp = ICP(dev);
+ ICPStateClass *icpc = ICP_GET_CLASS(icp);
icp->xirr = 0;
icp->pending_priority = 0xff;
/* Make all outputs are deasserted */
qemu_set_irq(icp->output, 0);
+
+ if (icpc->reset) {
+ icpc->reset(icp);
+ }
}
static void icp_realize(DeviceState *dev, Error **errp)
{
ICPState *icp = ICP(dev);
+ ICPStateClass *icpc = ICP_GET_CLASS(dev);
+ PowerPCCPU *cpu;
+ CPUPPCState *env;
Object *obj;
Error *err = NULL;
- obj = object_property_get_link(OBJECT(dev), "xics", &err);
+ obj = object_property_get_link(OBJECT(dev), ICP_PROP_XICS, &err);
if (!obj) {
- error_setg(errp, "%s: required link 'xics' not found: %s",
- __func__, error_get_pretty(err));
+ error_propagate(errp, err);
+ error_prepend(errp, "required link '" ICP_PROP_XICS "' not found: ");
return;
}
icp->xics = XICS_FABRIC(obj);
+
+ obj = object_property_get_link(OBJECT(dev), ICP_PROP_CPU, &err);
+ if (!obj) {
+ error_propagate(errp, err);
+ error_prepend(errp, "required link '" ICP_PROP_CPU "' not found: ");
+ return;
+ }
+
+ cpu = POWERPC_CPU(obj);
+ icp->cs = CPU(obj);
+
+ env = &cpu->env;
+ switch (PPC_INPUT(env)) {
+ case PPC_FLAGS_INPUT_POWER7:
+ icp->output = env->irq_inputs[POWER7_INPUT_INT];
+ break;
+
+ case PPC_FLAGS_INPUT_970:
+ icp->output = env->irq_inputs[PPC970_INPUT_INT];
+ break;
+
+ default:
+ error_setg(errp, "XICS interrupt controller does not support this CPU bus model");
+ return;
+ }
+
+ if (icpc->realize) {
+ icpc->realize(icp, errp);
+ }
+
+ qemu_register_reset(icp_reset, dev);
+ vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp);
}
+static void icp_unrealize(DeviceState *dev, Error **errp)
+{
+ ICPState *icp = ICP(dev);
+
+ vmstate_unregister(NULL, &vmstate_icp_server, icp);
+ qemu_unregister_reset(icp_reset, dev);
+}
static void icp_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
- dc->reset = icp_reset;
- dc->vmsd = &vmstate_icp_server;
dc->realize = icp_realize;
- ic->print_info = icp_pic_print_info;
+ dc->unrealize = icp_unrealize;
}
static const TypeInfo icp_info = {
.instance_size = sizeof(ICPState),
.class_init = icp_class_init,
.class_size = sizeof(ICPStateClass),
- .interfaces = (InterfaceInfo[]) {
- { TYPE_INTERRUPT_STATS_PROVIDER },
- { }
- },
};
+Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, 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_XICS, OBJECT(xi),
+ &error_abort);
+ 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;
+}
+
/*
* ICS: Source layer
*/
}
}
-static void ics_simple_reset(DeviceState *dev)
+static void ics_simple_reset(void *dev)
{
ICSState *ics = ICS_SIMPLE(dev);
int i;
}
}
-static int ics_simple_post_load(ICSState *ics, int version_id)
-{
- int i;
-
- for (i = 0; i < ics->xics->nr_servers; i++) {
- icp_resend(&ics->xics->ss[i]);
- }
-
- return 0;
-}
-
-static void ics_simple_dispatch_pre_save(void *opaque)
+static int ics_simple_dispatch_pre_save(void *opaque)
{
ICSState *ics = opaque;
ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
if (info->pre_save) {
info->pre_save(ics);
}
+
+ return 0;
}
static int ics_simple_dispatch_post_load(void *opaque, int version_id)
.post_load = ics_simple_dispatch_post_load,
.fields = (VMStateField[]) {
/* Sanity check */
- VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
+ VMSTATE_UINT32_EQUAL(nr_irqs, ICSState, NULL),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
vmstate_ics_simple_irq,
ics->offset = XICS_IRQ_BASE;
}
-static void ics_simple_realize(DeviceState *dev, Error **errp)
+static void ics_simple_realize(ICSState *ics, Error **errp)
{
- ICSState *ics = ICS_SIMPLE(dev);
-
if (!ics->nr_irqs) {
error_setg(errp, "Number of interrupts needs to be greater 0");
return;
}
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
+
+ qemu_register_reset(ics_simple_reset, ics);
}
static Property ics_simple_properties[] = {
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_BASE_CLASS(klass);
- InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
isc->realize = ics_simple_realize;
dc->props = ics_simple_properties;
dc->vmsd = &vmstate_ics_simple;
- dc->reset = ics_simple_reset;
- isc->post_load = ics_simple_post_load;
isc->reject = ics_simple_reject;
isc->resend = ics_simple_resend;
isc->eoi = ics_simple_eoi;
- ic->print_info = ics_simple_pic_print_info;
}
static const TypeInfo ics_simple_info = {
.class_init = ics_simple_class_init,
.class_size = sizeof(ICSStateClass),
.instance_init = ics_simple_initfn,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_INTERRUPT_STATS_PROVIDER },
- { }
- },
};
static void ics_base_realize(DeviceState *dev, Error **errp)
Object *obj;
Error *err = NULL;
- obj = object_property_get_link(OBJECT(dev), "xics", &err);
+ obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err);
if (!obj) {
- error_setg(errp, "%s: required link 'xics' not found: %s",
- __func__, error_get_pretty(err));
+ error_propagate(errp, err);
+ error_prepend(errp, "required link '" ICS_PROP_XICS "' not found: ");
return;
}
- ics->xics = XICS_COMMON(obj);
+ ics->xics = XICS_FABRIC(obj);
if (icsc->realize) {
- icsc->realize(dev, errp);
+ icsc->realize(ics, errp);
}
}
/*
* Exported functions
*/
-qemu_irq xics_get_qirq(XICSFabric *xi, int irq)
+ICPState *xics_icp_get(XICSFabric *xi, int server)
{
XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
- ICSState *ics = xic->ics_get(xi, irq);
-
- if (ics) {
- return ics->qirqs[irq - ics->offset];
- }
- return NULL;
+ return xic->icp_get(xi, server);
}
void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
static void xics_register_types(void)
{
- type_register_static(&xics_common_info);
type_register_static(&ics_simple_info);
type_register_static(&ics_base_info);
type_register_static(&icp_info);