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