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