qemu/hw/intc/s390_flic_kvm.c
<<
>>
Prefs
   1/*
   2 * QEMU S390x KVM floating interrupt controller (flic)
   3 *
   4 * Copyright 2014 IBM Corp.
   5 * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
   6 *            Cornelia Huck <cornelia.huck@de.ibm.com>
   7 *
   8 * This work is licensed under the terms of the GNU GPL, version 2 or (at
   9 * your option) any later version. See the COPYING file in the top-level
  10 * directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "cpu.h"
  15#include "kvm_s390x.h"
  16#include <sys/ioctl.h>
  17#include "qemu/error-report.h"
  18#include "qemu/module.h"
  19#include "qapi/error.h"
  20#include "hw/sysbus.h"
  21#include "sysemu/kvm.h"
  22#include "hw/s390x/s390_flic.h"
  23#include "hw/s390x/adapter.h"
  24#include "hw/s390x/css.h"
  25#include "trace.h"
  26
  27#define FLIC_SAVE_INITIAL_SIZE getpagesize()
  28#define FLIC_FAILED (-1UL)
  29#define FLIC_SAVEVM_VERSION 1
  30
  31typedef struct KVMS390FLICState {
  32    S390FLICState parent_obj;
  33
  34    uint32_t fd;
  35    bool clear_io_supported;
  36} KVMS390FLICState;
  37
  38static KVMS390FLICState *s390_get_kvm_flic(S390FLICState *fs)
  39{
  40    static KVMS390FLICState *flic;
  41
  42    if (!flic) {
  43        /* we only have one flic device, so this is fine to cache */
  44        flic = KVM_S390_FLIC(fs);
  45    }
  46    return flic;
  47}
  48
  49/**
  50 * flic_get_all_irqs - store all pending irqs in buffer
  51 * @buf: pointer to buffer which is passed to kernel
  52 * @len: length of buffer
  53 * @flic: pointer to flic device state
  54 *
  55 * Returns: -ENOMEM if buffer is too small,
  56 * -EINVAL if attr.group is invalid,
  57 * -EFAULT if copying to userspace failed,
  58 * on success return number of stored interrupts
  59 */
  60static int flic_get_all_irqs(KVMS390FLICState *flic,
  61                             void *buf, int len)
  62{
  63    struct kvm_device_attr attr = {
  64        .group = KVM_DEV_FLIC_GET_ALL_IRQS,
  65        .addr = (uint64_t) buf,
  66        .attr = len,
  67    };
  68    int rc;
  69
  70    rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
  71
  72    return rc == -1 ? -errno : rc;
  73}
  74
  75static void flic_enable_pfault(KVMS390FLICState *flic)
  76{
  77    struct kvm_device_attr attr = {
  78        .group = KVM_DEV_FLIC_APF_ENABLE,
  79    };
  80    int rc;
  81
  82    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
  83
  84    if (rc) {
  85        fprintf(stderr, "flic: couldn't enable pfault\n");
  86    }
  87}
  88
  89static void flic_disable_wait_pfault(KVMS390FLICState *flic)
  90{
  91    struct kvm_device_attr attr = {
  92        .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
  93    };
  94    int rc;
  95
  96    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
  97
  98    if (rc) {
  99        fprintf(stderr, "flic: couldn't disable pfault\n");
 100    }
 101}
 102
 103/** flic_enqueue_irqs - returns 0 on success
 104 * @buf: pointer to buffer which is passed to kernel
 105 * @len: length of buffer
 106 * @flic: pointer to flic device state
 107 *
 108 * Returns: -EINVAL if attr.group is unknown
 109 */
 110static int flic_enqueue_irqs(void *buf, uint64_t len,
 111                            KVMS390FLICState *flic)
 112{
 113    int rc;
 114    struct kvm_device_attr attr = {
 115        .group = KVM_DEV_FLIC_ENQUEUE,
 116        .addr = (uint64_t) buf,
 117        .attr = len,
 118    };
 119
 120    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 121
 122    return rc ? -errno : 0;
 123}
 124
 125static void kvm_s390_inject_flic(S390FLICState *fs, struct kvm_s390_irq *irq)
 126{
 127    static bool use_flic = true;
 128    int r;
 129
 130    if (use_flic) {
 131        r = flic_enqueue_irqs(irq, sizeof(*irq), s390_get_kvm_flic(fs));
 132        if (r == -ENOSYS) {
 133            use_flic = false;
 134        }
 135        if (!r) {
 136            return;
 137        }
 138    }
 139    /* fallback to legacy KVM IOCTL in case FLIC fails */
 140    kvm_s390_floating_interrupt_legacy(irq);
 141}
 142
 143static void kvm_s390_inject_service(S390FLICState *fs, uint32_t parm)
 144{
 145        struct kvm_s390_irq irq = {
 146        .type = KVM_S390_INT_SERVICE,
 147        .u.ext.ext_params = parm,
 148    };
 149
 150    kvm_s390_inject_flic(fs, &irq);
 151}
 152
 153static void kvm_s390_inject_io(S390FLICState *fs, uint16_t subchannel_id,
 154                               uint16_t subchannel_nr, uint32_t io_int_parm,
 155                               uint32_t io_int_word)
 156{
 157    struct kvm_s390_irq irq = {
 158        .u.io.subchannel_id = subchannel_id,
 159        .u.io.subchannel_nr = subchannel_nr,
 160        .u.io.io_int_parm = io_int_parm,
 161        .u.io.io_int_word = io_int_word,
 162    };
 163
 164    if (io_int_word & IO_INT_WORD_AI) {
 165        irq.type = KVM_S390_INT_IO(1, 0, 0, 0);
 166    } else {
 167        irq.type = KVM_S390_INT_IO(0, (subchannel_id & 0xff00) >> 8,
 168                                      (subchannel_id & 0x0006),
 169                                      subchannel_nr);
 170    }
 171    kvm_s390_inject_flic(fs, &irq);
 172}
 173
 174static void kvm_s390_inject_crw_mchk(S390FLICState *fs)
 175{
 176    struct kvm_s390_irq irq = {
 177        .type = KVM_S390_MCHK,
 178        .u.mchk.cr14 = CR14_CHANNEL_REPORT_SC,
 179        .u.mchk.mcic = s390_build_validity_mcic() | MCIC_SC_CP,
 180    };
 181
 182    kvm_s390_inject_flic(fs, &irq);
 183}
 184
 185static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
 186                           uint16_t subchannel_nr)
 187{
 188    KVMS390FLICState *flic = s390_get_kvm_flic(fs);
 189    int rc;
 190    uint32_t sid = subchannel_id << 16 | subchannel_nr;
 191    struct kvm_device_attr attr = {
 192        .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
 193        .addr = (uint64_t) &sid,
 194        .attr = sizeof(sid),
 195    };
 196    if (unlikely(!flic->clear_io_supported)) {
 197        return -ENOSYS;
 198    }
 199    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 200    return rc ? -errno : 0;
 201}
 202
 203static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
 204                                    uint16_t mode)
 205{
 206    KVMS390FLICState *flic = s390_get_kvm_flic(fs);
 207    struct kvm_s390_ais_req req = {
 208        .isc = isc,
 209        .mode = mode,
 210    };
 211    struct kvm_device_attr attr = {
 212        .group = KVM_DEV_FLIC_AISM,
 213        .addr = (uint64_t)&req,
 214    };
 215
 216    if (!fs->ais_supported) {
 217        return -ENOSYS;
 218    }
 219
 220    return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
 221}
 222
 223static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type,
 224                                uint8_t isc, uint8_t flags)
 225{
 226    KVMS390FLICState *flic = s390_get_kvm_flic(fs);
 227    uint32_t id = css_get_adapter_id(type, isc);
 228    struct kvm_device_attr attr = {
 229        .group = KVM_DEV_FLIC_AIRQ_INJECT,
 230        .attr = id,
 231    };
 232
 233    if (!fs->ais_supported) {
 234        return -ENOSYS;
 235    }
 236
 237    return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
 238}
 239
 240/**
 241 * __get_all_irqs - store all pending irqs in buffer
 242 * @flic: pointer to flic device state
 243 * @buf: pointer to pointer to a buffer
 244 * @len: length of buffer
 245 *
 246 * Returns: return value of flic_get_all_irqs
 247 * Note: Retry and increase buffer size until flic_get_all_irqs
 248 * either returns a value >= 0 or a negative error code.
 249 * -ENOMEM is an exception, which means the buffer is too small
 250 * and we should try again. Other negative error codes can be
 251 * -EFAULT and -EINVAL which we ignore at this point
 252 */
 253static int __get_all_irqs(KVMS390FLICState *flic,
 254                          void **buf, int len)
 255{
 256    int r;
 257
 258    do {
 259        /* returns -ENOMEM if buffer is too small and number
 260         * of queued interrupts on success */
 261        r = flic_get_all_irqs(flic, *buf, len);
 262        if (r >= 0) {
 263            break;
 264        }
 265        len *= 2;
 266        *buf = g_try_realloc(*buf, len);
 267        if (!buf) {
 268            return -ENOMEM;
 269        }
 270    } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
 271
 272    return r;
 273}
 274
 275static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
 276                                        uint8_t isc, bool swap,
 277                                        bool is_maskable, uint8_t flags)
 278{
 279    struct kvm_s390_io_adapter adapter = {
 280        .id = id,
 281        .isc = isc,
 282        .maskable = is_maskable,
 283        .swap = swap,
 284        .flags = flags,
 285    };
 286    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
 287    int r;
 288    struct kvm_device_attr attr = {
 289        .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
 290        .addr = (uint64_t)&adapter,
 291    };
 292
 293    if (!kvm_gsi_routing_enabled()) {
 294        /* nothing to do */
 295        return 0;
 296    }
 297
 298    r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 299
 300    return r ? -errno : 0;
 301}
 302
 303static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
 304                                   uint64_t map_addr, bool do_map)
 305{
 306    struct kvm_s390_io_adapter_req req = {
 307        .id = id,
 308        .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
 309        .addr = map_addr,
 310    };
 311    struct kvm_device_attr attr = {
 312        .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
 313        .addr = (uint64_t)&req,
 314    };
 315    KVMS390FLICState *flic = s390_get_kvm_flic(fs);
 316    int r;
 317
 318    if (!kvm_gsi_routing_enabled()) {
 319        /* nothing to do */
 320        return 0;
 321    }
 322
 323    r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 324    return r ? -errno : 0;
 325}
 326
 327static int kvm_s390_add_adapter_routes(S390FLICState *fs,
 328                                       AdapterRoutes *routes)
 329{
 330    int ret, i;
 331    uint64_t ind_offset = routes->adapter.ind_offset;
 332
 333    for (i = 0; i < routes->num_routes; i++) {
 334        ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
 335        if (ret < 0) {
 336            goto out_undo;
 337        }
 338        routes->gsi[i] = ret;
 339        routes->adapter.ind_offset++;
 340    }
 341    kvm_irqchip_commit_routes(kvm_state);
 342
 343    /* Restore passed-in structure to original state. */
 344    routes->adapter.ind_offset = ind_offset;
 345    return 0;
 346out_undo:
 347    while (--i >= 0) {
 348        kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
 349        routes->gsi[i] = -1;
 350    }
 351    routes->adapter.ind_offset = ind_offset;
 352    return ret;
 353}
 354
 355static void kvm_s390_release_adapter_routes(S390FLICState *fs,
 356                                            AdapterRoutes *routes)
 357{
 358    int i;
 359
 360    for (i = 0; i < routes->num_routes; i++) {
 361        if (routes->gsi[i] >= 0) {
 362            kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
 363            routes->gsi[i] = -1;
 364        }
 365    }
 366}
 367
 368/**
 369 * kvm_flic_save - Save pending floating interrupts
 370 * @f: QEMUFile containing migration state
 371 * @opaque: pointer to flic device state
 372 * @size: ignored
 373 *
 374 * Note: Pass buf and len to kernel. Start with one page and
 375 * increase until buffer is sufficient or maxium size is
 376 * reached
 377 */
 378static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
 379                         const VMStateField *field, QJSON *vmdesc)
 380{
 381    KVMS390FLICState *flic = opaque;
 382    int len = FLIC_SAVE_INITIAL_SIZE;
 383    void *buf;
 384    int count;
 385    int r = 0;
 386
 387    flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
 388
 389    buf = g_try_malloc0(len);
 390    if (!buf) {
 391        /* Storing FLIC_FAILED into the count field here will cause the
 392         * target system to fail when attempting to load irqs from the
 393         * migration state */
 394        error_report("flic: couldn't allocate memory");
 395        qemu_put_be64(f, FLIC_FAILED);
 396        return -ENOMEM;
 397    }
 398
 399    count = __get_all_irqs(flic, &buf, len);
 400    if (count < 0) {
 401        error_report("flic: couldn't retrieve irqs from kernel, rc %d",
 402                     count);
 403        /* Storing FLIC_FAILED into the count field here will cause the
 404         * target system to fail when attempting to load irqs from the
 405         * migration state */
 406        qemu_put_be64(f, FLIC_FAILED);
 407        r = count;
 408    } else {
 409        qemu_put_be64(f, count);
 410        qemu_put_buffer(f, (uint8_t *) buf,
 411                        count * sizeof(struct kvm_s390_irq));
 412    }
 413    g_free(buf);
 414
 415    return r;
 416}
 417
 418/**
 419 * kvm_flic_load - Load pending floating interrupts
 420 * @f: QEMUFile containing migration state
 421 * @opaque: pointer to flic device state
 422 * @size: ignored
 423 *
 424 * Returns: value of flic_enqueue_irqs, -EINVAL on error
 425 * Note: Do nothing when no interrupts where stored
 426 * in QEMUFile
 427 */
 428static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size,
 429                         const VMStateField *field)
 430{
 431    uint64_t len = 0;
 432    uint64_t count = 0;
 433    void *buf = NULL;
 434    int r = 0;
 435
 436    flic_enable_pfault((struct KVMS390FLICState *) opaque);
 437
 438    count = qemu_get_be64(f);
 439    len = count * sizeof(struct kvm_s390_irq);
 440    if (count == FLIC_FAILED) {
 441        r = -EINVAL;
 442        goto out;
 443    }
 444    if (count == 0) {
 445        r = 0;
 446        goto out;
 447    }
 448    buf = g_try_malloc0(len);
 449    if (!buf) {
 450        r = -ENOMEM;
 451        goto out;
 452    }
 453
 454    if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
 455        r = -EINVAL;
 456        goto out_free;
 457    }
 458    r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
 459
 460out_free:
 461    g_free(buf);
 462out:
 463    return r;
 464}
 465
 466typedef struct KVMS390FLICStateMigTmp {
 467    KVMS390FLICState *parent;
 468    uint8_t simm;
 469    uint8_t nimm;
 470} KVMS390FLICStateMigTmp;
 471
 472static int kvm_flic_ais_pre_save(void *opaque)
 473{
 474    KVMS390FLICStateMigTmp *tmp = opaque;
 475    KVMS390FLICState *flic = tmp->parent;
 476    struct kvm_s390_ais_all ais;
 477    struct kvm_device_attr attr = {
 478        .group = KVM_DEV_FLIC_AISM_ALL,
 479        .addr = (uint64_t)&ais,
 480        .attr = sizeof(ais),
 481    };
 482
 483    if (ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr)) {
 484        error_report("Failed to retrieve kvm flic ais states");
 485        return -EINVAL;
 486    }
 487
 488    tmp->simm = ais.simm;
 489    tmp->nimm = ais.nimm;
 490
 491    return 0;
 492}
 493
 494static int kvm_flic_ais_post_load(void *opaque, int version_id)
 495{
 496    KVMS390FLICStateMigTmp *tmp = opaque;
 497    KVMS390FLICState *flic = tmp->parent;
 498    struct kvm_s390_ais_all ais = {
 499        .simm = tmp->simm,
 500        .nimm = tmp->nimm,
 501    };
 502    struct kvm_device_attr attr = {
 503        .group = KVM_DEV_FLIC_AISM_ALL,
 504        .addr = (uint64_t)&ais,
 505    };
 506
 507    /* This can happen when the user mis-configures its guests in an
 508     * incompatible fashion or without a CPU model. For example using
 509     * qemu with -cpu host (which is not migration safe) and do a
 510     * migration from a host that has AIS to a host that has no AIS.
 511     * In that case the target system will reject the migration here.
 512     */
 513    if (!ais_needed(flic)) {
 514        return -ENOSYS;
 515    }
 516
 517    return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
 518}
 519
 520static const VMStateDescription kvm_s390_flic_ais_tmp = {
 521    .name = "s390-flic-ais-tmp",
 522    .pre_save = kvm_flic_ais_pre_save,
 523    .post_load = kvm_flic_ais_post_load,
 524    .fields = (VMStateField[]) {
 525        VMSTATE_UINT8(simm, KVMS390FLICStateMigTmp),
 526        VMSTATE_UINT8(nimm, KVMS390FLICStateMigTmp),
 527        VMSTATE_END_OF_LIST()
 528    }
 529};
 530
 531static const VMStateDescription kvm_s390_flic_vmstate_ais = {
 532    .name = "s390-flic/ais",
 533    .version_id = 1,
 534    .minimum_version_id = 1,
 535    .needed = ais_needed,
 536    .fields = (VMStateField[]) {
 537        VMSTATE_WITH_TMP(KVMS390FLICState, KVMS390FLICStateMigTmp,
 538                         kvm_s390_flic_ais_tmp),
 539        VMSTATE_END_OF_LIST()
 540    }
 541};
 542
 543static const VMStateDescription kvm_s390_flic_vmstate = {
 544    /* should have been like kvm-s390-flic,
 545     * can't change without breaking compat */
 546    .name = "s390-flic",
 547    .version_id = FLIC_SAVEVM_VERSION,
 548    .minimum_version_id = FLIC_SAVEVM_VERSION,
 549    .fields = (VMStateField[]) {
 550        {
 551            .name = "irqs",
 552            .info = &(const VMStateInfo) {
 553                .name = "irqs",
 554                .get = kvm_flic_load,
 555                .put = kvm_flic_save,
 556            },
 557            .flags = VMS_SINGLE,
 558        },
 559        VMSTATE_END_OF_LIST()
 560    },
 561    .subsections = (const VMStateDescription * []) {
 562        &kvm_s390_flic_vmstate_ais,
 563        NULL
 564    }
 565};
 566
 567typedef struct KVMS390FLICStateClass {
 568    S390FLICStateClass parent_class;
 569    DeviceRealize parent_realize;
 570} KVMS390FLICStateClass;
 571
 572#define KVM_S390_FLIC_GET_CLASS(obj) \
 573    OBJECT_GET_CLASS(KVMS390FLICStateClass, (obj), TYPE_KVM_S390_FLIC)
 574
 575#define KVM_S390_FLIC_CLASS(klass) \
 576    OBJECT_CLASS_CHECK(KVMS390FLICStateClass, (klass), TYPE_KVM_S390_FLIC)
 577
 578static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
 579{
 580    KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
 581    struct kvm_create_device cd = {0};
 582    struct kvm_device_attr test_attr = {0};
 583    int ret;
 584    Error *errp_local = NULL;
 585
 586    KVM_S390_FLIC_GET_CLASS(dev)->parent_realize(dev, &errp_local);
 587    if (errp_local) {
 588        goto fail;
 589    }
 590    flic_state->fd = -1;
 591    if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
 592        error_setg_errno(&errp_local, errno, "KVM is missing capability"
 593                         " KVM_CAP_DEVICE_CTRL");
 594        trace_flic_no_device_api(errno);
 595        goto fail;
 596    }
 597
 598    cd.type = KVM_DEV_TYPE_FLIC;
 599    ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
 600    if (ret < 0) {
 601        error_setg_errno(&errp_local, errno, "Creating the KVM device failed");
 602        trace_flic_create_device(errno);
 603        goto fail;
 604    }
 605    flic_state->fd = cd.fd;
 606
 607    /* Check clear_io_irq support */
 608    test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
 609    flic_state->clear_io_supported = !ioctl(flic_state->fd,
 610                                            KVM_HAS_DEVICE_ATTR, test_attr);
 611    return;
 612fail:
 613    error_propagate(errp, errp_local);
 614}
 615
 616static void kvm_s390_flic_reset(DeviceState *dev)
 617{
 618    KVMS390FLICState *flic = KVM_S390_FLIC(dev);
 619    S390FLICState *fs = S390_FLIC_COMMON(dev);
 620    struct kvm_device_attr attr = {
 621        .group = KVM_DEV_FLIC_CLEAR_IRQS,
 622    };
 623    int rc = 0;
 624    uint8_t isc;
 625
 626    if (flic->fd == -1) {
 627        return;
 628    }
 629
 630    flic_disable_wait_pfault(flic);
 631
 632    if (fs->ais_supported) {
 633        for (isc = 0; isc <= MAX_ISC; isc++) {
 634            rc = kvm_s390_modify_ais_mode(fs, isc, SIC_IRQ_MODE_ALL);
 635            if (rc) {
 636                error_report("Failed to reset ais mode for isc %d: %s",
 637                             isc, strerror(-rc));
 638            }
 639        }
 640    }
 641
 642    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 643    if (rc) {
 644        trace_flic_reset_failed(errno);
 645    }
 646
 647    flic_enable_pfault(flic);
 648}
 649
 650static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
 651{
 652    DeviceClass *dc = DEVICE_CLASS(oc);
 653    S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
 654
 655    KVM_S390_FLIC_CLASS(oc)->parent_realize = dc->realize;
 656    dc->realize = kvm_s390_flic_realize;
 657    dc->vmsd = &kvm_s390_flic_vmstate;
 658    dc->reset = kvm_s390_flic_reset;
 659    fsc->register_io_adapter = kvm_s390_register_io_adapter;
 660    fsc->io_adapter_map = kvm_s390_io_adapter_map;
 661    fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
 662    fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
 663    fsc->clear_io_irq = kvm_s390_clear_io_flic;
 664    fsc->modify_ais_mode = kvm_s390_modify_ais_mode;
 665    fsc->inject_airq = kvm_s390_inject_airq;
 666    fsc->inject_service = kvm_s390_inject_service;
 667    fsc->inject_io = kvm_s390_inject_io;
 668    fsc->inject_crw_mchk = kvm_s390_inject_crw_mchk;
 669}
 670
 671static const TypeInfo kvm_s390_flic_info = {
 672    .name          = TYPE_KVM_S390_FLIC,
 673    .parent        = TYPE_S390_FLIC_COMMON,
 674    .instance_size = sizeof(KVMS390FLICState),
 675    .class_size    = sizeof(KVMS390FLICStateClass),
 676    .class_init    = kvm_s390_flic_class_init,
 677};
 678
 679static void kvm_s390_flic_register_types(void)
 680{
 681    type_register_static(&kvm_s390_flic_info);
 682}
 683
 684type_init(kvm_s390_flic_register_types)
 685