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 <sys/ioctl.h>
  26#include "exec/address-spaces.h"
  27#include "hw/hw.h"
  28#include "hw/ppc/openpic.h"
  29#include "hw/pci/msi.h"
  30#include "hw/sysbus.h"
  31#include "sysemu/kvm.h"
  32#include "qemu/log.h"
  33
  34#define GCR_RESET        0x80000000
  35
  36#define KVM_OPENPIC(obj) \
  37    OBJECT_CHECK(KVMOpenPICState, (obj), TYPE_KVM_OPENPIC)
  38
  39typedef struct KVMOpenPICState {
  40    /*< private >*/
  41    SysBusDevice parent_obj;
  42    /*< public >*/
  43
  44    MemoryRegion mem;
  45    MemoryListener mem_listener;
  46    uint32_t fd;
  47    uint32_t model;
  48    hwaddr mapped;
  49} KVMOpenPICState;
  50
  51static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level)
  52{
  53    kvm_set_irq(kvm_state, n_IRQ, level);
  54}
  55
  56static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val,
  57                              unsigned size)
  58{
  59    KVMOpenPICState *opp = opaque;
  60    struct kvm_device_attr attr;
  61    uint32_t val32 = val;
  62    int ret;
  63
  64    attr.group = KVM_DEV_MPIC_GRP_REGISTER;
  65    attr.attr = addr;
  66    attr.addr = (uint64_t)(unsigned long)&val32;
  67
  68    ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
  69    if (ret < 0) {
  70        qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
  71                      strerror(errno), attr.attr);
  72    }
  73}
  74
  75static void kvm_openpic_reset(DeviceState *d)
  76{
  77    KVMOpenPICState *opp = KVM_OPENPIC(d);
  78
  79    /* Trigger the GCR.RESET bit to reset the PIC */
  80    kvm_openpic_write(opp, 0x1020, GCR_RESET, sizeof(uint32_t));
  81}
  82
  83static uint64_t kvm_openpic_read(void *opaque, hwaddr addr, unsigned size)
  84{
  85    KVMOpenPICState *opp = opaque;
  86    struct kvm_device_attr attr;
  87    uint32_t val = 0xdeadbeef;
  88    int ret;
  89
  90    attr.group = KVM_DEV_MPIC_GRP_REGISTER;
  91    attr.attr = addr;
  92    attr.addr = (uint64_t)(unsigned long)&val;
  93
  94    ret = ioctl(opp->fd, KVM_GET_DEVICE_ATTR, &attr);
  95    if (ret < 0) {
  96        qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
  97                      strerror(errno), attr.attr);
  98        return 0;
  99    }
 100
 101    return val;
 102}
 103
 104static const MemoryRegionOps kvm_openpic_mem_ops = {
 105    .write = kvm_openpic_write,
 106    .read  = kvm_openpic_read,
 107    .endianness = DEVICE_BIG_ENDIAN,
 108    .impl = {
 109        .min_access_size = 4,
 110        .max_access_size = 4,
 111    },
 112};
 113
 114static void kvm_openpic_region_add(MemoryListener *listener,
 115                                   MemoryRegionSection *section)
 116{
 117    KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
 118                                        mem_listener);
 119    struct kvm_device_attr attr;
 120    uint64_t reg_base;
 121    int ret;
 122
 123    if (section->address_space != &address_space_memory) {
 124        abort();
 125    }
 126
 127    /* Ignore events on regions that are not us */
 128    if (section->mr != &opp->mem) {
 129        return;
 130    }
 131
 132    if (opp->mapped) {
 133        /*
 134         * We can only map the MPIC once. Since we are already mapped,
 135         * the best we can do is ignore new maps.
 136         */
 137        return;
 138    }
 139
 140    reg_base = section->offset_within_address_space;
 141    opp->mapped = reg_base;
 142
 143    attr.group = KVM_DEV_MPIC_GRP_MISC;
 144    attr.attr = KVM_DEV_MPIC_BASE_ADDR;
 145    attr.addr = (uint64_t)(unsigned long)&reg_base;
 146
 147    ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
 148    if (ret < 0) {
 149        fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
 150                strerror(errno), reg_base);
 151    }
 152}
 153
 154static void kvm_openpic_region_del(MemoryListener *listener,
 155                                   MemoryRegionSection *section)
 156{
 157    KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
 158                                        mem_listener);
 159    struct kvm_device_attr attr;
 160    uint64_t reg_base = 0;
 161    int ret;
 162
 163    /* Ignore events on regions that are not us */
 164    if (section->mr != &opp->mem) {
 165        return;
 166    }
 167
 168    if (section->offset_within_address_space != opp->mapped) {
 169        /*
 170         * We can only map the MPIC once. This mapping was a secondary
 171         * one that we couldn't fulfill. Ignore it.
 172         */
 173        return;
 174    }
 175    opp->mapped = 0;
 176
 177    attr.group = KVM_DEV_MPIC_GRP_MISC;
 178    attr.attr = KVM_DEV_MPIC_BASE_ADDR;
 179    attr.addr = (uint64_t)(unsigned long)&reg_base;
 180
 181    ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
 182    if (ret < 0) {
 183        fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
 184                strerror(errno), reg_base);
 185    }
 186}
 187
 188static void kvm_openpic_init(Object *obj)
 189{
 190    KVMOpenPICState *opp = KVM_OPENPIC(obj);
 191
 192    memory_region_init_io(&opp->mem, OBJECT(opp), &kvm_openpic_mem_ops, opp,
 193                          "kvm-openpic", 0x40000);
 194}
 195
 196static void kvm_openpic_realize(DeviceState *dev, Error **errp)
 197{
 198    SysBusDevice *d = SYS_BUS_DEVICE(dev);
 199    KVMOpenPICState *opp = KVM_OPENPIC(dev);
 200    KVMState *s = kvm_state;
 201    int kvm_openpic_model;
 202    struct kvm_create_device cd = {0};
 203    int ret, i;
 204
 205    if (!kvm_check_extension(s, KVM_CAP_DEVICE_CTRL)) {
 206        error_setg(errp, "Kernel is lacking Device Control API");
 207        return;
 208    }
 209
 210    switch (opp->model) {
 211    case OPENPIC_MODEL_FSL_MPIC_20:
 212        kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_20;
 213        break;
 214
 215    case OPENPIC_MODEL_FSL_MPIC_42:
 216        kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_42;
 217        break;
 218
 219    default:
 220        error_setg(errp, "Unsupported OpenPIC model %" PRIu32, opp->model);
 221        return;
 222    }
 223
 224    cd.type = kvm_openpic_model;
 225    ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &cd);
 226    if (ret < 0) {
 227        error_setg(errp, "Can't create device %d: %s",
 228                   cd.type, strerror(errno));
 229        return;
 230    }
 231    opp->fd = cd.fd;
 232
 233    sysbus_init_mmio(d, &opp->mem);
 234    qdev_init_gpio_in(dev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ);
 235
 236    opp->mem_listener.region_add = kvm_openpic_region_add;
 237    opp->mem_listener.region_del = kvm_openpic_region_del;
 238    memory_listener_register(&opp->mem_listener, &address_space_memory);
 239
 240    /* indicate pic capabilities */
 241    msi_supported = true;
 242    kvm_kernel_irqchip = true;
 243    kvm_async_interrupts_allowed = true;
 244
 245    /* set up irq routing */
 246    kvm_init_irq_routing(kvm_state);
 247    for (i = 0; i < 256; ++i) {
 248        kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
 249    }
 250
 251    kvm_msi_via_irqfd_allowed = true;
 252    kvm_gsi_routing_allowed = true;
 253
 254    kvm_irqchip_commit_routes(s);
 255}
 256
 257int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
 258{
 259    KVMOpenPICState *opp = KVM_OPENPIC(d);
 260
 261    return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
 262                               kvm_arch_vcpu_id(cs));
 263}
 264
 265static Property kvm_openpic_properties[] = {
 266    DEFINE_PROP_UINT32("model", KVMOpenPICState, model,
 267                       OPENPIC_MODEL_FSL_MPIC_20),
 268    DEFINE_PROP_END_OF_LIST(),
 269};
 270
 271static void kvm_openpic_class_init(ObjectClass *oc, void *data)
 272{
 273    DeviceClass *dc = DEVICE_CLASS(oc);
 274
 275    dc->realize = kvm_openpic_realize;
 276    dc->props = kvm_openpic_properties;
 277    dc->reset = kvm_openpic_reset;
 278    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 279}
 280
 281static const TypeInfo kvm_openpic_info = {
 282    .name          = TYPE_KVM_OPENPIC,
 283    .parent        = TYPE_SYS_BUS_DEVICE,
 284    .instance_size = sizeof(KVMOpenPICState),
 285    .instance_init = kvm_openpic_init,
 286    .class_init    = kvm_openpic_class_init,
 287};
 288
 289static void kvm_openpic_register_types(void)
 290{
 291    type_register_static(&kvm_openpic_info);
 292}
 293
 294type_init(kvm_openpic_register_types)
 295