xref: /qemu/hw/intc/xics.c (revision cc706a530518f867c29177a5a337bb08503e617e)
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"
38b5cec4c5SDavid Gibson 
399c7027baSBenjamin Herrenschmidt int xics_get_cpu_index_by_dt_id(int cpu_dt_id)
400f20ba62SAlexey Kardashevskiy {
410f20ba62SAlexey Kardashevskiy     PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
420f20ba62SAlexey Kardashevskiy 
430f20ba62SAlexey Kardashevskiy     if (cpu) {
440f20ba62SAlexey Kardashevskiy         return cpu->parent_obj.cpu_index;
450f20ba62SAlexey Kardashevskiy     }
460f20ba62SAlexey Kardashevskiy 
470f20ba62SAlexey Kardashevskiy     return -1;
480f20ba62SAlexey Kardashevskiy }
490f20ba62SAlexey Kardashevskiy 
5027f24582SBenjamin Herrenschmidt void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu)
514a4b344cSBharata B Rao {
524a4b344cSBharata B Rao     CPUState *cs = CPU(cpu);
5327f24582SBenjamin Herrenschmidt     ICPState *ss = &xics->ss[cs->cpu_index];
544a4b344cSBharata B Rao 
5527f24582SBenjamin Herrenschmidt     assert(cs->cpu_index < xics->nr_servers);
564a4b344cSBharata B Rao     assert(cs == ss->cs);
574a4b344cSBharata B Rao 
584a4b344cSBharata B Rao     ss->output = NULL;
594a4b344cSBharata B Rao     ss->cs = NULL;
604a4b344cSBharata B Rao }
614a4b344cSBharata B Rao 
6227f24582SBenjamin Herrenschmidt void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
638ffe04edSAlexey Kardashevskiy {
648ffe04edSAlexey Kardashevskiy     CPUState *cs = CPU(cpu);
658ffe04edSAlexey Kardashevskiy     CPUPPCState *env = &cpu->env;
6627f24582SBenjamin Herrenschmidt     ICPState *ss = &xics->ss[cs->cpu_index];
6727f24582SBenjamin Herrenschmidt     XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
688ffe04edSAlexey Kardashevskiy 
6927f24582SBenjamin Herrenschmidt     assert(cs->cpu_index < xics->nr_servers);
708ffe04edSAlexey Kardashevskiy 
714a4b344cSBharata B Rao     ss->cs = cs;
724a4b344cSBharata B Rao 
735eb92cccSAlexey Kardashevskiy     if (info->cpu_setup) {
7427f24582SBenjamin Herrenschmidt         info->cpu_setup(xics, cpu);
755eb92cccSAlexey Kardashevskiy     }
765eb92cccSAlexey Kardashevskiy 
778ffe04edSAlexey Kardashevskiy     switch (PPC_INPUT(env)) {
788ffe04edSAlexey Kardashevskiy     case PPC_FLAGS_INPUT_POWER7:
798ffe04edSAlexey Kardashevskiy         ss->output = env->irq_inputs[POWER7_INPUT_INT];
808ffe04edSAlexey Kardashevskiy         break;
818ffe04edSAlexey Kardashevskiy 
828ffe04edSAlexey Kardashevskiy     case PPC_FLAGS_INPUT_970:
838ffe04edSAlexey Kardashevskiy         ss->output = env->irq_inputs[PPC970_INPUT_INT];
848ffe04edSAlexey Kardashevskiy         break;
858ffe04edSAlexey Kardashevskiy 
868ffe04edSAlexey Kardashevskiy     default:
879ccff2a4SAlexey Kardashevskiy         error_report("XICS interrupt controller does not support this CPU "
889ccff2a4SAlexey Kardashevskiy                      "bus model");
898ffe04edSAlexey Kardashevskiy         abort();
908ffe04edSAlexey Kardashevskiy     }
918ffe04edSAlexey Kardashevskiy }
928ffe04edSAlexey Kardashevskiy 
935a3d7b23SAlexey Kardashevskiy /*
945a3d7b23SAlexey Kardashevskiy  * XICS Common class - parent for emulated XICS and KVM-XICS
955a3d7b23SAlexey Kardashevskiy  */
965a3d7b23SAlexey Kardashevskiy static void xics_common_reset(DeviceState *d)
978ffe04edSAlexey Kardashevskiy {
9827f24582SBenjamin Herrenschmidt     XICSState *xics = XICS_COMMON(d);
99*cc706a53SBenjamin Herrenschmidt     ICSState *ics;
1008ffe04edSAlexey Kardashevskiy     int i;
1018ffe04edSAlexey Kardashevskiy 
10227f24582SBenjamin Herrenschmidt     for (i = 0; i < xics->nr_servers; i++) {
10327f24582SBenjamin Herrenschmidt         device_reset(DEVICE(&xics->ss[i]));
1048ffe04edSAlexey Kardashevskiy     }
1058ffe04edSAlexey Kardashevskiy 
106*cc706a53SBenjamin Herrenschmidt     QLIST_FOREACH(ics, &xics->ics, list) {
107*cc706a53SBenjamin Herrenschmidt         device_reset(DEVICE(ics));
108*cc706a53SBenjamin Herrenschmidt     }
1098ffe04edSAlexey Kardashevskiy }
1108ffe04edSAlexey Kardashevskiy 
111d7bce999SEric Blake static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name,
112d7bce999SEric Blake                                   void *opaque, Error **errp)
1135a3d7b23SAlexey Kardashevskiy {
11427f24582SBenjamin Herrenschmidt     XICSState *xics = XICS_COMMON(obj);
11527f24582SBenjamin Herrenschmidt     int64_t value = xics->nr_irqs;
1165a3d7b23SAlexey Kardashevskiy 
11751e72bc1SEric Blake     visit_type_int(v, name, &value, errp);
1185a3d7b23SAlexey Kardashevskiy }
1195a3d7b23SAlexey Kardashevskiy 
120d7bce999SEric Blake static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name,
121d7bce999SEric Blake                                   void *opaque, Error **errp)
1225a3d7b23SAlexey Kardashevskiy {
12327f24582SBenjamin Herrenschmidt     XICSState *xics = XICS_COMMON(obj);
12427f24582SBenjamin Herrenschmidt     XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
1255a3d7b23SAlexey Kardashevskiy     Error *error = NULL;
1265a3d7b23SAlexey Kardashevskiy     int64_t value;
1275a3d7b23SAlexey Kardashevskiy 
12851e72bc1SEric Blake     visit_type_int(v, name, &value, &error);
1295a3d7b23SAlexey Kardashevskiy     if (error) {
1305a3d7b23SAlexey Kardashevskiy         error_propagate(errp, error);
1315a3d7b23SAlexey Kardashevskiy         return;
1325a3d7b23SAlexey Kardashevskiy     }
13327f24582SBenjamin Herrenschmidt     if (xics->nr_irqs) {
1345a3d7b23SAlexey Kardashevskiy         error_setg(errp, "Number of interrupts is already set to %u",
13527f24582SBenjamin Herrenschmidt                    xics->nr_irqs);
1365a3d7b23SAlexey Kardashevskiy         return;
1375a3d7b23SAlexey Kardashevskiy     }
1385a3d7b23SAlexey Kardashevskiy 
1395a3d7b23SAlexey Kardashevskiy     assert(info->set_nr_irqs);
14027f24582SBenjamin Herrenschmidt     info->set_nr_irqs(xics, value, errp);
1415a3d7b23SAlexey Kardashevskiy }
1425a3d7b23SAlexey Kardashevskiy 
1435a3d7b23SAlexey Kardashevskiy static void xics_prop_get_nr_servers(Object *obj, Visitor *v,
144d7bce999SEric Blake                                      const char *name, void *opaque,
1455a3d7b23SAlexey Kardashevskiy                                      Error **errp)
1465a3d7b23SAlexey Kardashevskiy {
14727f24582SBenjamin Herrenschmidt     XICSState *xics = XICS_COMMON(obj);
14827f24582SBenjamin Herrenschmidt     int64_t value = xics->nr_servers;
1495a3d7b23SAlexey Kardashevskiy 
15051e72bc1SEric Blake     visit_type_int(v, name, &value, errp);
1515a3d7b23SAlexey Kardashevskiy }
1525a3d7b23SAlexey Kardashevskiy 
1535a3d7b23SAlexey Kardashevskiy static void xics_prop_set_nr_servers(Object *obj, Visitor *v,
154d7bce999SEric Blake                                      const char *name, void *opaque,
1555a3d7b23SAlexey Kardashevskiy                                      Error **errp)
1565a3d7b23SAlexey Kardashevskiy {
15727f24582SBenjamin Herrenschmidt     XICSState *xics = XICS_COMMON(obj);
15827f24582SBenjamin Herrenschmidt     XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
1595a3d7b23SAlexey Kardashevskiy     Error *error = NULL;
1605a3d7b23SAlexey Kardashevskiy     int64_t value;
1615a3d7b23SAlexey Kardashevskiy 
16251e72bc1SEric Blake     visit_type_int(v, name, &value, &error);
1635a3d7b23SAlexey Kardashevskiy     if (error) {
1645a3d7b23SAlexey Kardashevskiy         error_propagate(errp, error);
1655a3d7b23SAlexey Kardashevskiy         return;
1665a3d7b23SAlexey Kardashevskiy     }
16727f24582SBenjamin Herrenschmidt     if (xics->nr_servers) {
1685a3d7b23SAlexey Kardashevskiy         error_setg(errp, "Number of servers is already set to %u",
16927f24582SBenjamin Herrenschmidt                    xics->nr_servers);
1705a3d7b23SAlexey Kardashevskiy         return;
1715a3d7b23SAlexey Kardashevskiy     }
1725a3d7b23SAlexey Kardashevskiy 
1735a3d7b23SAlexey Kardashevskiy     assert(info->set_nr_servers);
17427f24582SBenjamin Herrenschmidt     info->set_nr_servers(xics, value, errp);
1755a3d7b23SAlexey Kardashevskiy }
1765a3d7b23SAlexey Kardashevskiy 
1775a3d7b23SAlexey Kardashevskiy static void xics_common_initfn(Object *obj)
1785a3d7b23SAlexey Kardashevskiy {
179*cc706a53SBenjamin Herrenschmidt     XICSState *xics = XICS_COMMON(obj);
180*cc706a53SBenjamin Herrenschmidt 
181*cc706a53SBenjamin Herrenschmidt     QLIST_INIT(&xics->ics);
1825a3d7b23SAlexey Kardashevskiy     object_property_add(obj, "nr_irqs", "int",
1835a3d7b23SAlexey Kardashevskiy                         xics_prop_get_nr_irqs, xics_prop_set_nr_irqs,
1845a3d7b23SAlexey Kardashevskiy                         NULL, NULL, NULL);
1855a3d7b23SAlexey Kardashevskiy     object_property_add(obj, "nr_servers", "int",
1865a3d7b23SAlexey Kardashevskiy                         xics_prop_get_nr_servers, xics_prop_set_nr_servers,
1875a3d7b23SAlexey Kardashevskiy                         NULL, NULL, NULL);
1885a3d7b23SAlexey Kardashevskiy }
1895a3d7b23SAlexey Kardashevskiy 
1905a3d7b23SAlexey Kardashevskiy static void xics_common_class_init(ObjectClass *oc, void *data)
1915a3d7b23SAlexey Kardashevskiy {
1925a3d7b23SAlexey Kardashevskiy     DeviceClass *dc = DEVICE_CLASS(oc);
1935a3d7b23SAlexey Kardashevskiy 
1945a3d7b23SAlexey Kardashevskiy     dc->reset = xics_common_reset;
1955a3d7b23SAlexey Kardashevskiy }
1965a3d7b23SAlexey Kardashevskiy 
1975a3d7b23SAlexey Kardashevskiy static const TypeInfo xics_common_info = {
1985a3d7b23SAlexey Kardashevskiy     .name          = TYPE_XICS_COMMON,
1995a3d7b23SAlexey Kardashevskiy     .parent        = TYPE_SYS_BUS_DEVICE,
2005a3d7b23SAlexey Kardashevskiy     .instance_size = sizeof(XICSState),
2015a3d7b23SAlexey Kardashevskiy     .class_size    = sizeof(XICSStateClass),
2025a3d7b23SAlexey Kardashevskiy     .instance_init = xics_common_initfn,
2035a3d7b23SAlexey Kardashevskiy     .class_init    = xics_common_class_init,
2045a3d7b23SAlexey Kardashevskiy };
2055a3d7b23SAlexey Kardashevskiy 
206b5cec4c5SDavid Gibson /*
207b5cec4c5SDavid Gibson  * ICP: Presentation layer
208b5cec4c5SDavid Gibson  */
209b5cec4c5SDavid Gibson 
210b5cec4c5SDavid Gibson #define XISR_MASK  0x00ffffff
211b5cec4c5SDavid Gibson #define CPPR_MASK  0xff000000
212b5cec4c5SDavid Gibson 
213b5cec4c5SDavid Gibson #define XISR(ss)   (((ss)->xirr) & XISR_MASK)
214b5cec4c5SDavid Gibson #define CPPR(ss)   (((ss)->xirr) >> 24)
215b5cec4c5SDavid Gibson 
216c04d6cfaSAnthony Liguori static void ics_reject(ICSState *ics, int nr);
217c04d6cfaSAnthony Liguori static void ics_resend(ICSState *ics);
218c04d6cfaSAnthony Liguori static void ics_eoi(ICSState *ics, int nr);
219b5cec4c5SDavid Gibson 
220*cc706a53SBenjamin Herrenschmidt static void icp_check_ipi(ICPState *ss)
221b5cec4c5SDavid Gibson {
222b5cec4c5SDavid Gibson     if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
223b5cec4c5SDavid Gibson         return;
224b5cec4c5SDavid Gibson     }
225b5cec4c5SDavid Gibson 
226*cc706a53SBenjamin Herrenschmidt     trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr);
227500efa23SDavid Gibson 
228*cc706a53SBenjamin Herrenschmidt     if (XISR(ss) && ss->xirr_owner) {
229*cc706a53SBenjamin Herrenschmidt         ics_reject(ss->xirr_owner, XISR(ss));
230b5cec4c5SDavid Gibson     }
231b5cec4c5SDavid Gibson 
232b5cec4c5SDavid Gibson     ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
233b5cec4c5SDavid Gibson     ss->pending_priority = ss->mfrr;
234*cc706a53SBenjamin Herrenschmidt     ss->xirr_owner = NULL;
235b5cec4c5SDavid Gibson     qemu_irq_raise(ss->output);
236b5cec4c5SDavid Gibson }
237b5cec4c5SDavid Gibson 
23827f24582SBenjamin Herrenschmidt static void icp_resend(XICSState *xics, int server)
239b5cec4c5SDavid Gibson {
24027f24582SBenjamin Herrenschmidt     ICPState *ss = xics->ss + server;
241*cc706a53SBenjamin Herrenschmidt     ICSState *ics;
242b5cec4c5SDavid Gibson 
243b5cec4c5SDavid Gibson     if (ss->mfrr < CPPR(ss)) {
244*cc706a53SBenjamin Herrenschmidt         icp_check_ipi(ss);
245b5cec4c5SDavid Gibson     }
246*cc706a53SBenjamin Herrenschmidt     QLIST_FOREACH(ics, &xics->ics, list) {
247*cc706a53SBenjamin Herrenschmidt         ics_resend(ics);
248*cc706a53SBenjamin Herrenschmidt     }
249b5cec4c5SDavid Gibson }
250b5cec4c5SDavid Gibson 
25127f24582SBenjamin Herrenschmidt void icp_set_cppr(XICSState *xics, int server, uint8_t cppr)
252b5cec4c5SDavid Gibson {
25327f24582SBenjamin Herrenschmidt     ICPState *ss = xics->ss + server;
254b5cec4c5SDavid Gibson     uint8_t old_cppr;
255b5cec4c5SDavid Gibson     uint32_t old_xisr;
256b5cec4c5SDavid Gibson 
257b5cec4c5SDavid Gibson     old_cppr = CPPR(ss);
258b5cec4c5SDavid Gibson     ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
259b5cec4c5SDavid Gibson 
260b5cec4c5SDavid Gibson     if (cppr < old_cppr) {
261b5cec4c5SDavid Gibson         if (XISR(ss) && (cppr <= ss->pending_priority)) {
262b5cec4c5SDavid Gibson             old_xisr = XISR(ss);
263b5cec4c5SDavid Gibson             ss->xirr &= ~XISR_MASK; /* Clear XISR */
264e03c902cSDavid Gibson             ss->pending_priority = 0xff;
265b5cec4c5SDavid Gibson             qemu_irq_lower(ss->output);
266*cc706a53SBenjamin Herrenschmidt             if (ss->xirr_owner) {
267*cc706a53SBenjamin Herrenschmidt                 ics_reject(ss->xirr_owner, old_xisr);
268*cc706a53SBenjamin Herrenschmidt                 ss->xirr_owner = NULL;
269*cc706a53SBenjamin Herrenschmidt             }
270b5cec4c5SDavid Gibson         }
271b5cec4c5SDavid Gibson     } else {
272b5cec4c5SDavid Gibson         if (!XISR(ss)) {
27327f24582SBenjamin Herrenschmidt             icp_resend(xics, server);
274b5cec4c5SDavid Gibson         }
275b5cec4c5SDavid Gibson     }
276b5cec4c5SDavid Gibson }
277b5cec4c5SDavid Gibson 
27827f24582SBenjamin Herrenschmidt void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr)
279b5cec4c5SDavid Gibson {
28027f24582SBenjamin Herrenschmidt     ICPState *ss = xics->ss + server;
281b5cec4c5SDavid Gibson 
282b5cec4c5SDavid Gibson     ss->mfrr = mfrr;
283b5cec4c5SDavid Gibson     if (mfrr < CPPR(ss)) {
284*cc706a53SBenjamin Herrenschmidt         icp_check_ipi(ss);
285b5cec4c5SDavid Gibson     }
286b5cec4c5SDavid Gibson }
287b5cec4c5SDavid Gibson 
2889c7027baSBenjamin Herrenschmidt uint32_t icp_accept(ICPState *ss)
289b5cec4c5SDavid Gibson {
290500efa23SDavid Gibson     uint32_t xirr = ss->xirr;
291b5cec4c5SDavid Gibson 
292b5cec4c5SDavid Gibson     qemu_irq_lower(ss->output);
293b5cec4c5SDavid Gibson     ss->xirr = ss->pending_priority << 24;
294e03c902cSDavid Gibson     ss->pending_priority = 0xff;
295*cc706a53SBenjamin Herrenschmidt     ss->xirr_owner = NULL;
296500efa23SDavid Gibson 
297500efa23SDavid Gibson     trace_xics_icp_accept(xirr, ss->xirr);
298500efa23SDavid Gibson 
299b5cec4c5SDavid Gibson     return xirr;
300b5cec4c5SDavid Gibson }
301b5cec4c5SDavid Gibson 
3021cbd2220SBenjamin Herrenschmidt uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)
3031cbd2220SBenjamin Herrenschmidt {
3041cbd2220SBenjamin Herrenschmidt     if (mfrr) {
3051cbd2220SBenjamin Herrenschmidt         *mfrr = ss->mfrr;
3061cbd2220SBenjamin Herrenschmidt     }
3071cbd2220SBenjamin Herrenschmidt     return ss->xirr;
3081cbd2220SBenjamin Herrenschmidt }
3091cbd2220SBenjamin Herrenschmidt 
31027f24582SBenjamin Herrenschmidt void icp_eoi(XICSState *xics, int server, uint32_t xirr)
311b5cec4c5SDavid Gibson {
31227f24582SBenjamin Herrenschmidt     ICPState *ss = xics->ss + server;
313*cc706a53SBenjamin Herrenschmidt     ICSState *ics;
314*cc706a53SBenjamin Herrenschmidt     uint32_t irq;
315b5cec4c5SDavid Gibson 
316b5cec4c5SDavid Gibson     /* Send EOI -> ICS */
317b5cec4c5SDavid Gibson     ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
318500efa23SDavid Gibson     trace_xics_icp_eoi(server, xirr, ss->xirr);
319*cc706a53SBenjamin Herrenschmidt     irq = xirr & XISR_MASK;
320*cc706a53SBenjamin Herrenschmidt     QLIST_FOREACH(ics, &xics->ics, list) {
321*cc706a53SBenjamin Herrenschmidt         if (ics_valid_irq(ics, irq)) {
322*cc706a53SBenjamin Herrenschmidt             ics_eoi(ics, irq);
323*cc706a53SBenjamin Herrenschmidt         }
324*cc706a53SBenjamin Herrenschmidt     }
325b5cec4c5SDavid Gibson     if (!XISR(ss)) {
32627f24582SBenjamin Herrenschmidt         icp_resend(xics, server);
327b5cec4c5SDavid Gibson     }
328b5cec4c5SDavid Gibson }
329b5cec4c5SDavid Gibson 
330*cc706a53SBenjamin Herrenschmidt static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority)
331b5cec4c5SDavid Gibson {
332*cc706a53SBenjamin Herrenschmidt     XICSState *xics = ics->xics;
33327f24582SBenjamin Herrenschmidt     ICPState *ss = xics->ss + server;
334b5cec4c5SDavid Gibson 
335500efa23SDavid Gibson     trace_xics_icp_irq(server, nr, priority);
336500efa23SDavid Gibson 
337b5cec4c5SDavid Gibson     if ((priority >= CPPR(ss))
338b5cec4c5SDavid Gibson         || (XISR(ss) && (ss->pending_priority <= priority))) {
339*cc706a53SBenjamin Herrenschmidt         ics_reject(ics, nr);
340b5cec4c5SDavid Gibson     } else {
341*cc706a53SBenjamin Herrenschmidt         if (XISR(ss) && ss->xirr_owner) {
342*cc706a53SBenjamin Herrenschmidt             ics_reject(ss->xirr_owner, XISR(ss));
343*cc706a53SBenjamin Herrenschmidt             ss->xirr_owner = NULL;
344b5cec4c5SDavid Gibson         }
345b5cec4c5SDavid Gibson         ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
346*cc706a53SBenjamin Herrenschmidt         ss->xirr_owner = ics;
347b5cec4c5SDavid Gibson         ss->pending_priority = priority;
348500efa23SDavid Gibson         trace_xics_icp_raise(ss->xirr, ss->pending_priority);
349b5cec4c5SDavid Gibson         qemu_irq_raise(ss->output);
350b5cec4c5SDavid Gibson     }
351b5cec4c5SDavid Gibson }
352b5cec4c5SDavid Gibson 
353d1b5682dSAlexey Kardashevskiy static void icp_dispatch_pre_save(void *opaque)
354d1b5682dSAlexey Kardashevskiy {
355d1b5682dSAlexey Kardashevskiy     ICPState *ss = opaque;
356d1b5682dSAlexey Kardashevskiy     ICPStateClass *info = ICP_GET_CLASS(ss);
357d1b5682dSAlexey Kardashevskiy 
358d1b5682dSAlexey Kardashevskiy     if (info->pre_save) {
359d1b5682dSAlexey Kardashevskiy         info->pre_save(ss);
360d1b5682dSAlexey Kardashevskiy     }
361d1b5682dSAlexey Kardashevskiy }
362d1b5682dSAlexey Kardashevskiy 
363d1b5682dSAlexey Kardashevskiy static int icp_dispatch_post_load(void *opaque, int version_id)
364d1b5682dSAlexey Kardashevskiy {
365d1b5682dSAlexey Kardashevskiy     ICPState *ss = opaque;
366d1b5682dSAlexey Kardashevskiy     ICPStateClass *info = ICP_GET_CLASS(ss);
367d1b5682dSAlexey Kardashevskiy 
368d1b5682dSAlexey Kardashevskiy     if (info->post_load) {
369d1b5682dSAlexey Kardashevskiy         return info->post_load(ss, version_id);
370d1b5682dSAlexey Kardashevskiy     }
371d1b5682dSAlexey Kardashevskiy 
372d1b5682dSAlexey Kardashevskiy     return 0;
373d1b5682dSAlexey Kardashevskiy }
374d1b5682dSAlexey Kardashevskiy 
375c04d6cfaSAnthony Liguori static const VMStateDescription vmstate_icp_server = {
376c04d6cfaSAnthony Liguori     .name = "icp/server",
377c04d6cfaSAnthony Liguori     .version_id = 1,
378c04d6cfaSAnthony Liguori     .minimum_version_id = 1,
379d1b5682dSAlexey Kardashevskiy     .pre_save = icp_dispatch_pre_save,
380d1b5682dSAlexey Kardashevskiy     .post_load = icp_dispatch_post_load,
381c04d6cfaSAnthony Liguori     .fields = (VMStateField[]) {
382c04d6cfaSAnthony Liguori         /* Sanity check */
383c04d6cfaSAnthony Liguori         VMSTATE_UINT32(xirr, ICPState),
384c04d6cfaSAnthony Liguori         VMSTATE_UINT8(pending_priority, ICPState),
385c04d6cfaSAnthony Liguori         VMSTATE_UINT8(mfrr, ICPState),
386c04d6cfaSAnthony Liguori         VMSTATE_END_OF_LIST()
387c04d6cfaSAnthony Liguori     },
388c04d6cfaSAnthony Liguori };
389c04d6cfaSAnthony Liguori 
390c04d6cfaSAnthony Liguori static void icp_reset(DeviceState *dev)
391c04d6cfaSAnthony Liguori {
392c04d6cfaSAnthony Liguori     ICPState *icp = ICP(dev);
393c04d6cfaSAnthony Liguori 
394c04d6cfaSAnthony Liguori     icp->xirr = 0;
395c04d6cfaSAnthony Liguori     icp->pending_priority = 0xff;
396c04d6cfaSAnthony Liguori     icp->mfrr = 0xff;
397c04d6cfaSAnthony Liguori 
398c04d6cfaSAnthony Liguori     /* Make all outputs are deasserted */
399c04d6cfaSAnthony Liguori     qemu_set_irq(icp->output, 0);
400c04d6cfaSAnthony Liguori }
401c04d6cfaSAnthony Liguori 
402c04d6cfaSAnthony Liguori static void icp_class_init(ObjectClass *klass, void *data)
403c04d6cfaSAnthony Liguori {
404c04d6cfaSAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
405c04d6cfaSAnthony Liguori 
406c04d6cfaSAnthony Liguori     dc->reset = icp_reset;
407c04d6cfaSAnthony Liguori     dc->vmsd = &vmstate_icp_server;
408c04d6cfaSAnthony Liguori }
409c04d6cfaSAnthony Liguori 
410456df19cSAlexey Kardashevskiy static const TypeInfo icp_info = {
411c04d6cfaSAnthony Liguori     .name = TYPE_ICP,
412c04d6cfaSAnthony Liguori     .parent = TYPE_DEVICE,
413c04d6cfaSAnthony Liguori     .instance_size = sizeof(ICPState),
414c04d6cfaSAnthony Liguori     .class_init = icp_class_init,
415d1b5682dSAlexey Kardashevskiy     .class_size = sizeof(ICPStateClass),
416c04d6cfaSAnthony Liguori };
417c04d6cfaSAnthony Liguori 
418b5cec4c5SDavid Gibson /*
419b5cec4c5SDavid Gibson  * ICS: Source layer
420b5cec4c5SDavid Gibson  */
421c04d6cfaSAnthony Liguori static void resend_msi(ICSState *ics, int srcno)
422b5cec4c5SDavid Gibson {
423c04d6cfaSAnthony Liguori     ICSIRQState *irq = ics->irqs + srcno;
424d07fee7eSDavid Gibson 
425d07fee7eSDavid Gibson     /* FIXME: filter by server#? */
42698ca8c02SDavid Gibson     if (irq->status & XICS_STATUS_REJECTED) {
42798ca8c02SDavid Gibson         irq->status &= ~XICS_STATUS_REJECTED;
428d07fee7eSDavid Gibson         if (irq->priority != 0xff) {
429*cc706a53SBenjamin Herrenschmidt             icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
430d07fee7eSDavid Gibson         }
431d07fee7eSDavid Gibson     }
432d07fee7eSDavid Gibson }
433d07fee7eSDavid Gibson 
434c04d6cfaSAnthony Liguori static void resend_lsi(ICSState *ics, int srcno)
435d07fee7eSDavid Gibson {
436c04d6cfaSAnthony Liguori     ICSIRQState *irq = ics->irqs + srcno;
437d07fee7eSDavid Gibson 
43898ca8c02SDavid Gibson     if ((irq->priority != 0xff)
43998ca8c02SDavid Gibson         && (irq->status & XICS_STATUS_ASSERTED)
44098ca8c02SDavid Gibson         && !(irq->status & XICS_STATUS_SENT)) {
44198ca8c02SDavid Gibson         irq->status |= XICS_STATUS_SENT;
442*cc706a53SBenjamin Herrenschmidt         icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
443d07fee7eSDavid Gibson     }
444d07fee7eSDavid Gibson }
445d07fee7eSDavid Gibson 
446c04d6cfaSAnthony Liguori static void set_irq_msi(ICSState *ics, int srcno, int val)
447d07fee7eSDavid Gibson {
448c04d6cfaSAnthony Liguori     ICSIRQState *irq = ics->irqs + srcno;
449b5cec4c5SDavid Gibson 
450500efa23SDavid Gibson     trace_xics_set_irq_msi(srcno, srcno + ics->offset);
451500efa23SDavid Gibson 
452b5cec4c5SDavid Gibson     if (val) {
453b5cec4c5SDavid Gibson         if (irq->priority == 0xff) {
45498ca8c02SDavid Gibson             irq->status |= XICS_STATUS_MASKED_PENDING;
455500efa23SDavid Gibson             trace_xics_masked_pending();
456b5cec4c5SDavid Gibson         } else  {
457*cc706a53SBenjamin Herrenschmidt             icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
458b5cec4c5SDavid Gibson         }
459b5cec4c5SDavid Gibson     }
460b5cec4c5SDavid Gibson }
461b5cec4c5SDavid Gibson 
462c04d6cfaSAnthony Liguori static void set_irq_lsi(ICSState *ics, int srcno, int val)
463d07fee7eSDavid Gibson {
464c04d6cfaSAnthony Liguori     ICSIRQState *irq = ics->irqs + srcno;
465d07fee7eSDavid Gibson 
466500efa23SDavid Gibson     trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
46798ca8c02SDavid Gibson     if (val) {
46898ca8c02SDavid Gibson         irq->status |= XICS_STATUS_ASSERTED;
46998ca8c02SDavid Gibson     } else {
47098ca8c02SDavid Gibson         irq->status &= ~XICS_STATUS_ASSERTED;
47198ca8c02SDavid Gibson     }
472d07fee7eSDavid Gibson     resend_lsi(ics, srcno);
473d07fee7eSDavid Gibson }
474d07fee7eSDavid Gibson 
475d07fee7eSDavid Gibson static void ics_set_irq(void *opaque, int srcno, int val)
476d07fee7eSDavid Gibson {
477c04d6cfaSAnthony Liguori     ICSState *ics = (ICSState *)opaque;
478d07fee7eSDavid Gibson 
4794af88944SAlexey Kardashevskiy     if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
480d07fee7eSDavid Gibson         set_irq_lsi(ics, srcno, val);
481d07fee7eSDavid Gibson     } else {
482d07fee7eSDavid Gibson         set_irq_msi(ics, srcno, val);
483d07fee7eSDavid Gibson     }
484d07fee7eSDavid Gibson }
485d07fee7eSDavid Gibson 
486c04d6cfaSAnthony Liguori static void write_xive_msi(ICSState *ics, int srcno)
487d07fee7eSDavid Gibson {
488c04d6cfaSAnthony Liguori     ICSIRQState *irq = ics->irqs + srcno;
489d07fee7eSDavid Gibson 
49098ca8c02SDavid Gibson     if (!(irq->status & XICS_STATUS_MASKED_PENDING)
49198ca8c02SDavid Gibson         || (irq->priority == 0xff)) {
492d07fee7eSDavid Gibson         return;
493d07fee7eSDavid Gibson     }
494d07fee7eSDavid Gibson 
49598ca8c02SDavid Gibson     irq->status &= ~XICS_STATUS_MASKED_PENDING;
496*cc706a53SBenjamin Herrenschmidt     icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
497d07fee7eSDavid Gibson }
498d07fee7eSDavid Gibson 
499c04d6cfaSAnthony Liguori static void write_xive_lsi(ICSState *ics, int srcno)
500d07fee7eSDavid Gibson {
501d07fee7eSDavid Gibson     resend_lsi(ics, srcno);
502d07fee7eSDavid Gibson }
503d07fee7eSDavid Gibson 
5049c7027baSBenjamin Herrenschmidt void ics_write_xive(ICSState *ics, int nr, int server,
5053fe719f4SDavid Gibson                     uint8_t priority, uint8_t saved_priority)
506d07fee7eSDavid Gibson {
507d07fee7eSDavid Gibson     int srcno = nr - ics->offset;
508c04d6cfaSAnthony Liguori     ICSIRQState *irq = ics->irqs + srcno;
509d07fee7eSDavid Gibson 
510d07fee7eSDavid Gibson     irq->server = server;
511d07fee7eSDavid Gibson     irq->priority = priority;
5123fe719f4SDavid Gibson     irq->saved_priority = saved_priority;
513d07fee7eSDavid Gibson 
514500efa23SDavid Gibson     trace_xics_ics_write_xive(nr, srcno, server, priority);
515500efa23SDavid Gibson 
5164af88944SAlexey Kardashevskiy     if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
517d07fee7eSDavid Gibson         write_xive_lsi(ics, srcno);
518d07fee7eSDavid Gibson     } else {
519d07fee7eSDavid Gibson         write_xive_msi(ics, srcno);
520d07fee7eSDavid Gibson     }
521d07fee7eSDavid Gibson }
522d07fee7eSDavid Gibson 
523c04d6cfaSAnthony Liguori static void ics_reject(ICSState *ics, int nr)
524b5cec4c5SDavid Gibson {
525c04d6cfaSAnthony Liguori     ICSIRQState *irq = ics->irqs + nr - ics->offset;
526b5cec4c5SDavid Gibson 
527500efa23SDavid Gibson     trace_xics_ics_reject(nr, nr - ics->offset);
528056b9775SNikunj A Dadhania     if (irq->flags & XICS_FLAGS_IRQ_MSI) {
529056b9775SNikunj A Dadhania         irq->status |= XICS_STATUS_REJECTED;
530056b9775SNikunj A Dadhania     } else if (irq->flags & XICS_FLAGS_IRQ_LSI) {
531056b9775SNikunj A Dadhania         irq->status &= ~XICS_STATUS_SENT;
532056b9775SNikunj A Dadhania     }
533b5cec4c5SDavid Gibson }
534b5cec4c5SDavid Gibson 
535c04d6cfaSAnthony Liguori static void ics_resend(ICSState *ics)
536b5cec4c5SDavid Gibson {
537b5cec4c5SDavid Gibson     int i;
538b5cec4c5SDavid Gibson 
539b5cec4c5SDavid Gibson     for (i = 0; i < ics->nr_irqs; i++) {
540b5cec4c5SDavid Gibson         /* FIXME: filter by server#? */
5414af88944SAlexey Kardashevskiy         if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
542d07fee7eSDavid Gibson             resend_lsi(ics, i);
543d07fee7eSDavid Gibson         } else {
544d07fee7eSDavid Gibson             resend_msi(ics, i);
545b5cec4c5SDavid Gibson         }
546b5cec4c5SDavid Gibson     }
547b5cec4c5SDavid Gibson }
548b5cec4c5SDavid Gibson 
549c04d6cfaSAnthony Liguori static void ics_eoi(ICSState *ics, int nr)
550b5cec4c5SDavid Gibson {
551d07fee7eSDavid Gibson     int srcno = nr - ics->offset;
552c04d6cfaSAnthony Liguori     ICSIRQState *irq = ics->irqs + srcno;
553d07fee7eSDavid Gibson 
554500efa23SDavid Gibson     trace_xics_ics_eoi(nr);
555500efa23SDavid Gibson 
5564af88944SAlexey Kardashevskiy     if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
55798ca8c02SDavid Gibson         irq->status &= ~XICS_STATUS_SENT;
558d07fee7eSDavid Gibson     }
559b5cec4c5SDavid Gibson }
560b5cec4c5SDavid Gibson 
561c04d6cfaSAnthony Liguori static void ics_reset(DeviceState *dev)
562c04d6cfaSAnthony Liguori {
563c04d6cfaSAnthony Liguori     ICSState *ics = ICS(dev);
564c04d6cfaSAnthony Liguori     int i;
565a7e519a8SAlexey Kardashevskiy     uint8_t flags[ics->nr_irqs];
566a7e519a8SAlexey Kardashevskiy 
567a7e519a8SAlexey Kardashevskiy     for (i = 0; i < ics->nr_irqs; i++) {
568a7e519a8SAlexey Kardashevskiy         flags[i] = ics->irqs[i].flags;
569a7e519a8SAlexey Kardashevskiy     }
570c04d6cfaSAnthony Liguori 
571c04d6cfaSAnthony Liguori     memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
572a7e519a8SAlexey Kardashevskiy 
573c04d6cfaSAnthony Liguori     for (i = 0; i < ics->nr_irqs; i++) {
574c04d6cfaSAnthony Liguori         ics->irqs[i].priority = 0xff;
575c04d6cfaSAnthony Liguori         ics->irqs[i].saved_priority = 0xff;
576a7e519a8SAlexey Kardashevskiy         ics->irqs[i].flags = flags[i];
577c04d6cfaSAnthony Liguori     }
578c04d6cfaSAnthony Liguori }
579c04d6cfaSAnthony Liguori 
580d1b5682dSAlexey Kardashevskiy static int ics_post_load(ICSState *ics, int version_id)
581c04d6cfaSAnthony Liguori {
582c04d6cfaSAnthony Liguori     int i;
583c04d6cfaSAnthony Liguori 
58427f24582SBenjamin Herrenschmidt     for (i = 0; i < ics->xics->nr_servers; i++) {
58527f24582SBenjamin Herrenschmidt         icp_resend(ics->xics, i);
586c04d6cfaSAnthony Liguori     }
587c04d6cfaSAnthony Liguori 
588c04d6cfaSAnthony Liguori     return 0;
589c04d6cfaSAnthony Liguori }
590c04d6cfaSAnthony Liguori 
591d1b5682dSAlexey Kardashevskiy static void ics_dispatch_pre_save(void *opaque)
592d1b5682dSAlexey Kardashevskiy {
593d1b5682dSAlexey Kardashevskiy     ICSState *ics = opaque;
594d1b5682dSAlexey Kardashevskiy     ICSStateClass *info = ICS_GET_CLASS(ics);
595d1b5682dSAlexey Kardashevskiy 
596d1b5682dSAlexey Kardashevskiy     if (info->pre_save) {
597d1b5682dSAlexey Kardashevskiy         info->pre_save(ics);
598d1b5682dSAlexey Kardashevskiy     }
599d1b5682dSAlexey Kardashevskiy }
600d1b5682dSAlexey Kardashevskiy 
601d1b5682dSAlexey Kardashevskiy static int ics_dispatch_post_load(void *opaque, int version_id)
602d1b5682dSAlexey Kardashevskiy {
603d1b5682dSAlexey Kardashevskiy     ICSState *ics = opaque;
604d1b5682dSAlexey Kardashevskiy     ICSStateClass *info = ICS_GET_CLASS(ics);
605d1b5682dSAlexey Kardashevskiy 
606d1b5682dSAlexey Kardashevskiy     if (info->post_load) {
607d1b5682dSAlexey Kardashevskiy         return info->post_load(ics, version_id);
608d1b5682dSAlexey Kardashevskiy     }
609d1b5682dSAlexey Kardashevskiy 
610d1b5682dSAlexey Kardashevskiy     return 0;
611d1b5682dSAlexey Kardashevskiy }
612d1b5682dSAlexey Kardashevskiy 
613c04d6cfaSAnthony Liguori static const VMStateDescription vmstate_ics_irq = {
614c04d6cfaSAnthony Liguori     .name = "ics/irq",
6154af88944SAlexey Kardashevskiy     .version_id = 2,
616c04d6cfaSAnthony Liguori     .minimum_version_id = 1,
617c04d6cfaSAnthony Liguori     .fields = (VMStateField[]) {
618c04d6cfaSAnthony Liguori         VMSTATE_UINT32(server, ICSIRQState),
619c04d6cfaSAnthony Liguori         VMSTATE_UINT8(priority, ICSIRQState),
620c04d6cfaSAnthony Liguori         VMSTATE_UINT8(saved_priority, ICSIRQState),
621c04d6cfaSAnthony Liguori         VMSTATE_UINT8(status, ICSIRQState),
6224af88944SAlexey Kardashevskiy         VMSTATE_UINT8(flags, ICSIRQState),
623c04d6cfaSAnthony Liguori         VMSTATE_END_OF_LIST()
624c04d6cfaSAnthony Liguori     },
625c04d6cfaSAnthony Liguori };
626c04d6cfaSAnthony Liguori 
627c04d6cfaSAnthony Liguori static const VMStateDescription vmstate_ics = {
628c04d6cfaSAnthony Liguori     .name = "ics",
629c04d6cfaSAnthony Liguori     .version_id = 1,
630c04d6cfaSAnthony Liguori     .minimum_version_id = 1,
631d1b5682dSAlexey Kardashevskiy     .pre_save = ics_dispatch_pre_save,
632d1b5682dSAlexey Kardashevskiy     .post_load = ics_dispatch_post_load,
633c04d6cfaSAnthony Liguori     .fields = (VMStateField[]) {
634c04d6cfaSAnthony Liguori         /* Sanity check */
635c04d6cfaSAnthony Liguori         VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
636c04d6cfaSAnthony Liguori 
637c04d6cfaSAnthony Liguori         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
638c04d6cfaSAnthony Liguori                                              vmstate_ics_irq, ICSIRQState),
639c04d6cfaSAnthony Liguori         VMSTATE_END_OF_LIST()
640c04d6cfaSAnthony Liguori     },
641c04d6cfaSAnthony Liguori };
642c04d6cfaSAnthony Liguori 
6435a3d7b23SAlexey Kardashevskiy static void ics_initfn(Object *obj)
6445a3d7b23SAlexey Kardashevskiy {
6455a3d7b23SAlexey Kardashevskiy     ICSState *ics = ICS(obj);
6465a3d7b23SAlexey Kardashevskiy 
6475a3d7b23SAlexey Kardashevskiy     ics->offset = XICS_IRQ_BASE;
6485a3d7b23SAlexey Kardashevskiy }
6495a3d7b23SAlexey Kardashevskiy 
650b45ff2d9SAlexey Kardashevskiy static void ics_realize(DeviceState *dev, Error **errp)
651c04d6cfaSAnthony Liguori {
652c04d6cfaSAnthony Liguori     ICSState *ics = ICS(dev);
653c04d6cfaSAnthony Liguori 
654b45ff2d9SAlexey Kardashevskiy     if (!ics->nr_irqs) {
655b45ff2d9SAlexey Kardashevskiy         error_setg(errp, "Number of interrupts needs to be greater 0");
656b45ff2d9SAlexey Kardashevskiy         return;
657b45ff2d9SAlexey Kardashevskiy     }
658c04d6cfaSAnthony Liguori     ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
659c04d6cfaSAnthony Liguori     ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
660c04d6cfaSAnthony Liguori }
661c04d6cfaSAnthony Liguori 
662c04d6cfaSAnthony Liguori static void ics_class_init(ObjectClass *klass, void *data)
663c04d6cfaSAnthony Liguori {
664c04d6cfaSAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
665d1b5682dSAlexey Kardashevskiy     ICSStateClass *isc = ICS_CLASS(klass);
666c04d6cfaSAnthony Liguori 
667b45ff2d9SAlexey Kardashevskiy     dc->realize = ics_realize;
668c04d6cfaSAnthony Liguori     dc->vmsd = &vmstate_ics;
669c04d6cfaSAnthony Liguori     dc->reset = ics_reset;
670d1b5682dSAlexey Kardashevskiy     isc->post_load = ics_post_load;
671c04d6cfaSAnthony Liguori }
672c04d6cfaSAnthony Liguori 
673456df19cSAlexey Kardashevskiy static const TypeInfo ics_info = {
674c04d6cfaSAnthony Liguori     .name = TYPE_ICS,
675c04d6cfaSAnthony Liguori     .parent = TYPE_DEVICE,
676c04d6cfaSAnthony Liguori     .instance_size = sizeof(ICSState),
677c04d6cfaSAnthony Liguori     .class_init = ics_class_init,
678d1b5682dSAlexey Kardashevskiy     .class_size = sizeof(ICSStateClass),
6795a3d7b23SAlexey Kardashevskiy     .instance_init = ics_initfn,
680c04d6cfaSAnthony Liguori };
681c04d6cfaSAnthony Liguori 
682b5cec4c5SDavid Gibson /*
683b5cec4c5SDavid Gibson  * Exported functions
684b5cec4c5SDavid Gibson  */
685*cc706a53SBenjamin Herrenschmidt ICSState *xics_find_source(XICSState *xics, int irq)
686641c3493SAlexey Kardashevskiy {
687*cc706a53SBenjamin Herrenschmidt     ICSState *ics;
688641c3493SAlexey Kardashevskiy 
689*cc706a53SBenjamin Herrenschmidt     QLIST_FOREACH(ics, &xics->ics, list) {
690641c3493SAlexey Kardashevskiy         if (ics_valid_irq(ics, irq)) {
691*cc706a53SBenjamin Herrenschmidt             return ics;
692641c3493SAlexey Kardashevskiy         }
693641c3493SAlexey Kardashevskiy     }
694*cc706a53SBenjamin Herrenschmidt     return NULL;
695641c3493SAlexey Kardashevskiy }
696b5cec4c5SDavid Gibson 
69727f24582SBenjamin Herrenschmidt qemu_irq xics_get_qirq(XICSState *xics, int irq)
698b5cec4c5SDavid Gibson {
699*cc706a53SBenjamin Herrenschmidt     ICSState *ics = xics_find_source(xics, irq);
700641c3493SAlexey Kardashevskiy 
701*cc706a53SBenjamin Herrenschmidt     if (ics) {
702641c3493SAlexey Kardashevskiy         return ics->qirqs[irq - ics->offset];
703b5cec4c5SDavid Gibson     }
704b5cec4c5SDavid Gibson 
705641c3493SAlexey Kardashevskiy     return NULL;
706a307d594SAlexey Kardashevskiy }
707a307d594SAlexey Kardashevskiy 
7089c7027baSBenjamin Herrenschmidt void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
7094af88944SAlexey Kardashevskiy {
7104af88944SAlexey Kardashevskiy     assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK));
7114af88944SAlexey Kardashevskiy 
7124af88944SAlexey Kardashevskiy     ics->irqs[srcno].flags |=
7134af88944SAlexey Kardashevskiy         lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
7144af88944SAlexey Kardashevskiy }
7154af88944SAlexey Kardashevskiy 
716c04d6cfaSAnthony Liguori static void xics_register_types(void)
717c04d6cfaSAnthony Liguori {
7185a3d7b23SAlexey Kardashevskiy     type_register_static(&xics_common_info);
719c04d6cfaSAnthony Liguori     type_register_static(&ics_info);
720c04d6cfaSAnthony Liguori     type_register_static(&icp_info);
721c04d6cfaSAnthony Liguori }
722c04d6cfaSAnthony Liguori 
723c04d6cfaSAnthony Liguori type_init(xics_register_types)
724