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
  39int xics_get_cpu_index_by_dt_id(int cpu_dt_id)
  40{
  41    PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
  42
  43    if (cpu) {
  44        return cpu->parent_obj.cpu_index;
  45    }
  46
  47    return -1;
  48}
  49
  50void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu)
  51{
  52    CPUState *cs = CPU(cpu);
  53    ICPState *ss = &xics->ss[cs->cpu_index];
  54
  55    assert(cs->cpu_index < xics->nr_servers);
  56    assert(cs == ss->cs);
  57
  58    ss->output = NULL;
  59    ss->cs = NULL;
  60}
  61
  62void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
  63{
  64    CPUState *cs = CPU(cpu);
  65    CPUPPCState *env = &cpu->env;
  66    ICPState *ss = &xics->ss[cs->cpu_index];
  67    XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
  68
  69    assert(cs->cpu_index < xics->nr_servers);
  70
  71    ss->cs = cs;
  72
  73    if (info->cpu_setup) {
  74        info->cpu_setup(xics, cpu);
  75    }
  76
  77    switch (PPC_INPUT(env)) {
  78    case PPC_FLAGS_INPUT_POWER7:
  79        ss->output = env->irq_inputs[POWER7_INPUT_INT];
  80        break;
  81
  82    case PPC_FLAGS_INPUT_970:
  83        ss->output = env->irq_inputs[PPC970_INPUT_INT];
  84        break;
  85
  86    default:
  87        error_report("XICS interrupt controller does not support this CPU "
  88                     "bus model");
  89        abort();
  90    }
  91}
  92
  93/*
  94 * XICS Common class - parent for emulated XICS and KVM-XICS
  95 */
  96static void xics_common_reset(DeviceState *d)
  97{
  98    XICSState *xics = XICS_COMMON(d);
  99    int i;
 100
 101    for (i = 0; i < xics->nr_servers; i++) {
 102        device_reset(DEVICE(&xics->ss[i]));
 103    }
 104
 105    device_reset(DEVICE(xics->ics));
 106}
 107
 108static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name,
 109                                  void *opaque, Error **errp)
 110{
 111    XICSState *xics = XICS_COMMON(obj);
 112    int64_t value = xics->nr_irqs;
 113
 114    visit_type_int(v, name, &value, errp);
 115}
 116
 117static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name,
 118                                  void *opaque, Error **errp)
 119{
 120    XICSState *xics = XICS_COMMON(obj);
 121    XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
 122    Error *error = NULL;
 123    int64_t value;
 124
 125    visit_type_int(v, name, &value, &error);
 126    if (error) {
 127        error_propagate(errp, error);
 128        return;
 129    }
 130    if (xics->nr_irqs) {
 131        error_setg(errp, "Number of interrupts is already set to %u",
 132                   xics->nr_irqs);
 133        return;
 134    }
 135
 136    assert(info->set_nr_irqs);
 137    assert(xics->ics);
 138    info->set_nr_irqs(xics, value, errp);
 139}
 140
 141static void xics_prop_get_nr_servers(Object *obj, Visitor *v,
 142                                     const char *name, void *opaque,
 143                                     Error **errp)
 144{
 145    XICSState *xics = XICS_COMMON(obj);
 146    int64_t value = xics->nr_servers;
 147
 148    visit_type_int(v, name, &value, errp);
 149}
 150
 151static void xics_prop_set_nr_servers(Object *obj, Visitor *v,
 152                                     const char *name, void *opaque,
 153                                     Error **errp)
 154{
 155    XICSState *xics = XICS_COMMON(obj);
 156    XICSStateClass *info = XICS_COMMON_GET_CLASS(xics);
 157    Error *error = NULL;
 158    int64_t value;
 159
 160    visit_type_int(v, name, &value, &error);
 161    if (error) {
 162        error_propagate(errp, error);
 163        return;
 164    }
 165    if (xics->nr_servers) {
 166        error_setg(errp, "Number of servers is already set to %u",
 167                   xics->nr_servers);
 168        return;
 169    }
 170
 171    assert(info->set_nr_servers);
 172    info->set_nr_servers(xics, value, errp);
 173}
 174
 175static void xics_common_initfn(Object *obj)
 176{
 177    object_property_add(obj, "nr_irqs", "int",
 178                        xics_prop_get_nr_irqs, xics_prop_set_nr_irqs,
 179                        NULL, NULL, NULL);
 180    object_property_add(obj, "nr_servers", "int",
 181                        xics_prop_get_nr_servers, xics_prop_set_nr_servers,
 182                        NULL, NULL, NULL);
 183}
 184
 185static void xics_common_class_init(ObjectClass *oc, void *data)
 186{
 187    DeviceClass *dc = DEVICE_CLASS(oc);
 188
 189    dc->reset = xics_common_reset;
 190}
 191
 192static const TypeInfo xics_common_info = {
 193    .name          = TYPE_XICS_COMMON,
 194    .parent        = TYPE_SYS_BUS_DEVICE,
 195    .instance_size = sizeof(XICSState),
 196    .class_size    = sizeof(XICSStateClass),
 197    .instance_init = xics_common_initfn,
 198    .class_init    = xics_common_class_init,
 199};
 200
 201/*
 202 * ICP: Presentation layer
 203 */
 204
 205#define XISR_MASK  0x00ffffff
 206#define CPPR_MASK  0xff000000
 207
 208#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
 209#define CPPR(ss)   (((ss)->xirr) >> 24)
 210
 211static void ics_reject(ICSState *ics, int nr);
 212static void ics_resend(ICSState *ics);
 213static void ics_eoi(ICSState *ics, int nr);
 214
 215static void icp_check_ipi(XICSState *xics, int server)
 216{
 217    ICPState *ss = xics->ss + server;
 218
 219    if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
 220        return;
 221    }
 222
 223    trace_xics_icp_check_ipi(server, ss->mfrr);
 224
 225    if (XISR(ss)) {
 226        ics_reject(xics->ics, XISR(ss));
 227    }
 228
 229    ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
 230    ss->pending_priority = ss->mfrr;
 231    qemu_irq_raise(ss->output);
 232}
 233
 234static void icp_resend(XICSState *xics, int server)
 235{
 236    ICPState *ss = xics->ss + server;
 237
 238    if (ss->mfrr < CPPR(ss)) {
 239        icp_check_ipi(xics, server);
 240    }
 241    ics_resend(xics->ics);
 242}
 243
 244void icp_set_cppr(XICSState *xics, int server, uint8_t cppr)
 245{
 246    ICPState *ss = xics->ss + server;
 247    uint8_t old_cppr;
 248    uint32_t old_xisr;
 249
 250    old_cppr = CPPR(ss);
 251    ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
 252
 253    if (cppr < old_cppr) {
 254        if (XISR(ss) && (cppr <= ss->pending_priority)) {
 255            old_xisr = XISR(ss);
 256            ss->xirr &= ~XISR_MASK; /* Clear XISR */
 257            ss->pending_priority = 0xff;
 258            qemu_irq_lower(ss->output);
 259            ics_reject(xics->ics, old_xisr);
 260        }
 261    } else {
 262        if (!XISR(ss)) {
 263            icp_resend(xics, server);
 264        }
 265    }
 266}
 267
 268void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr)
 269{
 270    ICPState *ss = xics->ss + server;
 271
 272    ss->mfrr = mfrr;
 273    if (mfrr < CPPR(ss)) {
 274        icp_check_ipi(xics, server);
 275    }
 276}
 277
 278uint32_t icp_accept(ICPState *ss)
 279{
 280    uint32_t xirr = ss->xirr;
 281
 282    qemu_irq_lower(ss->output);
 283    ss->xirr = ss->pending_priority << 24;
 284    ss->pending_priority = 0xff;
 285
 286    trace_xics_icp_accept(xirr, ss->xirr);
 287
 288    return xirr;
 289}
 290
 291uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)
 292{
 293    if (mfrr) {
 294        *mfrr = ss->mfrr;
 295    }
 296    return ss->xirr;
 297}
 298
 299void icp_eoi(XICSState *xics, int server, uint32_t xirr)
 300{
 301    ICPState *ss = xics->ss + server;
 302
 303    /* Send EOI -> ICS */
 304    ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
 305    trace_xics_icp_eoi(server, xirr, ss->xirr);
 306    ics_eoi(xics->ics, xirr & XISR_MASK);
 307    if (!XISR(ss)) {
 308        icp_resend(xics, server);
 309    }
 310}
 311
 312static void icp_irq(XICSState *xics, int server, int nr, uint8_t priority)
 313{
 314    ICPState *ss = xics->ss + server;
 315
 316    trace_xics_icp_irq(server, nr, priority);
 317
 318    if ((priority >= CPPR(ss))
 319        || (XISR(ss) && (ss->pending_priority <= priority))) {
 320        ics_reject(xics->ics, nr);
 321    } else {
 322        if (XISR(ss)) {
 323            ics_reject(xics->ics, XISR(ss));
 324        }
 325        ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
 326        ss->pending_priority = priority;
 327        trace_xics_icp_raise(ss->xirr, ss->pending_priority);
 328        qemu_irq_raise(ss->output);
 329    }
 330}
 331
 332static void icp_dispatch_pre_save(void *opaque)
 333{
 334    ICPState *ss = opaque;
 335    ICPStateClass *info = ICP_GET_CLASS(ss);
 336
 337    if (info->pre_save) {
 338        info->pre_save(ss);
 339    }
 340}
 341
 342static int icp_dispatch_post_load(void *opaque, int version_id)
 343{
 344    ICPState *ss = opaque;
 345    ICPStateClass *info = ICP_GET_CLASS(ss);
 346
 347    if (info->post_load) {
 348        return info->post_load(ss, version_id);
 349    }
 350
 351    return 0;
 352}
 353
 354static const VMStateDescription vmstate_icp_server = {
 355    .name = "icp/server",
 356    .version_id = 1,
 357    .minimum_version_id = 1,
 358    .pre_save = icp_dispatch_pre_save,
 359    .post_load = icp_dispatch_post_load,
 360    .fields = (VMStateField[]) {
 361        /* Sanity check */
 362        VMSTATE_UINT32(xirr, ICPState),
 363        VMSTATE_UINT8(pending_priority, ICPState),
 364        VMSTATE_UINT8(mfrr, ICPState),
 365        VMSTATE_END_OF_LIST()
 366    },
 367};
 368
 369static void icp_reset(DeviceState *dev)
 370{
 371    ICPState *icp = ICP(dev);
 372
 373    icp->xirr = 0;
 374    icp->pending_priority = 0xff;
 375    icp->mfrr = 0xff;
 376
 377    /* Make all outputs are deasserted */
 378    qemu_set_irq(icp->output, 0);
 379}
 380
 381static void icp_class_init(ObjectClass *klass, void *data)
 382{
 383    DeviceClass *dc = DEVICE_CLASS(klass);
 384
 385    dc->reset = icp_reset;
 386    dc->vmsd = &vmstate_icp_server;
 387}
 388
 389static const TypeInfo icp_info = {
 390    .name = TYPE_ICP,
 391    .parent = TYPE_DEVICE,
 392    .instance_size = sizeof(ICPState),
 393    .class_init = icp_class_init,
 394    .class_size = sizeof(ICPStateClass),
 395};
 396
 397/*
 398 * ICS: Source layer
 399 */
 400static void resend_msi(ICSState *ics, int srcno)
 401{
 402    ICSIRQState *irq = ics->irqs + srcno;
 403
 404    /* FIXME: filter by server#? */
 405    if (irq->status & XICS_STATUS_REJECTED) {
 406        irq->status &= ~XICS_STATUS_REJECTED;
 407        if (irq->priority != 0xff) {
 408            icp_irq(ics->xics, irq->server, srcno + ics->offset,
 409                    irq->priority);
 410        }
 411    }
 412}
 413
 414static void resend_lsi(ICSState *ics, int srcno)
 415{
 416    ICSIRQState *irq = ics->irqs + srcno;
 417
 418    if ((irq->priority != 0xff)
 419        && (irq->status & XICS_STATUS_ASSERTED)
 420        && !(irq->status & XICS_STATUS_SENT)) {
 421        irq->status |= XICS_STATUS_SENT;
 422        icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority);
 423    }
 424}
 425
 426static void set_irq_msi(ICSState *ics, int srcno, int val)
 427{
 428    ICSIRQState *irq = ics->irqs + srcno;
 429
 430    trace_xics_set_irq_msi(srcno, srcno + ics->offset);
 431
 432    if (val) {
 433        if (irq->priority == 0xff) {
 434            irq->status |= XICS_STATUS_MASKED_PENDING;
 435            trace_xics_masked_pending();
 436        } else  {
 437            icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority);
 438        }
 439    }
 440}
 441
 442static void set_irq_lsi(ICSState *ics, int srcno, int val)
 443{
 444    ICSIRQState *irq = ics->irqs + srcno;
 445
 446    trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
 447    if (val) {
 448        irq->status |= XICS_STATUS_ASSERTED;
 449    } else {
 450        irq->status &= ~XICS_STATUS_ASSERTED;
 451    }
 452    resend_lsi(ics, srcno);
 453}
 454
 455static void ics_set_irq(void *opaque, int srcno, int val)
 456{
 457    ICSState *ics = (ICSState *)opaque;
 458
 459    if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
 460        set_irq_lsi(ics, srcno, val);
 461    } else {
 462        set_irq_msi(ics, srcno, val);
 463    }
 464}
 465
 466static void write_xive_msi(ICSState *ics, int srcno)
 467{
 468    ICSIRQState *irq = ics->irqs + srcno;
 469
 470    if (!(irq->status & XICS_STATUS_MASKED_PENDING)
 471        || (irq->priority == 0xff)) {
 472        return;
 473    }
 474
 475    irq->status &= ~XICS_STATUS_MASKED_PENDING;
 476    icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority);
 477}
 478
 479static void write_xive_lsi(ICSState *ics, int srcno)
 480{
 481    resend_lsi(ics, srcno);
 482}
 483
 484void ics_write_xive(ICSState *ics, int nr, int server,
 485                    uint8_t priority, uint8_t saved_priority)
 486{
 487    int srcno = nr - ics->offset;
 488    ICSIRQState *irq = ics->irqs + srcno;
 489
 490    irq->server = server;
 491    irq->priority = priority;
 492    irq->saved_priority = saved_priority;
 493
 494    trace_xics_ics_write_xive(nr, srcno, server, priority);
 495
 496    if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
 497        write_xive_lsi(ics, srcno);
 498    } else {
 499        write_xive_msi(ics, srcno);
 500    }
 501}
 502
 503static void ics_reject(ICSState *ics, int nr)
 504{
 505    ICSIRQState *irq = ics->irqs + nr - ics->offset;
 506
 507    trace_xics_ics_reject(nr, nr - ics->offset);
 508    irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
 509    irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
 510}
 511
 512static void ics_resend(ICSState *ics)
 513{
 514    int i;
 515
 516    for (i = 0; i < ics->nr_irqs; i++) {
 517        /* FIXME: filter by server#? */
 518        if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
 519            resend_lsi(ics, i);
 520        } else {
 521            resend_msi(ics, i);
 522        }
 523    }
 524}
 525
 526static void ics_eoi(ICSState *ics, int nr)
 527{
 528    int srcno = nr - ics->offset;
 529    ICSIRQState *irq = ics->irqs + srcno;
 530
 531    trace_xics_ics_eoi(nr);
 532
 533    if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
 534        irq->status &= ~XICS_STATUS_SENT;
 535    }
 536}
 537
 538static void ics_reset(DeviceState *dev)
 539{
 540    ICSState *ics = ICS(dev);
 541    int i;
 542    uint8_t flags[ics->nr_irqs];
 543
 544    for (i = 0; i < ics->nr_irqs; i++) {
 545        flags[i] = ics->irqs[i].flags;
 546    }
 547
 548    memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
 549
 550    for (i = 0; i < ics->nr_irqs; i++) {
 551        ics->irqs[i].priority = 0xff;
 552        ics->irqs[i].saved_priority = 0xff;
 553        ics->irqs[i].flags = flags[i];
 554    }
 555}
 556
 557static int ics_post_load(ICSState *ics, int version_id)
 558{
 559    int i;
 560
 561    for (i = 0; i < ics->xics->nr_servers; i++) {
 562        icp_resend(ics->xics, i);
 563    }
 564
 565    return 0;
 566}
 567
 568static void ics_dispatch_pre_save(void *opaque)
 569{
 570    ICSState *ics = opaque;
 571    ICSStateClass *info = ICS_GET_CLASS(ics);
 572
 573    if (info->pre_save) {
 574        info->pre_save(ics);
 575    }
 576}
 577
 578static int ics_dispatch_post_load(void *opaque, int version_id)
 579{
 580    ICSState *ics = opaque;
 581    ICSStateClass *info = ICS_GET_CLASS(ics);
 582
 583    if (info->post_load) {
 584        return info->post_load(ics, version_id);
 585    }
 586
 587    return 0;
 588}
 589
 590static const VMStateDescription vmstate_ics_irq = {
 591    .name = "ics/irq",
 592    .version_id = 2,
 593    .minimum_version_id = 1,
 594    .fields = (VMStateField[]) {
 595        VMSTATE_UINT32(server, ICSIRQState),
 596        VMSTATE_UINT8(priority, ICSIRQState),
 597        VMSTATE_UINT8(saved_priority, ICSIRQState),
 598        VMSTATE_UINT8(status, ICSIRQState),
 599        VMSTATE_UINT8(flags, ICSIRQState),
 600        VMSTATE_END_OF_LIST()
 601    },
 602};
 603
 604static const VMStateDescription vmstate_ics = {
 605    .name = "ics",
 606    .version_id = 1,
 607    .minimum_version_id = 1,
 608    .pre_save = ics_dispatch_pre_save,
 609    .post_load = ics_dispatch_post_load,
 610    .fields = (VMStateField[]) {
 611        /* Sanity check */
 612        VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
 613
 614        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
 615                                             vmstate_ics_irq, ICSIRQState),
 616        VMSTATE_END_OF_LIST()
 617    },
 618};
 619
 620static void ics_initfn(Object *obj)
 621{
 622    ICSState *ics = ICS(obj);
 623
 624    ics->offset = XICS_IRQ_BASE;
 625}
 626
 627static void ics_realize(DeviceState *dev, Error **errp)
 628{
 629    ICSState *ics = ICS(dev);
 630
 631    if (!ics->nr_irqs) {
 632        error_setg(errp, "Number of interrupts needs to be greater 0");
 633        return;
 634    }
 635    ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
 636    ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
 637}
 638
 639static void ics_class_init(ObjectClass *klass, void *data)
 640{
 641    DeviceClass *dc = DEVICE_CLASS(klass);
 642    ICSStateClass *isc = ICS_CLASS(klass);
 643
 644    dc->realize = ics_realize;
 645    dc->vmsd = &vmstate_ics;
 646    dc->reset = ics_reset;
 647    isc->post_load = ics_post_load;
 648}
 649
 650static const TypeInfo ics_info = {
 651    .name = TYPE_ICS,
 652    .parent = TYPE_DEVICE,
 653    .instance_size = sizeof(ICSState),
 654    .class_init = ics_class_init,
 655    .class_size = sizeof(ICSStateClass),
 656    .instance_init = ics_initfn,
 657};
 658
 659/*
 660 * Exported functions
 661 */
 662int xics_find_source(XICSState *xics, int irq)
 663{
 664    int sources = 1;
 665    int src;
 666
 667    /* FIXME: implement multiple sources */
 668    for (src = 0; src < sources; ++src) {
 669        ICSState *ics = &xics->ics[src];
 670        if (ics_valid_irq(ics, irq)) {
 671            return src;
 672        }
 673    }
 674
 675    return -1;
 676}
 677
 678qemu_irq xics_get_qirq(XICSState *xics, int irq)
 679{
 680    int src = xics_find_source(xics, irq);
 681
 682    if (src >= 0) {
 683        ICSState *ics = &xics->ics[src];
 684        return ics->qirqs[irq - ics->offset];
 685    }
 686
 687    return NULL;
 688}
 689
 690void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
 691{
 692    assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK));
 693
 694    ics->irqs[srcno].flags |=
 695        lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
 696}
 697
 698static void xics_register_types(void)
 699{
 700    type_register_static(&xics_common_info);
 701    type_register_static(&ics_info);
 702    type_register_static(&icp_info);
 703}
 704
 705type_init(xics_register_types)
 706