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
  25S390FLICState *s390_get_flic(void)
  26{
  27    static S390FLICState *fs;
  28
  29    if (!fs) {
  30        fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL));
  31        if (!fs) {
  32            fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC,
  33                                                      NULL));
  34        }
  35    }
  36    return fs;
  37}
  38
  39void s390_flic_init(void)
  40{
  41    DeviceState *dev;
  42
  43    dev = s390_flic_kvm_create();
  44    if (!dev) {
  45        dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC);
  46        object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC,
  47                                  OBJECT(dev), NULL);
  48    }
  49    qdev_init_nofail(dev);
  50}
  51
  52static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
  53                                         uint8_t isc, bool swap,
  54                                         bool is_maskable, uint8_t flags)
  55{
  56    /* nothing to do */
  57    return 0;
  58}
  59
  60static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
  61                                    uint64_t map_addr, bool do_map)
  62{
  63    /* nothing to do */
  64    return 0;
  65}
  66
  67static int qemu_s390_add_adapter_routes(S390FLICState *fs,
  68                                        AdapterRoutes *routes)
  69{
  70    return -ENOSYS;
  71}
  72
  73static void qemu_s390_release_adapter_routes(S390FLICState *fs,
  74                                             AdapterRoutes *routes)
  75{
  76}
  77
  78static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
  79                           uint16_t subchannel_nr)
  80{
  81    /* Fixme TCG */
  82    return -ENOSYS;
  83}
  84
  85static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
  86                                     uint16_t mode)
  87{
  88    QEMUS390FLICState *flic  = QEMU_S390_FLIC(fs);
  89
  90    switch (mode) {
  91    case SIC_IRQ_MODE_ALL:
  92        flic->simm &= ~AIS_MODE_MASK(isc);
  93        flic->nimm &= ~AIS_MODE_MASK(isc);
  94        break;
  95    case SIC_IRQ_MODE_SINGLE:
  96        flic->simm |= AIS_MODE_MASK(isc);
  97        flic->nimm &= ~AIS_MODE_MASK(isc);
  98        break;
  99    default:
 100        return -EINVAL;
 101    }
 102
 103    return 0;
 104}
 105
 106static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type,
 107                                 uint8_t isc, uint8_t flags)
 108{
 109    QEMUS390FLICState *flic = QEMU_S390_FLIC(fs);
 110    bool flag = flags & S390_ADAPTER_SUPPRESSIBLE;
 111    uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
 112
 113    if (flag && (flic->nimm & AIS_MODE_MASK(isc))) {
 114        trace_qemu_s390_airq_suppressed(type, isc);
 115        return 0;
 116    }
 117
 118    s390_io_interrupt(0, 0, 0, io_int_word);
 119
 120    if (flag && (flic->simm & AIS_MODE_MASK(isc))) {
 121        flic->nimm |= AIS_MODE_MASK(isc);
 122        trace_qemu_s390_suppress_airq(isc, "Single-Interruption Mode",
 123                                      "NO-Interruptions Mode");
 124    }
 125
 126    return 0;
 127}
 128
 129static void qemu_s390_flic_reset(DeviceState *dev)
 130{
 131    QEMUS390FLICState *flic = QEMU_S390_FLIC(dev);
 132
 133    flic->simm = 0;
 134    flic->nimm = 0;
 135}
 136
 137bool ais_needed(void *opaque)
 138{
 139    S390FLICState *s = opaque;
 140
 141    return s->ais_supported;
 142}
 143
 144static const VMStateDescription qemu_s390_flic_vmstate = {
 145    .name = "qemu-s390-flic",
 146    .version_id = 1,
 147    .minimum_version_id = 1,
 148    .needed = ais_needed,
 149    .fields = (VMStateField[]) {
 150        VMSTATE_UINT8(simm, QEMUS390FLICState),
 151        VMSTATE_UINT8(nimm, QEMUS390FLICState),
 152        VMSTATE_END_OF_LIST()
 153    }
 154};
 155
 156static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
 157{
 158    DeviceClass *dc = DEVICE_CLASS(oc);
 159    S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
 160
 161    dc->reset = qemu_s390_flic_reset;
 162    dc->vmsd = &qemu_s390_flic_vmstate;
 163    fsc->register_io_adapter = qemu_s390_register_io_adapter;
 164    fsc->io_adapter_map = qemu_s390_io_adapter_map;
 165    fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
 166    fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
 167    fsc->clear_io_irq = qemu_s390_clear_io_flic;
 168    fsc->modify_ais_mode = qemu_s390_modify_ais_mode;
 169    fsc->inject_airq = qemu_s390_inject_airq;
 170}
 171
 172static Property s390_flic_common_properties[] = {
 173    DEFINE_PROP_UINT32("adapter_routes_max_batch", S390FLICState,
 174                       adapter_routes_max_batch, ADAPTER_ROUTES_MAX_GSI),
 175    DEFINE_PROP_END_OF_LIST(),
 176};
 177
 178static void s390_flic_common_realize(DeviceState *dev, Error **errp)
 179{
 180    S390FLICState *fs = S390_FLIC_COMMON(dev);
 181    uint32_t max_batch = fs->adapter_routes_max_batch;
 182
 183    if (max_batch > ADAPTER_ROUTES_MAX_GSI) {
 184        error_setg(errp, "flic property adapter_routes_max_batch too big"
 185                   " (%d > %d)", max_batch, ADAPTER_ROUTES_MAX_GSI);
 186        return;
 187    }
 188
 189    fs->ais_supported = s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION);
 190}
 191
 192static void s390_flic_class_init(ObjectClass *oc, void *data)
 193{
 194    DeviceClass *dc = DEVICE_CLASS(oc);
 195
 196    dc->props = s390_flic_common_properties;
 197    dc->realize = s390_flic_common_realize;
 198}
 199
 200static const TypeInfo qemu_s390_flic_info = {
 201    .name          = TYPE_QEMU_S390_FLIC,
 202    .parent        = TYPE_S390_FLIC_COMMON,
 203    .instance_size = sizeof(QEMUS390FLICState),
 204    .class_init    = qemu_s390_flic_class_init,
 205};
 206
 207
 208static const TypeInfo s390_flic_common_info = {
 209    .name          = TYPE_S390_FLIC_COMMON,
 210    .parent        = TYPE_SYS_BUS_DEVICE,
 211    .instance_size = sizeof(S390FLICState),
 212    .class_init    = s390_flic_class_init,
 213    .class_size    = sizeof(S390FLICStateClass),
 214};
 215
 216static void qemu_s390_flic_register_types(void)
 217{
 218    type_register_static(&s390_flic_common_info);
 219    type_register_static(&qemu_s390_flic_info);
 220}
 221
 222type_init(qemu_s390_flic_register_types)
 223
 224static bool adapter_info_so_needed(void *opaque)
 225{
 226    return css_migration_enabled();
 227}
 228
 229const VMStateDescription vmstate_adapter_info_so = {
 230    .name = "s390_adapter_info/summary_offset",
 231    .version_id = 1,
 232    .minimum_version_id = 1,
 233    .needed = adapter_info_so_needed,
 234    .fields = (VMStateField[]) {
 235        VMSTATE_UINT32(summary_offset, AdapterInfo),
 236        VMSTATE_END_OF_LIST()
 237    }
 238};
 239
 240const VMStateDescription vmstate_adapter_info = {
 241    .name = "s390_adapter_info",
 242    .version_id = 1,
 243    .minimum_version_id = 1,
 244    .fields = (VMStateField[]) {
 245        VMSTATE_UINT64(ind_offset, AdapterInfo),
 246        /*
 247         * We do not have to migrate neither the id nor the addresses.
 248         * The id is set by css_register_io_adapter and the addresses
 249         * are set based on the IndAddr objects after those get mapped.
 250         */
 251        VMSTATE_END_OF_LIST()
 252    },
 253    .subsections = (const VMStateDescription * []) {
 254        &vmstate_adapter_info_so,
 255        NULL
 256    }
 257};
 258
 259const VMStateDescription vmstate_adapter_routes = {
 260
 261    .name = "s390_adapter_routes",
 262    .version_id = 1,
 263    .minimum_version_id = 1,
 264    .fields = (VMStateField[]) {
 265        VMSTATE_STRUCT(adapter, AdapterRoutes, 1, vmstate_adapter_info,
 266                       AdapterInfo),
 267        VMSTATE_END_OF_LIST()
 268    }
 269};
 270