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 "qemu-common.h"
  15#include "cpu.h"
  16#include <sys/ioctl.h>
  17#include "qemu/error-report.h"
  18#include "qapi/error.h"
  19#include "hw/sysbus.h"
  20#include "sysemu/kvm.h"
  21#include "hw/s390x/s390_flic.h"
  22#include "hw/s390x/adapter.h"
  23#include "hw/s390x/css.h"
  24#include "trace.h"
  25
  26#define FLIC_SAVE_INITIAL_SIZE getpagesize()
  27#define FLIC_FAILED (-1UL)
  28#define FLIC_SAVEVM_VERSION 1
  29
  30typedef struct KVMS390FLICState {
  31    S390FLICState parent_obj;
  32
  33    uint32_t fd;
  34    bool clear_io_supported;
  35} KVMS390FLICState;
  36
  37DeviceState *s390_flic_kvm_create(void)
  38{
  39    DeviceState *dev = NULL;
  40
  41    if (kvm_enabled()) {
  42        dev = qdev_create(NULL, TYPE_KVM_S390_FLIC);
  43        object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC,
  44                                  OBJECT(dev), NULL);
  45    }
  46    return dev;
  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
 125int kvm_s390_inject_flic(struct kvm_s390_irq *irq)
 126{
 127    static KVMS390FLICState *flic;
 128
 129    if (unlikely(!flic)) {
 130        flic = KVM_S390_FLIC(s390_get_flic());
 131    }
 132    return flic_enqueue_irqs(irq, sizeof(*irq), flic);
 133}
 134
 135static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
 136                           uint16_t subchannel_nr)
 137{
 138    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
 139    int rc;
 140    uint32_t sid = subchannel_id << 16 | subchannel_nr;
 141    struct kvm_device_attr attr = {
 142        .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
 143        .addr = (uint64_t) &sid,
 144        .attr = sizeof(sid),
 145    };
 146    if (unlikely(!flic->clear_io_supported)) {
 147        return -ENOSYS;
 148    }
 149    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 150    return rc ? -errno : 0;
 151}
 152
 153static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
 154                                    uint16_t mode)
 155{
 156    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
 157    struct kvm_s390_ais_req req = {
 158        .isc = isc,
 159        .mode = mode,
 160    };
 161    struct kvm_device_attr attr = {
 162        .group = KVM_DEV_FLIC_AISM,
 163        .addr = (uint64_t)&req,
 164    };
 165
 166    if (!fs->ais_supported) {
 167        return -ENOSYS;
 168    }
 169
 170    return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
 171}
 172
 173static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type,
 174                                uint8_t isc, uint8_t flags)
 175{
 176    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
 177    uint32_t id = css_get_adapter_id(type, isc);
 178    struct kvm_device_attr attr = {
 179        .group = KVM_DEV_FLIC_AIRQ_INJECT,
 180        .attr = id,
 181    };
 182
 183    if (!fs->ais_supported) {
 184        return -ENOSYS;
 185    }
 186
 187    return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
 188}
 189
 190/**
 191 * __get_all_irqs - store all pending irqs in buffer
 192 * @flic: pointer to flic device state
 193 * @buf: pointer to pointer to a buffer
 194 * @len: length of buffer
 195 *
 196 * Returns: return value of flic_get_all_irqs
 197 * Note: Retry and increase buffer size until flic_get_all_irqs
 198 * either returns a value >= 0 or a negative error code.
 199 * -ENOMEM is an exception, which means the buffer is too small
 200 * and we should try again. Other negative error codes can be
 201 * -EFAULT and -EINVAL which we ignore at this point
 202 */
 203static int __get_all_irqs(KVMS390FLICState *flic,
 204                          void **buf, int len)
 205{
 206    int r;
 207
 208    do {
 209        /* returns -ENOMEM if buffer is too small and number
 210         * of queued interrupts on success */
 211        r = flic_get_all_irqs(flic, *buf, len);
 212        if (r >= 0) {
 213            break;
 214        }
 215        len *= 2;
 216        *buf = g_try_realloc(*buf, len);
 217        if (!buf) {
 218            return -ENOMEM;
 219        }
 220    } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
 221
 222    return r;
 223}
 224
 225static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
 226                                        uint8_t isc, bool swap,
 227                                        bool is_maskable, uint8_t flags)
 228{
 229    struct kvm_s390_io_adapter adapter = {
 230        .id = id,
 231        .isc = isc,
 232        .maskable = is_maskable,
 233        .swap = swap,
 234        .flags = flags,
 235    };
 236    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
 237    int r;
 238    struct kvm_device_attr attr = {
 239        .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
 240        .addr = (uint64_t)&adapter,
 241    };
 242
 243    if (!kvm_gsi_routing_enabled()) {
 244        /* nothing to do */
 245        return 0;
 246    }
 247
 248    r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 249
 250    return r ? -errno : 0;
 251}
 252
 253static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
 254                                   uint64_t map_addr, bool do_map)
 255{
 256    struct kvm_s390_io_adapter_req req = {
 257        .id = id,
 258        .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
 259        .addr = map_addr,
 260    };
 261    struct kvm_device_attr attr = {
 262        .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
 263        .addr = (uint64_t)&req,
 264    };
 265    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
 266    int r;
 267
 268    if (!kvm_gsi_routing_enabled()) {
 269        /* nothing to do */
 270        return 0;
 271    }
 272
 273    r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 274    return r ? -errno : 0;
 275}
 276
 277static int kvm_s390_add_adapter_routes(S390FLICState *fs,
 278                                       AdapterRoutes *routes)
 279{
 280    int ret, i;
 281    uint64_t ind_offset = routes->adapter.ind_offset;
 282
 283    for (i = 0; i < routes->num_routes; i++) {
 284        ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
 285        if (ret < 0) {
 286            goto out_undo;
 287        }
 288        routes->gsi[i] = ret;
 289        routes->adapter.ind_offset++;
 290    }
 291    kvm_irqchip_commit_routes(kvm_state);
 292
 293    /* Restore passed-in structure to original state. */
 294    routes->adapter.ind_offset = ind_offset;
 295    return 0;
 296out_undo:
 297    while (--i >= 0) {
 298        kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
 299        routes->gsi[i] = -1;
 300    }
 301    routes->adapter.ind_offset = ind_offset;
 302    return ret;
 303}
 304
 305static void kvm_s390_release_adapter_routes(S390FLICState *fs,
 306                                            AdapterRoutes *routes)
 307{
 308    int i;
 309
 310    for (i = 0; i < routes->num_routes; i++) {
 311        if (routes->gsi[i] >= 0) {
 312            kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
 313            routes->gsi[i] = -1;
 314        }
 315    }
 316}
 317
 318/**
 319 * kvm_flic_save - Save pending floating interrupts
 320 * @f: QEMUFile containing migration state
 321 * @opaque: pointer to flic device state
 322 * @size: ignored
 323 *
 324 * Note: Pass buf and len to kernel. Start with one page and
 325 * increase until buffer is sufficient or maxium size is
 326 * reached
 327 */
 328static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
 329                         VMStateField *field, QJSON *vmdesc)
 330{
 331    KVMS390FLICState *flic = opaque;
 332    int len = FLIC_SAVE_INITIAL_SIZE;
 333    void *buf;
 334    int count;
 335    int r = 0;
 336
 337    flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
 338
 339    buf = g_try_malloc0(len);
 340    if (!buf) {
 341        /* Storing FLIC_FAILED into the count field here will cause the
 342         * target system to fail when attempting to load irqs from the
 343         * migration state */
 344        error_report("flic: couldn't allocate memory");
 345        qemu_put_be64(f, FLIC_FAILED);
 346        return -ENOMEM;
 347    }
 348
 349    count = __get_all_irqs(flic, &buf, len);
 350    if (count < 0) {
 351        error_report("flic: couldn't retrieve irqs from kernel, rc %d",
 352                     count);
 353        /* Storing FLIC_FAILED into the count field here will cause the
 354         * target system to fail when attempting to load irqs from the
 355         * migration state */
 356        qemu_put_be64(f, FLIC_FAILED);
 357        r = count;
 358    } else {
 359        qemu_put_be64(f, count);
 360        qemu_put_buffer(f, (uint8_t *) buf,
 361                        count * sizeof(struct kvm_s390_irq));
 362    }
 363    g_free(buf);
 364
 365    return r;
 366}
 367
 368/**
 369 * kvm_flic_load - Load pending floating interrupts
 370 * @f: QEMUFile containing migration state
 371 * @opaque: pointer to flic device state
 372 * @size: ignored
 373 *
 374 * Returns: value of flic_enqueue_irqs, -EINVAL on error
 375 * Note: Do nothing when no interrupts where stored
 376 * in QEMUFile
 377 */
 378static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size,
 379                         VMStateField *field)
 380{
 381    uint64_t len = 0;
 382    uint64_t count = 0;
 383    void *buf = NULL;
 384    int r = 0;
 385
 386    flic_enable_pfault((struct KVMS390FLICState *) opaque);
 387
 388    count = qemu_get_be64(f);
 389    len = count * sizeof(struct kvm_s390_irq);
 390    if (count == FLIC_FAILED) {
 391        r = -EINVAL;
 392        goto out;
 393    }
 394    if (count == 0) {
 395        r = 0;
 396        goto out;
 397    }
 398    buf = g_try_malloc0(len);
 399    if (!buf) {
 400        r = -ENOMEM;
 401        goto out;
 402    }
 403
 404    if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
 405        r = -EINVAL;
 406        goto out_free;
 407    }
 408    r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
 409
 410out_free:
 411    g_free(buf);
 412out:
 413    return r;
 414}
 415
 416typedef struct KVMS390FLICStateMigTmp {
 417    KVMS390FLICState *parent;
 418    uint8_t simm;
 419    uint8_t nimm;
 420} KVMS390FLICStateMigTmp;
 421
 422static void kvm_flic_ais_pre_save(void *opaque)
 423{
 424    KVMS390FLICStateMigTmp *tmp = opaque;
 425    KVMS390FLICState *flic = tmp->parent;
 426    struct kvm_s390_ais_all ais;
 427    struct kvm_device_attr attr = {
 428        .group = KVM_DEV_FLIC_AISM_ALL,
 429        .addr = (uint64_t)&ais,
 430        .attr = sizeof(ais),
 431    };
 432
 433    if (ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr)) {
 434        error_report("Failed to retrieve kvm flic ais states");
 435        return;
 436    }
 437
 438    tmp->simm = ais.simm;
 439    tmp->nimm = ais.nimm;
 440}
 441
 442static int kvm_flic_ais_post_load(void *opaque, int version_id)
 443{
 444    KVMS390FLICStateMigTmp *tmp = opaque;
 445    KVMS390FLICState *flic = tmp->parent;
 446    struct kvm_s390_ais_all ais = {
 447        .simm = tmp->simm,
 448        .nimm = tmp->nimm,
 449    };
 450    struct kvm_device_attr attr = {
 451        .group = KVM_DEV_FLIC_AISM_ALL,
 452        .addr = (uint64_t)&ais,
 453    };
 454
 455    /* This can happen when the user mis-configures its guests in an
 456     * incompatible fashion or without a CPU model. For example using
 457     * qemu with -cpu host (which is not migration safe) and do a
 458     * migration from a host that has AIS to a host that has no AIS.
 459     * In that case the target system will reject the migration here.
 460     */
 461    if (!ais_needed(flic)) {
 462        return -ENOSYS;
 463    }
 464
 465    return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
 466}
 467
 468static const VMStateDescription kvm_s390_flic_ais_tmp = {
 469    .name = "s390-flic-ais-tmp",
 470    .pre_save = kvm_flic_ais_pre_save,
 471    .post_load = kvm_flic_ais_post_load,
 472    .fields = (VMStateField[]) {
 473        VMSTATE_UINT8(simm, KVMS390FLICStateMigTmp),
 474        VMSTATE_UINT8(nimm, KVMS390FLICStateMigTmp),
 475        VMSTATE_END_OF_LIST()
 476    }
 477};
 478
 479static const VMStateDescription kvm_s390_flic_vmstate_ais = {
 480    .name = "s390-flic/ais",
 481    .version_id = 1,
 482    .minimum_version_id = 1,
 483    .needed = ais_needed,
 484    .fields = (VMStateField[]) {
 485        VMSTATE_WITH_TMP(KVMS390FLICState, KVMS390FLICStateMigTmp,
 486                         kvm_s390_flic_ais_tmp),
 487        VMSTATE_END_OF_LIST()
 488    }
 489};
 490
 491static const VMStateDescription kvm_s390_flic_vmstate = {
 492    /* should have been like kvm-s390-flic,
 493     * can't change without breaking compat */
 494    .name = "s390-flic",
 495    .version_id = FLIC_SAVEVM_VERSION,
 496    .minimum_version_id = FLIC_SAVEVM_VERSION,
 497    .fields = (VMStateField[]) {
 498        {
 499            .name = "irqs",
 500            .info = &(const VMStateInfo) {
 501                .name = "irqs",
 502                .get = kvm_flic_load,
 503                .put = kvm_flic_save,
 504            },
 505            .flags = VMS_SINGLE,
 506        },
 507        VMSTATE_END_OF_LIST()
 508    },
 509    .subsections = (const VMStateDescription * []) {
 510        &kvm_s390_flic_vmstate_ais,
 511        NULL
 512    }
 513};
 514
 515typedef struct KVMS390FLICStateClass {
 516    S390FLICStateClass parent_class;
 517    DeviceRealize parent_realize;
 518} KVMS390FLICStateClass;
 519
 520#define KVM_S390_FLIC_GET_CLASS(obj) \
 521    OBJECT_GET_CLASS(KVMS390FLICStateClass, (obj), TYPE_KVM_S390_FLIC)
 522
 523#define KVM_S390_FLIC_CLASS(klass) \
 524    OBJECT_CLASS_CHECK(KVMS390FLICStateClass, (klass), TYPE_KVM_S390_FLIC)
 525
 526static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
 527{
 528    KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
 529    struct kvm_create_device cd = {0};
 530    struct kvm_device_attr test_attr = {0};
 531    int ret;
 532    Error *errp_local = NULL;
 533
 534    KVM_S390_FLIC_GET_CLASS(dev)->parent_realize(dev, &errp_local);
 535    if (errp_local) {
 536        goto fail;
 537    }
 538    flic_state->fd = -1;
 539    if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
 540        error_setg_errno(&errp_local, errno, "KVM is missing capability"
 541                         " KVM_CAP_DEVICE_CTRL");
 542        trace_flic_no_device_api(errno);
 543        goto fail;
 544    }
 545
 546    cd.type = KVM_DEV_TYPE_FLIC;
 547    ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
 548    if (ret < 0) {
 549        error_setg_errno(&errp_local, errno, "Creating the KVM device failed");
 550        trace_flic_create_device(errno);
 551        goto fail;
 552    }
 553    flic_state->fd = cd.fd;
 554
 555    /* Check clear_io_irq support */
 556    test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
 557    flic_state->clear_io_supported = !ioctl(flic_state->fd,
 558                                            KVM_HAS_DEVICE_ATTR, test_attr);
 559    return;
 560fail:
 561    error_propagate(errp, errp_local);
 562}
 563
 564static void kvm_s390_flic_reset(DeviceState *dev)
 565{
 566    KVMS390FLICState *flic = KVM_S390_FLIC(dev);
 567    S390FLICState *fs = S390_FLIC_COMMON(dev);
 568    struct kvm_device_attr attr = {
 569        .group = KVM_DEV_FLIC_CLEAR_IRQS,
 570    };
 571    int rc = 0;
 572    uint8_t isc;
 573
 574    if (flic->fd == -1) {
 575        return;
 576    }
 577
 578    flic_disable_wait_pfault(flic);
 579
 580    if (fs->ais_supported) {
 581        for (isc = 0; isc <= MAX_ISC; isc++) {
 582            rc = kvm_s390_modify_ais_mode(fs, isc, SIC_IRQ_MODE_ALL);
 583            if (rc) {
 584                error_report("Failed to reset ais mode for isc %d: %s",
 585                             isc, strerror(-rc));
 586            }
 587        }
 588    }
 589
 590    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
 591    if (rc) {
 592        trace_flic_reset_failed(errno);
 593    }
 594
 595    flic_enable_pfault(flic);
 596}
 597
 598static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
 599{
 600    DeviceClass *dc = DEVICE_CLASS(oc);
 601    S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
 602
 603    KVM_S390_FLIC_CLASS(oc)->parent_realize = dc->realize;
 604    dc->realize = kvm_s390_flic_realize;
 605    dc->vmsd = &kvm_s390_flic_vmstate;
 606    dc->reset = kvm_s390_flic_reset;
 607    fsc->register_io_adapter = kvm_s390_register_io_adapter;
 608    fsc->io_adapter_map = kvm_s390_io_adapter_map;
 609    fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
 610    fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
 611    fsc->clear_io_irq = kvm_s390_clear_io_flic;
 612    fsc->modify_ais_mode = kvm_s390_modify_ais_mode;
 613    fsc->inject_airq = kvm_s390_inject_airq;
 614}
 615
 616static const TypeInfo kvm_s390_flic_info = {
 617    .name          = TYPE_KVM_S390_FLIC,
 618    .parent        = TYPE_S390_FLIC_COMMON,
 619    .instance_size = sizeof(KVMS390FLICState),
 620    .class_size    = sizeof(KVMS390FLICStateClass),
 621    .class_init    = kvm_s390_flic_class_init,
 622};
 623
 624static void kvm_s390_flic_register_types(void)
 625{
 626    type_register_static(&kvm_s390_flic_info);
 627}
 628
 629type_init(kvm_s390_flic_register_types)
 630