qemu/hw/intc/xics.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
   3 *
   4 * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
   5 *
   6 * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 * copies of the Software, and to permit persons to whom the Software is
  13 * furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 * THE SOFTWARE.
  25 *
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "qapi/error.h"
  30#include "qemu-common.h"
  31#include "cpu.h"
  32#include "hw/hw.h"
  33#include "trace.h"
  34#include "qemu/timer.h"
  35#include "hw/ppc/xics.h"
  36#include "qemu/error-report.h"
  37#include "qapi/visitor.h"
  38#include "monitor/monitor.h"
  39#include "hw/intc/intc.h"
  40
  41int xics_get_cpu_index_by_dt_id(int cpu_dt_id)
  42{
  43    PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
  44
  45    if (cpu) {
  46        return cpu->parent_obj.cpu_index;
  47    }
  48
  49    return -1;
  50}
  51
  52void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu)
  53{
  54    CPUState *cs = CPU(cpu);
  55    ICPState *ss = &xics->ss[cs->cpu_index];
  56
  57    assert(cs->cpu_index < xics->nr_servers);
  58    assert(cs == ss->cs);
  59
  60    ss->output = NULL;
  61    ss->cs = NULL;
  62}
  63
  64void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
  65{
  66    CPUState *cs = CPU(cpu);
  67    CPUPPCState *env = &cpu->env;
  68    ICPState *ss = &xics->ss[cs->cpu_index];
  69    XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
  70
  71    assert(cs->cpu_index < xics->nr_servers);
  72
  73    ss->cs = cs;
  74
  75    if (info->cpu_setup) {
  76        info->cpu_setup(xics, cpu);
  77    }
  78
  79    switch (PPC_INPUT(env)) {
  80    case PPC_FLAGS_INPUT_POWER7:
  81        ss->output = env->irq_inputs[POWER7_INPUT_INT];
  82        break;
  83
  84    case PPC_FLAGS_INPUT_970:
  85        ss->output = env->irq_inputs[PPC970_INPUT_INT];
  86        break;
  87
  88    default:
  89        error_report("XICS interrupt controller does not support this CPU "
  90                     "bus model");
  91        abort();
  92    }
  93}
  94
  95static void xics_common_pic_print_info(InterruptStatsProvider *obj,
  96                                       Monitor *mon)
  97{
  98    XICSState *xics = XICS_COMMON(obj);
  99    ICSState *ics;
 100    uint32_t i;
 101
 102    for (i = 0; i < xics->nr_servers; i++) {
 103        ICPState *icp = &xics->ss[i];
 104
 105        if (!icp->output) {
 106            continue;
 107        }
 108        monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n",
 109                       i, icp->xirr, icp->xirr_owner,
 110                       icp->pending_priority, icp->mfrr);
 111    }
 112
 113    QLIST_FOREACH(ics, &xics->ics, list) {
 114        monitor_printf(mon, "ICS %4x..%4x %p\n",
 115                       ics->offset, ics->offset + ics->nr_irqs - 1, ics);
 116
 117        if (!ics->irqs) {
 118            continue;
 119        }
 120
 121        for (i = 0; i < ics->nr_irqs; i++) {
 122            ICSIRQState *irq = ics->irqs + i;
 123
 124            if (!(irq->flags & XICS_FLAGS_IRQ_MASK)) {
 125                continue;
 126            }
 127            monitor_printf(mon, "  %4x %s %02x %02x\n",
 128                           ics->offset + i,
 129                           (irq->flags & XICS_FLAGS_IRQ_LSI) ?
 130                           "LSI" : "MSI",
 131                           irq->priority, irq->status);
 132        }
 133    }
 134}
 135
 136/*
 137 * XICS Common class - parent for emulated XICS and KVM-XICS
 138 */
 139static void xics_common_reset(DeviceState *d)
 140{
 141    XICSState *xics = XICS_COMMON(d);
 142    ICSState *ics;
 143    int i;
 144
 145    for (i = 0; i < xics->nr_servers; i++) {
 146        device_reset(DEVICE(&xics->ss[i]));
 147    }
 148
 149    QLIST_FOREACH(ics, &xics->ics, list) {
 150        device_reset(DEVICE(ics));
 151    }
 152}
 153
 154static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name,
 155                                  void *opaque, Error **errp)
 156{
 157    XICSState *xics = XICS_COMMON(obj);
 158    int64_t value = xics->nr_irqs;
 159
 160    visit_type_int(v, name, &value, errp);
 161}
 162
 163static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name,
 164                                  void *opaque, Error **errp)
 165{
 166    XICSState *xics = XICS_COMMON(obj);
 167    XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
 168    Error *error = NULL;
 169    int64_t value;
 170
 171    visit_type_int(v, name, &value, &error);
 172    if (error) {
 173        error_propagate(errp, error);
 174        return;
 175    }
 176    if (xics->nr_irqs) {
 177        error_setg(errp, "Number of interrupts is already set to %u",
 178                   xics->nr_irqs);
 179        return;
 180    }
 181
 182    assert(info->set_nr_irqs);
 183    info->set_nr_irqs(xics, value, errp);
 184}
 185
 186void xics_set_nr_servers(XICSState *xics, uint32_t nr_servers,
 187                         const char *typename, Error **errp)
 188{
 189    int i;
 190
 191    xics->nr_servers = nr_servers;
 192
 193    xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState));
 194    for (i = 0; i < xics->nr_servers; i++) {
 195        char name[32];
 196        ICPState *icp = &xics->ss[i];
 197
 198        object_initialize(icp, sizeof(*icp), typename);
 199        snprintf(name, sizeof(name), "icp[%d]", i);
 200        object_property_add_child(OBJECT(xics), name, OBJECT(icp), errp);
 201        icp->xics = xics;
 202    }
 203}
 204
 205static void xics_prop_get_nr_servers(Object *obj, Visitor *v,
 206                                     const char *name, void *opaque,
 207                                     Error **errp)
 208{
 209    XICSState *xics = XICS_COMMON(obj);
 210    int64_t value = xics->nr_servers;
 211
 212    visit_type_int(v, name, &value, errp);
 213}
 214
 215static void xics_prop_set_nr_servers(Object *obj, Visitor *v,
 216                                     const char *name, void *opaque,
 217                                     Error **errp)
 218{
 219    XICSState *xics = XICS_COMMON(obj);
 220    XICSStateClass *xsc = XICS_COMMON_GET_CLASS(xics);
 221    Error *error = NULL;
 222    int64_t value;
 223
 224    visit_type_int(v, name, &value, &error);
 225    if (error) {
 226        error_propagate(errp, error);
 227        return;
 228    }
 229    if (xics->nr_servers) {
 230        error_setg(errp, "Number of servers is already set to %u",
 231                   xics->nr_servers);
 232        return;
 233    }
 234
 235    assert(xsc->set_nr_servers);
 236    xsc->set_nr_servers(xics, value, errp);
 237}
 238
 239static void xics_common_initfn(Object *obj)
 240{
 241    XICSState *xics = XICS_COMMON(obj);
 242
 243    QLIST_INIT(&xics->ics);
 244    object_property_add(obj, "nr_irqs", "int",
 245                        xics_prop_get_nr_irqs, xics_prop_set_nr_irqs,
 246                        NULL, NULL, NULL);
 247    object_property_add(obj, "nr_servers", "int",
 248                        xics_prop_get_nr_servers, xics_prop_set_nr_servers,
 249                        NULL, NULL, NULL);
 250}
 251
 252static void xics_common_class_init(ObjectClass *oc, void *data)
 253{
 254    DeviceClass *dc = DEVICE_CLASS(oc);
 255    InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
 256
 257    dc->reset = xics_common_reset;
 258    ic->print_info = xics_common_pic_print_info;
 259}
 260
 261static const TypeInfo xics_common_info = {
 262    .name          = TYPE_XICS_COMMON,
 263    .parent        = TYPE_SYS_BUS_DEVICE,
 264    .instance_size = sizeof(XICSState),
 265    .class_size    = sizeof(XICSStateClass),
 266    .instance_init = xics_common_initfn,
 267    .class_init    = xics_common_class_init,
 268    .interfaces = (InterfaceInfo[]) {
 269        { TYPE_INTERRUPT_STATS_PROVIDER },
 270        { }
 271    },
 272};
 273
 274/*
 275 * ICP: Presentation layer
 276 */
 277
 278#define XISR_MASK  0x00ffffff
 279#define CPPR_MASK  0xff000000
 280
 281#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
 282#define CPPR(ss)   (((ss)->xirr) >> 24)
 283
 284static void ics_reject(ICSState *ics, uint32_t nr)
 285{
 286    ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
 287
 288    if (k->reject) {
 289        k->reject(ics, nr);
 290    }
 291}
 292
 293static void ics_resend(ICSState *ics)
 294{
 295    ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
 296
 297    if (k->resend) {
 298        k->resend(ics);
 299    }
 300}
 301
 302static void ics_eoi(ICSState *ics, int nr)
 303{
 304    ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
 305
 306    if (k->eoi) {
 307        k->eoi(ics, nr);
 308    }
 309}
 310
 311static void icp_check_ipi(ICPState *ss)
 312{
 313    if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
 314        return;
 315    }
 316
 317    trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr);
 318
 319    if (XISR(ss) && ss->xirr_owner) {
 320        ics_reject(ss->xirr_owner, XISR(ss));
 321    }
 322
 323    ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
 324    ss->pending_priority = ss->mfrr;
 325    ss->xirr_owner = NULL;
 326    qemu_irq_raise(ss->output);
 327}
 328
 329static void icp_resend(ICPState *ss)
 330{
 331    ICSState *ics;
 332
 333    if (ss->mfrr < CPPR(ss)) {
 334        icp_check_ipi(ss);
 335    }
 336    QLIST_FOREACH(ics, &ss->xics->ics, list) {
 337        ics_resend(ics);
 338    }
 339}
 340
 341void icp_set_cppr(ICPState *ss, uint8_t cppr)
 342{
 343    uint8_t old_cppr;
 344    uint32_t old_xisr;
 345
 346    old_cppr = CPPR(ss);
 347    ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
 348
 349    if (cppr < old_cppr) {
 350        if (XISR(ss) && (cppr <= ss->pending_priority)) {
 351            old_xisr = XISR(ss);
 352            ss->xirr &= ~XISR_MASK; /* Clear XISR */
 353            ss->pending_priority = 0xff;
 354            qemu_irq_lower(ss->output);
 355            if (ss->xirr_owner) {
 356                ics_reject(ss->xirr_owner, old_xisr);
 357                ss->xirr_owner = NULL;
 358            }
 359        }
 360    } else {
 361        if (!XISR(ss)) {
 362            icp_resend(ss);
 363        }
 364    }
 365}
 366
 367void icp_set_mfrr(ICPState *ss, uint8_t mfrr)
 368{
 369    ss->mfrr = mfrr;
 370    if (mfrr < CPPR(ss)) {
 371        icp_check_ipi(ss);
 372    }
 373}
 374
 375uint32_t icp_accept(ICPState *ss)
 376{
 377    uint32_t xirr = ss->xirr;
 378
 379    qemu_irq_lower(ss->output);
 380    ss->xirr = ss->pending_priority << 24;
 381    ss->pending_priority = 0xff;
 382    ss->xirr_owner = NULL;
 383
 384    trace_xics_icp_accept(xirr, ss->xirr);
 385
 386    return xirr;
 387}
 388
 389uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)
 390{
 391    if (mfrr) {
 392        *mfrr = ss->mfrr;
 393    }
 394    return ss->xirr;
 395}
 396
 397void icp_eoi(ICPState *ss, uint32_t xirr)
 398{
 399    ICSState *ics;
 400    uint32_t irq;
 401
 402    /* Send EOI -> ICS */
 403    ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
 404    trace_xics_icp_eoi(ss->cs->cpu_index, xirr, ss->xirr);
 405    irq = xirr & XISR_MASK;
 406    QLIST_FOREACH(ics, &ss->xics->ics, list) {
 407        if (ics_valid_irq(ics, irq)) {
 408            ics_eoi(ics, irq);
 409        }
 410    }
 411    if (!XISR(ss)) {
 412        icp_resend(ss);
 413    }
 414}
 415
 416static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority)
 417{
 418    XICSState *xics = ics->xics;
 419    ICPState *ss = xics->ss + server;
 420
 421    trace_xics_icp_irq(server, nr, priority);
 422
 423    if ((priority >= CPPR(ss))
 424        || (XISR(ss) && (ss->pending_priority <= priority))) {
 425        ics_reject(ics, nr);
 426    } else {
 427        if (XISR(ss) && ss->xirr_owner) {
 428            ics_reject(ss->xirr_owner, XISR(ss));
 429            ss->xirr_owner = NULL;
 430        }
 431        ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
 432        ss->xirr_owner = ics;
 433        ss->pending_priority = priority;
 434        trace_xics_icp_raise(ss->xirr, ss->pending_priority);
 435        qemu_irq_raise(ss->output);
 436    }
 437}
 438
 439static void icp_dispatch_pre_save(void *opaque)
 440{
 441    ICPState *ss = opaque;
 442    ICPStateClass *info = ICP_GET_CLASS(ss);
 443
 444    if (info->pre_save) {
 445        info->pre_save(ss);
 446    }
 447}
 448
 449static int icp_dispatch_post_load(void *opaque, int version_id)
 450{
 451    ICPState *ss = opaque;
 452    ICPStateClass *info = ICP_GET_CLASS(ss);
 453
 454    if (info->post_load) {
 455        return info->post_load(ss, version_id);
 456    }
 457
 458    return 0;
 459}
 460
 461static const VMStateDescription vmstate_icp_server = {
 462    .name = "icp/server",
 463    .version_id = 1,
 464    .minimum_version_id = 1,
 465    .pre_save = icp_dispatch_pre_save,
 466    .post_load = icp_dispatch_post_load,
 467    .fields = (VMStateField[]) {
 468        /* Sanity check */
 469        VMSTATE_UINT32(xirr, ICPState),
 470        VMSTATE_UINT8(pending_priority, ICPState),
 471        VMSTATE_UINT8(mfrr, ICPState),
 472        VMSTATE_END_OF_LIST()
 473    },
 474};
 475
 476static void icp_reset(DeviceState *dev)
 477{
 478    ICPState *icp = ICP(dev);
 479
 480    icp->xirr = 0;
 481    icp->pending_priority = 0xff;
 482    icp->mfrr = 0xff;
 483
 484    /* Make all outputs are deasserted */
 485    qemu_set_irq(icp->output, 0);
 486}
 487
 488static void icp_class_init(ObjectClass *klass, void *data)
 489{
 490    DeviceClass *dc = DEVICE_CLASS(klass);
 491
 492    dc->reset = icp_reset;
 493    dc->vmsd = &vmstate_icp_server;
 494}
 495
 496static const TypeInfo icp_info = {
 497    .name = TYPE_ICP,
 498    .parent = TYPE_DEVICE,
 499    .instance_size = sizeof(ICPState),
 500    .class_init = icp_class_init,
 501    .class_size = sizeof(ICPStateClass),
 502};
 503
 504/*
 505 * ICS: Source layer
 506 */
 507static void ics_simple_resend_msi(ICSState *ics, int srcno)
 508{
 509    ICSIRQState *irq = ics->irqs + srcno;
 510
 511    /* FIXME: filter by server#? */
 512    if (irq->status & XICS_STATUS_REJECTED) {
 513        irq->status &= ~XICS_STATUS_REJECTED;
 514        if (irq->priority != 0xff) {
 515            icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
 516        }
 517    }
 518}
 519
 520static void ics_simple_resend_lsi(ICSState *ics, int srcno)
 521{
 522    ICSIRQState *irq = ics->irqs + srcno;
 523
 524    if ((irq->priority != 0xff)
 525        && (irq->status & XICS_STATUS_ASSERTED)
 526        && !(irq->status & XICS_STATUS_SENT)) {
 527        irq->status |= XICS_STATUS_SENT;
 528        icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
 529    }
 530}
 531
 532static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val)
 533{
 534    ICSIRQState *irq = ics->irqs + srcno;
 535
 536    trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset);
 537
 538    if (val) {
 539        if (irq->priority == 0xff) {
 540            irq->status |= XICS_STATUS_MASKED_PENDING;
 541            trace_xics_masked_pending();
 542        } else  {
 543            icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
 544        }
 545    }
 546}
 547
 548static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val)
 549{
 550    ICSIRQState *irq = ics->irqs + srcno;
 551
 552    trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset);
 553    if (val) {
 554        irq->status |= XICS_STATUS_ASSERTED;
 555    } else {
 556        irq->status &= ~XICS_STATUS_ASSERTED;
 557    }
 558    ics_simple_resend_lsi(ics, srcno);
 559}
 560
 561static void ics_simple_set_irq(void *opaque, int srcno, int val)
 562{
 563    ICSState *ics = (ICSState *)opaque;
 564
 565    if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
 566        ics_simple_set_irq_lsi(ics, srcno, val);
 567    } else {
 568        ics_simple_set_irq_msi(ics, srcno, val);
 569    }
 570}
 571
 572static void ics_simple_write_xive_msi(ICSState *ics, int srcno)
 573{
 574    ICSIRQState *irq = ics->irqs + srcno;
 575
 576    if (!(irq->status & XICS_STATUS_MASKED_PENDING)
 577        || (irq->priority == 0xff)) {
 578        return;
 579    }
 580
 581    irq->status &= ~XICS_STATUS_MASKED_PENDING;
 582    icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
 583}
 584
 585static void ics_simple_write_xive_lsi(ICSState *ics, int srcno)
 586{
 587    ics_simple_resend_lsi(ics, srcno);
 588}
 589
 590void ics_simple_write_xive(ICSState *ics, int srcno, int server,
 591                           uint8_t priority, uint8_t saved_priority)
 592{
 593    ICSIRQState *irq = ics->irqs + srcno;
 594
 595    irq->server = server;
 596    irq->priority = priority;
 597    irq->saved_priority = saved_priority;
 598
 599    trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server,
 600                                     priority);
 601
 602    if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
 603        ics_simple_write_xive_lsi(ics, srcno);
 604    } else {
 605        ics_simple_write_xive_msi(ics, srcno);
 606    }
 607}
 608
 609static void ics_simple_reject(ICSState *ics, uint32_t nr)
 610{
 611    ICSIRQState *irq = ics->irqs + nr - ics->offset;
 612
 613    trace_xics_ics_simple_reject(nr, nr - ics->offset);
 614    if (irq->flags & XICS_FLAGS_IRQ_MSI) {
 615        irq->status |= XICS_STATUS_REJECTED;
 616    } else if (irq->flags & XICS_FLAGS_IRQ_LSI) {
 617        irq->status &= ~XICS_STATUS_SENT;
 618    }
 619}
 620
 621static void ics_simple_resend(ICSState *ics)
 622{
 623    int i;
 624
 625    for (i = 0; i < ics->nr_irqs; i++) {
 626        /* FIXME: filter by server#? */
 627        if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
 628            ics_simple_resend_lsi(ics, i);
 629        } else {
 630            ics_simple_resend_msi(ics, i);
 631        }
 632    }
 633}
 634
 635static void ics_simple_eoi(ICSState *ics, uint32_t nr)
 636{
 637    int srcno = nr - ics->offset;
 638    ICSIRQState *irq = ics->irqs + srcno;
 639
 640    trace_xics_ics_simple_eoi(nr);
 641
 642    if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
 643        irq->status &= ~XICS_STATUS_SENT;
 644    }
 645}
 646
 647static void ics_simple_reset(DeviceState *dev)
 648{
 649    ICSState *ics = ICS_SIMPLE(dev);
 650    int i;
 651    uint8_t flags[ics->nr_irqs];
 652
 653    for (i = 0; i < ics->nr_irqs; i++) {
 654        flags[i] = ics->irqs[i].flags;
 655    }
 656
 657    memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
 658
 659    for (i = 0; i < ics->nr_irqs; i++) {
 660        ics->irqs[i].priority = 0xff;
 661        ics->irqs[i].saved_priority = 0xff;
 662        ics->irqs[i].flags = flags[i];
 663    }
 664}
 665
 666static int ics_simple_post_load(ICSState *ics, int version_id)
 667{
 668    int i;
 669
 670    for (i = 0; i < ics->xics->nr_servers; i++) {
 671        icp_resend(&ics->xics->ss[i]);
 672    }
 673
 674    return 0;
 675}
 676
 677static void ics_simple_dispatch_pre_save(void *opaque)
 678{
 679    ICSState *ics = opaque;
 680    ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
 681
 682    if (info->pre_save) {
 683        info->pre_save(ics);
 684    }
 685}
 686
 687static int ics_simple_dispatch_post_load(void *opaque, int version_id)
 688{
 689    ICSState *ics = opaque;
 690    ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
 691
 692    if (info->post_load) {
 693        return info->post_load(ics, version_id);
 694    }
 695
 696    return 0;
 697}
 698
 699static const VMStateDescription vmstate_ics_simple_irq = {
 700    .name = "ics/irq",
 701    .version_id = 2,
 702    .minimum_version_id = 1,
 703    .fields = (VMStateField[]) {
 704        VMSTATE_UINT32(server, ICSIRQState),
 705        VMSTATE_UINT8(priority, ICSIRQState),
 706        VMSTATE_UINT8(saved_priority, ICSIRQState),
 707        VMSTATE_UINT8(status, ICSIRQState),
 708        VMSTATE_UINT8(flags, ICSIRQState),
 709        VMSTATE_END_OF_LIST()
 710    },
 711};
 712
 713static const VMStateDescription vmstate_ics_simple = {
 714    .name = "ics",
 715    .version_id = 1,
 716    .minimum_version_id = 1,
 717    .pre_save = ics_simple_dispatch_pre_save,
 718    .post_load = ics_simple_dispatch_post_load,
 719    .fields = (VMStateField[]) {
 720        /* Sanity check */
 721        VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
 722
 723        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
 724                                             vmstate_ics_simple_irq,
 725                                             ICSIRQState),
 726        VMSTATE_END_OF_LIST()
 727    },
 728};
 729
 730static void ics_simple_initfn(Object *obj)
 731{
 732    ICSState *ics = ICS_SIMPLE(obj);
 733
 734    ics->offset = XICS_IRQ_BASE;
 735}
 736
 737static void ics_simple_realize(DeviceState *dev, Error **errp)
 738{
 739    ICSState *ics = ICS_SIMPLE(dev);
 740
 741    if (!ics->nr_irqs) {
 742        error_setg(errp, "Number of interrupts needs to be greater 0");
 743        return;
 744    }
 745    ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
 746    ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
 747}
 748
 749static void ics_simple_class_init(ObjectClass *klass, void *data)
 750{
 751    DeviceClass *dc = DEVICE_CLASS(klass);
 752    ICSStateClass *isc = ICS_BASE_CLASS(klass);
 753
 754    dc->realize = ics_simple_realize;
 755    dc->vmsd = &vmstate_ics_simple;
 756    dc->reset = ics_simple_reset;
 757    isc->post_load = ics_simple_post_load;
 758    isc->reject = ics_simple_reject;
 759    isc->resend = ics_simple_resend;
 760    isc->eoi = ics_simple_eoi;
 761}
 762
 763static const TypeInfo ics_simple_info = {
 764    .name = TYPE_ICS_SIMPLE,
 765    .parent = TYPE_ICS_BASE,
 766    .instance_size = sizeof(ICSState),
 767    .class_init = ics_simple_class_init,
 768    .class_size = sizeof(ICSStateClass),
 769    .instance_init = ics_simple_initfn,
 770};
 771
 772static const TypeInfo ics_base_info = {
 773    .name = TYPE_ICS_BASE,
 774    .parent = TYPE_DEVICE,
 775    .abstract = true,
 776    .instance_size = sizeof(ICSState),
 777    .class_size = sizeof(ICSStateClass),
 778};
 779
 780/*
 781 * Exported functions
 782 */
 783ICSState *xics_find_source(XICSState *xics, int irq)
 784{
 785    ICSState *ics;
 786
 787    QLIST_FOREACH(ics, &xics->ics, list) {
 788        if (ics_valid_irq(ics, irq)) {
 789            return ics;
 790        }
 791    }
 792    return NULL;
 793}
 794
 795qemu_irq xics_get_qirq(XICSState *xics, int irq)
 796{
 797    ICSState *ics = xics_find_source(xics, irq);
 798
 799    if (ics) {
 800        return ics->qirqs[irq - ics->offset];
 801    }
 802
 803    return NULL;
 804}
 805
 806void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
 807{
 808    assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK));
 809
 810    ics->irqs[srcno].flags |=
 811        lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
 812}
 813
 814static void xics_register_types(void)
 815{
 816    type_register_static(&xics_common_info);
 817    type_register_static(&ics_simple_info);
 818    type_register_static(&ics_base_info);
 819    type_register_static(&icp_info);
 820}
 821
 822type_init(xics_register_types)
 823