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 2883c9f4caSPaolo Bonzini #include "hw/hw.h" 29500efa23SDavid Gibson #include "trace.h" 300d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h" 310d09e41aSPaolo Bonzini #include "hw/ppc/xics.h" 329ccff2a4SAlexey Kardashevskiy #include "qemu/error-report.h" 33b5cec4c5SDavid Gibson 348ffe04edSAlexey Kardashevskiy void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) 358ffe04edSAlexey Kardashevskiy { 368ffe04edSAlexey Kardashevskiy CPUState *cs = CPU(cpu); 378ffe04edSAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 388ffe04edSAlexey Kardashevskiy ICPState *ss = &icp->ss[cs->cpu_index]; 398ffe04edSAlexey Kardashevskiy 408ffe04edSAlexey Kardashevskiy assert(cs->cpu_index < icp->nr_servers); 418ffe04edSAlexey Kardashevskiy 428ffe04edSAlexey Kardashevskiy switch (PPC_INPUT(env)) { 438ffe04edSAlexey Kardashevskiy case PPC_FLAGS_INPUT_POWER7: 448ffe04edSAlexey Kardashevskiy ss->output = env->irq_inputs[POWER7_INPUT_INT]; 458ffe04edSAlexey Kardashevskiy break; 468ffe04edSAlexey Kardashevskiy 478ffe04edSAlexey Kardashevskiy case PPC_FLAGS_INPUT_970: 488ffe04edSAlexey Kardashevskiy ss->output = env->irq_inputs[PPC970_INPUT_INT]; 498ffe04edSAlexey Kardashevskiy break; 508ffe04edSAlexey Kardashevskiy 518ffe04edSAlexey Kardashevskiy default: 529ccff2a4SAlexey Kardashevskiy error_report("XICS interrupt controller does not support this CPU " 539ccff2a4SAlexey Kardashevskiy "bus model"); 548ffe04edSAlexey Kardashevskiy abort(); 558ffe04edSAlexey Kardashevskiy } 568ffe04edSAlexey Kardashevskiy } 578ffe04edSAlexey Kardashevskiy 588ffe04edSAlexey Kardashevskiy static void xics_reset(DeviceState *d) 598ffe04edSAlexey Kardashevskiy { 608ffe04edSAlexey Kardashevskiy XICSState *icp = XICS(d); 618ffe04edSAlexey Kardashevskiy int i; 628ffe04edSAlexey Kardashevskiy 638ffe04edSAlexey Kardashevskiy for (i = 0; i < icp->nr_servers; i++) { 648ffe04edSAlexey Kardashevskiy device_reset(DEVICE(&icp->ss[i])); 658ffe04edSAlexey Kardashevskiy } 668ffe04edSAlexey Kardashevskiy 678ffe04edSAlexey Kardashevskiy device_reset(DEVICE(icp->ics)); 688ffe04edSAlexey Kardashevskiy } 698ffe04edSAlexey Kardashevskiy 70b5cec4c5SDavid Gibson /* 71b5cec4c5SDavid Gibson * ICP: Presentation layer 72b5cec4c5SDavid Gibson */ 73b5cec4c5SDavid Gibson 74b5cec4c5SDavid Gibson #define XISR_MASK 0x00ffffff 75b5cec4c5SDavid Gibson #define CPPR_MASK 0xff000000 76b5cec4c5SDavid Gibson 77b5cec4c5SDavid Gibson #define XISR(ss) (((ss)->xirr) & XISR_MASK) 78b5cec4c5SDavid Gibson #define CPPR(ss) (((ss)->xirr) >> 24) 79b5cec4c5SDavid Gibson 80c04d6cfaSAnthony Liguori static void ics_reject(ICSState *ics, int nr); 81c04d6cfaSAnthony Liguori static void ics_resend(ICSState *ics); 82c04d6cfaSAnthony Liguori static void ics_eoi(ICSState *ics, int nr); 83b5cec4c5SDavid Gibson 84c04d6cfaSAnthony Liguori static void icp_check_ipi(XICSState *icp, int server) 85b5cec4c5SDavid Gibson { 86c04d6cfaSAnthony Liguori ICPState *ss = icp->ss + server; 87b5cec4c5SDavid Gibson 88b5cec4c5SDavid Gibson if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { 89b5cec4c5SDavid Gibson return; 90b5cec4c5SDavid Gibson } 91b5cec4c5SDavid Gibson 92500efa23SDavid Gibson trace_xics_icp_check_ipi(server, ss->mfrr); 93500efa23SDavid Gibson 94b5cec4c5SDavid Gibson if (XISR(ss)) { 95b5cec4c5SDavid Gibson ics_reject(icp->ics, XISR(ss)); 96b5cec4c5SDavid Gibson } 97b5cec4c5SDavid Gibson 98b5cec4c5SDavid Gibson ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; 99b5cec4c5SDavid Gibson ss->pending_priority = ss->mfrr; 100b5cec4c5SDavid Gibson qemu_irq_raise(ss->output); 101b5cec4c5SDavid Gibson } 102b5cec4c5SDavid Gibson 103c04d6cfaSAnthony Liguori static void icp_resend(XICSState *icp, int server) 104b5cec4c5SDavid Gibson { 105c04d6cfaSAnthony Liguori ICPState *ss = icp->ss + server; 106b5cec4c5SDavid Gibson 107b5cec4c5SDavid Gibson if (ss->mfrr < CPPR(ss)) { 108b5cec4c5SDavid Gibson icp_check_ipi(icp, server); 109b5cec4c5SDavid Gibson } 110b5cec4c5SDavid Gibson ics_resend(icp->ics); 111b5cec4c5SDavid Gibson } 112b5cec4c5SDavid Gibson 113c04d6cfaSAnthony Liguori static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) 114b5cec4c5SDavid Gibson { 115c04d6cfaSAnthony Liguori ICPState *ss = icp->ss + server; 116b5cec4c5SDavid Gibson uint8_t old_cppr; 117b5cec4c5SDavid Gibson uint32_t old_xisr; 118b5cec4c5SDavid Gibson 119b5cec4c5SDavid Gibson old_cppr = CPPR(ss); 120b5cec4c5SDavid Gibson ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24); 121b5cec4c5SDavid Gibson 122b5cec4c5SDavid Gibson if (cppr < old_cppr) { 123b5cec4c5SDavid Gibson if (XISR(ss) && (cppr <= ss->pending_priority)) { 124b5cec4c5SDavid Gibson old_xisr = XISR(ss); 125b5cec4c5SDavid Gibson ss->xirr &= ~XISR_MASK; /* Clear XISR */ 126e03c902cSDavid Gibson ss->pending_priority = 0xff; 127b5cec4c5SDavid Gibson qemu_irq_lower(ss->output); 128b5cec4c5SDavid Gibson ics_reject(icp->ics, old_xisr); 129b5cec4c5SDavid Gibson } 130b5cec4c5SDavid Gibson } else { 131b5cec4c5SDavid Gibson if (!XISR(ss)) { 132b5cec4c5SDavid Gibson icp_resend(icp, server); 133b5cec4c5SDavid Gibson } 134b5cec4c5SDavid Gibson } 135b5cec4c5SDavid Gibson } 136b5cec4c5SDavid Gibson 137c04d6cfaSAnthony Liguori static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) 138b5cec4c5SDavid Gibson { 139c04d6cfaSAnthony Liguori ICPState *ss = icp->ss + server; 140b5cec4c5SDavid Gibson 141b5cec4c5SDavid Gibson ss->mfrr = mfrr; 142b5cec4c5SDavid Gibson if (mfrr < CPPR(ss)) { 143bf0175deSDavid Gibson icp_check_ipi(icp, server); 144b5cec4c5SDavid Gibson } 145b5cec4c5SDavid Gibson } 146b5cec4c5SDavid Gibson 147c04d6cfaSAnthony Liguori static uint32_t icp_accept(ICPState *ss) 148b5cec4c5SDavid Gibson { 149500efa23SDavid Gibson uint32_t xirr = ss->xirr; 150b5cec4c5SDavid Gibson 151b5cec4c5SDavid Gibson qemu_irq_lower(ss->output); 152b5cec4c5SDavid Gibson ss->xirr = ss->pending_priority << 24; 153e03c902cSDavid Gibson ss->pending_priority = 0xff; 154500efa23SDavid Gibson 155500efa23SDavid Gibson trace_xics_icp_accept(xirr, ss->xirr); 156500efa23SDavid Gibson 157b5cec4c5SDavid Gibson return xirr; 158b5cec4c5SDavid Gibson } 159b5cec4c5SDavid Gibson 160c04d6cfaSAnthony Liguori static void icp_eoi(XICSState *icp, int server, uint32_t xirr) 161b5cec4c5SDavid Gibson { 162c04d6cfaSAnthony Liguori ICPState *ss = icp->ss + server; 163b5cec4c5SDavid Gibson 164b5cec4c5SDavid Gibson /* Send EOI -> ICS */ 165b5cec4c5SDavid Gibson ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); 166500efa23SDavid Gibson trace_xics_icp_eoi(server, xirr, ss->xirr); 167d07fee7eSDavid Gibson ics_eoi(icp->ics, xirr & XISR_MASK); 168b5cec4c5SDavid Gibson if (!XISR(ss)) { 169b5cec4c5SDavid Gibson icp_resend(icp, server); 170b5cec4c5SDavid Gibson } 171b5cec4c5SDavid Gibson } 172b5cec4c5SDavid Gibson 173c04d6cfaSAnthony Liguori static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority) 174b5cec4c5SDavid Gibson { 175c04d6cfaSAnthony Liguori ICPState *ss = icp->ss + server; 176b5cec4c5SDavid Gibson 177500efa23SDavid Gibson trace_xics_icp_irq(server, nr, priority); 178500efa23SDavid Gibson 179b5cec4c5SDavid Gibson if ((priority >= CPPR(ss)) 180b5cec4c5SDavid Gibson || (XISR(ss) && (ss->pending_priority <= priority))) { 181b5cec4c5SDavid Gibson ics_reject(icp->ics, nr); 182b5cec4c5SDavid Gibson } else { 183b5cec4c5SDavid Gibson if (XISR(ss)) { 184b5cec4c5SDavid Gibson ics_reject(icp->ics, XISR(ss)); 185b5cec4c5SDavid Gibson } 186b5cec4c5SDavid Gibson ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); 187b5cec4c5SDavid Gibson ss->pending_priority = priority; 188500efa23SDavid Gibson trace_xics_icp_raise(ss->xirr, ss->pending_priority); 189b5cec4c5SDavid Gibson qemu_irq_raise(ss->output); 190b5cec4c5SDavid Gibson } 191b5cec4c5SDavid Gibson } 192b5cec4c5SDavid Gibson 193d1b5682dSAlexey Kardashevskiy static void icp_dispatch_pre_save(void *opaque) 194d1b5682dSAlexey Kardashevskiy { 195d1b5682dSAlexey Kardashevskiy ICPState *ss = opaque; 196d1b5682dSAlexey Kardashevskiy ICPStateClass *info = ICP_GET_CLASS(ss); 197d1b5682dSAlexey Kardashevskiy 198d1b5682dSAlexey Kardashevskiy if (info->pre_save) { 199d1b5682dSAlexey Kardashevskiy info->pre_save(ss); 200d1b5682dSAlexey Kardashevskiy } 201d1b5682dSAlexey Kardashevskiy } 202d1b5682dSAlexey Kardashevskiy 203d1b5682dSAlexey Kardashevskiy static int icp_dispatch_post_load(void *opaque, int version_id) 204d1b5682dSAlexey Kardashevskiy { 205d1b5682dSAlexey Kardashevskiy ICPState *ss = opaque; 206d1b5682dSAlexey Kardashevskiy ICPStateClass *info = ICP_GET_CLASS(ss); 207d1b5682dSAlexey Kardashevskiy 208d1b5682dSAlexey Kardashevskiy if (info->post_load) { 209d1b5682dSAlexey Kardashevskiy return info->post_load(ss, version_id); 210d1b5682dSAlexey Kardashevskiy } 211d1b5682dSAlexey Kardashevskiy 212d1b5682dSAlexey Kardashevskiy return 0; 213d1b5682dSAlexey Kardashevskiy } 214d1b5682dSAlexey Kardashevskiy 215c04d6cfaSAnthony Liguori static const VMStateDescription vmstate_icp_server = { 216c04d6cfaSAnthony Liguori .name = "icp/server", 217c04d6cfaSAnthony Liguori .version_id = 1, 218c04d6cfaSAnthony Liguori .minimum_version_id = 1, 219c04d6cfaSAnthony Liguori .minimum_version_id_old = 1, 220d1b5682dSAlexey Kardashevskiy .pre_save = icp_dispatch_pre_save, 221d1b5682dSAlexey Kardashevskiy .post_load = icp_dispatch_post_load, 222c04d6cfaSAnthony Liguori .fields = (VMStateField []) { 223c04d6cfaSAnthony Liguori /* Sanity check */ 224c04d6cfaSAnthony Liguori VMSTATE_UINT32(xirr, ICPState), 225c04d6cfaSAnthony Liguori VMSTATE_UINT8(pending_priority, ICPState), 226c04d6cfaSAnthony Liguori VMSTATE_UINT8(mfrr, ICPState), 227c04d6cfaSAnthony Liguori VMSTATE_END_OF_LIST() 228c04d6cfaSAnthony Liguori }, 229c04d6cfaSAnthony Liguori }; 230c04d6cfaSAnthony Liguori 231c04d6cfaSAnthony Liguori static void icp_reset(DeviceState *dev) 232c04d6cfaSAnthony Liguori { 233c04d6cfaSAnthony Liguori ICPState *icp = ICP(dev); 234c04d6cfaSAnthony Liguori 235c04d6cfaSAnthony Liguori icp->xirr = 0; 236c04d6cfaSAnthony Liguori icp->pending_priority = 0xff; 237c04d6cfaSAnthony Liguori icp->mfrr = 0xff; 238c04d6cfaSAnthony Liguori 239c04d6cfaSAnthony Liguori /* Make all outputs are deasserted */ 240c04d6cfaSAnthony Liguori qemu_set_irq(icp->output, 0); 241c04d6cfaSAnthony Liguori } 242c04d6cfaSAnthony Liguori 243c04d6cfaSAnthony Liguori static void icp_class_init(ObjectClass *klass, void *data) 244c04d6cfaSAnthony Liguori { 245c04d6cfaSAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 246c04d6cfaSAnthony Liguori 247c04d6cfaSAnthony Liguori dc->reset = icp_reset; 248c04d6cfaSAnthony Liguori dc->vmsd = &vmstate_icp_server; 249c04d6cfaSAnthony Liguori } 250c04d6cfaSAnthony Liguori 251*456df19cSAlexey Kardashevskiy static const TypeInfo icp_info = { 252c04d6cfaSAnthony Liguori .name = TYPE_ICP, 253c04d6cfaSAnthony Liguori .parent = TYPE_DEVICE, 254c04d6cfaSAnthony Liguori .instance_size = sizeof(ICPState), 255c04d6cfaSAnthony Liguori .class_init = icp_class_init, 256d1b5682dSAlexey Kardashevskiy .class_size = sizeof(ICPStateClass), 257c04d6cfaSAnthony Liguori }; 258c04d6cfaSAnthony Liguori 259b5cec4c5SDavid Gibson /* 260b5cec4c5SDavid Gibson * ICS: Source layer 261b5cec4c5SDavid Gibson */ 262c04d6cfaSAnthony Liguori static int ics_valid_irq(ICSState *ics, uint32_t nr) 263b5cec4c5SDavid Gibson { 264b5cec4c5SDavid Gibson return (nr >= ics->offset) 265b5cec4c5SDavid Gibson && (nr < (ics->offset + ics->nr_irqs)); 266b5cec4c5SDavid Gibson } 267b5cec4c5SDavid Gibson 268c04d6cfaSAnthony Liguori static void resend_msi(ICSState *ics, int srcno) 269b5cec4c5SDavid Gibson { 270c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 271d07fee7eSDavid Gibson 272d07fee7eSDavid Gibson /* FIXME: filter by server#? */ 27398ca8c02SDavid Gibson if (irq->status & XICS_STATUS_REJECTED) { 27498ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_REJECTED; 275d07fee7eSDavid Gibson if (irq->priority != 0xff) { 276d07fee7eSDavid Gibson icp_irq(ics->icp, irq->server, srcno + ics->offset, 277d07fee7eSDavid Gibson irq->priority); 278d07fee7eSDavid Gibson } 279d07fee7eSDavid Gibson } 280d07fee7eSDavid Gibson } 281d07fee7eSDavid Gibson 282c04d6cfaSAnthony Liguori static void resend_lsi(ICSState *ics, int srcno) 283d07fee7eSDavid Gibson { 284c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 285d07fee7eSDavid Gibson 28698ca8c02SDavid Gibson if ((irq->priority != 0xff) 28798ca8c02SDavid Gibson && (irq->status & XICS_STATUS_ASSERTED) 28898ca8c02SDavid Gibson && !(irq->status & XICS_STATUS_SENT)) { 28998ca8c02SDavid Gibson irq->status |= XICS_STATUS_SENT; 290d07fee7eSDavid Gibson icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); 291d07fee7eSDavid Gibson } 292d07fee7eSDavid Gibson } 293d07fee7eSDavid Gibson 294c04d6cfaSAnthony Liguori static void set_irq_msi(ICSState *ics, int srcno, int val) 295d07fee7eSDavid Gibson { 296c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 297b5cec4c5SDavid Gibson 298500efa23SDavid Gibson trace_xics_set_irq_msi(srcno, srcno + ics->offset); 299500efa23SDavid Gibson 300b5cec4c5SDavid Gibson if (val) { 301b5cec4c5SDavid Gibson if (irq->priority == 0xff) { 30298ca8c02SDavid Gibson irq->status |= XICS_STATUS_MASKED_PENDING; 303500efa23SDavid Gibson trace_xics_masked_pending(); 304b5cec4c5SDavid Gibson } else { 305cc67b9c8SDavid Gibson icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); 306b5cec4c5SDavid Gibson } 307b5cec4c5SDavid Gibson } 308b5cec4c5SDavid Gibson } 309b5cec4c5SDavid Gibson 310c04d6cfaSAnthony Liguori static void set_irq_lsi(ICSState *ics, int srcno, int val) 311d07fee7eSDavid Gibson { 312c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 313d07fee7eSDavid Gibson 314500efa23SDavid Gibson trace_xics_set_irq_lsi(srcno, srcno + ics->offset); 31598ca8c02SDavid Gibson if (val) { 31698ca8c02SDavid Gibson irq->status |= XICS_STATUS_ASSERTED; 31798ca8c02SDavid Gibson } else { 31898ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_ASSERTED; 31998ca8c02SDavid Gibson } 320d07fee7eSDavid Gibson resend_lsi(ics, srcno); 321d07fee7eSDavid Gibson } 322d07fee7eSDavid Gibson 323d07fee7eSDavid Gibson static void ics_set_irq(void *opaque, int srcno, int val) 324d07fee7eSDavid Gibson { 325c04d6cfaSAnthony Liguori ICSState *ics = (ICSState *)opaque; 326d07fee7eSDavid Gibson 32722a2611cSDavid Gibson if (ics->islsi[srcno]) { 328d07fee7eSDavid Gibson set_irq_lsi(ics, srcno, val); 329d07fee7eSDavid Gibson } else { 330d07fee7eSDavid Gibson set_irq_msi(ics, srcno, val); 331d07fee7eSDavid Gibson } 332d07fee7eSDavid Gibson } 333d07fee7eSDavid Gibson 334c04d6cfaSAnthony Liguori static void write_xive_msi(ICSState *ics, int srcno) 335d07fee7eSDavid Gibson { 336c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 337d07fee7eSDavid Gibson 33898ca8c02SDavid Gibson if (!(irq->status & XICS_STATUS_MASKED_PENDING) 33998ca8c02SDavid Gibson || (irq->priority == 0xff)) { 340d07fee7eSDavid Gibson return; 341d07fee7eSDavid Gibson } 342d07fee7eSDavid Gibson 34398ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_MASKED_PENDING; 344d07fee7eSDavid Gibson icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); 345d07fee7eSDavid Gibson } 346d07fee7eSDavid Gibson 347c04d6cfaSAnthony Liguori static void write_xive_lsi(ICSState *ics, int srcno) 348d07fee7eSDavid Gibson { 349d07fee7eSDavid Gibson resend_lsi(ics, srcno); 350d07fee7eSDavid Gibson } 351d07fee7eSDavid Gibson 352c04d6cfaSAnthony Liguori static void ics_write_xive(ICSState *ics, int nr, int server, 3533fe719f4SDavid Gibson uint8_t priority, uint8_t saved_priority) 354d07fee7eSDavid Gibson { 355d07fee7eSDavid Gibson int srcno = nr - ics->offset; 356c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 357d07fee7eSDavid Gibson 358d07fee7eSDavid Gibson irq->server = server; 359d07fee7eSDavid Gibson irq->priority = priority; 3603fe719f4SDavid Gibson irq->saved_priority = saved_priority; 361d07fee7eSDavid Gibson 362500efa23SDavid Gibson trace_xics_ics_write_xive(nr, srcno, server, priority); 363500efa23SDavid Gibson 36422a2611cSDavid Gibson if (ics->islsi[srcno]) { 365d07fee7eSDavid Gibson write_xive_lsi(ics, srcno); 366d07fee7eSDavid Gibson } else { 367d07fee7eSDavid Gibson write_xive_msi(ics, srcno); 368d07fee7eSDavid Gibson } 369d07fee7eSDavid Gibson } 370d07fee7eSDavid Gibson 371c04d6cfaSAnthony Liguori static void ics_reject(ICSState *ics, int nr) 372b5cec4c5SDavid Gibson { 373c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + nr - ics->offset; 374b5cec4c5SDavid Gibson 375500efa23SDavid Gibson trace_xics_ics_reject(nr, nr - ics->offset); 37698ca8c02SDavid Gibson irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ 37798ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ 378b5cec4c5SDavid Gibson } 379b5cec4c5SDavid Gibson 380c04d6cfaSAnthony Liguori static void ics_resend(ICSState *ics) 381b5cec4c5SDavid Gibson { 382b5cec4c5SDavid Gibson int i; 383b5cec4c5SDavid Gibson 384b5cec4c5SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 385b5cec4c5SDavid Gibson /* FIXME: filter by server#? */ 38622a2611cSDavid Gibson if (ics->islsi[i]) { 387d07fee7eSDavid Gibson resend_lsi(ics, i); 388d07fee7eSDavid Gibson } else { 389d07fee7eSDavid Gibson resend_msi(ics, i); 390b5cec4c5SDavid Gibson } 391b5cec4c5SDavid Gibson } 392b5cec4c5SDavid Gibson } 393b5cec4c5SDavid Gibson 394c04d6cfaSAnthony Liguori static void ics_eoi(ICSState *ics, int nr) 395b5cec4c5SDavid Gibson { 396d07fee7eSDavid Gibson int srcno = nr - ics->offset; 397c04d6cfaSAnthony Liguori ICSIRQState *irq = ics->irqs + srcno; 398d07fee7eSDavid Gibson 399500efa23SDavid Gibson trace_xics_ics_eoi(nr); 400500efa23SDavid Gibson 40122a2611cSDavid Gibson if (ics->islsi[srcno]) { 40298ca8c02SDavid Gibson irq->status &= ~XICS_STATUS_SENT; 403d07fee7eSDavid Gibson } 404b5cec4c5SDavid Gibson } 405b5cec4c5SDavid Gibson 406c04d6cfaSAnthony Liguori static void ics_reset(DeviceState *dev) 407c04d6cfaSAnthony Liguori { 408c04d6cfaSAnthony Liguori ICSState *ics = ICS(dev); 409c04d6cfaSAnthony Liguori int i; 410c04d6cfaSAnthony Liguori 411c04d6cfaSAnthony Liguori memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs); 412c04d6cfaSAnthony Liguori for (i = 0; i < ics->nr_irqs; i++) { 413c04d6cfaSAnthony Liguori ics->irqs[i].priority = 0xff; 414c04d6cfaSAnthony Liguori ics->irqs[i].saved_priority = 0xff; 415c04d6cfaSAnthony Liguori } 416c04d6cfaSAnthony Liguori } 417c04d6cfaSAnthony Liguori 418d1b5682dSAlexey Kardashevskiy static int ics_post_load(ICSState *ics, int version_id) 419c04d6cfaSAnthony Liguori { 420c04d6cfaSAnthony Liguori int i; 421c04d6cfaSAnthony Liguori 422c04d6cfaSAnthony Liguori for (i = 0; i < ics->icp->nr_servers; i++) { 423c04d6cfaSAnthony Liguori icp_resend(ics->icp, i); 424c04d6cfaSAnthony Liguori } 425c04d6cfaSAnthony Liguori 426c04d6cfaSAnthony Liguori return 0; 427c04d6cfaSAnthony Liguori } 428c04d6cfaSAnthony Liguori 429d1b5682dSAlexey Kardashevskiy static void ics_dispatch_pre_save(void *opaque) 430d1b5682dSAlexey Kardashevskiy { 431d1b5682dSAlexey Kardashevskiy ICSState *ics = opaque; 432d1b5682dSAlexey Kardashevskiy ICSStateClass *info = ICS_GET_CLASS(ics); 433d1b5682dSAlexey Kardashevskiy 434d1b5682dSAlexey Kardashevskiy if (info->pre_save) { 435d1b5682dSAlexey Kardashevskiy info->pre_save(ics); 436d1b5682dSAlexey Kardashevskiy } 437d1b5682dSAlexey Kardashevskiy } 438d1b5682dSAlexey Kardashevskiy 439d1b5682dSAlexey Kardashevskiy static int ics_dispatch_post_load(void *opaque, int version_id) 440d1b5682dSAlexey Kardashevskiy { 441d1b5682dSAlexey Kardashevskiy ICSState *ics = opaque; 442d1b5682dSAlexey Kardashevskiy ICSStateClass *info = ICS_GET_CLASS(ics); 443d1b5682dSAlexey Kardashevskiy 444d1b5682dSAlexey Kardashevskiy if (info->post_load) { 445d1b5682dSAlexey Kardashevskiy return info->post_load(ics, version_id); 446d1b5682dSAlexey Kardashevskiy } 447d1b5682dSAlexey Kardashevskiy 448d1b5682dSAlexey Kardashevskiy return 0; 449d1b5682dSAlexey Kardashevskiy } 450d1b5682dSAlexey Kardashevskiy 451c04d6cfaSAnthony Liguori static const VMStateDescription vmstate_ics_irq = { 452c04d6cfaSAnthony Liguori .name = "ics/irq", 453c04d6cfaSAnthony Liguori .version_id = 1, 454c04d6cfaSAnthony Liguori .minimum_version_id = 1, 455c04d6cfaSAnthony Liguori .minimum_version_id_old = 1, 456c04d6cfaSAnthony Liguori .fields = (VMStateField []) { 457c04d6cfaSAnthony Liguori VMSTATE_UINT32(server, ICSIRQState), 458c04d6cfaSAnthony Liguori VMSTATE_UINT8(priority, ICSIRQState), 459c04d6cfaSAnthony Liguori VMSTATE_UINT8(saved_priority, ICSIRQState), 460c04d6cfaSAnthony Liguori VMSTATE_UINT8(status, ICSIRQState), 461c04d6cfaSAnthony Liguori VMSTATE_END_OF_LIST() 462c04d6cfaSAnthony Liguori }, 463c04d6cfaSAnthony Liguori }; 464c04d6cfaSAnthony Liguori 465c04d6cfaSAnthony Liguori static const VMStateDescription vmstate_ics = { 466c04d6cfaSAnthony Liguori .name = "ics", 467c04d6cfaSAnthony Liguori .version_id = 1, 468c04d6cfaSAnthony Liguori .minimum_version_id = 1, 469c04d6cfaSAnthony Liguori .minimum_version_id_old = 1, 470d1b5682dSAlexey Kardashevskiy .pre_save = ics_dispatch_pre_save, 471d1b5682dSAlexey Kardashevskiy .post_load = ics_dispatch_post_load, 472c04d6cfaSAnthony Liguori .fields = (VMStateField []) { 473c04d6cfaSAnthony Liguori /* Sanity check */ 474c04d6cfaSAnthony Liguori VMSTATE_UINT32_EQUAL(nr_irqs, ICSState), 475c04d6cfaSAnthony Liguori 476c04d6cfaSAnthony Liguori VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs, 477c04d6cfaSAnthony Liguori vmstate_ics_irq, ICSIRQState), 478c04d6cfaSAnthony Liguori VMSTATE_END_OF_LIST() 479c04d6cfaSAnthony Liguori }, 480c04d6cfaSAnthony Liguori }; 481c04d6cfaSAnthony Liguori 482b45ff2d9SAlexey Kardashevskiy static void ics_realize(DeviceState *dev, Error **errp) 483c04d6cfaSAnthony Liguori { 484c04d6cfaSAnthony Liguori ICSState *ics = ICS(dev); 485c04d6cfaSAnthony Liguori 486b45ff2d9SAlexey Kardashevskiy if (!ics->nr_irqs) { 487b45ff2d9SAlexey Kardashevskiy error_setg(errp, "Number of interrupts needs to be greater 0"); 488b45ff2d9SAlexey Kardashevskiy return; 489b45ff2d9SAlexey Kardashevskiy } 490c04d6cfaSAnthony Liguori ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); 491c04d6cfaSAnthony Liguori ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool)); 492c04d6cfaSAnthony Liguori ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs); 493c04d6cfaSAnthony Liguori } 494c04d6cfaSAnthony Liguori 495c04d6cfaSAnthony Liguori static void ics_class_init(ObjectClass *klass, void *data) 496c04d6cfaSAnthony Liguori { 497c04d6cfaSAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 498d1b5682dSAlexey Kardashevskiy ICSStateClass *isc = ICS_CLASS(klass); 499c04d6cfaSAnthony Liguori 500b45ff2d9SAlexey Kardashevskiy dc->realize = ics_realize; 501c04d6cfaSAnthony Liguori dc->vmsd = &vmstate_ics; 502c04d6cfaSAnthony Liguori dc->reset = ics_reset; 503d1b5682dSAlexey Kardashevskiy isc->post_load = ics_post_load; 504c04d6cfaSAnthony Liguori } 505c04d6cfaSAnthony Liguori 506*456df19cSAlexey Kardashevskiy static const TypeInfo ics_info = { 507c04d6cfaSAnthony Liguori .name = TYPE_ICS, 508c04d6cfaSAnthony Liguori .parent = TYPE_DEVICE, 509c04d6cfaSAnthony Liguori .instance_size = sizeof(ICSState), 510c04d6cfaSAnthony Liguori .class_init = ics_class_init, 511d1b5682dSAlexey Kardashevskiy .class_size = sizeof(ICSStateClass), 512c04d6cfaSAnthony Liguori }; 513c04d6cfaSAnthony Liguori 514b5cec4c5SDavid Gibson /* 515b5cec4c5SDavid Gibson * Exported functions 516b5cec4c5SDavid Gibson */ 517b5cec4c5SDavid Gibson 518c04d6cfaSAnthony Liguori qemu_irq xics_get_qirq(XICSState *icp, int irq) 519b5cec4c5SDavid Gibson { 5201ecbbab4SDavid Gibson if (!ics_valid_irq(icp->ics, irq)) { 521b5cec4c5SDavid Gibson return NULL; 522b5cec4c5SDavid Gibson } 523b5cec4c5SDavid Gibson 524a307d594SAlexey Kardashevskiy return icp->ics->qirqs[irq - icp->ics->offset]; 525a307d594SAlexey Kardashevskiy } 526a307d594SAlexey Kardashevskiy 527c04d6cfaSAnthony Liguori void xics_set_irq_type(XICSState *icp, int irq, bool lsi) 528a307d594SAlexey Kardashevskiy { 5291ecbbab4SDavid Gibson assert(ics_valid_irq(icp->ics, irq)); 530d07fee7eSDavid Gibson 53122a2611cSDavid Gibson icp->ics->islsi[irq - icp->ics->offset] = lsi; 532b5cec4c5SDavid Gibson } 533b5cec4c5SDavid Gibson 534c04d6cfaSAnthony Liguori /* 535c04d6cfaSAnthony Liguori * Guest interfaces 536c04d6cfaSAnthony Liguori */ 537c04d6cfaSAnthony Liguori 538b13ce26dSAndreas Färber static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, 539b5cec4c5SDavid Gibson target_ulong opcode, target_ulong *args) 540b5cec4c5SDavid Gibson { 54155e5c285SAndreas Färber CPUState *cs = CPU(cpu); 542b5cec4c5SDavid Gibson target_ulong cppr = args[0]; 543b5cec4c5SDavid Gibson 54455e5c285SAndreas Färber icp_set_cppr(spapr->icp, cs->cpu_index, cppr); 545b5cec4c5SDavid Gibson return H_SUCCESS; 546b5cec4c5SDavid Gibson } 547b5cec4c5SDavid Gibson 548b13ce26dSAndreas Färber static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr, 549b5cec4c5SDavid Gibson target_ulong opcode, target_ulong *args) 550b5cec4c5SDavid Gibson { 551b5cec4c5SDavid Gibson target_ulong server = args[0]; 552b5cec4c5SDavid Gibson target_ulong mfrr = args[1]; 553b5cec4c5SDavid Gibson 554b5cec4c5SDavid Gibson if (server >= spapr->icp->nr_servers) { 555b5cec4c5SDavid Gibson return H_PARAMETER; 556b5cec4c5SDavid Gibson } 557b5cec4c5SDavid Gibson 558b5cec4c5SDavid Gibson icp_set_mfrr(spapr->icp, server, mfrr); 559b5cec4c5SDavid Gibson return H_SUCCESS; 560b5cec4c5SDavid Gibson } 561b5cec4c5SDavid Gibson 562b13ce26dSAndreas Färber static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr, 563b5cec4c5SDavid Gibson target_ulong opcode, target_ulong *args) 564b5cec4c5SDavid Gibson { 56555e5c285SAndreas Färber CPUState *cs = CPU(cpu); 56655e5c285SAndreas Färber uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); 567b5cec4c5SDavid Gibson 568b5cec4c5SDavid Gibson args[0] = xirr; 569b5cec4c5SDavid Gibson return H_SUCCESS; 570b5cec4c5SDavid Gibson } 571b5cec4c5SDavid Gibson 572b13ce26dSAndreas Färber static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr, 573b5cec4c5SDavid Gibson target_ulong opcode, target_ulong *args) 574b5cec4c5SDavid Gibson { 57555e5c285SAndreas Färber CPUState *cs = CPU(cpu); 576b5cec4c5SDavid Gibson target_ulong xirr = args[0]; 577b5cec4c5SDavid Gibson 57855e5c285SAndreas Färber icp_eoi(spapr->icp, cs->cpu_index, xirr); 579b5cec4c5SDavid Gibson return H_SUCCESS; 580b5cec4c5SDavid Gibson } 581b5cec4c5SDavid Gibson 582210b580bSAnthony Liguori static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, 583210b580bSAnthony Liguori uint32_t token, 584b5cec4c5SDavid Gibson uint32_t nargs, target_ulong args, 585b5cec4c5SDavid Gibson uint32_t nret, target_ulong rets) 586b5cec4c5SDavid Gibson { 587c04d6cfaSAnthony Liguori ICSState *ics = spapr->icp->ics; 588b5cec4c5SDavid Gibson uint32_t nr, server, priority; 589b5cec4c5SDavid Gibson 590b5cec4c5SDavid Gibson if ((nargs != 3) || (nret != 1)) { 591b5cec4c5SDavid Gibson rtas_st(rets, 0, -3); 592b5cec4c5SDavid Gibson return; 593b5cec4c5SDavid Gibson } 594b5cec4c5SDavid Gibson 595b5cec4c5SDavid Gibson nr = rtas_ld(args, 0); 596b5cec4c5SDavid Gibson server = rtas_ld(args, 1); 597b5cec4c5SDavid Gibson priority = rtas_ld(args, 2); 598b5cec4c5SDavid Gibson 599b5cec4c5SDavid Gibson if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) 600b5cec4c5SDavid Gibson || (priority > 0xff)) { 601b5cec4c5SDavid Gibson rtas_st(rets, 0, -3); 602b5cec4c5SDavid Gibson return; 603b5cec4c5SDavid Gibson } 604b5cec4c5SDavid Gibson 6053fe719f4SDavid Gibson ics_write_xive(ics, nr, server, priority, priority); 606b5cec4c5SDavid Gibson 607b5cec4c5SDavid Gibson rtas_st(rets, 0, 0); /* Success */ 608b5cec4c5SDavid Gibson } 609b5cec4c5SDavid Gibson 610210b580bSAnthony Liguori static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, 611210b580bSAnthony Liguori uint32_t token, 612b5cec4c5SDavid Gibson uint32_t nargs, target_ulong args, 613b5cec4c5SDavid Gibson uint32_t nret, target_ulong rets) 614b5cec4c5SDavid Gibson { 615c04d6cfaSAnthony Liguori ICSState *ics = spapr->icp->ics; 616b5cec4c5SDavid Gibson uint32_t nr; 617b5cec4c5SDavid Gibson 618b5cec4c5SDavid Gibson if ((nargs != 1) || (nret != 3)) { 619b5cec4c5SDavid Gibson rtas_st(rets, 0, -3); 620b5cec4c5SDavid Gibson return; 621b5cec4c5SDavid Gibson } 622b5cec4c5SDavid Gibson 623b5cec4c5SDavid Gibson nr = rtas_ld(args, 0); 624b5cec4c5SDavid Gibson 625b5cec4c5SDavid Gibson if (!ics_valid_irq(ics, nr)) { 626b5cec4c5SDavid Gibson rtas_st(rets, 0, -3); 627b5cec4c5SDavid Gibson return; 628b5cec4c5SDavid Gibson } 629b5cec4c5SDavid Gibson 630b5cec4c5SDavid Gibson rtas_st(rets, 0, 0); /* Success */ 631b5cec4c5SDavid Gibson rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); 632b5cec4c5SDavid Gibson rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); 633b5cec4c5SDavid Gibson } 634b5cec4c5SDavid Gibson 635210b580bSAnthony Liguori static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, 636210b580bSAnthony Liguori uint32_t token, 637b5cec4c5SDavid Gibson uint32_t nargs, target_ulong args, 638b5cec4c5SDavid Gibson uint32_t nret, target_ulong rets) 639b5cec4c5SDavid Gibson { 640c04d6cfaSAnthony Liguori ICSState *ics = spapr->icp->ics; 641b5cec4c5SDavid Gibson uint32_t nr; 642b5cec4c5SDavid Gibson 643b5cec4c5SDavid Gibson if ((nargs != 1) || (nret != 1)) { 644b5cec4c5SDavid Gibson rtas_st(rets, 0, -3); 645b5cec4c5SDavid Gibson return; 646b5cec4c5SDavid Gibson } 647b5cec4c5SDavid Gibson 648b5cec4c5SDavid Gibson nr = rtas_ld(args, 0); 649b5cec4c5SDavid Gibson 650b5cec4c5SDavid Gibson if (!ics_valid_irq(ics, nr)) { 651b5cec4c5SDavid Gibson rtas_st(rets, 0, -3); 652b5cec4c5SDavid Gibson return; 653b5cec4c5SDavid Gibson } 654b5cec4c5SDavid Gibson 6553fe719f4SDavid Gibson ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, 6563fe719f4SDavid Gibson ics->irqs[nr - ics->offset].priority); 657b5cec4c5SDavid Gibson 658b5cec4c5SDavid Gibson rtas_st(rets, 0, 0); /* Success */ 659b5cec4c5SDavid Gibson } 660b5cec4c5SDavid Gibson 661210b580bSAnthony Liguori static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, 662210b580bSAnthony Liguori uint32_t token, 663b5cec4c5SDavid Gibson uint32_t nargs, target_ulong args, 664b5cec4c5SDavid Gibson uint32_t nret, target_ulong rets) 665b5cec4c5SDavid Gibson { 666c04d6cfaSAnthony Liguori ICSState *ics = spapr->icp->ics; 667b5cec4c5SDavid Gibson uint32_t nr; 668b5cec4c5SDavid Gibson 669b5cec4c5SDavid Gibson if ((nargs != 1) || (nret != 1)) { 670b5cec4c5SDavid Gibson rtas_st(rets, 0, -3); 671b5cec4c5SDavid Gibson return; 672b5cec4c5SDavid Gibson } 673b5cec4c5SDavid Gibson 674b5cec4c5SDavid Gibson nr = rtas_ld(args, 0); 675b5cec4c5SDavid Gibson 676b5cec4c5SDavid Gibson if (!ics_valid_irq(ics, nr)) { 677b5cec4c5SDavid Gibson rtas_st(rets, 0, -3); 678b5cec4c5SDavid Gibson return; 679b5cec4c5SDavid Gibson } 680b5cec4c5SDavid Gibson 6813fe719f4SDavid Gibson ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 6823fe719f4SDavid Gibson ics->irqs[nr - ics->offset].saved_priority, 6833fe719f4SDavid Gibson ics->irqs[nr - ics->offset].saved_priority); 684b5cec4c5SDavid Gibson 685b5cec4c5SDavid Gibson rtas_st(rets, 0, 0); /* Success */ 686b5cec4c5SDavid Gibson } 687b5cec4c5SDavid Gibson 688c04d6cfaSAnthony Liguori /* 689c04d6cfaSAnthony Liguori * XICS 690c04d6cfaSAnthony Liguori */ 691c04d6cfaSAnthony Liguori 692c04d6cfaSAnthony Liguori static void xics_realize(DeviceState *dev, Error **errp) 6937b565160SDavid Gibson { 694c04d6cfaSAnthony Liguori XICSState *icp = XICS(dev); 695c04d6cfaSAnthony Liguori ICSState *ics = icp->ics; 696b45ff2d9SAlexey Kardashevskiy Error *error = NULL; 697c04d6cfaSAnthony Liguori int i; 6987b565160SDavid Gibson 699b45ff2d9SAlexey Kardashevskiy if (!icp->nr_servers) { 700b45ff2d9SAlexey Kardashevskiy error_setg(errp, "Number of servers needs to be greater 0"); 701b45ff2d9SAlexey Kardashevskiy return; 702b45ff2d9SAlexey Kardashevskiy } 703b45ff2d9SAlexey Kardashevskiy 70433a0e5d8SAlexey Kardashevskiy /* Registration of global state belongs into realize */ 70533a0e5d8SAlexey Kardashevskiy spapr_rtas_register("ibm,set-xive", rtas_set_xive); 70633a0e5d8SAlexey Kardashevskiy spapr_rtas_register("ibm,get-xive", rtas_get_xive); 70733a0e5d8SAlexey Kardashevskiy spapr_rtas_register("ibm,int-off", rtas_int_off); 70833a0e5d8SAlexey Kardashevskiy spapr_rtas_register("ibm,int-on", rtas_int_on); 70933a0e5d8SAlexey Kardashevskiy 71033a0e5d8SAlexey Kardashevskiy spapr_register_hypercall(H_CPPR, h_cppr); 71133a0e5d8SAlexey Kardashevskiy spapr_register_hypercall(H_IPI, h_ipi); 71233a0e5d8SAlexey Kardashevskiy spapr_register_hypercall(H_XIRR, h_xirr); 71333a0e5d8SAlexey Kardashevskiy spapr_register_hypercall(H_EOI, h_eoi); 71433a0e5d8SAlexey Kardashevskiy 715c04d6cfaSAnthony Liguori ics->nr_irqs = icp->nr_irqs; 716bf3bc4c4SBen Herrenschmidt ics->offset = XICS_IRQ_BASE; 717b5cec4c5SDavid Gibson ics->icp = icp; 718b45ff2d9SAlexey Kardashevskiy object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); 719b45ff2d9SAlexey Kardashevskiy if (error) { 720b45ff2d9SAlexey Kardashevskiy error_propagate(errp, error); 721b45ff2d9SAlexey Kardashevskiy return; 722b45ff2d9SAlexey Kardashevskiy } 723b5cec4c5SDavid Gibson 724c04d6cfaSAnthony Liguori icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); 725c04d6cfaSAnthony Liguori for (i = 0; i < icp->nr_servers; i++) { 726c04d6cfaSAnthony Liguori char buffer[32]; 727213f0c4fSAndreas Färber object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP); 728c04d6cfaSAnthony Liguori snprintf(buffer, sizeof(buffer), "icp[%d]", i); 729c04d6cfaSAnthony Liguori object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), NULL); 730b45ff2d9SAlexey Kardashevskiy object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); 731b45ff2d9SAlexey Kardashevskiy if (error) { 732b45ff2d9SAlexey Kardashevskiy error_propagate(errp, error); 733b45ff2d9SAlexey Kardashevskiy return; 734b45ff2d9SAlexey Kardashevskiy } 735c04d6cfaSAnthony Liguori } 736c04d6cfaSAnthony Liguori } 737b5cec4c5SDavid Gibson 738c04d6cfaSAnthony Liguori static void xics_initfn(Object *obj) 739c04d6cfaSAnthony Liguori { 740c04d6cfaSAnthony Liguori XICSState *xics = XICS(obj); 741c04d6cfaSAnthony Liguori 742c04d6cfaSAnthony Liguori xics->ics = ICS(object_new(TYPE_ICS)); 743c04d6cfaSAnthony Liguori object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); 744c04d6cfaSAnthony Liguori } 745c04d6cfaSAnthony Liguori 746c04d6cfaSAnthony Liguori static Property xics_properties[] = { 747c04d6cfaSAnthony Liguori DEFINE_PROP_UINT32("nr_servers", XICSState, nr_servers, -1), 748c04d6cfaSAnthony Liguori DEFINE_PROP_UINT32("nr_irqs", XICSState, nr_irqs, -1), 749c04d6cfaSAnthony Liguori DEFINE_PROP_END_OF_LIST(), 750c04d6cfaSAnthony Liguori }; 751c04d6cfaSAnthony Liguori 752c04d6cfaSAnthony Liguori static void xics_class_init(ObjectClass *oc, void *data) 753c04d6cfaSAnthony Liguori { 754c04d6cfaSAnthony Liguori DeviceClass *dc = DEVICE_CLASS(oc); 755c04d6cfaSAnthony Liguori 756c04d6cfaSAnthony Liguori dc->realize = xics_realize; 757c04d6cfaSAnthony Liguori dc->props = xics_properties; 758c04d6cfaSAnthony Liguori dc->reset = xics_reset; 759b5cec4c5SDavid Gibson } 760c04d6cfaSAnthony Liguori 761c04d6cfaSAnthony Liguori static const TypeInfo xics_info = { 762c04d6cfaSAnthony Liguori .name = TYPE_XICS, 763c04d6cfaSAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 764c04d6cfaSAnthony Liguori .instance_size = sizeof(XICSState), 765c04d6cfaSAnthony Liguori .class_init = xics_class_init, 766c04d6cfaSAnthony Liguori .instance_init = xics_initfn, 767c04d6cfaSAnthony Liguori }; 768c04d6cfaSAnthony Liguori 769c04d6cfaSAnthony Liguori static void xics_register_types(void) 770c04d6cfaSAnthony Liguori { 771c04d6cfaSAnthony Liguori type_register_static(&xics_info); 772c04d6cfaSAnthony Liguori type_register_static(&ics_info); 773c04d6cfaSAnthony Liguori type_register_static(&icp_info); 774c04d6cfaSAnthony Liguori } 775c04d6cfaSAnthony Liguori 776c04d6cfaSAnthony Liguori type_init(xics_register_types) 777