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 4511ad93f6SDavid Gibson /* 4611ad93f6SDavid Gibson * ICP-KVM 4711ad93f6SDavid Gibson */ 48*8e4fba20SCédric Le Goater static void icp_get_kvm_state(ICPState *icp) 4911ad93f6SDavid Gibson { 5011ad93f6SDavid Gibson uint64_t state; 5111ad93f6SDavid Gibson struct kvm_one_reg reg = { 5211ad93f6SDavid Gibson .id = KVM_REG_PPC_ICP_STATE, 5311ad93f6SDavid Gibson .addr = (uintptr_t)&state, 5411ad93f6SDavid Gibson }; 5511ad93f6SDavid Gibson int ret; 5611ad93f6SDavid Gibson 5711ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 58*8e4fba20SCédric Le Goater if (!icp->cs) { 5911ad93f6SDavid Gibson return; 6011ad93f6SDavid Gibson } 6111ad93f6SDavid Gibson 62*8e4fba20SCédric Le Goater ret = kvm_vcpu_ioctl(icp->cs, KVM_GET_ONE_REG, ®); 6311ad93f6SDavid Gibson if (ret != 0) { 6411ad93f6SDavid Gibson error_report("Unable to retrieve KVM interrupt controller state" 65*8e4fba20SCédric Le Goater " for CPU %ld: %s", kvm_arch_vcpu_id(icp->cs), strerror(errno)); 6611ad93f6SDavid Gibson exit(1); 6711ad93f6SDavid Gibson } 6811ad93f6SDavid Gibson 69*8e4fba20SCédric Le Goater icp->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT; 70*8e4fba20SCédric Le Goater icp->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT) 7111ad93f6SDavid Gibson & KVM_REG_PPC_ICP_MFRR_MASK; 72*8e4fba20SCédric Le Goater icp->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT) 7311ad93f6SDavid Gibson & KVM_REG_PPC_ICP_PPRI_MASK; 7411ad93f6SDavid Gibson } 7511ad93f6SDavid Gibson 76*8e4fba20SCédric Le Goater static int icp_set_kvm_state(ICPState *icp, int version_id) 7711ad93f6SDavid Gibson { 7811ad93f6SDavid Gibson uint64_t state; 7911ad93f6SDavid Gibson struct kvm_one_reg reg = { 8011ad93f6SDavid Gibson .id = KVM_REG_PPC_ICP_STATE, 8111ad93f6SDavid Gibson .addr = (uintptr_t)&state, 8211ad93f6SDavid Gibson }; 8311ad93f6SDavid Gibson int ret; 8411ad93f6SDavid Gibson 8511ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 86*8e4fba20SCédric Le Goater if (!icp->cs) { 8711ad93f6SDavid Gibson return 0; 8811ad93f6SDavid Gibson } 8911ad93f6SDavid Gibson 90*8e4fba20SCédric Le Goater state = ((uint64_t)icp->xirr << KVM_REG_PPC_ICP_XISR_SHIFT) 91*8e4fba20SCédric Le Goater | ((uint64_t)icp->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) 92*8e4fba20SCédric Le Goater | ((uint64_t)icp->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT); 9311ad93f6SDavid Gibson 94*8e4fba20SCédric Le Goater ret = kvm_vcpu_ioctl(icp->cs, KVM_SET_ONE_REG, ®); 9511ad93f6SDavid Gibson if (ret != 0) { 9611ad93f6SDavid Gibson error_report("Unable to restore KVM interrupt controller state (0x%" 97*8e4fba20SCédric Le Goater PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(icp->cs), 9811ad93f6SDavid Gibson strerror(errno)); 9911ad93f6SDavid Gibson return ret; 10011ad93f6SDavid Gibson } 10111ad93f6SDavid Gibson 10211ad93f6SDavid Gibson return 0; 10311ad93f6SDavid Gibson } 10411ad93f6SDavid Gibson 10511ad93f6SDavid Gibson static void icp_kvm_reset(DeviceState *dev) 10611ad93f6SDavid Gibson { 10711ad93f6SDavid Gibson ICPState *icp = ICP(dev); 10811ad93f6SDavid Gibson 10911ad93f6SDavid Gibson icp->xirr = 0; 11011ad93f6SDavid Gibson icp->pending_priority = 0xff; 11111ad93f6SDavid Gibson icp->mfrr = 0xff; 11211ad93f6SDavid Gibson 1134a4b344cSBharata B Rao /* Make all outputs as deasserted only if the CPU thread is in use */ 1144a4b344cSBharata B Rao if (icp->output) { 11511ad93f6SDavid Gibson qemu_set_irq(icp->output, 0); 1164a4b344cSBharata B Rao } 11711ad93f6SDavid Gibson 11811ad93f6SDavid Gibson icp_set_kvm_state(icp, 1); 11911ad93f6SDavid Gibson } 12011ad93f6SDavid Gibson 121*8e4fba20SCédric Le Goater static void icp_kvm_cpu_setup(ICPState *icp, PowerPCCPU *cpu) 122f0232434SCédric Le Goater { 123f0232434SCédric Le Goater CPUState *cs = CPU(cpu); 124f0232434SCédric Le Goater int ret; 125f0232434SCédric Le Goater 126f0232434SCédric Le Goater if (kernel_xics_fd == -1) { 127f0232434SCédric Le Goater abort(); 128f0232434SCédric Le Goater } 129f0232434SCédric Le Goater 130f0232434SCédric Le Goater /* 131f0232434SCédric Le Goater * If we are reusing a parked vCPU fd corresponding to the CPU 132f0232434SCédric Le Goater * which was hot-removed earlier we don't have to renable 133f0232434SCédric Le Goater * KVM_CAP_IRQ_XICS capability again. 134f0232434SCédric Le Goater */ 135*8e4fba20SCédric Le Goater if (icp->cap_irq_xics_enabled) { 136f0232434SCédric Le Goater return; 137f0232434SCédric Le Goater } 138f0232434SCédric Le Goater 139f0232434SCédric Le Goater ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, 140f0232434SCédric Le Goater kvm_arch_vcpu_id(cs)); 141f0232434SCédric Le Goater if (ret < 0) { 142f0232434SCédric Le Goater error_report("Unable to connect CPU%ld to kernel XICS: %s", 143f0232434SCédric Le Goater kvm_arch_vcpu_id(cs), strerror(errno)); 144f0232434SCédric Le Goater exit(1); 145f0232434SCédric Le Goater } 146*8e4fba20SCédric Le Goater icp->cap_irq_xics_enabled = true; 147f0232434SCédric Le Goater } 148f0232434SCédric Le Goater 14911ad93f6SDavid Gibson static void icp_kvm_class_init(ObjectClass *klass, void *data) 15011ad93f6SDavid Gibson { 15111ad93f6SDavid Gibson DeviceClass *dc = DEVICE_CLASS(klass); 15211ad93f6SDavid Gibson ICPStateClass *icpc = ICP_CLASS(klass); 15311ad93f6SDavid Gibson 15411ad93f6SDavid Gibson dc->reset = icp_kvm_reset; 15511ad93f6SDavid Gibson icpc->pre_save = icp_get_kvm_state; 15611ad93f6SDavid Gibson icpc->post_load = icp_set_kvm_state; 157f0232434SCédric Le Goater icpc->cpu_setup = icp_kvm_cpu_setup; 15811ad93f6SDavid Gibson } 15911ad93f6SDavid Gibson 16011ad93f6SDavid Gibson static const TypeInfo icp_kvm_info = { 16111ad93f6SDavid Gibson .name = TYPE_KVM_ICP, 16211ad93f6SDavid Gibson .parent = TYPE_ICP, 16311ad93f6SDavid Gibson .instance_size = sizeof(ICPState), 16411ad93f6SDavid Gibson .class_init = icp_kvm_class_init, 16511ad93f6SDavid Gibson .class_size = sizeof(ICPStateClass), 16611ad93f6SDavid Gibson }; 16711ad93f6SDavid Gibson 16811ad93f6SDavid Gibson /* 16911ad93f6SDavid Gibson * ICS-KVM 17011ad93f6SDavid Gibson */ 17111ad93f6SDavid Gibson static void ics_get_kvm_state(ICSState *ics) 17211ad93f6SDavid Gibson { 17311ad93f6SDavid Gibson uint64_t state; 17411ad93f6SDavid Gibson struct kvm_device_attr attr = { 17511ad93f6SDavid Gibson .flags = 0, 17611ad93f6SDavid Gibson .group = KVM_DEV_XICS_GRP_SOURCES, 17711ad93f6SDavid Gibson .addr = (uint64_t)(uintptr_t)&state, 17811ad93f6SDavid Gibson }; 17911ad93f6SDavid Gibson int i; 18011ad93f6SDavid Gibson 18111ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 18211ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 18311ad93f6SDavid Gibson int ret; 18411ad93f6SDavid Gibson 18511ad93f6SDavid Gibson attr.attr = i + ics->offset; 18611ad93f6SDavid Gibson 187729f8a4fSCédric Le Goater ret = ioctl(kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr); 18811ad93f6SDavid Gibson if (ret != 0) { 18911ad93f6SDavid Gibson error_report("Unable to retrieve KVM interrupt controller state" 19011ad93f6SDavid Gibson " for IRQ %d: %s", i + ics->offset, strerror(errno)); 19111ad93f6SDavid Gibson exit(1); 19211ad93f6SDavid Gibson } 19311ad93f6SDavid Gibson 19411ad93f6SDavid Gibson irq->server = state & KVM_XICS_DESTINATION_MASK; 19511ad93f6SDavid Gibson irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT) 19611ad93f6SDavid Gibson & KVM_XICS_PRIORITY_MASK; 19711ad93f6SDavid Gibson /* 19811ad93f6SDavid Gibson * To be consistent with the software emulation in xics.c, we 19911ad93f6SDavid Gibson * split out the masked state + priority that we get from the 20011ad93f6SDavid Gibson * kernel into 'current priority' (0xff if masked) and 20111ad93f6SDavid Gibson * 'saved priority' (if masked, this is the priority the 20211ad93f6SDavid Gibson * interrupt had before it was masked). Masking and unmasking 20311ad93f6SDavid Gibson * are done with the ibm,int-off and ibm,int-on RTAS calls. 20411ad93f6SDavid Gibson */ 20511ad93f6SDavid Gibson if (state & KVM_XICS_MASKED) { 20611ad93f6SDavid Gibson irq->priority = 0xff; 20711ad93f6SDavid Gibson } else { 20811ad93f6SDavid Gibson irq->priority = irq->saved_priority; 20911ad93f6SDavid Gibson } 21011ad93f6SDavid Gibson 21111ad93f6SDavid Gibson if (state & KVM_XICS_PENDING) { 21211ad93f6SDavid Gibson if (state & KVM_XICS_LEVEL_SENSITIVE) { 21311ad93f6SDavid Gibson irq->status |= XICS_STATUS_ASSERTED; 21411ad93f6SDavid Gibson } else { 21511ad93f6SDavid Gibson /* 21611ad93f6SDavid Gibson * A pending edge-triggered interrupt (or MSI) 21711ad93f6SDavid Gibson * must have been rejected previously when we 21811ad93f6SDavid Gibson * first detected it and tried to deliver it, 21911ad93f6SDavid Gibson * so mark it as pending and previously rejected 22011ad93f6SDavid Gibson * for consistency with how xics.c works. 22111ad93f6SDavid Gibson */ 22211ad93f6SDavid Gibson irq->status |= XICS_STATUS_MASKED_PENDING 22311ad93f6SDavid Gibson | XICS_STATUS_REJECTED; 22411ad93f6SDavid Gibson } 22511ad93f6SDavid Gibson } 22611ad93f6SDavid Gibson } 22711ad93f6SDavid Gibson } 22811ad93f6SDavid Gibson 22911ad93f6SDavid Gibson static int ics_set_kvm_state(ICSState *ics, int version_id) 23011ad93f6SDavid Gibson { 23111ad93f6SDavid Gibson uint64_t state; 23211ad93f6SDavid Gibson struct kvm_device_attr attr = { 23311ad93f6SDavid Gibson .flags = 0, 23411ad93f6SDavid Gibson .group = KVM_DEV_XICS_GRP_SOURCES, 23511ad93f6SDavid Gibson .addr = (uint64_t)(uintptr_t)&state, 23611ad93f6SDavid Gibson }; 23711ad93f6SDavid Gibson int i; 23811ad93f6SDavid Gibson 23911ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 24011ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 24111ad93f6SDavid Gibson int ret; 24211ad93f6SDavid Gibson 24311ad93f6SDavid Gibson attr.attr = i + ics->offset; 24411ad93f6SDavid Gibson 24511ad93f6SDavid Gibson state = irq->server; 24611ad93f6SDavid Gibson state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK) 24711ad93f6SDavid Gibson << KVM_XICS_PRIORITY_SHIFT; 24811ad93f6SDavid Gibson if (irq->priority != irq->saved_priority) { 24911ad93f6SDavid Gibson assert(irq->priority == 0xff); 25011ad93f6SDavid Gibson state |= KVM_XICS_MASKED; 25111ad93f6SDavid Gibson } 25211ad93f6SDavid Gibson 2534af88944SAlexey Kardashevskiy if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) { 25411ad93f6SDavid Gibson state |= KVM_XICS_LEVEL_SENSITIVE; 25511ad93f6SDavid Gibson if (irq->status & XICS_STATUS_ASSERTED) { 25611ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 25711ad93f6SDavid Gibson } 25811ad93f6SDavid Gibson } else { 25911ad93f6SDavid Gibson if (irq->status & XICS_STATUS_MASKED_PENDING) { 26011ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 26111ad93f6SDavid Gibson } 26211ad93f6SDavid Gibson } 26311ad93f6SDavid Gibson 264729f8a4fSCédric Le Goater ret = ioctl(kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); 26511ad93f6SDavid Gibson if (ret != 0) { 26611ad93f6SDavid Gibson error_report("Unable to restore KVM interrupt controller state" 26711ad93f6SDavid Gibson " for IRQs %d: %s", i + ics->offset, strerror(errno)); 26811ad93f6SDavid Gibson return ret; 26911ad93f6SDavid Gibson } 27011ad93f6SDavid Gibson } 27111ad93f6SDavid Gibson 27211ad93f6SDavid Gibson return 0; 27311ad93f6SDavid Gibson } 27411ad93f6SDavid Gibson 27511ad93f6SDavid Gibson static void ics_kvm_set_irq(void *opaque, int srcno, int val) 27611ad93f6SDavid Gibson { 27711ad93f6SDavid Gibson ICSState *ics = opaque; 27811ad93f6SDavid Gibson struct kvm_irq_level args; 27911ad93f6SDavid Gibson int rc; 28011ad93f6SDavid Gibson 28111ad93f6SDavid Gibson args.irq = srcno + ics->offset; 2824af88944SAlexey Kardashevskiy if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) { 28311ad93f6SDavid Gibson if (!val) { 28411ad93f6SDavid Gibson return; 28511ad93f6SDavid Gibson } 28611ad93f6SDavid Gibson args.level = KVM_INTERRUPT_SET; 28711ad93f6SDavid Gibson } else { 28811ad93f6SDavid Gibson args.level = val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; 28911ad93f6SDavid Gibson } 29011ad93f6SDavid Gibson rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args); 29111ad93f6SDavid Gibson if (rc < 0) { 29211ad93f6SDavid Gibson perror("kvm_irq_line"); 29311ad93f6SDavid Gibson } 29411ad93f6SDavid Gibson } 29511ad93f6SDavid Gibson 29611ad93f6SDavid Gibson static void ics_kvm_reset(DeviceState *dev) 29711ad93f6SDavid Gibson { 298d4d7a59aSBenjamin Herrenschmidt ICSState *ics = ICS_SIMPLE(dev); 299fb0e843aSAlexey Kardashevskiy int i; 300a7e519a8SAlexey Kardashevskiy uint8_t flags[ics->nr_irqs]; 301a7e519a8SAlexey Kardashevskiy 302a7e519a8SAlexey Kardashevskiy for (i = 0; i < ics->nr_irqs; i++) { 303a7e519a8SAlexey Kardashevskiy flags[i] = ics->irqs[i].flags; 304a7e519a8SAlexey Kardashevskiy } 305fb0e843aSAlexey Kardashevskiy 306fb0e843aSAlexey Kardashevskiy memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs); 307a7e519a8SAlexey Kardashevskiy 308fb0e843aSAlexey Kardashevskiy for (i = 0; i < ics->nr_irqs; i++) { 309fb0e843aSAlexey Kardashevskiy ics->irqs[i].priority = 0xff; 310fb0e843aSAlexey Kardashevskiy ics->irqs[i].saved_priority = 0xff; 311a7e519a8SAlexey Kardashevskiy ics->irqs[i].flags = flags[i]; 312fb0e843aSAlexey Kardashevskiy } 313fb0e843aSAlexey Kardashevskiy 314fb0e843aSAlexey Kardashevskiy ics_set_kvm_state(ics, 1); 31511ad93f6SDavid Gibson } 31611ad93f6SDavid Gibson 31711ad93f6SDavid Gibson static void ics_kvm_realize(DeviceState *dev, Error **errp) 31811ad93f6SDavid Gibson { 319d4d7a59aSBenjamin Herrenschmidt ICSState *ics = ICS_SIMPLE(dev); 32011ad93f6SDavid Gibson 32111ad93f6SDavid Gibson if (!ics->nr_irqs) { 32211ad93f6SDavid Gibson error_setg(errp, "Number of interrupts needs to be greater 0"); 32311ad93f6SDavid Gibson return; 32411ad93f6SDavid Gibson } 32511ad93f6SDavid Gibson ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); 32611ad93f6SDavid Gibson ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs); 32711ad93f6SDavid Gibson } 32811ad93f6SDavid Gibson 32911ad93f6SDavid Gibson static void ics_kvm_class_init(ObjectClass *klass, void *data) 33011ad93f6SDavid Gibson { 33111ad93f6SDavid Gibson DeviceClass *dc = DEVICE_CLASS(klass); 332d4d7a59aSBenjamin Herrenschmidt ICSStateClass *icsc = ICS_BASE_CLASS(klass); 33311ad93f6SDavid Gibson 3344e4169f7SCédric Le Goater icsc->realize = ics_kvm_realize; 33511ad93f6SDavid Gibson dc->reset = ics_kvm_reset; 33611ad93f6SDavid Gibson icsc->pre_save = ics_get_kvm_state; 33711ad93f6SDavid Gibson icsc->post_load = ics_set_kvm_state; 33811ad93f6SDavid Gibson } 33911ad93f6SDavid Gibson 34011ad93f6SDavid Gibson static const TypeInfo ics_kvm_info = { 341d4d7a59aSBenjamin Herrenschmidt .name = TYPE_ICS_KVM, 342d4d7a59aSBenjamin Herrenschmidt .parent = TYPE_ICS_SIMPLE, 34311ad93f6SDavid Gibson .instance_size = sizeof(ICSState), 34411ad93f6SDavid Gibson .class_init = ics_kvm_class_init, 34511ad93f6SDavid Gibson }; 34611ad93f6SDavid Gibson 34711ad93f6SDavid Gibson /* 34811ad93f6SDavid Gibson * XICS-KVM 34911ad93f6SDavid Gibson */ 35011ad93f6SDavid Gibson 35128e02042SDavid Gibson static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr, 35211ad93f6SDavid Gibson uint32_t token, 35311ad93f6SDavid Gibson uint32_t nargs, target_ulong args, 35411ad93f6SDavid Gibson uint32_t nret, target_ulong rets) 35511ad93f6SDavid Gibson { 35611ad93f6SDavid Gibson error_report("pseries: %s must never be called for in-kernel XICS", 35711ad93f6SDavid Gibson __func__); 35811ad93f6SDavid Gibson } 35911ad93f6SDavid Gibson 3602192a930SCédric Le Goater int xics_kvm_init(sPAPRMachineState *spapr, Error **errp) 36111ad93f6SDavid Gibson { 362817bb6a4SCédric Le Goater int rc; 36311ad93f6SDavid Gibson struct kvm_create_device xics_create_device = { 36411ad93f6SDavid Gibson .type = KVM_DEV_TYPE_XICS, 36511ad93f6SDavid Gibson .flags = 0, 36611ad93f6SDavid Gibson }; 36711ad93f6SDavid Gibson 36811ad93f6SDavid Gibson if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) { 36911ad93f6SDavid Gibson error_setg(errp, 37011ad93f6SDavid Gibson "KVM and IRQ_XICS capability must be present for in-kernel XICS"); 37111ad93f6SDavid Gibson goto fail; 37211ad93f6SDavid Gibson } 37311ad93f6SDavid Gibson 3743a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_dummy); 3753a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_dummy); 3763a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_dummy); 3773a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_dummy); 37811ad93f6SDavid Gibson 3793a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive"); 38011ad93f6SDavid Gibson if (rc < 0) { 38111ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive"); 38211ad93f6SDavid Gibson goto fail; 38311ad93f6SDavid Gibson } 38411ad93f6SDavid Gibson 3853a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive"); 38611ad93f6SDavid Gibson if (rc < 0) { 38711ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive"); 38811ad93f6SDavid Gibson goto fail; 38911ad93f6SDavid Gibson } 39011ad93f6SDavid Gibson 3913a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on"); 39211ad93f6SDavid Gibson if (rc < 0) { 39311ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on"); 39411ad93f6SDavid Gibson goto fail; 39511ad93f6SDavid Gibson } 39611ad93f6SDavid Gibson 3973a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off"); 39811ad93f6SDavid Gibson if (rc < 0) { 39911ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off"); 40011ad93f6SDavid Gibson goto fail; 40111ad93f6SDavid Gibson } 40211ad93f6SDavid Gibson 40311ad93f6SDavid Gibson /* Create the kernel ICP */ 40411ad93f6SDavid Gibson rc = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &xics_create_device); 40511ad93f6SDavid Gibson if (rc < 0) { 40611ad93f6SDavid Gibson error_setg_errno(errp, -rc, "Error on KVM_CREATE_DEVICE for XICS"); 40711ad93f6SDavid Gibson goto fail; 40811ad93f6SDavid Gibson } 40911ad93f6SDavid Gibson 410729f8a4fSCédric Le Goater kernel_xics_fd = xics_create_device.fd; 41111ad93f6SDavid Gibson 4129554233cSAlexey Kardashevskiy kvm_kernel_irqchip = true; 4139554233cSAlexey Kardashevskiy kvm_msi_via_irqfd_allowed = true; 4149554233cSAlexey Kardashevskiy kvm_gsi_direct_mapping = true; 4159554233cSAlexey Kardashevskiy 4162192a930SCédric Le Goater return rc; 41711ad93f6SDavid Gibson 41811ad93f6SDavid Gibson fail: 41911ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); 42011ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); 42111ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); 42211ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); 4232192a930SCédric Le Goater return -1; 42411ad93f6SDavid Gibson } 42511ad93f6SDavid Gibson 42611ad93f6SDavid Gibson static void xics_kvm_register_types(void) 42711ad93f6SDavid Gibson { 42811ad93f6SDavid Gibson type_register_static(&ics_kvm_info); 42911ad93f6SDavid Gibson type_register_static(&icp_kvm_info); 43011ad93f6SDavid Gibson } 43111ad93f6SDavid Gibson 43211ad93f6SDavid Gibson type_init(xics_kvm_register_types) 433