diff options
Diffstat (limited to 'hw/intc')
| -rw-r--r-- | hw/intc/xics.c | 99 | ||||
| -rw-r--r-- | hw/intc/xics_kvm.c | 13 | ||||
| -rw-r--r-- | hw/intc/xics_spapr.c | 53 |
3 files changed, 116 insertions, 49 deletions
diff --git a/hw/intc/xics.c b/hw/intc/xics.c index f40b00003a..095c16a300 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -35,6 +35,8 @@ #include "hw/ppc/xics.h" #include "qemu/error-report.h" #include "qapi/visitor.h" +#include "monitor/monitor.h" +#include "hw/intc/intc.h" int xics_get_cpu_index_by_dt_id(int cpu_dt_id) { @@ -90,6 +92,47 @@ void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu) } } +static void xics_common_pic_print_info(InterruptStatsProvider *obj, + Monitor *mon) +{ + XICSState *xics = XICS_COMMON(obj); + ICSState *ics; + uint32_t i; + + for (i = 0; i < xics->nr_servers; i++) { + ICPState *icp = &xics->ss[i]; + + if (!icp->output) { + continue; + } + monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n", + i, icp->xirr, icp->xirr_owner, + icp->pending_priority, icp->mfrr); + } + + QLIST_FOREACH(ics, &xics->ics, list) { + monitor_printf(mon, "ICS %4x..%4x %p\n", + ics->offset, ics->offset + ics->nr_irqs - 1, ics); + + if (!ics->irqs) { + continue; + } + + for (i = 0; i < ics->nr_irqs; i++) { + ICSIRQState *irq = ics->irqs + i; + + if (!(irq->flags & XICS_FLAGS_IRQ_MASK)) { + continue; + } + monitor_printf(mon, " %4x %s %02x %02x\n", + ics->offset + i, + (irq->flags & XICS_FLAGS_IRQ_LSI) ? + "LSI" : "MSI", + irq->priority, irq->status); + } + } +} + /* * XICS Common class - parent for emulated XICS and KVM-XICS */ @@ -140,6 +183,25 @@ static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name, info->set_nr_irqs(xics, value, errp); } +void xics_set_nr_servers(XICSState *xics, uint32_t nr_servers, + const char *typename, Error **errp) +{ + int i; + + xics->nr_servers = nr_servers; + + xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState)); + for (i = 0; i < xics->nr_servers; i++) { + char name[32]; + ICPState *icp = &xics->ss[i]; + + object_initialize(icp, sizeof(*icp), typename); + snprintf(name, sizeof(name), "icp[%d]", i); + object_property_add_child(OBJECT(xics), name, OBJECT(icp), errp); + icp->xics = xics; + } +} + static void xics_prop_get_nr_servers(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -155,7 +217,7 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v, Error **errp) { XICSState *xics = XICS_COMMON(obj); - XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); + XICSStateClass *xsc = XICS_COMMON_GET_CLASS(xics); Error *error = NULL; int64_t value; @@ -170,8 +232,8 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v, return; } - assert(info->set_nr_servers); - info->set_nr_servers(xics, value, errp); + assert(xsc->set_nr_servers); + xsc->set_nr_servers(xics, value, errp); } static void xics_common_initfn(Object *obj) @@ -190,8 +252,10 @@ static void xics_common_initfn(Object *obj) static void xics_common_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); dc->reset = xics_common_reset; + ic->print_info = xics_common_pic_print_info; } static const TypeInfo xics_common_info = { @@ -201,6 +265,10 @@ static const TypeInfo xics_common_info = { .class_size = sizeof(XICSStateClass), .instance_init = xics_common_initfn, .class_init = xics_common_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; /* @@ -258,22 +326,20 @@ static void icp_check_ipi(ICPState *ss) qemu_irq_raise(ss->output); } -static void icp_resend(XICSState *xics, int server) +static void icp_resend(ICPState *ss) { - ICPState *ss = xics->ss + server; ICSState *ics; if (ss->mfrr < CPPR(ss)) { icp_check_ipi(ss); } - QLIST_FOREACH(ics, &xics->ics, list) { + QLIST_FOREACH(ics, &ss->xics->ics, list) { ics_resend(ics); } } -void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) +void icp_set_cppr(ICPState *ss, uint8_t cppr) { - ICPState *ss = xics->ss + server; uint8_t old_cppr; uint32_t old_xisr; @@ -293,15 +359,13 @@ void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) } } else { if (!XISR(ss)) { - icp_resend(xics, server); + icp_resend(ss); } } } -void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr) +void icp_set_mfrr(ICPState *ss, uint8_t mfrr) { - ICPState *ss = xics->ss + server; - ss->mfrr = mfrr; if (mfrr < CPPR(ss)) { icp_check_ipi(ss); @@ -330,23 +394,22 @@ uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr) return ss->xirr; } -void icp_eoi(XICSState *xics, int server, uint32_t xirr) +void icp_eoi(ICPState *ss, uint32_t xirr) { - ICPState *ss = xics->ss + server; ICSState *ics; uint32_t irq; /* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); - trace_xics_icp_eoi(server, xirr, ss->xirr); + trace_xics_icp_eoi(ss->cs->cpu_index, xirr, ss->xirr); irq = xirr & XISR_MASK; - QLIST_FOREACH(ics, &xics->ics, list) { + QLIST_FOREACH(ics, &ss->xics->ics, list) { if (ics_valid_irq(ics, irq)) { ics_eoi(ics, irq); } } if (!XISR(ss)) { - icp_resend(xics, server); + icp_resend(ss); } } @@ -605,7 +668,7 @@ 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, i); + icp_resend(&ics->xics->ss[i]); } return 0; diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 9c2f198fd1..17694eaa87 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -373,18 +373,7 @@ static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, static void xics_kvm_set_nr_servers(XICSState *xics, uint32_t nr_servers, Error **errp) { - int i; - - xics->nr_servers = nr_servers; - - xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState)); - for (i = 0; i < xics->nr_servers; i++) { - char buffer[32]; - object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_KVM_ICP); - snprintf(buffer, sizeof(buffer), "icp[%d]", i); - object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]), - errp); - } + xics_set_nr_servers(xics, nr_servers, TYPE_KVM_ICP, errp); } static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr, diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index e8d0623c2c..2e3f1c5e95 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -32,6 +32,7 @@ #include "qemu/timer.h" #include "hw/ppc/spapr.h" #include "hw/ppc/xics.h" +#include "hw/ppc/fdt.h" #include "qapi/visitor.h" #include "qapi/error.h" @@ -43,9 +44,10 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); + ICPState *icp = &spapr->xics->ss[cs->cpu_index]; target_ulong cppr = args[0]; - icp_set_cppr(spapr->xics, cs->cpu_index, cppr); + icp_set_cppr(icp, cppr); return H_SUCCESS; } @@ -59,7 +61,7 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr, return H_PARAMETER; } - icp_set_mfrr(spapr->xics, server, mfrr); + icp_set_mfrr(spapr->xics->ss + server, mfrr); return H_SUCCESS; } @@ -67,7 +69,8 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - uint32_t xirr = icp_accept(spapr->xics->ss + cs->cpu_index); + ICPState *icp = &spapr->xics->ss[cs->cpu_index]; + uint32_t xirr = icp_accept(icp); args[0] = xirr; return H_SUCCESS; @@ -77,8 +80,8 @@ static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - ICPState *ss = &spapr->xics->ss[cs->cpu_index]; - uint32_t xirr = icp_accept(ss); + ICPState *icp = &spapr->xics->ss[cs->cpu_index]; + uint32_t xirr = icp_accept(icp); args[0] = xirr; args[1] = cpu_get_host_ticks(); @@ -89,9 +92,10 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); + ICPState *icp = &spapr->xics->ss[cs->cpu_index]; target_ulong xirr = args[0]; - icp_eoi(spapr->xics, cs->cpu_index, xirr); + icp_eoi(icp, xirr); return H_SUCCESS; } @@ -99,8 +103,9 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); + ICPState *icp = &spapr->xics->ss[cs->cpu_index]; uint32_t mfrr; - uint32_t xirr = icp_ipoll(spapr->xics->ss + cs->cpu_index, &mfrr); + uint32_t xirr = icp_ipoll(icp, &mfrr); args[0] = xirr; args[1] = mfrr; @@ -249,18 +254,7 @@ static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers, Error **errp) { - int i; - - xics->nr_servers = nr_servers; - - xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState)); - for (i = 0; i < xics->nr_servers; i++) { - char buffer[32]; - object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_ICP); - snprintf(buffer, sizeof(buffer), "icp[%d]", i); - object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]), - errp); - } + xics_set_nr_servers(xics, nr_servers, TYPE_ICP, errp); } static void xics_spapr_realize(DeviceState *dev, Error **errp) @@ -456,6 +450,27 @@ void xics_spapr_free(XICSState *xics, int irq, int num) } } +void spapr_dt_xics(XICSState *xics, void *fdt, uint32_t phandle) +{ + uint32_t interrupt_server_ranges_prop[] = { + 0, cpu_to_be32(xics->nr_servers), + }; + int node; + + _FDT(node = fdt_add_subnode(fdt, 0, "interrupt-controller")); + + _FDT(fdt_setprop_string(fdt, node, "device_type", + "PowerPC-External-Interrupt-Presentation")); + _FDT(fdt_setprop_string(fdt, node, "compatible", "IBM,ppc-xicp")); + _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); + _FDT(fdt_setprop(fdt, node, "ibm,interrupt-server-ranges", + interrupt_server_ranges_prop, + sizeof(interrupt_server_ranges_prop))); + _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); + _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); + _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); +} + static void xics_spapr_register_types(void) { type_register_static(&xics_spapr_info); |