qemu/hw/intc/s390_flic.c
<<
>>
Prefs
   1/*
   2 * QEMU S390x 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/error-report.h"
  15#include "hw/sysbus.h"
  16#include "hw/s390x/ioinst.h"
  17#include "hw/s390x/s390_flic.h"
  18#include "hw/s390x/css.h"
  19#include "trace.h"
  20#include "cpu.h"
  21#include "hw/qdev.h"
  22#include "qapi/error.h"
  23#include "hw/s390x/s390-virtio-ccw.h"
  24
  25S390FLICStateClass *s390_get_flic_class(S390FLICState *fs)
  26{
  27    static S390FLICStateClass *class;
  28
  29    if (!class) {
  30        /* we only have one flic device, so this is fine to cache */
  31        class = S390_FLIC_COMMON_GET_CLASS(fs);
  32    }
  33    return class;
  34}
  35
  36QEMUS390FLICState *s390_get_qemu_flic(S390FLICState *fs)
  37{
  38    static QEMUS390FLICState *flic;
  39
  40    if (!flic) {
  41        /* we only have one flic device, so this is fine to cache */
  42        flic = QEMU_S390_FLIC(fs);
  43    }
  44    return flic;
  45}
  46
  47S390FLICState *s390_get_flic(void)
  48{
  49    static S390FLICState *fs;
  50
  51    if (!fs) {
  52        fs = S390_FLIC_COMMON(object_resolve_path_type("",
  53                                                       TYPE_S390_FLIC_COMMON,
  54                                                       NULL));
  55    }
  56    return fs;
  57}
  58
  59void s390_flic_init(void)
  60{
  61    DeviceState *dev;
  62
  63    if (kvm_enabled()) {
  64        dev = qdev_create(NULL, TYPE_KVM_S390_FLIC);
  65        object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC,
  66                                  OBJECT(dev), NULL);
  67    } else {
  68        dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC);
  69        object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC,
  70                                  OBJECT(dev), NULL);
  71    }
  72    qdev_init_nofail(dev);
  73}
  74
  75static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
  76                                         uint8_t isc, bool swap,
  77                                         bool is_maskable, uint8_t flags)
  78{
  79    /* nothing to do */
  80    return 0;
  81}
  82
  83static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
  84                                    uint64_t map_addr, bool do_map)
  85{
  86    /* nothing to do */
  87    return 0;
  88}
  89
  90static int qemu_s390_add_adapter_routes(S390FLICState *fs,
  91                                        AdapterRoutes *routes)
  92{
  93    return -ENOSYS;
  94}
  95
  96static void qemu_s390_release_adapter_routes(S390FLICState *fs,
  97                                             AdapterRoutes *routes)
  98{
  99}
 100
 101static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
 102                           uint16_t subchannel_nr)
 103{
 104    QEMUS390FLICState *flic  = s390_get_qemu_flic(fs);
 105    QEMUS390FlicIO *cur, *next;
 106    uint8_t isc;
 107
 108    g_assert(qemu_mutex_iothread_locked());
 109    if (!(flic->pending & FLIC_PENDING_IO)) {
 110        return 0;
 111    }
 112
 113    /* check all iscs */
 114    for (isc = 0; isc < 8; isc++) {
 115        if (QLIST_EMPTY(&flic->io[isc])) {
 116            continue;
 117        }
 118
 119        /* search and delete any matching one */
 120        QLIST_FOREACH_SAFE(cur, &flic->io[isc], next, next) {
 121            if (cur->id == subchannel_id && cur->nr == subchannel_nr) {
 122                QLIST_REMOVE(cur, next);
 123                g_free(cur);
 124            }
 125        }
 126
 127        /* update our indicator bit */
 128        if (QLIST_EMPTY(&flic->io[isc])) {
 129            flic->pending &= ~ISC_TO_PENDING_IO(isc);
 130        }
 131    }
 132    return 0;
 133}
 134
 135static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
 136                                     uint16_t mode)
 137{
 138    QEMUS390FLICState *flic  = s390_get_qemu_flic(fs);
 139
 140    switch (mode) {
 141    case SIC_IRQ_MODE_ALL:
 142        flic->simm &= ~AIS_MODE_MASK(isc);
 143        flic->nimm &= ~AIS_MODE_MASK(isc);
 144        break;
 145    case SIC_IRQ_MODE_SINGLE:
 146        flic->simm |= AIS_MODE_MASK(isc);
 147        flic->nimm &= ~AIS_MODE_MASK(isc);
 148        break;
 149    default:
 150        return -EINVAL;
 151    }
 152
 153    return 0;
 154}
 155
 156static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type,
 157                                 uint8_t isc, uint8_t flags)
 158{
 159    QEMUS390FLICState *flic = s390_get_qemu_flic(fs);
 160    S390FLICStateClass *fsc = s390_get_flic_class(fs);
 161    bool flag = flags & S390_ADAPTER_SUPPRESSIBLE;
 162    uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
 163
 164    if (flag && (flic->nimm & AIS_MODE_MASK(isc))) {
 165        trace_qemu_s390_airq_suppressed(type, isc);
 166        return 0;
 167    }
 168
 169    fsc->inject_io(fs, 0, 0, 0, io_int_word);
 170
 171    if (flag && (flic->simm & AIS_MODE_MASK(isc))) {
 172        flic->nimm |= AIS_MODE_MASK(isc);
 173        trace_qemu_s390_suppress_airq(isc, "Single-Interruption Mode",
 174                                      "NO-Interruptions Mode");
 175    }
 176
 177    return 0;
 178}
 179
 180static void qemu_s390_flic_notify(uint32_t type)
 181{
 182    CPUState *cs;
 183
 184    /*
 185     * We have to make all CPUs see CPU_INTERRUPT_HARD, so they might
 186     * consider it. We will kick all running CPUs and only relevant
 187     * sleeping ones.
 188     */
 189    CPU_FOREACH(cs) {
 190        S390CPU *cpu = S390_CPU(cs);
 191
 192        cs->interrupt_request |= CPU_INTERRUPT_HARD;
 193
 194        /* ignore CPUs that are not sleeping */
 195        if (s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING &&
 196            s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD) {
 197            continue;
 198        }
 199
 200        /* we always kick running CPUs for now, this is tricky */
 201        if (cs->halted) {
 202            /* don't check for subclasses, CPUs double check when waking up */
 203            if (type & FLIC_PENDING_SERVICE) {
 204                if (!(cpu->env.psw.mask & PSW_MASK_EXT)) {
 205                    continue;
 206                }
 207            } else if (type & FLIC_PENDING_IO) {
 208                if (!(cpu->env.psw.mask & PSW_MASK_IO)) {
 209                    continue;
 210                }
 211            } else if (type & FLIC_PENDING_MCHK_CR) {
 212                if (!(cpu->env.psw.mask & PSW_MASK_MCHECK)) {
 213                    continue;
 214                }
 215            }
 216        }
 217        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 218    }
 219}
 220
 221uint32_t qemu_s390_flic_dequeue_service(QEMUS390FLICState *flic)
 222{
 223    uint32_t tmp;
 224
 225    g_assert(qemu_mutex_iothread_locked());
 226    g_assert(flic->pending & FLIC_PENDING_SERVICE);
 227    tmp = flic->service_param;
 228    flic->service_param = 0;
 229    flic->pending &= ~FLIC_PENDING_SERVICE;
 230
 231    return tmp;
 232}
 233
 234/* caller has to free the returned object */
 235QEMUS390FlicIO *qemu_s390_flic_dequeue_io(QEMUS390FLICState *flic, uint64_t cr6)
 236{
 237    QEMUS390FlicIO *io;
 238    uint8_t isc;
 239
 240    g_assert(qemu_mutex_iothread_locked());
 241    if (!(flic->pending & CR6_TO_PENDING_IO(cr6))) {
 242        return NULL;
 243    }
 244
 245    for (isc = 0; isc < 8; isc++) {
 246        if (QLIST_EMPTY(&flic->io[isc]) || !(cr6 & ISC_TO_ISC_BITS(isc))) {
 247            continue;
 248        }
 249        io = QLIST_FIRST(&flic->io[isc]);
 250        QLIST_REMOVE(io, next);
 251
 252        /* update our indicator bit */
 253        if (QLIST_EMPTY(&flic->io[isc])) {
 254            flic->pending &= ~ISC_TO_PENDING_IO(isc);
 255        }
 256        return io;
 257    }
 258
 259    return NULL;
 260}
 261
 262void qemu_s390_flic_dequeue_crw_mchk(QEMUS390FLICState *flic)
 263{
 264    g_assert(qemu_mutex_iothread_locked());
 265    g_assert(flic->pending & FLIC_PENDING_MCHK_CR);
 266    flic->pending &= ~FLIC_PENDING_MCHK_CR;
 267}
 268
 269static void qemu_s390_inject_service(S390FLICState *fs, uint32_t parm)
 270{
 271    QEMUS390FLICState *flic = s390_get_qemu_flic(fs);
 272
 273    g_assert(qemu_mutex_iothread_locked());
 274    /* multiplexing is good enough for sclp - kvm does it internally as well */
 275    flic->service_param |= parm;
 276    flic->pending |= FLIC_PENDING_SERVICE;
 277
 278    qemu_s390_flic_notify(FLIC_PENDING_SERVICE);
 279}
 280
 281static void qemu_s390_inject_io(S390FLICState *fs, uint16_t subchannel_id,
 282                                uint16_t subchannel_nr, uint32_t io_int_parm,
 283                                uint32_t io_int_word)
 284{
 285    const uint8_t isc = IO_INT_WORD_ISC(io_int_word);
 286    QEMUS390FLICState *flic = s390_get_qemu_flic(fs);
 287    QEMUS390FlicIO *io;
 288
 289    g_assert(qemu_mutex_iothread_locked());
 290    io = g_new0(QEMUS390FlicIO, 1);
 291    io->id = subchannel_id;
 292    io->nr = subchannel_nr;
 293    io->parm = io_int_parm;
 294    io->word = io_int_word;
 295
 296    QLIST_INSERT_HEAD(&flic->io[isc], io, next);
 297    flic->pending |= ISC_TO_PENDING_IO(isc);
 298
 299    qemu_s390_flic_notify(ISC_TO_PENDING_IO(isc));
 300}
 301
 302static void qemu_s390_inject_crw_mchk(S390FLICState *fs)
 303{
 304    QEMUS390FLICState *flic = s390_get_qemu_flic(fs);
 305
 306    g_assert(qemu_mutex_iothread_locked());
 307    flic->pending |= FLIC_PENDING_MCHK_CR;
 308
 309    qemu_s390_flic_notify(FLIC_PENDING_MCHK_CR);
 310}
 311
 312bool qemu_s390_flic_has_service(QEMUS390FLICState *flic)
 313{
 314    /* called without lock via cc->has_work, will be validated under lock */
 315    return !!(flic->pending & FLIC_PENDING_SERVICE);
 316}
 317
 318bool qemu_s390_flic_has_io(QEMUS390FLICState *flic, uint64_t cr6)
 319{
 320    /* called without lock via cc->has_work, will be validated under lock */
 321    return !!(flic->pending & CR6_TO_PENDING_IO(cr6));
 322}
 323
 324bool qemu_s390_flic_has_crw_mchk(QEMUS390FLICState *flic)
 325{
 326    /* called without lock via cc->has_work, will be validated under lock */
 327    return !!(flic->pending & FLIC_PENDING_MCHK_CR);
 328}
 329
 330bool qemu_s390_flic_has_any(QEMUS390FLICState *flic)
 331{
 332    g_assert(qemu_mutex_iothread_locked());
 333    return !!flic->pending;
 334}
 335
 336static void qemu_s390_flic_reset(DeviceState *dev)
 337{
 338    QEMUS390FLICState *flic = QEMU_S390_FLIC(dev);
 339    QEMUS390FlicIO *cur, *next;
 340    int isc;
 341
 342    g_assert(qemu_mutex_iothread_locked());
 343    flic->simm = 0;
 344    flic->nimm = 0;
 345    flic->pending = 0;
 346
 347    /* remove all pending io interrupts */
 348    for (isc = 0; isc < 8; isc++) {
 349        QLIST_FOREACH_SAFE(cur, &flic->io[isc], next, next) {
 350            QLIST_REMOVE(cur, next);
 351            g_free(cur);
 352        }
 353    }
 354}
 355
 356bool ais_needed(void *opaque)
 357{
 358    S390FLICState *s = opaque;
 359
 360    return s->ais_supported;
 361}
 362
 363static const VMStateDescription qemu_s390_flic_vmstate = {
 364    .name = "qemu-s390-flic",
 365    .version_id = 1,
 366    .minimum_version_id = 1,
 367    .needed = ais_needed,
 368    .fields = (VMStateField[]) {
 369        VMSTATE_UINT8(simm, QEMUS390FLICState),
 370        VMSTATE_UINT8(nimm, QEMUS390FLICState),
 371        VMSTATE_END_OF_LIST()
 372    }
 373};
 374
 375static void qemu_s390_flic_instance_init(Object *obj)
 376{
 377    QEMUS390FLICState *flic = QEMU_S390_FLIC(obj);
 378    int isc;
 379
 380    for (isc = 0; isc < 8; isc++) {
 381        QLIST_INIT(&flic->io[isc]);
 382    }
 383}
 384
 385static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
 386{
 387    DeviceClass *dc = DEVICE_CLASS(oc);
 388    S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
 389
 390    dc->reset = qemu_s390_flic_reset;
 391    dc->vmsd = &qemu_s390_flic_vmstate;
 392    fsc->register_io_adapter = qemu_s390_register_io_adapter;
 393    fsc->io_adapter_map = qemu_s390_io_adapter_map;
 394    fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
 395    fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
 396    fsc->clear_io_irq = qemu_s390_clear_io_flic;
 397    fsc->modify_ais_mode = qemu_s390_modify_ais_mode;
 398    fsc->inject_airq = qemu_s390_inject_airq;
 399    fsc->inject_service = qemu_s390_inject_service;
 400    fsc->inject_io = qemu_s390_inject_io;
 401    fsc->inject_crw_mchk = qemu_s390_inject_crw_mchk;
 402}
 403
 404static Property s390_flic_common_properties[] = {
 405    DEFINE_PROP_UINT32("adapter_routes_max_batch", S390FLICState,
 406                       adapter_routes_max_batch, ADAPTER_ROUTES_MAX_GSI),
 407    DEFINE_PROP_END_OF_LIST(),
 408};
 409
 410static void s390_flic_common_realize(DeviceState *dev, Error **errp)
 411{
 412    S390FLICState *fs = S390_FLIC_COMMON(dev);
 413    uint32_t max_batch = fs->adapter_routes_max_batch;
 414
 415    if (max_batch > ADAPTER_ROUTES_MAX_GSI) {
 416        error_setg(errp, "flic property adapter_routes_max_batch too big"
 417                   " (%d > %d)", max_batch, ADAPTER_ROUTES_MAX_GSI);
 418        return;
 419    }
 420
 421    fs->ais_supported = s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION);
 422}
 423
 424static void s390_flic_class_init(ObjectClass *oc, void *data)
 425{
 426    DeviceClass *dc = DEVICE_CLASS(oc);
 427
 428    dc->props = s390_flic_common_properties;
 429    dc->realize = s390_flic_common_realize;
 430}
 431
 432static const TypeInfo qemu_s390_flic_info = {
 433    .name          = TYPE_QEMU_S390_FLIC,
 434    .parent        = TYPE_S390_FLIC_COMMON,
 435    .instance_size = sizeof(QEMUS390FLICState),
 436    .instance_init = qemu_s390_flic_instance_init,
 437    .class_init    = qemu_s390_flic_class_init,
 438};
 439
 440
 441static const TypeInfo s390_flic_common_info = {
 442    .name          = TYPE_S390_FLIC_COMMON,
 443    .parent        = TYPE_SYS_BUS_DEVICE,
 444    .instance_size = sizeof(S390FLICState),
 445    .class_init    = s390_flic_class_init,
 446    .class_size    = sizeof(S390FLICStateClass),
 447};
 448
 449static void qemu_s390_flic_register_types(void)
 450{
 451    type_register_static(&s390_flic_common_info);
 452    type_register_static(&qemu_s390_flic_info);
 453}
 454
 455type_init(qemu_s390_flic_register_types)
 456
 457static bool adapter_info_so_needed(void *opaque)
 458{
 459    return css_migration_enabled();
 460}
 461
 462const VMStateDescription vmstate_adapter_info_so = {
 463    .name = "s390_adapter_info/summary_offset",
 464    .version_id = 1,
 465    .minimum_version_id = 1,
 466    .needed = adapter_info_so_needed,
 467    .fields = (VMStateField[]) {
 468        VMSTATE_UINT32(summary_offset, AdapterInfo),
 469        VMSTATE_END_OF_LIST()
 470    }
 471};
 472
 473const VMStateDescription vmstate_adapter_info = {
 474    .name = "s390_adapter_info",
 475    .version_id = 1,
 476    .minimum_version_id = 1,
 477    .fields = (VMStateField[]) {
 478        VMSTATE_UINT64(ind_offset, AdapterInfo),
 479        /*
 480         * We do not have to migrate neither the id nor the addresses.
 481         * The id is set by css_register_io_adapter and the addresses
 482         * are set based on the IndAddr objects after those get mapped.
 483         */
 484        VMSTATE_END_OF_LIST()
 485    },
 486    .subsections = (const VMStateDescription * []) {
 487        &vmstate_adapter_info_so,
 488        NULL
 489    }
 490};
 491
 492const VMStateDescription vmstate_adapter_routes = {
 493
 494    .name = "s390_adapter_routes",
 495    .version_id = 1,
 496    .minimum_version_id = 1,
 497    .fields = (VMStateField[]) {
 498        VMSTATE_STRUCT(adapter, AdapterRoutes, 1, vmstate_adapter_info,
 499                       AdapterInfo),
 500        VMSTATE_END_OF_LIST()
 501    }
 502};
 503