111ad93f6SDavid Gibson /* 211ad93f6SDavid Gibson * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator 311ad93f6SDavid Gibson * 411ad93f6SDavid Gibson * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics, in-kernel emulation 511ad93f6SDavid Gibson * 611ad93f6SDavid Gibson * Copyright (c) 2013 David Gibson, IBM Corporation. 711ad93f6SDavid Gibson * 811ad93f6SDavid Gibson * Permission is hereby granted, free of charge, to any person obtaining a copy 911ad93f6SDavid Gibson * of this software and associated documentation files (the "Software"), to deal 1011ad93f6SDavid Gibson * in the Software without restriction, including without limitation the rights 1111ad93f6SDavid Gibson * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1211ad93f6SDavid Gibson * copies of the Software, and to permit persons to whom the Software is 1311ad93f6SDavid Gibson * furnished to do so, subject to the following conditions: 1411ad93f6SDavid Gibson * 1511ad93f6SDavid Gibson * The above copyright notice and this permission notice shall be included in 1611ad93f6SDavid Gibson * all copies or substantial portions of the Software. 1711ad93f6SDavid Gibson * 1811ad93f6SDavid Gibson * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1911ad93f6SDavid Gibson * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2011ad93f6SDavid Gibson * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2111ad93f6SDavid Gibson * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2211ad93f6SDavid Gibson * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2311ad93f6SDavid Gibson * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2411ad93f6SDavid Gibson * THE SOFTWARE. 2511ad93f6SDavid Gibson * 2611ad93f6SDavid Gibson */ 2711ad93f6SDavid Gibson 280d75590dSPeter Maydell #include "qemu/osdep.h" 29da34e65cSMarkus Armbruster #include "qapi/error.h" 304771d756SPaolo Bonzini #include "qemu-common.h" 314771d756SPaolo Bonzini #include "cpu.h" 3211ad93f6SDavid Gibson #include "hw/hw.h" 3311ad93f6SDavid Gibson #include "trace.h" 3477ac58ddSPaolo Bonzini #include "sysemu/kvm.h" 3511ad93f6SDavid Gibson #include "hw/ppc/spapr.h" 3611ad93f6SDavid Gibson #include "hw/ppc/xics.h" 3711ad93f6SDavid Gibson #include "kvm_ppc.h" 3811ad93f6SDavid Gibson #include "qemu/config-file.h" 3911ad93f6SDavid Gibson #include "qemu/error-report.h" 4011ad93f6SDavid Gibson 4111ad93f6SDavid Gibson #include <sys/ioctl.h> 4211ad93f6SDavid Gibson 43729f8a4fSCédric Le Goater static int kernel_xics_fd = -1; 44729f8a4fSCédric Le Goater 45de86ecccSGreg Kurz typedef struct KVMEnabledICP { 46de86ecccSGreg Kurz unsigned long vcpu_id; 47de86ecccSGreg Kurz QLIST_ENTRY(KVMEnabledICP) node; 48de86ecccSGreg Kurz } KVMEnabledICP; 49de86ecccSGreg Kurz 50de86ecccSGreg Kurz static QLIST_HEAD(, KVMEnabledICP) 51de86ecccSGreg Kurz kvm_enabled_icps = QLIST_HEAD_INITIALIZER(&kvm_enabled_icps); 52de86ecccSGreg Kurz 5311ad93f6SDavid Gibson /* 5411ad93f6SDavid Gibson * ICP-KVM 5511ad93f6SDavid Gibson */ 568e4fba20SCédric Le Goater static void icp_get_kvm_state(ICPState *icp) 5711ad93f6SDavid Gibson { 5811ad93f6SDavid Gibson uint64_t state; 5911ad93f6SDavid Gibson int ret; 6011ad93f6SDavid Gibson 6111ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 628e4fba20SCédric Le Goater if (!icp->cs) { 6311ad93f6SDavid Gibson return; 6411ad93f6SDavid Gibson } 6511ad93f6SDavid Gibson 66bf358b54SCédric Le Goater ret = kvm_get_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state); 6711ad93f6SDavid Gibson if (ret != 0) { 6811ad93f6SDavid Gibson error_report("Unable to retrieve KVM interrupt controller state" 698e4fba20SCédric Le Goater " for CPU %ld: %s", kvm_arch_vcpu_id(icp->cs), strerror(errno)); 7011ad93f6SDavid Gibson exit(1); 7111ad93f6SDavid Gibson } 7211ad93f6SDavid Gibson 738e4fba20SCédric Le Goater icp->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT; 748e4fba20SCédric Le Goater icp->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT) 7511ad93f6SDavid Gibson & KVM_REG_PPC_ICP_MFRR_MASK; 768e4fba20SCédric Le Goater icp->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT) 7711ad93f6SDavid Gibson & KVM_REG_PPC_ICP_PPRI_MASK; 7811ad93f6SDavid Gibson } 7911ad93f6SDavid Gibson 80dcb556fcSGreg Kurz static void do_icp_synchronize_state(CPUState *cpu, run_on_cpu_data arg) 81dcb556fcSGreg Kurz { 82dcb556fcSGreg Kurz icp_get_kvm_state(arg.host_ptr); 83dcb556fcSGreg Kurz } 84dcb556fcSGreg Kurz 85dcb556fcSGreg Kurz static void icp_synchronize_state(ICPState *icp) 86dcb556fcSGreg Kurz { 87dcb556fcSGreg Kurz if (icp->cs) { 88dcb556fcSGreg Kurz run_on_cpu(icp->cs, do_icp_synchronize_state, RUN_ON_CPU_HOST_PTR(icp)); 89dcb556fcSGreg Kurz } 90dcb556fcSGreg Kurz } 91dcb556fcSGreg Kurz 928e4fba20SCédric Le Goater static int icp_set_kvm_state(ICPState *icp, int version_id) 9311ad93f6SDavid Gibson { 9411ad93f6SDavid Gibson uint64_t state; 9511ad93f6SDavid Gibson int ret; 9611ad93f6SDavid Gibson 9711ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 988e4fba20SCédric Le Goater if (!icp->cs) { 9911ad93f6SDavid Gibson return 0; 10011ad93f6SDavid Gibson } 10111ad93f6SDavid Gibson 1028e4fba20SCédric Le Goater state = ((uint64_t)icp->xirr << KVM_REG_PPC_ICP_XISR_SHIFT) 1038e4fba20SCédric Le Goater | ((uint64_t)icp->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) 1048e4fba20SCédric Le Goater | ((uint64_t)icp->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT); 10511ad93f6SDavid Gibson 106bf358b54SCédric Le Goater ret = kvm_set_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state); 10711ad93f6SDavid Gibson if (ret != 0) { 10811ad93f6SDavid Gibson error_report("Unable to restore KVM interrupt controller state (0x%" 1098e4fba20SCédric Le Goater PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(icp->cs), 11011ad93f6SDavid Gibson strerror(errno)); 11111ad93f6SDavid Gibson return ret; 11211ad93f6SDavid Gibson } 11311ad93f6SDavid Gibson 11411ad93f6SDavid Gibson return 0; 11511ad93f6SDavid Gibson } 11611ad93f6SDavid Gibson 117a028dd42SCédric Le Goater static void icp_kvm_reset(DeviceState *dev) 11811ad93f6SDavid Gibson { 119a028dd42SCédric Le Goater ICPStateClass *icpc = ICP_GET_CLASS(dev); 120a028dd42SCédric Le Goater 121a028dd42SCédric Le Goater icpc->parent_reset(dev); 122a028dd42SCédric Le Goater 123a028dd42SCédric Le Goater icp_set_kvm_state(ICP(dev), 1); 12411ad93f6SDavid Gibson } 12511ad93f6SDavid Gibson 126a028dd42SCédric Le Goater static void icp_kvm_realize(DeviceState *dev, Error **errp) 127f0232434SCédric Le Goater { 128a028dd42SCédric Le Goater ICPState *icp = ICP(dev); 129a028dd42SCédric Le Goater ICPStateClass *icpc = ICP_GET_CLASS(icp); 130a028dd42SCédric Le Goater Error *local_err = NULL; 131a028dd42SCédric Le Goater CPUState *cs; 132de86ecccSGreg Kurz KVMEnabledICP *enabled_icp; 133a028dd42SCédric Le Goater unsigned long vcpu_id; 134f0232434SCédric Le Goater int ret; 135f0232434SCédric Le Goater 136f0232434SCédric Le Goater if (kernel_xics_fd == -1) { 137f0232434SCédric Le Goater abort(); 138f0232434SCédric Le Goater } 139f0232434SCédric Le Goater 140a028dd42SCédric Le Goater icpc->parent_realize(dev, &local_err); 141a028dd42SCédric Le Goater if (local_err) { 142a028dd42SCédric Le Goater error_propagate(errp, local_err); 143a028dd42SCédric Le Goater return; 144a028dd42SCédric Le Goater } 145a028dd42SCédric Le Goater 146a028dd42SCédric Le Goater cs = icp->cs; 147a028dd42SCédric Le Goater vcpu_id = kvm_arch_vcpu_id(cs); 148a028dd42SCédric Le Goater 149f0232434SCédric Le Goater /* 150f0232434SCédric Le Goater * If we are reusing a parked vCPU fd corresponding to the CPU 151f0232434SCédric Le Goater * which was hot-removed earlier we don't have to renable 152f0232434SCédric Le Goater * KVM_CAP_IRQ_XICS capability again. 153f0232434SCédric Le Goater */ 154de86ecccSGreg Kurz QLIST_FOREACH(enabled_icp, &kvm_enabled_icps, node) { 155de86ecccSGreg Kurz if (enabled_icp->vcpu_id == vcpu_id) { 156f0232434SCédric Le Goater return; 157f0232434SCédric Le Goater } 158de86ecccSGreg Kurz } 159f0232434SCédric Le Goater 160de86ecccSGreg Kurz ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, vcpu_id); 161f0232434SCédric Le Goater if (ret < 0) { 162b1fd36c3SGreg Kurz error_setg(errp, "Unable to connect CPU%ld to kernel XICS: %s", vcpu_id, 163de86ecccSGreg Kurz strerror(errno)); 164b1fd36c3SGreg Kurz return; 165f0232434SCédric Le Goater } 166de86ecccSGreg Kurz enabled_icp = g_malloc(sizeof(*enabled_icp)); 167de86ecccSGreg Kurz enabled_icp->vcpu_id = vcpu_id; 168de86ecccSGreg Kurz QLIST_INSERT_HEAD(&kvm_enabled_icps, enabled_icp, node); 169f0232434SCédric Le Goater } 170f0232434SCédric Le Goater 17111ad93f6SDavid Gibson static void icp_kvm_class_init(ObjectClass *klass, void *data) 17211ad93f6SDavid Gibson { 173a028dd42SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 17411ad93f6SDavid Gibson ICPStateClass *icpc = ICP_CLASS(klass); 17511ad93f6SDavid Gibson 176a028dd42SCédric Le Goater device_class_set_parent_realize(dc, icp_kvm_realize, 177a028dd42SCédric Le Goater &icpc->parent_realize); 178a028dd42SCédric Le Goater device_class_set_parent_reset(dc, icp_kvm_reset, 179a028dd42SCédric Le Goater &icpc->parent_reset); 180a028dd42SCédric Le Goater 18111ad93f6SDavid Gibson icpc->pre_save = icp_get_kvm_state; 18211ad93f6SDavid Gibson icpc->post_load = icp_set_kvm_state; 183dcb556fcSGreg Kurz icpc->synchronize_state = icp_synchronize_state; 18411ad93f6SDavid Gibson } 18511ad93f6SDavid Gibson 18611ad93f6SDavid Gibson static const TypeInfo icp_kvm_info = { 18711ad93f6SDavid Gibson .name = TYPE_KVM_ICP, 18811ad93f6SDavid Gibson .parent = TYPE_ICP, 18911ad93f6SDavid Gibson .instance_size = sizeof(ICPState), 19011ad93f6SDavid Gibson .class_init = icp_kvm_class_init, 19111ad93f6SDavid Gibson .class_size = sizeof(ICPStateClass), 19211ad93f6SDavid Gibson }; 19311ad93f6SDavid Gibson 19411ad93f6SDavid Gibson /* 19511ad93f6SDavid Gibson * ICS-KVM 19611ad93f6SDavid Gibson */ 19711ad93f6SDavid Gibson static void ics_get_kvm_state(ICSState *ics) 19811ad93f6SDavid Gibson { 19911ad93f6SDavid Gibson uint64_t state; 20011ad93f6SDavid Gibson int i; 201bf358b54SCédric Le Goater Error *local_err = NULL; 20211ad93f6SDavid Gibson 20311ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 20411ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 20511ad93f6SDavid Gibson 206bf358b54SCédric Le Goater kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, 207bf358b54SCédric Le Goater i + ics->offset, &state, false, &local_err); 208bf358b54SCédric Le Goater if (local_err) { 20952b43881SCédric Le Goater error_report_err(local_err); 21011ad93f6SDavid Gibson exit(1); 21111ad93f6SDavid Gibson } 21211ad93f6SDavid Gibson 21311ad93f6SDavid Gibson irq->server = state & KVM_XICS_DESTINATION_MASK; 21411ad93f6SDavid Gibson irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT) 21511ad93f6SDavid Gibson & KVM_XICS_PRIORITY_MASK; 21611ad93f6SDavid Gibson /* 21711ad93f6SDavid Gibson * To be consistent with the software emulation in xics.c, we 21811ad93f6SDavid Gibson * split out the masked state + priority that we get from the 21911ad93f6SDavid Gibson * kernel into 'current priority' (0xff if masked) and 22011ad93f6SDavid Gibson * 'saved priority' (if masked, this is the priority the 22111ad93f6SDavid Gibson * interrupt had before it was masked). Masking and unmasking 22211ad93f6SDavid Gibson * are done with the ibm,int-off and ibm,int-on RTAS calls. 22311ad93f6SDavid Gibson */ 22411ad93f6SDavid Gibson if (state & KVM_XICS_MASKED) { 22511ad93f6SDavid Gibson irq->priority = 0xff; 22611ad93f6SDavid Gibson } else { 22711ad93f6SDavid Gibson irq->priority = irq->saved_priority; 22811ad93f6SDavid Gibson } 22911ad93f6SDavid Gibson 230063cb7cbSSam Bobroff irq->status = 0; 23111ad93f6SDavid Gibson if (state & KVM_XICS_PENDING) { 23211ad93f6SDavid Gibson if (state & KVM_XICS_LEVEL_SENSITIVE) { 23311ad93f6SDavid Gibson irq->status |= XICS_STATUS_ASSERTED; 23411ad93f6SDavid Gibson } else { 23511ad93f6SDavid Gibson /* 23611ad93f6SDavid Gibson * A pending edge-triggered interrupt (or MSI) 23711ad93f6SDavid Gibson * must have been rejected previously when we 23811ad93f6SDavid Gibson * first detected it and tried to deliver it, 23911ad93f6SDavid Gibson * so mark it as pending and previously rejected 24011ad93f6SDavid Gibson * for consistency with how xics.c works. 24111ad93f6SDavid Gibson */ 24211ad93f6SDavid Gibson irq->status |= XICS_STATUS_MASKED_PENDING 24311ad93f6SDavid Gibson | XICS_STATUS_REJECTED; 24411ad93f6SDavid Gibson } 24511ad93f6SDavid Gibson } 246229e16fdSSam Bobroff if (state & KVM_XICS_PRESENTED) { 247229e16fdSSam Bobroff irq->status |= XICS_STATUS_PRESENTED; 248229e16fdSSam Bobroff } 249229e16fdSSam Bobroff if (state & KVM_XICS_QUEUED) { 250229e16fdSSam Bobroff irq->status |= XICS_STATUS_QUEUED; 251229e16fdSSam Bobroff } 25211ad93f6SDavid Gibson } 25311ad93f6SDavid Gibson } 25411ad93f6SDavid Gibson 255dcb556fcSGreg Kurz static void ics_synchronize_state(ICSState *ics) 256dcb556fcSGreg Kurz { 257dcb556fcSGreg Kurz ics_get_kvm_state(ics); 258dcb556fcSGreg Kurz } 259dcb556fcSGreg Kurz 26011ad93f6SDavid Gibson static int ics_set_kvm_state(ICSState *ics, int version_id) 26111ad93f6SDavid Gibson { 26211ad93f6SDavid Gibson uint64_t state; 26311ad93f6SDavid Gibson int i; 264bf358b54SCédric Le Goater Error *local_err = NULL; 26511ad93f6SDavid Gibson 26611ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 26711ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 26811ad93f6SDavid Gibson int ret; 26911ad93f6SDavid Gibson 27011ad93f6SDavid Gibson state = irq->server; 27111ad93f6SDavid Gibson state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK) 27211ad93f6SDavid Gibson << KVM_XICS_PRIORITY_SHIFT; 27311ad93f6SDavid Gibson if (irq->priority != irq->saved_priority) { 27411ad93f6SDavid Gibson assert(irq->priority == 0xff); 27511ad93f6SDavid Gibson state |= KVM_XICS_MASKED; 27611ad93f6SDavid Gibson } 27711ad93f6SDavid Gibson 2784af88944SAlexey Kardashevskiy if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) { 27911ad93f6SDavid Gibson state |= KVM_XICS_LEVEL_SENSITIVE; 28011ad93f6SDavid Gibson if (irq->status & XICS_STATUS_ASSERTED) { 28111ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 28211ad93f6SDavid Gibson } 28311ad93f6SDavid Gibson } else { 28411ad93f6SDavid Gibson if (irq->status & XICS_STATUS_MASKED_PENDING) { 28511ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 28611ad93f6SDavid Gibson } 28711ad93f6SDavid Gibson } 288229e16fdSSam Bobroff if (irq->status & XICS_STATUS_PRESENTED) { 289229e16fdSSam Bobroff state |= KVM_XICS_PRESENTED; 290229e16fdSSam Bobroff } 291229e16fdSSam Bobroff if (irq->status & XICS_STATUS_QUEUED) { 292229e16fdSSam Bobroff state |= KVM_XICS_QUEUED; 293229e16fdSSam Bobroff } 29411ad93f6SDavid Gibson 29552b43881SCédric Le Goater ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, 296bf358b54SCédric Le Goater i + ics->offset, &state, true, &local_err); 297bf358b54SCédric Le Goater if (local_err) { 29852b43881SCédric Le Goater error_report_err(local_err); 29911ad93f6SDavid Gibson return ret; 30011ad93f6SDavid Gibson } 30111ad93f6SDavid Gibson } 30211ad93f6SDavid Gibson 30311ad93f6SDavid Gibson return 0; 30411ad93f6SDavid Gibson } 30511ad93f6SDavid Gibson 30611ad93f6SDavid Gibson static void ics_kvm_set_irq(void *opaque, int srcno, int val) 30711ad93f6SDavid Gibson { 30811ad93f6SDavid Gibson ICSState *ics = opaque; 30911ad93f6SDavid Gibson struct kvm_irq_level args; 31011ad93f6SDavid Gibson int rc; 31111ad93f6SDavid Gibson 31211ad93f6SDavid Gibson args.irq = srcno + ics->offset; 3134af88944SAlexey Kardashevskiy if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) { 31411ad93f6SDavid Gibson if (!val) { 31511ad93f6SDavid Gibson return; 31611ad93f6SDavid Gibson } 31711ad93f6SDavid Gibson args.level = KVM_INTERRUPT_SET; 31811ad93f6SDavid Gibson } else { 31911ad93f6SDavid Gibson args.level = val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; 32011ad93f6SDavid Gibson } 32111ad93f6SDavid Gibson rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args); 32211ad93f6SDavid Gibson if (rc < 0) { 32311ad93f6SDavid Gibson perror("kvm_irq_line"); 32411ad93f6SDavid Gibson } 32511ad93f6SDavid Gibson } 32611ad93f6SDavid Gibson 327*eeefd43bSCédric Le Goater static void ics_kvm_reset(DeviceState *dev) 32811ad93f6SDavid Gibson { 329*eeefd43bSCédric Le Goater ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev); 330a7e519a8SAlexey Kardashevskiy 331*eeefd43bSCédric Le Goater icsc->parent_reset(dev); 332*eeefd43bSCédric Le Goater 333*eeefd43bSCédric Le Goater ics_set_kvm_state(ICS_KVM(dev), 1); 334a7e519a8SAlexey Kardashevskiy } 335fb0e843aSAlexey Kardashevskiy 336*eeefd43bSCédric Le Goater static void ics_kvm_reset_handler(void *dev) 337*eeefd43bSCédric Le Goater { 338*eeefd43bSCédric Le Goater ics_kvm_reset(dev); 33911ad93f6SDavid Gibson } 34011ad93f6SDavid Gibson 3410a647b76SCédric Le Goater static void ics_kvm_realize(DeviceState *dev, Error **errp) 34211ad93f6SDavid Gibson { 3430a647b76SCédric Le Goater ICSState *ics = ICS_KVM(dev); 3440a647b76SCédric Le Goater ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics); 3450a647b76SCédric Le Goater Error *local_err = NULL; 3460a647b76SCédric Le Goater 3470a647b76SCédric Le Goater icsc->parent_realize(dev, &local_err); 3480a647b76SCédric Le Goater if (local_err) { 3490a647b76SCédric Le Goater error_propagate(errp, local_err); 35011ad93f6SDavid Gibson return; 35111ad93f6SDavid Gibson } 35211ad93f6SDavid Gibson ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs); 3537ea6e067SCédric Le Goater 354*eeefd43bSCédric Le Goater qemu_register_reset(ics_kvm_reset_handler, ics); 35511ad93f6SDavid Gibson } 35611ad93f6SDavid Gibson 35711ad93f6SDavid Gibson static void ics_kvm_class_init(ObjectClass *klass, void *data) 35811ad93f6SDavid Gibson { 359d4d7a59aSBenjamin Herrenschmidt ICSStateClass *icsc = ICS_BASE_CLASS(klass); 3600a647b76SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 36111ad93f6SDavid Gibson 3620a647b76SCédric Le Goater /* 3630a647b76SCédric Le Goater * Use device_class_set_parent_realize() when ics-kvm inherits 3640a647b76SCédric Le Goater * directly from ics-base and not from ics-simple anymore. 3650a647b76SCédric Le Goater */ 3660a647b76SCédric Le Goater dc->realize = ics_kvm_realize; 367*eeefd43bSCédric Le Goater dc->reset = ics_kvm_reset; 3680a647b76SCédric Le Goater 36911ad93f6SDavid Gibson icsc->pre_save = ics_get_kvm_state; 37011ad93f6SDavid Gibson icsc->post_load = ics_set_kvm_state; 371dcb556fcSGreg Kurz icsc->synchronize_state = ics_synchronize_state; 37211ad93f6SDavid Gibson } 37311ad93f6SDavid Gibson 37411ad93f6SDavid Gibson static const TypeInfo ics_kvm_info = { 375d4d7a59aSBenjamin Herrenschmidt .name = TYPE_ICS_KVM, 376d4d7a59aSBenjamin Herrenschmidt .parent = TYPE_ICS_SIMPLE, 37711ad93f6SDavid Gibson .instance_size = sizeof(ICSState), 37811ad93f6SDavid Gibson .class_init = ics_kvm_class_init, 37911ad93f6SDavid Gibson }; 38011ad93f6SDavid Gibson 38111ad93f6SDavid Gibson /* 38211ad93f6SDavid Gibson * XICS-KVM 38311ad93f6SDavid Gibson */ 38411ad93f6SDavid Gibson 38528e02042SDavid Gibson static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr, 38611ad93f6SDavid Gibson uint32_t token, 38711ad93f6SDavid Gibson uint32_t nargs, target_ulong args, 38811ad93f6SDavid Gibson uint32_t nret, target_ulong rets) 38911ad93f6SDavid Gibson { 39011ad93f6SDavid Gibson error_report("pseries: %s must never be called for in-kernel XICS", 39111ad93f6SDavid Gibson __func__); 39211ad93f6SDavid Gibson } 39311ad93f6SDavid Gibson 3942192a930SCédric Le Goater int xics_kvm_init(sPAPRMachineState *spapr, Error **errp) 39511ad93f6SDavid Gibson { 396817bb6a4SCédric Le Goater int rc; 39711ad93f6SDavid Gibson 39811ad93f6SDavid Gibson if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) { 39911ad93f6SDavid Gibson error_setg(errp, 40011ad93f6SDavid Gibson "KVM and IRQ_XICS capability must be present for in-kernel XICS"); 40111ad93f6SDavid Gibson goto fail; 40211ad93f6SDavid Gibson } 40311ad93f6SDavid Gibson 4043a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_dummy); 4053a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_dummy); 4063a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_dummy); 4073a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_dummy); 40811ad93f6SDavid Gibson 4093a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive"); 41011ad93f6SDavid Gibson if (rc < 0) { 41111ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive"); 41211ad93f6SDavid Gibson goto fail; 41311ad93f6SDavid Gibson } 41411ad93f6SDavid Gibson 4153a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive"); 41611ad93f6SDavid Gibson if (rc < 0) { 41711ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive"); 41811ad93f6SDavid Gibson goto fail; 41911ad93f6SDavid Gibson } 42011ad93f6SDavid Gibson 4213a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on"); 42211ad93f6SDavid Gibson if (rc < 0) { 42311ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on"); 42411ad93f6SDavid Gibson goto fail; 42511ad93f6SDavid Gibson } 42611ad93f6SDavid Gibson 4273a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off"); 42811ad93f6SDavid Gibson if (rc < 0) { 42911ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off"); 43011ad93f6SDavid Gibson goto fail; 43111ad93f6SDavid Gibson } 43211ad93f6SDavid Gibson 433bf358b54SCédric Le Goater /* Create the KVM XICS device */ 434bf358b54SCédric Le Goater rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false); 43511ad93f6SDavid Gibson if (rc < 0) { 43611ad93f6SDavid Gibson error_setg_errno(errp, -rc, "Error on KVM_CREATE_DEVICE for XICS"); 43711ad93f6SDavid Gibson goto fail; 43811ad93f6SDavid Gibson } 43911ad93f6SDavid Gibson 440bf358b54SCédric Le Goater kernel_xics_fd = rc; 4419554233cSAlexey Kardashevskiy kvm_kernel_irqchip = true; 4429554233cSAlexey Kardashevskiy kvm_msi_via_irqfd_allowed = true; 4439554233cSAlexey Kardashevskiy kvm_gsi_direct_mapping = true; 4449554233cSAlexey Kardashevskiy 445bf358b54SCédric Le Goater return 0; 44611ad93f6SDavid Gibson 44711ad93f6SDavid Gibson fail: 44811ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); 44911ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); 45011ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); 45111ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); 4522192a930SCédric Le Goater return -1; 45311ad93f6SDavid Gibson } 45411ad93f6SDavid Gibson 45511ad93f6SDavid Gibson static void xics_kvm_register_types(void) 45611ad93f6SDavid Gibson { 45711ad93f6SDavid Gibson type_register_static(&ics_kvm_info); 45811ad93f6SDavid Gibson type_register_static(&icp_kvm_info); 45911ad93f6SDavid Gibson } 46011ad93f6SDavid Gibson 46111ad93f6SDavid Gibson type_init(xics_kvm_register_types) 462