qemu/hw/intc/openpic_kvm.c
<<
>>
Prefs
   1/*
   2 * KVM in-kernel OpenPIC
   3 *
   4 * Copyright 2013 Freescale Semiconductor, Inc.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "qapi/error.h"
  27#include <sys/ioctl.h>
  28#include "exec/address-spaces.h"
  29#include "hw/hw.h"
  30#include "hw/ppc/openpic.h"
  31#include "hw/pci/msi.h"
  32#include "hw/sysbus.h"
  33#include "sysemu/kvm.h"
  34#include "qemu/log.h"
  35
  36#define GCR_RESET        0x80000000
  37
  38#define KVM_OPENPIC(obj) \
  39    OBJECT_CHECK(KVMOpenPICState, (obj), TYPE_KVM_OPENPIC)
  40
  41typedef struct KVMOpenPICState {
  42    /*< private >*/
  43    SysBusDevice parent_obj;
  44    /*< public >*/
  45
  46    MemoryRegion mem;
  47    MemoryListener mem_listener;
  48    uint32_t fd;
  49    uint32_t model;
  50    hwaddr mapped;
  51} KVMOpenPICState;
  52
  53static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level)
  54{
  55    kvm_set_irq(kvm_state, n_IRQ, level);
  56}
  57
  58static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val,
  59                              unsigned size)
  60{
  61    KVMOpenPICState *opp = opaque;
  62    struct kvm_device_attr attr;
  63    uint32_t val32 = val;
  64    int ret;
  65
  66    attr.group = KVM_DEV_MPIC_GRP_REGISTER;
  67    attr.attr = addr;
  68    attr.addr = (uint64_t)(unsigned long)&val32;
  69
  70    ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
  71    if (ret < 0) {
  72        qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
  73                      strerror(errno), attr.attr);
  74    }
  75}
  76
  77static void kvm_openpic_reset(DeviceState *d)
  78{
  79    KVMOpenPICState *opp = KVM_OPENPIC(d);
  80
  81    /* Trigger the GCR.RESET bit to reset the PIC */
  82    kvm_openpic_write(opp, 0x1020, GCR_RESET, sizeof(uint32_t));
  83}
  84
  85static uint64_t kvm_openpic_read(void *opaque, hwaddr addr, unsigned size)
  86{
  87    KVMOpenPICState *opp = opaque;
  88    struct kvm_device_attr attr;
  89    uint32_t val = 0xdeadbeef;
  90    int ret;
  91
  92    attr.group = KVM_DEV_MPIC_GRP_REGISTER;
  93    attr.attr = addr;
  94    attr.addr = (uint64_t)(unsigned long)&val;
  95
  96    ret = ioctl(opp->fd, KVM_GET_DEVICE_ATTR, &attr);
  97    if (ret < 0) {
  98        qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
  99                      strerror(errno), attr.attr);
 100        return 0;
 101    }
 102
 103    return val;
 104}
 105
 106static const MemoryRegionOps kvm_openpic_mem_ops = {
 107    .write = kvm_openpic_write,
 108    .read  = kvm_openpic_read,
 109    .endianness = DEVICE_BIG_ENDIAN,
 110    .impl = {
 111        .min_access_size = 4,
 112        .max_access_size = 4,
 113    },
 114};
 115
 116static void kvm_openpic_region_add(MemoryListener *listener,
 117                                   MemoryRegionSection *section)
 118{
 119    KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
 120                                        mem_listener);
 121    struct kvm_device_attr attr;
 122    uint64_t reg_base;
 123    int ret;
 124
 125    if (section->address_space != &address_space_memory) {
 126        abort();
 127    }
 128
 129    /* Ignore events on regions that are not us */
 130    if (section->mr != &opp->mem) {
 131        return;
 132    }
 133
 134    if (opp->mapped) {
 135        /*
 136         * We can only map the MPIC once. Since we are already mapped,
 137         * the best we can do is ignore new maps.
 138         */
 139        return;
 140    }
 141
 142    reg_base = section->offset_within_address_space;
 143    opp->mapped = reg_base;
 144
 145    attr.group = KVM_DEV_MPIC_GRP_MISC;
 146    attr.attr = KVM_DEV_MPIC_BASE_ADDR;
 147    attr.addr = (uint64_t)(unsigned long)&reg_base;
 148
 149    ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
 150    if (ret < 0) {
 151        fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
 152                strerror(errno), reg_base);
 153    }
 154}
 155
 156static void kvm_openpic_region_del(MemoryListener *listener,
 157                                   MemoryRegionSection *section)
 158{
 159    KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
 160                                        mem_listener);
 161    struct kvm_device_attr attr;
 162    uint64_t reg_base = 0;
 163    int ret;
 164
 165    /* Ignore events on regions that are not us */
 166    if (section->mr != &opp->mem) {
 167        return;
 168    }
 169
 170    if (section->offset_within_address_space != opp->mapped) {
 171        /*
 172         * We can only map the MPIC once. This mapping was a secondary
 173         * one that we couldn't fulfill. Ignore it.
 174         */
 175        return;
 176    }
 177    opp->mapped = 0;
 178
 179    attr.group = KVM_DEV_MPIC_GRP_MISC;
 180    attr.attr = KVM_DEV_MPIC_BASE_ADDR;
 181    attr.addr = (uint64_t)(unsigned long)&reg_base;
 182
 183    ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
 184    if (ret < 0) {
 185        fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
 186                strerror(errno), reg_base);
 187    }
 188}
 189
 190static void kvm_openpic_init(Object *obj)
 191{
 192    KVMOpenPICState *opp = KVM_OPENPIC(obj);
 193
 194    memory_region_init_io(&opp->mem, OBJECT(opp), &kvm_openpic_mem_ops, opp,
 195                          "kvm-openpic", 0x40000);
 196}
 197
 198static void kvm_openpic_realize(DeviceState *dev, Error **errp)
 199{
 200    SysBusDevice *d = SYS_BUS_DEVICE(dev);
 201    KVMOpenPICState *opp = KVM_OPENPIC(dev);
 202    KVMState *s = kvm_state;
 203    int kvm_openpic_model;
 204    struct kvm_create_device cd = {0};
 205    int ret, i;
 206
 207    if (!kvm_check_extension(s, KVM_CAP_DEVICE_CTRL)) {
 208        error_setg(errp, "Kernel is lacking Device Control API");
 209        return;
 210    }
 211
 212    switch (opp->model) {
 213    case OPENPIC_MODEL_FSL_MPIC_20:
 214        kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_20;
 215        break;
 216
 217    case OPENPIC_MODEL_FSL_MPIC_42:
 218        kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_42;
 219        break;
 220
 221    default:
 222        error_setg(errp, "Unsupported OpenPIC model %" PRIu32, opp->model);
 223        return;
 224    }
 225
 226    cd.type = kvm_openpic_model;
 227    ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &cd);
 228    if (ret < 0) {
 229        error_setg(errp, "Can't create device %d: %s",
 230                   cd.type, strerror(errno));
 231        return;
 232    }
 233    opp->fd = cd.fd;
 234
 235    sysbus_init_mmio(d, &opp->mem);
 236    qdev_init_gpio_in(dev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ);
 237
 238    opp->mem_listener.region_add = kvm_openpic_region_add;
 239    opp->mem_listener.region_del = kvm_openpic_region_del;
 240    memory_listener_register(&opp->mem_listener, &address_space_memory);
 241
 242    /* indicate pic capabilities */
 243    msi_nonbroken = true;
 244    kvm_kernel_irqchip = true;
 245    kvm_async_interrupts_allowed = true;
 246
 247    /* set up irq routing */
 248    kvm_init_irq_routing(kvm_state);
 249    for (i = 0; i < 256; ++i) {
 250        kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
 251    }
 252
 253    kvm_msi_via_irqfd_allowed = true;
 254    kvm_gsi_routing_allowed = true;
 255
 256    kvm_irqchip_commit_routes(s);
 257}
 258
 259int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
 260{
 261    KVMOpenPICState *opp = KVM_OPENPIC(d);
 262
 263    return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
 264                               kvm_arch_vcpu_id(cs));
 265}
 266
 267static Property kvm_openpic_properties[] = {
 268    DEFINE_PROP_UINT32("model", KVMOpenPICState, model,
 269                       OPENPIC_MODEL_FSL_MPIC_20),
 270    DEFINE_PROP_END_OF_LIST(),
 271};
 272
 273static void kvm_openpic_class_init(ObjectClass *oc, void *data)
 274{
 275    DeviceClass *dc = DEVICE_CLASS(oc);
 276
 277    dc->realize = kvm_openpic_realize;
 278    dc->props = kvm_openpic_properties;
 279    dc->reset = kvm_openpic_reset;
 280    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 281}
 282
 283static const TypeInfo kvm_openpic_info = {
 284    .name          = TYPE_KVM_OPENPIC,
 285    .parent        = TYPE_SYS_BUS_DEVICE,
 286    .instance_size = sizeof(KVMOpenPICState),
 287    .instance_init = kvm_openpic_init,
 288    .class_init    = kvm_openpic_class_init,
 289};
 290
 291static void kvm_openpic_register_types(void)
 292{
 293    type_register_static(&kvm_openpic_info);
 294}
 295
 296type_init(kvm_openpic_register_types)
 297