1b5cec4c5SDavid Gibson /* 2b5cec4c5SDavid Gibson * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator 3b5cec4c5SDavid Gibson * 4b5cec4c5SDavid Gibson * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics 5b5cec4c5SDavid Gibson * 6b5cec4c5SDavid Gibson * Copyright (c) 2010,2011 David Gibson, IBM Corporation. 7b5cec4c5SDavid Gibson * 8b5cec4c5SDavid Gibson * Permission is hereby granted, free of charge, to any person obtaining a copy 9b5cec4c5SDavid Gibson * of this software and associated documentation files (the "Software"), to deal 10b5cec4c5SDavid Gibson * in the Software without restriction, including without limitation the rights 11b5cec4c5SDavid Gibson * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12b5cec4c5SDavid Gibson * copies of the Software, and to permit persons to whom the Software is 13b5cec4c5SDavid Gibson * furnished to do so, subject to the following conditions: 14b5cec4c5SDavid Gibson * 15b5cec4c5SDavid Gibson * The above copyright notice and this permission notice shall be included in 16b5cec4c5SDavid Gibson * all copies or substantial portions of the Software. 17b5cec4c5SDavid Gibson * 18b5cec4c5SDavid Gibson * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19b5cec4c5SDavid Gibson * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20b5cec4c5SDavid Gibson * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21b5cec4c5SDavid Gibson * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22b5cec4c5SDavid Gibson * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23b5cec4c5SDavid Gibson * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24b5cec4c5SDavid Gibson * THE SOFTWARE. 25b5cec4c5SDavid Gibson * 26b5cec4c5SDavid Gibson */ 27b5cec4c5SDavid Gibson 280d75590dSPeter Maydell #include "qemu/osdep.h" 29da34e65cSMarkus Armbruster #include "qapi/error.h" 304771d756SPaolo Bonzini #include "qemu-common.h" 314771d756SPaolo Bonzini #include "cpu.h" 3283c9f4caSPaolo Bonzini #include "hw/hw.h" 33500efa23SDavid Gibson #include "trace.h" 345d87e4b7SBenjamin Herrenschmidt #include "qemu/timer.h" 350d09e41aSPaolo Bonzini #include "hw/ppc/xics.h" 369ccff2a4SAlexey Kardashevskiy #include "qemu/error-report.h" 375a3d7b23SAlexey Kardashevskiy #include "qapi/visitor.h" 38*b1fc72f0SBenjamin Herrenschmidt #include "monitor/monitor.h" 39*b1fc72f0SBenjamin Herrenschmidt #include "hw/intc/intc.h" 40b5cec4c5SDavid Gibson 419c7027baSBenjamin Herrenschmidt int xics_get_cpu_index_by_dt_id(int cpu_dt_id) 420f20ba62SAlexey Kardashevskiy { 430f20ba62SAlexey Kardashevskiy PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id); 440f20ba62SAlexey Kardashevskiy 450f20ba62SAlexey Kardashevskiy if (cpu) { 460f20ba62SAlexey Kardashevskiy return cpu->parent_obj.cpu_index; 470f20ba62SAlexey Kardashevskiy } 480f20ba62SAlexey Kardashevskiy 490f20ba62SAlexey Kardashevskiy return -1; 500f20ba62SAlexey Kardashevskiy } 510f20ba62SAlexey Kardashevskiy 5227f24582SBenjamin Herrenschmidt void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu) 534a4b344cSBharata B Rao { 544a4b344cSBharata B Rao CPUState *cs = CPU(cpu); 5527f24582SBenjamin Herrenschmidt ICPState *ss = &xics->ss[cs->cpu_index]; 564a4b344cSBharata B Rao 5727f24582SBenjamin Herrenschmidt assert(cs->cpu_index < xics->nr_servers); 584a4b344cSBharata B Rao assert(cs == ss->cs); 594a4b344cSBharata B Rao 604a4b344cSBharata B Rao ss->output = NULL; 614a4b344cSBharata B Rao ss->cs = NULL; 624a4b344cSBharata B Rao } 634a4b344cSBharata B Rao 6427f24582SBenjamin Herrenschmidt void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu) 658ffe04edSAlexey Kardashevskiy { 668ffe04edSAlexey Kardashevskiy CPUState *cs = CPU(cpu); 678ffe04edSAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 6827f24582SBenjamin Herrenschmidt ICPState *ss = &xics->ss[cs->cpu_index]; 6927f24582SBenjamin Herrenschmidt XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); 708ffe04edSAlexey Kardashevskiy 7127f24582SBenjamin Herrenschmidt assert(cs->cpu_index < xics->nr_servers); 728ffe04edSAlexey Kardashevskiy 734a4b344cSBharata B Rao ss->cs = cs; 744a4b344cSBharata B Rao 755eb92cccSAlexey Kardashevskiy if (info->cpu_setup) { 7627f24582SBenjamin Herrenschmidt info->cpu_setup(xics, cpu); 775eb92cccSAlexey Kardashevskiy } 785eb92cccSAlexey Kardashevskiy 798ffe04edSAlexey Kardashevskiy switch (PPC_INPUT(env)) { 808ffe04edSAlexey Kardashevskiy case PPC_FLAGS_INPUT_POWER7: 818ffe04edSAlexey Kardashevskiy ss->output = env->irq_inputs[POWER7_INPUT_INT]; 828ffe04edSAlexey Kardashevskiy break; 838ffe04edSAlexey Kardashevskiy 848ffe04edSAlexey Kardashevskiy case PPC_FLAGS_INPUT_970: 858ffe04edSAlexey Kardashevskiy ss->output = env->irq_inputs[PPC970_INPUT_INT]; 868ffe04edSAlexey Kardashevskiy break; 878ffe04edSAlexey Kardashevskiy 888ffe04edSAlexey Kardashevskiy default: 899ccff2a4SAlexey Kardashevskiy error_report("XICS interrupt controller does not support this CPU " 909ccff2a4SAlexey Kardashevskiy "bus model"); 918ffe04edSAlexey Kardashevskiy abort(); 928ffe04edSAlexey Kardashevskiy } 938ffe04edSAlexey Kardashevskiy } 948ffe04edSAlexey Kardashevskiy 95*b1fc72f0SBenjamin Herrenschmidt static void xics_common_pic_print_info(InterruptStatsProvider *obj, 96*b1fc72f0SBenjamin Herrenschmidt Monitor *mon) 97*b1fc72f0SBenjamin Herrenschmidt { 98*b1fc72f0SBenjamin Herrenschmidt XICSState *xics = XICS_COMMON(obj); 99*b1fc72f0SBenjamin Herrenschmidt ICSState *ics; 100*b1fc72f0SBenjamin Herrenschmidt uint32_t i; 101*b1fc72f0SBenjamin Herrenschmidt 102*b1fc72f0SBenjamin Herrenschmidt for (i = 0; i < xics->nr_servers; i++) { 103*b1fc72f0SBenjamin Herrenschmidt ICPState *icp = &xics->ss[i]; 104*b1fc72f0SBenjamin Herrenschmidt 105*b1fc72f0SBenjamin Herrenschmidt if (!icp->output) { 106*b1fc72f0SBenjamin Herrenschmidt continue; 107*b1fc72f0SBenjamin Herrenschmidt } 108*b1fc72f0SBenjamin Herrenschmidt monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n", 109*b1fc72f0SBenjamin Herrenschmidt i, icp->xirr, icp->xirr_owner, 110*b1fc72f0SBenjamin Herrenschmidt icp->pending_priority, icp->mfrr); 111*b1fc72f0SBenjamin Herrenschmidt } 112*b1fc72f0SBenjamin Herrenschmidt 113*b1fc72f0SBenjamin Herrenschmidt QLIST_FOREACH(ics, &xics->ics, list) { 114*b1fc72f0SBenjamin Herrenschmidt monitor_printf(mon, "ICS %4x..%4x %p\n", 115*b1fc72f0SBenjamin Herrenschmidt ics->offset, ics->offset + ics->nr_irqs - 1, ics); 116*b1fc72f0SBenjamin Herrenschmidt 117*b1fc72f0SBenjamin Herrenschmidt if (!ics->irqs) { 118*b1fc72f0SBenjamin Herrenschmidt continue; 119*b1fc72f0SBenjamin Herrenschmidt } 120*b1fc72f0SBenjamin Herrenschmidt 121*b1fc72f0SBenjamin Herrenschmidt for (i = 0; i < ics->nr_irqs; i++) { 122*b1fc72f0SBenjamin Herrenschmidt ICSIRQState *irq = ics->irqs + i; 123*b1fc72f0SBenjamin Herrenschmidt 124*b1fc72f0SBenjamin Herrenschmidt if (!(irq->flags & XICS_FLAGS_IRQ_MASK)) { 125*b1fc72f0SBenjamin Herrenschmidt continue; 126*b1fc72f0SBenjamin Herrenschmidt } 127*b1fc72f0SBenjamin Herrenschmidt monitor_printf(mon, " %4x %s %02x %02x\n", 128*b1fc72f0SBenjamin Herrenschmidt ics->offset + i, 129*b1fc72f0SBenjamin Herrenschmidt (irq->flags & XICS_FLAGS_IRQ_LSI) ? 130*b1fc72f0SBenjamin Herrenschmidt "LSI" : "MSI", 131*b1fc72f0SBenjamin Herrenschmidt irq->priority, irq->status); 132*b1fc72f0SBenjamin Herrenschmidt } 133*b1fc72f0SBenjamin Herrenschmidt } 134*b1fc72f0SBenjamin Herrenschmidt } 135*b1fc72f0SBenjamin Herrenschmidt 1365a3d7b23SAlexey Kardashevskiy /* 1375a3d7b23SAlexey Kardashevskiy * XICS Common class - parent for emulated XICS and KVM-XICS 1385a3d7b23SAlexey Kardashevskiy */ 1395a3d7b23SAlexey Kardashevskiy static void xics_common_reset(DeviceState *d) 1408ffe04edSAlexey Kardashevskiy { 14127f24582SBenjamin Herrenschmidt XICSState *xics = XICS_COMMON(d); 142cc706a53SBenjamin Herrenschmidt ICSState *ics; 1438ffe04edSAlexey Kardashevskiy int i; 1448ffe04edSAlexey Kardashevskiy 14527f24582SBenjamin Herrenschmidt for (i = 0; i < xics->nr_servers; i++) { 14627f24582SBenjamin Herrenschmidt device_reset(DEVICE(&xics->ss[i])); 1478ffe04edSAlexey Kardashevskiy } 1488ffe04edSAlexey Kardashevskiy 149cc706a53SBenjamin Herrenschmidt QLIST_FOREACH(ics, &xics->ics, list) { 150cc706a53SBenjamin Herrenschmidt device_reset(DEVICE(ics)); 151cc706a53SBenjamin Herrenschmidt } 1528ffe04edSAlexey Kardashevskiy } 1538ffe04edSAlexey Kardashevskiy 154d7bce999SEric Blake static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name, 155d7bce999SEric Blake void *opaque, Error **errp) 1565a3d7b23SAlexey Kardashevskiy { 15727f24582SBenjamin Herrenschmidt XICSState *xics = XICS_COMMON(obj); 15827f24582SBenjamin Herrenschmidt int64_t value = xics->nr_irqs; 1595a3d7b23SAlexey Kardashevskiy 16051e72bc1SEric Blake visit_type_int(v, name, &value, errp); 1615a3d7b23SAlexey Kardashevskiy } 1625a3d7b23SAlexey Kardashevskiy 163d7bce999SEric Blake static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name, 164d7bce999SEric Blake void *opaque, Error **errp) 1655a3d7b23SAlexey Kardashevskiy { 16627f24582SBenjamin Herrenschmidt XICSState *xics = XICS_COMMON(obj); 16727f24582SBenjamin Herrenschmidt XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); 1685a3d7b23SAlexey Kardashevskiy Error *error = NULL; 1695a3d7b23SAlexey Kardashevskiy int64_t value; 1705a3d7b23SAlexey Kardashevskiy 17151e72bc1SEric Blake visit_type_int(v, name, &value, &error); 1725a3d7b23SAlexey Kardashevskiy if (error) { 1735a3d7b23SAlexey Kardashevskiy error_propagate(errp, error); 1745a3d7b23SAlexey Kardashevskiy return; 1755a3d7b23SAlexey Kardashevskiy } 17627f24582SBenjamin Herrenschmidt if (xics->nr_irqs) { 1775a3d7b23SAlexey Kardashevskiy error_setg(errp, "Number of interrupts is already set to %u", 17827f24582SBenjamin Herrenschmidt xics->nr_irqs); 1795a3d7b23SAlexey Kardashevskiy return; 1805a3d7b23SAlexey Kardashevskiy } 1815a3d7b23SAlexey Kardashevskiy 1825a3d7b23SAlexey Kardashevskiy assert(info->set_nr_irqs); 18327f24582SBenjamin Herrenschmidt info->set_nr_irqs(xics, value, errp); 1845a3d7b23SAlexey Kardashevskiy } 1855a3d7b23SAlexey Kardashevskiy 1865a3d7b23SAlexey Kardashevskiy static void xics_prop_get_nr_servers(Object *obj, Visitor *v, 187d7bce999SEric Blake const char *name, void *opaque, 1885a3d7b23SAlexey Kardashevskiy Error **errp) 1895a3d7b23SAlexey Kardashevskiy { 19027f24582SBenjamin Herrenschmidt XICSState *xics = XICS_COMMON(obj); 19127f24582SBenjamin Herrenschmidt int64_t value = xics->nr_servers; 1925a3d7b23SAlexey Kardashevskiy 19351e72bc1SEric Blake visit_type_int(v, name, &value, errp); 1945a3d7b23SAlexey Kardashevskiy } 1955a3d7b23SAlexey Kardashevskiy 1965a3d7b23SAlexey Kardashevskiy static void xics_prop_set_nr_servers(Object *obj, Visitor *v, 197d7bce999SEric Blake const char *name, void *opaque, 1985a3d7b23SAlexey Kardashevskiy Error **errp) 1995a3d7b23SAlexey Kardashevskiy { 20027f24582SBenjamin Herrenschmidt XICSState *xics = XICS_COMMON(obj); 20127f24582SBenjamin Herrenschmidt XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); 2025a3d7b23SAlexey Kardashevskiy Error *error = NULL; 2035a3d7b23SAlexey Kardashevskiy int64_t value; 2045a3d7b23SAlexey Kardashevskiy 20551e72bc1SEric Blake visit_type_int(v, name, &value, &error); 2065a3d7b23SAlexey Kardashevskiy if (error) { 2075a3d7b23SAlexey Kardashevskiy error_propagate(errp, error); 2085a3d7b23SAlexey Kardashevskiy return; 2095a3d7b23SAlexey Kardashevskiy } 21027f24582SBenjamin Herrenschmidt if (xics->nr_servers) { 2115a3d7b23SAlexey Kardashevskiy error_setg(errp, "Number of servers is already set to %u", 21227f24582SBenjamin Herrenschmidt xics->nr_servers); 2135a3d7b23SAlexey Kardashevskiy return; 2145a3d7b23SAlexey Kardashevskiy } 2155a3d7b23SAlexey Kardashevskiy 2165a3d7b23SAlexey Kardashevskiy assert(info->set_nr_servers); 21727f24582SBenjamin Herrenschmidt info->set_nr_servers(xics, value, errp); 2185a3d7b23SAlexey Kardashevskiy } 2195a3d7b23SAlexey Kardashevskiy 2205a3d7b23SAlexey Kardashevskiy static void xics_common_initfn(Object *obj) 2215a3d7b23SAlexey Kardashevskiy { 222cc706a53SBenjamin Herrenschmidt XICSState *xics = XICS_COMMON(obj); 223cc706a53SBenjamin Herrenschmidt 224cc706a53SBenjamin Herrenschmidt QLIST_INIT(&xics->ics); 2255a3d7b23SAlexey Kardashevskiy object_property_add(obj, "nr_irqs", "int", 2265a3d7b23SAlexey Kardashevskiy xics_prop_get_nr_irqs, xics_prop_set_nr_irqs, 2275a3d7b23SAlexey Kardashevskiy NULL, NULL, NULL); 2285a3d7b23SAlexey Kardashevskiy object_property_add(obj, "nr_servers", "int", 2295a3d7b23SAlexey Kardashevskiy xics_prop_get_nr_servers, xics_prop_set_nr_servers, 2305a3d7b23SAlexey Kardashevskiy NULL, NULL, NULL); 2315a3d7b23SAlexey Kardashevskiy } 2325a3d7b23SAlexey Kardashevskiy 2335a3d7b23SAlexey Kardashevskiy static void xics_common_class_init(ObjectClass *oc, void *data) 2345a3d7b23SAlexey Kardashevskiy { 2355a3d7b23SAlexey Kardashevskiy DeviceClass *dc = DEVICE_CLASS(oc); 236*b1fc72f0SBenjamin Herrenschmidt InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); 2375a3d7b23SAlexey Kardashevskiy 2385a3d7b23SAlexey Kardashevskiy dc->reset = xics_common_reset; 239*b1fc72f0SBenjamin Herrenschmidt ic->print_info = xics_common_pic_print_info; 2405a3d7b23SAlexey Kardashevskiy } 2415a3d7b23SAlexey Kardashevskiy 2425a3d7b23SAlexey Kardashevskiy static const TypeInfo xics_common_info = { 2435a3d7b23SAlexey Kardashevskiy .name = TYPE_XICS_COMMON, 2445a3d7b23SAlexey Kardashevskiy .parent = TYPE_SYS_BUS_DEVICE, 2455a3d7b23SAlexey Kardashevskiy .instance_size = sizeof(XICSState), 2465a3d7b23SAlexey Kardashevskiy .class_size = sizeof(XICSStateClass), 2475a3d7b23SAlexey Kardashevskiy .instance_init = xics_common_initfn, 2485a3d7b23SAlexey Kardashevskiy .class_init = xics_common_class_init, 249*b1fc72f0SBenjamin Herrenschmidt .interfaces = (InterfaceInfo[]) { 250*b1fc72f0SBenjamin Herrenschmidt { TYPE_INTERRUPT_STATS_PROVIDER }, 251*b1fc72f0SBenjamin Herrenschmidt { } 252*b1fc72f0SBenjamin Herrenschmidt }, 2535a3d7b23SAlexey Kardashevskiy }; 2545a3d7b23SAlexey Kardashevskiy 255b5cec4c5SDavid Gibson /* 256b5cec4c5SDavid Gibson * ICP: Presentation layer 257b5cec4c5SDavid Gibson */ 258b5cec4c5SDavid Gibson 259b5cec4c5SDavid Gibson #define XISR_MASK 0x00ffffff 260b5cec4c5SDavid Gibson #define CPPR_MASK 0xff000000 261b5cec4c5SDavid Gibson 262b5cec4c5SDavid Gibson #define XISR(ss) (((ss)->xirr) & XISR_MASK) 263b5cec4c5SDavid Gibson #define CPPR(ss) (((ss)->xirr) >> 24) 264b5cec4c5SDavid Gibson 265d4d7a59aSBenjamin Herrenschmidt static void ics_reject(ICSState *ics, uint32_t nr) 266d4d7a59aSBenjamin Herrenschmidt { 267d4d7a59aSBenjamin Herrenschmidt ICSStateClass *k = ICS_BASE_GET_CLASS(ics); 268d4d7a59aSBenjamin Herrenschmidt 269d4d7a59aSBenjamin Herrenschmidt if (k->reject) { 270d4d7a59aSBenjamin Herrenschmidt k->reject(ics, nr); 271d4d7a59aSBenjamin Herrenschmidt } 272d4d7a59aSBenjamin Herrenschmidt } 273d4d7a59aSBenjamin Herrenschmidt 274d4d7a59aSBenjamin Herrenschmidt static void ics_resend(ICSState *ics) 275d4d7a59aSBenjamin Herrenschmidt { 276d4d7a59aSBenjamin Herrenschmidt ICSStateClass *k = ICS_BASE_GET_CLASS(ics); 277d4d7a59aSBenjamin Herrenschmidt 278d4d7a59aSBenjamin Herrenschmidt if (k->resend) { 279d4d7a59aSBenjamin Herrenschmidt k->resend(ics); 280d4d7a59aSBenjamin Herrenschmidt } 281d4d7a59aSBenjamin Herrenschmidt } 282d4d7a59aSBenjamin Herrenschmidt 283d4d7a59aSBenjamin Herrenschmidt static void ics_eoi(ICSState *ics, int nr) 284d4d7a59aSBenjamin Herrenschmidt { 285d4d7a59aSBenjamin Herrenschmidt ICSStateClass *k = ICS_BASE_GET_CLASS(ics); 286d4d7a59aSBenjamin Herrenschmidt 287d4d7a59aSBenjamin Herrenschmidt if (k->eoi) { 288d4d7a59aSBenjamin Herrenschmidt k->eoi(ics, nr); 289d4d7a59aSBenjamin Herrenschmidt } 290d4d7a59aSBenjamin Herrenschmidt } 291b5cec4c5SDavid Gibson 292cc706a53SBenjamin Herrenschmidt static void icp_check_ipi(ICPState *ss) 293b5cec4c5SDavid Gibson { 294b5cec4c5SDavid Gibson if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { 295b5cec4c5SDavid Gibson return; 296b5cec4c5SDavid Gibson } 297b5cec4c5SDavid Gibson 298cc706a53SBenjamin Herrenschmidt trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr); 299500efa23SDavid Gibson 300cc706a53SBenjamin Herrenschmidt if (XISR(ss) && ss->xirr_owner) { 301cc706a53SBenjamin Herrenschmidt ics_reject(ss->xirr_owner, XISR(ss)); 302b5cec4c5SDavid Gibson } 303b5cec4c5SDavid Gibson 304b5cec4c5SDavid Gibson ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; 305b5cec4c5SDavid Gibson ss->pending_priority = ss->mfrr; 306cc706a53SBenjamin Herrenschmidt ss->xirr_owner = NULL; 307b5cec4c5SDavid Gibson qemu_irq_raise(ss->output); 308b5cec4c5SDavid Gibson } 309b5cec4c5SDavid Gibson 31027f24582SBenjamin Herrenschmidt static void icp_resend(XICSState *xics, int server) 311b5cec4c5SDavid Gibson { 31227f24582SBenjamin Herrenschmidt ICPState *ss = xics->ss + server; 313cc706a53SBenjamin Herrenschmidt ICSState *ics; 314b5cec4c5SDavid Gibson 315b5cec4c5SDavid Gibson if (ss->mfrr < CPPR(ss)) { 316cc706a53SBenjamin Herrenschmidt icp_check_ipi(ss); 317b5cec4c5SDavid Gibson } 318cc706a53SBenjamin Herrenschmidt QLIST_FOREACH(ics, &xics->ics, list) { 319cc706a53SBenjamin Herrenschmidt ics_resend(ics); 320cc706a53SBenjamin Herrenschmidt } 321b5cec4c5SDavid Gibson } 322b5cec4c5SDavid Gibson 32327f24582SBenjamin Herrenschmidt void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) 324b5cec4c5SDavid Gibson { 32527f24582SBenjamin Herrenschmidt ICPState *ss = xics->ss + server; 326b5cec4c5SDavid Gibson uint8_t old_cppr; 327b5cec4c5SDavid Gibson uint32_t old_xisr; 328b5cec4c5SDavid Gibson 329b5cec4c5SDavid Gibson old_cppr = CPPR(ss); 330b5cec4c5SDavid Gibson ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24); 331b5cec4c5SDavid Gibson 332b5cec4c5SDavid Gibson if (cppr < old_cppr) { 333b5cec4c5SDavid Gibson if (XISR(ss) && (cppr <= ss->pending_priority)) { 334b5cec4c5SDavid Gibson old_xisr = XISR(ss); 335b5cec4c5SDavid Gibson ss->xirr &= ~XISR_MASK; /* Clear XISR */ 336e03c902cSDavid Gibson ss->pending_priority = 0xff; 337b5cec4c5SDavid Gibson qemu_irq_lower(ss->output); 338cc706a53SBenjamin Herrenschmidt if (ss->xirr_owner) { 339cc706a53SBenjamin Herrenschmidt ics_reject(ss->xirr_owner, old_xisr); 340cc706a53SBenjamin Herrenschmidt ss->xirr_owner = NULL; 341cc706a53SBenjamin Herrenschmidt } 342b5cec4c5SDavid Gibson } 343b5cec4c5SDavid Gibson } else { 344b5cec4c5SDavid Gibson if (!XISR(ss)) { 34527f24582SBenjamin Herrenschmidt icp_resend(xics, server); 346b5cec4c5SDavid Gibson } 347b5cec4c5SDavid Gibson } 348b5cec4c5SDavid Gibson } 349b5cec4c5SDavid Gibson 35027f24582SBenjamin Herrenschmidt void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr) 351b5cec4c5SDavid Gibson { 35227f24582SBenjamin Herrenschmidt ICPState *ss = xics->ss + server; 353b5cec4c5SDavid Gibson 354b5cec4c5SDavid Gibson ss->mfrr = mfrr; 355b5cec4c5SDavid Gibson if (mfrr < CPPR(ss)) { 356cc706a53SBenjamin Herrenschmidt icp_check_ipi(ss); 357b5cec4c5SDavid Gibson } 358b5cec4c5SDavid Gibson } 359b5cec4c5SDavid Gibson 3609c7027baSBenjamin Herrenschmidt uint32_t icp_accept(ICPState *ss) 361b5cec4c5SDavid Gibson { 362500efa23SDavid Gibson uint32_t xirr = ss->xirr; 363b5cec4c5SDavid Gibson 364b5cec4c5SDavid Gibson qemu_irq_lower(ss->output); 365b5cec4c5SDavid Gibson ss->xirr = ss->pending_priority << 24; 366e03c902cSDavid Gibson ss->pending_priority = 0xff; 367cc706a53SBenjamin Herrenschmidt ss->xirr_owner = NULL; 368500efa23SDavid Gibson 369500efa23SDavid Gibson trace_xics_icp_accept(xirr, ss->xirr); 370500efa23SDavid Gibson 371b5cec4c5SDavid Gibson return xirr; 372b5cec4c5SDavid Gibson } 373b5cec4c5SDavid Gibson 3741cbd2220SBenjamin Herrenschmidt uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr) 3751cbd2220SBenjamin Herrenschmidt { 3761cbd2220SBenjamin Herrenschmidt if (mfrr) { 3771cbd2220SBenjamin Herrenschmidt *mfrr = ss->mfrr; 3781cbd2220SBenjamin Herrenschmidt } 3791cbd2220SBenjamin Herrenschmidt return ss->xirr; 3801cbd2220SBenjamin Herrenschmidt } 3811cbd2220SBenjamin Herrenschmidt 38227f24582SBenjamin Herrenschmidt void icp_eoi(XICSState *xics, int server, uint32_t xirr) 383b5cec4c5SDavid Gibson { 38427f24582SBenjamin Herrenschmidt ICPState *ss = xics->ss + server; 385cc706a53SBenjamin Herrenschmidt ICSState *ics; 386cc706a53SBenjamin Herrenschmidt uint32_t irq; 387b5cec4c5SDavid Gibson 388b5cec4c5SDavid Gibson /* Send EOI -> ICS */ 389b5cec4c5SDavid Gibson ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); 390500efa23SDavid Gibson trace_xics_icp_eoi(server, xirr, ss->xirr); 391cc706a53SBenjamin Herrenschmidt irq = xirr & XISR_MASK; 392cc706a53SBenjamin Herrenschmidt QLIST_FOREACH(ics, &xics->ics, list) { 393cc706a53SBenjamin Herrenschmidt if (ics_valid_irq(ics, irq)) { 394cc706a53SBenjamin Herrenschmidt ics_eoi(ics, irq); 395cc706a53SBenjamin Herrenschmidt } 396cc706a53SBenjamin Herrenschmidt } 397b5cec4c5SDavid Gibson if (!XISR(ss)) { 39827f24582SBenjamin Herrenschmidt icp_resend(xics, server); 399b5cec4c5SDavid Gibson } 400b5cec4c5SDavid Gibson } 401b5cec4c5SDavid Gibson 402cc706a53SBenjamin Herrenschmidt static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority) 403b5cec4c5SDavid Gibson { 404cc706a53SBenjamin Herrenschmidt XICSState *xics = ics->xics; 40527f24582SBenjamin Herrenschmidt ICPState *ss = xics->ss + server; 406b5cec4c5SDavid Gibson 407500efa23SDavid Gibson trace_xics_icp_irq(server, nr, priority); 408500efa23SDavid Gibson 409b5cec4c5SDavid Gibson if ((priority >= CPPR(ss)) 410b5cec4c5SDavid Gibson || (XISR(ss) && (ss->pending_priority <= priority))) { 411cc706a53SBenjamin Herrenschmidt ics_reject(ics, nr); 412b5cec4c5SDavid Gibson } else { 413cc706a53SBenjamin Herrenschmidt if (XISR(ss) && ss->xirr_owner) { 414cc706a53SBenjamin Herrenschmidt ics_reject(ss->xirr_owner, XISR(ss)); 415cc706a53SBenjamin Herrenschmidt ss->xirr_owner = NULL; 416b5cec4c5SDavid Gibson } 417b5cec4c5SDavid Gibson ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); 418cc706a53SBenjamin Herrenschmidt ss->xirr_owner = ics; 419b5cec4c5SDavid Gibson ss->pending_priority = priority; 420500efa23SDavid Gibson trace_xics_icp_raise(ss->xirr, ss->pending_priority); 421b5cec4c5SDavid Gibson qemu_irq_raise(ss->output); 422b5cec4c5SDavid Gibson } 423b5cec4c5SDavid Gibson } 424b5cec4c5SDavid Gibson 425d1b5682dSAlexey Kardashevskiy static void icp_dispatch_pre_save(void *opaque) 426d1b5682dSAlexey Kardashevskiy { 427d1b5682dSAlexey Kardashevskiy ICPState *ss = opaque; 428d1b5682dSAlexey Kardashevskiy ICPStateClass *info = ICP_GET_CLASS(ss); 429d1b5682dSAlexey Kardashevskiy 430d1b5682dSAlexey Kardashevskiy if (info->pre_save) { 431d1b5682dSAlexey Kardashevskiy info->pre_save(ss); 432d1b5682dSAlexey Kardashevskiy } 433d1b5682dSAlexey Kardashevskiy } 434d1b5682dSAlexey Kardashevskiy 435d1b5682dSAlexey Kardashevskiy static int icp_dispatch_post_load(void *opaque, int version_id) 436d1b5682dSAlexey Kardashevskiy { 437d1b5682dSAlexey Kardashevskiy ICPState *ss = opaque; 438d1b5682dSAlexey Kardashevskiy ICPStateClass *info = ICP_GET_CLASS(ss); 439d1b5682dSAlexey Kardashevskiy 440d1b5682dSAlexey Kardashevskiy if (info->post_load) { 441d1b5682dSAlexey Kardashevskiy return info->post_load(ss, version_id); 442d1b5682dSAlexey Kardashevskiy } 443d1b5682dSAlexey Kardashevskiy 444d1b5682dSAlexey Kardashevskiy return 0; 445d1b5682dSAlexey Kardashevskiy } 446d1b5682dSAlexey Kardashevskiy 447c04d6cfaSAnthony Liguori static const VMStateDescription vmstate_icp_server = { 448c04d6cfaSAnthony Liguori .name = "icp/server", 449c04d6cfaSAnthony Liguori .version_id = 1, 450c04d6cfaSAnthony Liguori .minimum_version_id = 1, 451d1b5682dSAlexey Kardashevskiy .pre_save = icp_dispatch_pre_save, 452d1b5682dSAlexey Kardashevskiy .post_load = icp_dispatch_post_load, 453c04d6cfaSAnthony Liguori .fields = (VMStateField[]) { 454c04d6cfaSAnthony Liguori /* Sanity check */ 455c04d6cfaSAnthony Liguori VMSTATE_UINT32(xirr, ICPState), 456c04d6cfaSAnthony Liguori VMSTATE_UINT8(pending_priority, ICPState), 457c04d6cfaSAnthony Liguori VMSTATE_UINT8(mfrr, ICPState), 458c04d6cfaSAnthony Liguori VMSTATE_END_OF_LIST() 459c04d6cfaSAnthony Liguori }, 460c04d6cfaSAnthony Liguori }; 461c04d6cfaSAnthony Liguori 462c04d6cfaSAnthony Liguori static void icp_reset(DeviceState *dev) 463c04d6cfaSAnthony Liguori { 464c04d6cfaSAnthony Liguori ICPState *icp = ICP(dev); 465c04d6cfaSAnthony Liguori 466c04d6cfaSAnthony Liguori icp->xirr = 0; 467c04d6cfaSAnthony Liguori icp->pending_priority = 0xff; 468c04d6cfaSAnthony Liguori icp->mfrr = 0xff; 469c04d6cfaSAnthony Liguori 470c04d6cfaSAnthony Liguori /* Make all outputs are deasserted */ 471c04d6cfaSAnthony Liguori qemu_set_irq(icp->output, 0); 472c04d6cfaSAnthony Liguori } 473c04d6cfaSAnthony Liguori 474c04d6cfaSAnthony Liguori static void icp_class_init(ObjectClass *klass, void *data) 475c04d6cfaSAnthony Liguori { 476c04d6cfaSAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 477c04d6cfaSAnthony Liguori 478c04d6cfaSAnthony Liguori dc->reset = icp_reset; 479c04d6cfaSAnthony Liguori dc->vmsd = &vmstate_icp_server; 480c04d6cfaSAnthony Liguori } 481c04d6cfaSAnthony Liguori 482456df19cSAlexey Kardashevskiy static const TypeInfo icp_info = { 483c04d6cfaSAnthony Liguori .name = TYPE_ICP, 484c04d6cfaSAnthony Liguori .parent = TYPE_DEVICE, 485c04d6cfaSAnthony Liguori .instance_size = sizeof(ICPState), 486c04d6cfaSAnthony Liguori .class_init = icp_class_init, 487d1b5682dSAlexey Kardashevskiy .class_size = sizeof(ICPStateClass), 488c04d6cfaSAnthony Liguori }; 489c04d6cfaSAnthony Liguori 490b5cec4c5SDavid Gibson /* 491b5cec4c5SDavid Gibson * ICS: Source layer 492b5cec4c5SDavid Gibson */ 493d4d7a59aSBenjamin Herrenschmidt static void ics_simple_resend_msi(ICSState *ics, int srcno) 494b5cec4c5SDavid Gibson { 495c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 496d07fee7eSDavid Gibson 497d07fee7eSDavid Gibson /* FIXME: filter by server#? */ 49898ca8c02SDavid Gibson if (irq->status & XICS_STATUS_REJECTED) { 49998ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_REJECTED; 500d07fee7eSDavid Gibson if (irq->priority != 0xff) { 501cc706a53SBenjamin Herrenschmidt icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); 502d07fee7eSDavid Gibson } 503d07fee7eSDavid Gibson } 504d07fee7eSDavid Gibson } 505d07fee7eSDavid Gibson 506d4d7a59aSBenjamin Herrenschmidt static void ics_simple_resend_lsi(ICSState *ics, int srcno) 507d07fee7eSDavid Gibson { 508c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 509d07fee7eSDavid Gibson 51098ca8c02SDavid Gibson if ((irq->priority != 0xff) 51198ca8c02SDavid Gibson && (irq->status & XICS_STATUS_ASSERTED) 51298ca8c02SDavid Gibson && !(irq->status & XICS_STATUS_SENT)) { 51398ca8c02SDavid Gibson irq->status |= XICS_STATUS_SENT; 514cc706a53SBenjamin Herrenschmidt icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); 515d07fee7eSDavid Gibson } 516d07fee7eSDavid Gibson } 517d07fee7eSDavid Gibson 518d4d7a59aSBenjamin Herrenschmidt static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val) 519d07fee7eSDavid Gibson { 520c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 521b5cec4c5SDavid Gibson 522d4d7a59aSBenjamin Herrenschmidt trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset); 523500efa23SDavid Gibson 524b5cec4c5SDavid Gibson if (val) { 525b5cec4c5SDavid Gibson if (irq->priority == 0xff) { 52698ca8c02SDavid Gibson irq->status |= XICS_STATUS_MASKED_PENDING; 527500efa23SDavid Gibson trace_xics_masked_pending(); 528b5cec4c5SDavid Gibson } else { 529cc706a53SBenjamin Herrenschmidt icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); 530b5cec4c5SDavid Gibson } 531b5cec4c5SDavid Gibson } 532b5cec4c5SDavid Gibson } 533b5cec4c5SDavid Gibson 534d4d7a59aSBenjamin Herrenschmidt static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val) 535d07fee7eSDavid Gibson { 536c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 537d07fee7eSDavid Gibson 538d4d7a59aSBenjamin Herrenschmidt trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset); 53998ca8c02SDavid Gibson if (val) { 54098ca8c02SDavid Gibson irq->status |= XICS_STATUS_ASSERTED; 54198ca8c02SDavid Gibson } else { 54298ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_ASSERTED; 54398ca8c02SDavid Gibson } 544d4d7a59aSBenjamin Herrenschmidt ics_simple_resend_lsi(ics, srcno); 545d07fee7eSDavid Gibson } 546d07fee7eSDavid Gibson 547d4d7a59aSBenjamin Herrenschmidt static void ics_simple_set_irq(void *opaque, int srcno, int val) 548d07fee7eSDavid Gibson { 549c04d6cfaSAnthony Liguori ICSState *ics = (ICSState *)opaque; 550d07fee7eSDavid Gibson 5514af88944SAlexey Kardashevskiy if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { 552d4d7a59aSBenjamin Herrenschmidt ics_simple_set_irq_lsi(ics, srcno, val); 553d07fee7eSDavid Gibson } else { 554d4d7a59aSBenjamin Herrenschmidt ics_simple_set_irq_msi(ics, srcno, val); 555d07fee7eSDavid Gibson } 556d07fee7eSDavid Gibson } 557d07fee7eSDavid Gibson 558d4d7a59aSBenjamin Herrenschmidt static void ics_simple_write_xive_msi(ICSState *ics, int srcno) 559d07fee7eSDavid Gibson { 560c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 561d07fee7eSDavid Gibson 56298ca8c02SDavid Gibson if (!(irq->status & XICS_STATUS_MASKED_PENDING) 56398ca8c02SDavid Gibson || (irq->priority == 0xff)) { 564d07fee7eSDavid Gibson return; 565d07fee7eSDavid Gibson } 566d07fee7eSDavid Gibson 56798ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_MASKED_PENDING; 568cc706a53SBenjamin Herrenschmidt icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); 569d07fee7eSDavid Gibson } 570d07fee7eSDavid Gibson 571d4d7a59aSBenjamin Herrenschmidt static void ics_simple_write_xive_lsi(ICSState *ics, int srcno) 572d07fee7eSDavid Gibson { 573d4d7a59aSBenjamin Herrenschmidt ics_simple_resend_lsi(ics, srcno); 574d07fee7eSDavid Gibson } 575d07fee7eSDavid Gibson 576d4d7a59aSBenjamin Herrenschmidt void ics_simple_write_xive(ICSState *ics, int srcno, int server, 5773fe719f4SDavid Gibson uint8_t priority, uint8_t saved_priority) 578d07fee7eSDavid Gibson { 579c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 580d07fee7eSDavid Gibson 581d07fee7eSDavid Gibson irq->server = server; 582d07fee7eSDavid Gibson irq->priority = priority; 5833fe719f4SDavid Gibson irq->saved_priority = saved_priority; 584d07fee7eSDavid Gibson 585d4d7a59aSBenjamin Herrenschmidt trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server, 586d4d7a59aSBenjamin Herrenschmidt priority); 587500efa23SDavid Gibson 5884af88944SAlexey Kardashevskiy if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { 589d4d7a59aSBenjamin Herrenschmidt ics_simple_write_xive_lsi(ics, srcno); 590d07fee7eSDavid Gibson } else { 591d4d7a59aSBenjamin Herrenschmidt ics_simple_write_xive_msi(ics, srcno); 592d07fee7eSDavid Gibson } 593d07fee7eSDavid Gibson } 594d07fee7eSDavid Gibson 595d4d7a59aSBenjamin Herrenschmidt static void ics_simple_reject(ICSState *ics, uint32_t nr) 596b5cec4c5SDavid Gibson { 597c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + nr - ics->offset; 598b5cec4c5SDavid Gibson 599d4d7a59aSBenjamin Herrenschmidt trace_xics_ics_simple_reject(nr, nr - ics->offset); 600056b9775SNikunj A Dadhania if (irq->flags & XICS_FLAGS_IRQ_MSI) { 601056b9775SNikunj A Dadhania irq->status |= XICS_STATUS_REJECTED; 602056b9775SNikunj A Dadhania } else if (irq->flags & XICS_FLAGS_IRQ_LSI) { 603056b9775SNikunj A Dadhania irq->status &= ~XICS_STATUS_SENT; 604056b9775SNikunj A Dadhania } 605b5cec4c5SDavid Gibson } 606b5cec4c5SDavid Gibson 607d4d7a59aSBenjamin Herrenschmidt static void ics_simple_resend(ICSState *ics) 608b5cec4c5SDavid Gibson { 609b5cec4c5SDavid Gibson int i; 610b5cec4c5SDavid Gibson 611b5cec4c5SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 612b5cec4c5SDavid Gibson /* FIXME: filter by server#? */ 6134af88944SAlexey Kardashevskiy if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) { 614d4d7a59aSBenjamin Herrenschmidt ics_simple_resend_lsi(ics, i); 615d07fee7eSDavid Gibson } else { 616d4d7a59aSBenjamin Herrenschmidt ics_simple_resend_msi(ics, i); 617b5cec4c5SDavid Gibson } 618b5cec4c5SDavid Gibson } 619b5cec4c5SDavid Gibson } 620b5cec4c5SDavid Gibson 621d4d7a59aSBenjamin Herrenschmidt static void ics_simple_eoi(ICSState *ics, uint32_t nr) 622b5cec4c5SDavid Gibson { 623d07fee7eSDavid Gibson int srcno = nr - ics->offset; 624c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 625d07fee7eSDavid Gibson 626d4d7a59aSBenjamin Herrenschmidt trace_xics_ics_simple_eoi(nr); 627500efa23SDavid Gibson 6284af88944SAlexey Kardashevskiy if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { 62998ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_SENT; 630d07fee7eSDavid Gibson } 631b5cec4c5SDavid Gibson } 632b5cec4c5SDavid Gibson 633d4d7a59aSBenjamin Herrenschmidt static void ics_simple_reset(DeviceState *dev) 634c04d6cfaSAnthony Liguori { 635d4d7a59aSBenjamin Herrenschmidt ICSState *ics = ICS_SIMPLE(dev); 636c04d6cfaSAnthony Liguori int i; 637a7e519a8SAlexey Kardashevskiy uint8_t flags[ics->nr_irqs]; 638a7e519a8SAlexey Kardashevskiy 639a7e519a8SAlexey Kardashevskiy for (i = 0; i < ics->nr_irqs; i++) { 640a7e519a8SAlexey Kardashevskiy flags[i] = ics->irqs[i].flags; 641a7e519a8SAlexey Kardashevskiy } 642c04d6cfaSAnthony Liguori 643c04d6cfaSAnthony Liguori memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs); 644a7e519a8SAlexey Kardashevskiy 645c04d6cfaSAnthony Liguori for (i = 0; i < ics->nr_irqs; i++) { 646c04d6cfaSAnthony Liguori ics->irqs[i].priority = 0xff; 647c04d6cfaSAnthony Liguori ics->irqs[i].saved_priority = 0xff; 648a7e519a8SAlexey Kardashevskiy ics->irqs[i].flags = flags[i]; 649c04d6cfaSAnthony Liguori } 650c04d6cfaSAnthony Liguori } 651c04d6cfaSAnthony Liguori 652d4d7a59aSBenjamin Herrenschmidt static int ics_simple_post_load(ICSState *ics, int version_id) 653c04d6cfaSAnthony Liguori { 654c04d6cfaSAnthony Liguori int i; 655c04d6cfaSAnthony Liguori 65627f24582SBenjamin Herrenschmidt for (i = 0; i < ics->xics->nr_servers; i++) { 65727f24582SBenjamin Herrenschmidt icp_resend(ics->xics, i); 658c04d6cfaSAnthony Liguori } 659c04d6cfaSAnthony Liguori 660c04d6cfaSAnthony Liguori return 0; 661c04d6cfaSAnthony Liguori } 662c04d6cfaSAnthony Liguori 663d4d7a59aSBenjamin Herrenschmidt static void ics_simple_dispatch_pre_save(void *opaque) 664d1b5682dSAlexey Kardashevskiy { 665d1b5682dSAlexey Kardashevskiy ICSState *ics = opaque; 666d4d7a59aSBenjamin Herrenschmidt ICSStateClass *info = ICS_BASE_GET_CLASS(ics); 667d1b5682dSAlexey Kardashevskiy 668d1b5682dSAlexey Kardashevskiy if (info->pre_save) { 669d1b5682dSAlexey Kardashevskiy info->pre_save(ics); 670d1b5682dSAlexey Kardashevskiy } 671d1b5682dSAlexey Kardashevskiy } 672d1b5682dSAlexey Kardashevskiy 673d4d7a59aSBenjamin Herrenschmidt static int ics_simple_dispatch_post_load(void *opaque, int version_id) 674d1b5682dSAlexey Kardashevskiy { 675d1b5682dSAlexey Kardashevskiy ICSState *ics = opaque; 676d4d7a59aSBenjamin Herrenschmidt ICSStateClass *info = ICS_BASE_GET_CLASS(ics); 677d1b5682dSAlexey Kardashevskiy 678d1b5682dSAlexey Kardashevskiy if (info->post_load) { 679d1b5682dSAlexey Kardashevskiy return info->post_load(ics, version_id); 680d1b5682dSAlexey Kardashevskiy } 681d1b5682dSAlexey Kardashevskiy 682d1b5682dSAlexey Kardashevskiy return 0; 683d1b5682dSAlexey Kardashevskiy } 684d1b5682dSAlexey Kardashevskiy 685d4d7a59aSBenjamin Herrenschmidt static const VMStateDescription vmstate_ics_simple_irq = { 686c04d6cfaSAnthony Liguori .name = "ics/irq", 6874af88944SAlexey Kardashevskiy .version_id = 2, 688c04d6cfaSAnthony Liguori .minimum_version_id = 1, 689c04d6cfaSAnthony Liguori .fields = (VMStateField[]) { 690c04d6cfaSAnthony Liguori VMSTATE_UINT32(server, ICSIRQState), 691c04d6cfaSAnthony Liguori VMSTATE_UINT8(priority, ICSIRQState), 692c04d6cfaSAnthony Liguori VMSTATE_UINT8(saved_priority, ICSIRQState), 693c04d6cfaSAnthony Liguori VMSTATE_UINT8(status, ICSIRQState), 6944af88944SAlexey Kardashevskiy VMSTATE_UINT8(flags, ICSIRQState), 695c04d6cfaSAnthony Liguori VMSTATE_END_OF_LIST() 696c04d6cfaSAnthony Liguori }, 697c04d6cfaSAnthony Liguori }; 698c04d6cfaSAnthony Liguori 699d4d7a59aSBenjamin Herrenschmidt static const VMStateDescription vmstate_ics_simple = { 700c04d6cfaSAnthony Liguori .name = "ics", 701c04d6cfaSAnthony Liguori .version_id = 1, 702c04d6cfaSAnthony Liguori .minimum_version_id = 1, 703d4d7a59aSBenjamin Herrenschmidt .pre_save = ics_simple_dispatch_pre_save, 704d4d7a59aSBenjamin Herrenschmidt .post_load = ics_simple_dispatch_post_load, 705c04d6cfaSAnthony Liguori .fields = (VMStateField[]) { 706c04d6cfaSAnthony Liguori /* Sanity check */ 707c04d6cfaSAnthony Liguori VMSTATE_UINT32_EQUAL(nr_irqs, ICSState), 708c04d6cfaSAnthony Liguori 709c04d6cfaSAnthony Liguori VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs, 710d4d7a59aSBenjamin Herrenschmidt vmstate_ics_simple_irq, 711d4d7a59aSBenjamin Herrenschmidt ICSIRQState), 712c04d6cfaSAnthony Liguori VMSTATE_END_OF_LIST() 713c04d6cfaSAnthony Liguori }, 714c04d6cfaSAnthony Liguori }; 715c04d6cfaSAnthony Liguori 716d4d7a59aSBenjamin Herrenschmidt static void ics_simple_initfn(Object *obj) 7175a3d7b23SAlexey Kardashevskiy { 718d4d7a59aSBenjamin Herrenschmidt ICSState *ics = ICS_SIMPLE(obj); 7195a3d7b23SAlexey Kardashevskiy 7205a3d7b23SAlexey Kardashevskiy ics->offset = XICS_IRQ_BASE; 7215a3d7b23SAlexey Kardashevskiy } 7225a3d7b23SAlexey Kardashevskiy 723d4d7a59aSBenjamin Herrenschmidt static void ics_simple_realize(DeviceState *dev, Error **errp) 724c04d6cfaSAnthony Liguori { 725d4d7a59aSBenjamin Herrenschmidt ICSState *ics = ICS_SIMPLE(dev); 726c04d6cfaSAnthony Liguori 727b45ff2d9SAlexey Kardashevskiy if (!ics->nr_irqs) { 728b45ff2d9SAlexey Kardashevskiy error_setg(errp, "Number of interrupts needs to be greater 0"); 729b45ff2d9SAlexey Kardashevskiy return; 730b45ff2d9SAlexey Kardashevskiy } 731c04d6cfaSAnthony Liguori ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); 732d4d7a59aSBenjamin Herrenschmidt ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); 733c04d6cfaSAnthony Liguori } 734c04d6cfaSAnthony Liguori 735d4d7a59aSBenjamin Herrenschmidt static void ics_simple_class_init(ObjectClass *klass, void *data) 736c04d6cfaSAnthony Liguori { 737c04d6cfaSAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 738d4d7a59aSBenjamin Herrenschmidt ICSStateClass *isc = ICS_BASE_CLASS(klass); 739c04d6cfaSAnthony Liguori 740d4d7a59aSBenjamin Herrenschmidt dc->realize = ics_simple_realize; 741d4d7a59aSBenjamin Herrenschmidt dc->vmsd = &vmstate_ics_simple; 742d4d7a59aSBenjamin Herrenschmidt dc->reset = ics_simple_reset; 743d4d7a59aSBenjamin Herrenschmidt isc->post_load = ics_simple_post_load; 744d4d7a59aSBenjamin Herrenschmidt isc->reject = ics_simple_reject; 745d4d7a59aSBenjamin Herrenschmidt isc->resend = ics_simple_resend; 746d4d7a59aSBenjamin Herrenschmidt isc->eoi = ics_simple_eoi; 747c04d6cfaSAnthony Liguori } 748c04d6cfaSAnthony Liguori 749d4d7a59aSBenjamin Herrenschmidt static const TypeInfo ics_simple_info = { 750d4d7a59aSBenjamin Herrenschmidt .name = TYPE_ICS_SIMPLE, 751d4d7a59aSBenjamin Herrenschmidt .parent = TYPE_ICS_BASE, 752c04d6cfaSAnthony Liguori .instance_size = sizeof(ICSState), 753d4d7a59aSBenjamin Herrenschmidt .class_init = ics_simple_class_init, 754d1b5682dSAlexey Kardashevskiy .class_size = sizeof(ICSStateClass), 755d4d7a59aSBenjamin Herrenschmidt .instance_init = ics_simple_initfn, 756d4d7a59aSBenjamin Herrenschmidt }; 757d4d7a59aSBenjamin Herrenschmidt 758d4d7a59aSBenjamin Herrenschmidt static const TypeInfo ics_base_info = { 759d4d7a59aSBenjamin Herrenschmidt .name = TYPE_ICS_BASE, 760d4d7a59aSBenjamin Herrenschmidt .parent = TYPE_DEVICE, 761d4d7a59aSBenjamin Herrenschmidt .abstract = true, 762d4d7a59aSBenjamin Herrenschmidt .instance_size = sizeof(ICSState), 763d4d7a59aSBenjamin Herrenschmidt .class_size = sizeof(ICSStateClass), 764c04d6cfaSAnthony Liguori }; 765c04d6cfaSAnthony Liguori 766b5cec4c5SDavid Gibson /* 767b5cec4c5SDavid Gibson * Exported functions 768b5cec4c5SDavid Gibson */ 769cc706a53SBenjamin Herrenschmidt ICSState *xics_find_source(XICSState *xics, int irq) 770641c3493SAlexey Kardashevskiy { 771cc706a53SBenjamin Herrenschmidt ICSState *ics; 772641c3493SAlexey Kardashevskiy 773cc706a53SBenjamin Herrenschmidt QLIST_FOREACH(ics, &xics->ics, list) { 774641c3493SAlexey Kardashevskiy if (ics_valid_irq(ics, irq)) { 775cc706a53SBenjamin Herrenschmidt return ics; 776641c3493SAlexey Kardashevskiy } 777641c3493SAlexey Kardashevskiy } 778cc706a53SBenjamin Herrenschmidt return NULL; 779641c3493SAlexey Kardashevskiy } 780b5cec4c5SDavid Gibson 78127f24582SBenjamin Herrenschmidt qemu_irq xics_get_qirq(XICSState *xics, int irq) 782b5cec4c5SDavid Gibson { 783cc706a53SBenjamin Herrenschmidt ICSState *ics = xics_find_source(xics, irq); 784641c3493SAlexey Kardashevskiy 785cc706a53SBenjamin Herrenschmidt if (ics) { 786641c3493SAlexey Kardashevskiy return ics->qirqs[irq - ics->offset]; 787b5cec4c5SDavid Gibson } 788b5cec4c5SDavid Gibson 789641c3493SAlexey Kardashevskiy return NULL; 790a307d594SAlexey Kardashevskiy } 791a307d594SAlexey Kardashevskiy 7929c7027baSBenjamin Herrenschmidt void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) 7934af88944SAlexey Kardashevskiy { 7944af88944SAlexey Kardashevskiy assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK)); 7954af88944SAlexey Kardashevskiy 7964af88944SAlexey Kardashevskiy ics->irqs[srcno].flags |= 7974af88944SAlexey Kardashevskiy lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI; 7984af88944SAlexey Kardashevskiy } 7994af88944SAlexey Kardashevskiy 800c04d6cfaSAnthony Liguori static void xics_register_types(void) 801c04d6cfaSAnthony Liguori { 8025a3d7b23SAlexey Kardashevskiy type_register_static(&xics_common_info); 803d4d7a59aSBenjamin Herrenschmidt type_register_static(&ics_simple_info); 804d4d7a59aSBenjamin Herrenschmidt type_register_static(&ics_base_info); 805c04d6cfaSAnthony Liguori type_register_static(&icp_info); 806c04d6cfaSAnthony Liguori } 807c04d6cfaSAnthony Liguori 808c04d6cfaSAnthony Liguori type_init(xics_register_types) 809