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" 37a51d5afcSThomas Huth #include "hw/ppc/xics_spapr.h" 3811ad93f6SDavid Gibson #include "kvm_ppc.h" 3911ad93f6SDavid Gibson #include "qemu/config-file.h" 4011ad93f6SDavid Gibson #include "qemu/error-report.h" 4111ad93f6SDavid Gibson 4211ad93f6SDavid Gibson #include <sys/ioctl.h> 4311ad93f6SDavid Gibson 44729f8a4fSCédric Le Goater static int kernel_xics_fd = -1; 45729f8a4fSCédric Le Goater 46de86ecccSGreg Kurz typedef struct KVMEnabledICP { 47de86ecccSGreg Kurz unsigned long vcpu_id; 48de86ecccSGreg Kurz QLIST_ENTRY(KVMEnabledICP) node; 49de86ecccSGreg Kurz } KVMEnabledICP; 50de86ecccSGreg Kurz 51de86ecccSGreg Kurz static QLIST_HEAD(, KVMEnabledICP) 52de86ecccSGreg Kurz kvm_enabled_icps = QLIST_HEAD_INITIALIZER(&kvm_enabled_icps); 53de86ecccSGreg Kurz 54*56b11587SCédric Le Goater static void kvm_disable_icps(void) 55*56b11587SCédric Le Goater { 56*56b11587SCédric Le Goater KVMEnabledICP *enabled_icp, *next; 57*56b11587SCédric Le Goater 58*56b11587SCédric Le Goater QLIST_FOREACH_SAFE(enabled_icp, &kvm_enabled_icps, node, next) { 59*56b11587SCédric Le Goater QLIST_REMOVE(enabled_icp, node); 60*56b11587SCédric Le Goater g_free(enabled_icp); 61*56b11587SCédric Le Goater } 62*56b11587SCédric Le Goater } 63*56b11587SCédric Le Goater 6411ad93f6SDavid Gibson /* 6511ad93f6SDavid Gibson * ICP-KVM 6611ad93f6SDavid Gibson */ 670e5c7fadSGreg Kurz void icp_get_kvm_state(ICPState *icp) 6811ad93f6SDavid Gibson { 6911ad93f6SDavid Gibson uint64_t state; 7011ad93f6SDavid Gibson int ret; 7111ad93f6SDavid Gibson 7211ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 738e4fba20SCédric Le Goater if (!icp->cs) { 7411ad93f6SDavid Gibson return; 7511ad93f6SDavid Gibson } 7611ad93f6SDavid Gibson 77bf358b54SCédric Le Goater ret = kvm_get_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state); 7811ad93f6SDavid Gibson if (ret != 0) { 7911ad93f6SDavid Gibson error_report("Unable to retrieve KVM interrupt controller state" 808e4fba20SCédric Le Goater " for CPU %ld: %s", kvm_arch_vcpu_id(icp->cs), strerror(errno)); 8111ad93f6SDavid Gibson exit(1); 8211ad93f6SDavid Gibson } 8311ad93f6SDavid Gibson 848e4fba20SCédric Le Goater icp->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT; 858e4fba20SCédric Le Goater icp->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT) 8611ad93f6SDavid Gibson & KVM_REG_PPC_ICP_MFRR_MASK; 878e4fba20SCédric Le Goater icp->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT) 8811ad93f6SDavid Gibson & KVM_REG_PPC_ICP_PPRI_MASK; 8911ad93f6SDavid Gibson } 9011ad93f6SDavid Gibson 91dcb556fcSGreg Kurz static void do_icp_synchronize_state(CPUState *cpu, run_on_cpu_data arg) 92dcb556fcSGreg Kurz { 93dcb556fcSGreg Kurz icp_get_kvm_state(arg.host_ptr); 94dcb556fcSGreg Kurz } 95dcb556fcSGreg Kurz 960e5c7fadSGreg Kurz void icp_synchronize_state(ICPState *icp) 97dcb556fcSGreg Kurz { 98dcb556fcSGreg Kurz if (icp->cs) { 99dcb556fcSGreg Kurz run_on_cpu(icp->cs, do_icp_synchronize_state, RUN_ON_CPU_HOST_PTR(icp)); 100dcb556fcSGreg Kurz } 101dcb556fcSGreg Kurz } 102dcb556fcSGreg Kurz 1030e5c7fadSGreg Kurz int icp_set_kvm_state(ICPState *icp) 10411ad93f6SDavid Gibson { 10511ad93f6SDavid Gibson uint64_t state; 10611ad93f6SDavid Gibson int ret; 10711ad93f6SDavid Gibson 10811ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 1098e4fba20SCédric Le Goater if (!icp->cs) { 11011ad93f6SDavid Gibson return 0; 11111ad93f6SDavid Gibson } 11211ad93f6SDavid Gibson 1138e4fba20SCédric Le Goater state = ((uint64_t)icp->xirr << KVM_REG_PPC_ICP_XISR_SHIFT) 1148e4fba20SCédric Le Goater | ((uint64_t)icp->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) 1158e4fba20SCédric Le Goater | ((uint64_t)icp->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT); 11611ad93f6SDavid Gibson 117bf358b54SCédric Le Goater ret = kvm_set_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state); 11811ad93f6SDavid Gibson if (ret != 0) { 11911ad93f6SDavid Gibson error_report("Unable to restore KVM interrupt controller state (0x%" 1208e4fba20SCédric Le Goater PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(icp->cs), 12111ad93f6SDavid Gibson strerror(errno)); 12211ad93f6SDavid Gibson return ret; 12311ad93f6SDavid Gibson } 12411ad93f6SDavid Gibson 12511ad93f6SDavid Gibson return 0; 12611ad93f6SDavid Gibson } 12711ad93f6SDavid Gibson 1288e6e6efeSGreg Kurz void icp_kvm_realize(DeviceState *dev, Error **errp) 129f0232434SCédric Le Goater { 130a028dd42SCédric Le Goater ICPState *icp = ICP(dev); 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 cs = icp->cs; 141a028dd42SCédric Le Goater vcpu_id = kvm_arch_vcpu_id(cs); 142a028dd42SCédric Le Goater 143f0232434SCédric Le Goater /* 144f0232434SCédric Le Goater * If we are reusing a parked vCPU fd corresponding to the CPU 145f0232434SCédric Le Goater * which was hot-removed earlier we don't have to renable 146f0232434SCédric Le Goater * KVM_CAP_IRQ_XICS capability again. 147f0232434SCédric Le Goater */ 148de86ecccSGreg Kurz QLIST_FOREACH(enabled_icp, &kvm_enabled_icps, node) { 149de86ecccSGreg Kurz if (enabled_icp->vcpu_id == vcpu_id) { 150f0232434SCédric Le Goater return; 151f0232434SCédric Le Goater } 152de86ecccSGreg Kurz } 153f0232434SCédric Le Goater 154de86ecccSGreg Kurz ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, vcpu_id); 155f0232434SCédric Le Goater if (ret < 0) { 156b1fd36c3SGreg Kurz error_setg(errp, "Unable to connect CPU%ld to kernel XICS: %s", vcpu_id, 157de86ecccSGreg Kurz strerror(errno)); 158b1fd36c3SGreg Kurz return; 159f0232434SCédric Le Goater } 160de86ecccSGreg Kurz enabled_icp = g_malloc(sizeof(*enabled_icp)); 161de86ecccSGreg Kurz enabled_icp->vcpu_id = vcpu_id; 162de86ecccSGreg Kurz QLIST_INSERT_HEAD(&kvm_enabled_icps, enabled_icp, node); 163f0232434SCédric Le Goater } 164f0232434SCédric Le Goater 16511ad93f6SDavid Gibson /* 16611ad93f6SDavid Gibson * ICS-KVM 16711ad93f6SDavid Gibson */ 168d80b2ccfSGreg Kurz void ics_get_kvm_state(ICSState *ics) 16911ad93f6SDavid Gibson { 17011ad93f6SDavid Gibson uint64_t state; 17111ad93f6SDavid Gibson int i; 17211ad93f6SDavid Gibson 17311ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 17411ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 17511ad93f6SDavid Gibson 176bf358b54SCédric Le Goater kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, 17750beeb68SMarkus Armbruster i + ics->offset, &state, false, &error_fatal); 17811ad93f6SDavid Gibson 17911ad93f6SDavid Gibson irq->server = state & KVM_XICS_DESTINATION_MASK; 18011ad93f6SDavid Gibson irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT) 18111ad93f6SDavid Gibson & KVM_XICS_PRIORITY_MASK; 18211ad93f6SDavid Gibson /* 18311ad93f6SDavid Gibson * To be consistent with the software emulation in xics.c, we 18411ad93f6SDavid Gibson * split out the masked state + priority that we get from the 18511ad93f6SDavid Gibson * kernel into 'current priority' (0xff if masked) and 18611ad93f6SDavid Gibson * 'saved priority' (if masked, this is the priority the 18711ad93f6SDavid Gibson * interrupt had before it was masked). Masking and unmasking 18811ad93f6SDavid Gibson * are done with the ibm,int-off and ibm,int-on RTAS calls. 18911ad93f6SDavid Gibson */ 19011ad93f6SDavid Gibson if (state & KVM_XICS_MASKED) { 19111ad93f6SDavid Gibson irq->priority = 0xff; 19211ad93f6SDavid Gibson } else { 19311ad93f6SDavid Gibson irq->priority = irq->saved_priority; 19411ad93f6SDavid Gibson } 19511ad93f6SDavid Gibson 196063cb7cbSSam Bobroff irq->status = 0; 19711ad93f6SDavid Gibson if (state & KVM_XICS_PENDING) { 19811ad93f6SDavid Gibson if (state & KVM_XICS_LEVEL_SENSITIVE) { 19911ad93f6SDavid Gibson irq->status |= XICS_STATUS_ASSERTED; 20011ad93f6SDavid Gibson } else { 20111ad93f6SDavid Gibson /* 20211ad93f6SDavid Gibson * A pending edge-triggered interrupt (or MSI) 20311ad93f6SDavid Gibson * must have been rejected previously when we 20411ad93f6SDavid Gibson * first detected it and tried to deliver it, 20511ad93f6SDavid Gibson * so mark it as pending and previously rejected 20611ad93f6SDavid Gibson * for consistency with how xics.c works. 20711ad93f6SDavid Gibson */ 20811ad93f6SDavid Gibson irq->status |= XICS_STATUS_MASKED_PENDING 20911ad93f6SDavid Gibson | XICS_STATUS_REJECTED; 21011ad93f6SDavid Gibson } 21111ad93f6SDavid Gibson } 212229e16fdSSam Bobroff if (state & KVM_XICS_PRESENTED) { 213229e16fdSSam Bobroff irq->status |= XICS_STATUS_PRESENTED; 214229e16fdSSam Bobroff } 215229e16fdSSam Bobroff if (state & KVM_XICS_QUEUED) { 216229e16fdSSam Bobroff irq->status |= XICS_STATUS_QUEUED; 217229e16fdSSam Bobroff } 21811ad93f6SDavid Gibson } 21911ad93f6SDavid Gibson } 22011ad93f6SDavid Gibson 221d80b2ccfSGreg Kurz void ics_synchronize_state(ICSState *ics) 222dcb556fcSGreg Kurz { 223dcb556fcSGreg Kurz ics_get_kvm_state(ics); 224dcb556fcSGreg Kurz } 225dcb556fcSGreg Kurz 2266cead90cSGreg Kurz int ics_set_kvm_state_one(ICSState *ics, int srcno) 22711ad93f6SDavid Gibson { 22811ad93f6SDavid Gibson uint64_t state; 229bf358b54SCédric Le Goater Error *local_err = NULL; 2306cead90cSGreg Kurz ICSIRQState *irq = &ics->irqs[srcno]; 23111ad93f6SDavid Gibson int ret; 23211ad93f6SDavid Gibson 23311ad93f6SDavid Gibson state = irq->server; 23411ad93f6SDavid Gibson state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK) 23511ad93f6SDavid Gibson << KVM_XICS_PRIORITY_SHIFT; 23611ad93f6SDavid Gibson if (irq->priority != irq->saved_priority) { 23711ad93f6SDavid Gibson assert(irq->priority == 0xff); 23811ad93f6SDavid Gibson state |= KVM_XICS_MASKED; 23911ad93f6SDavid Gibson } 24011ad93f6SDavid Gibson 2416cead90cSGreg Kurz if (irq->flags & XICS_FLAGS_IRQ_LSI) { 24211ad93f6SDavid Gibson state |= KVM_XICS_LEVEL_SENSITIVE; 24311ad93f6SDavid Gibson if (irq->status & XICS_STATUS_ASSERTED) { 24411ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 24511ad93f6SDavid Gibson } 24611ad93f6SDavid Gibson } else { 24711ad93f6SDavid Gibson if (irq->status & XICS_STATUS_MASKED_PENDING) { 24811ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 24911ad93f6SDavid Gibson } 25011ad93f6SDavid Gibson } 251229e16fdSSam Bobroff if (irq->status & XICS_STATUS_PRESENTED) { 252229e16fdSSam Bobroff state |= KVM_XICS_PRESENTED; 253229e16fdSSam Bobroff } 254229e16fdSSam Bobroff if (irq->status & XICS_STATUS_QUEUED) { 255229e16fdSSam Bobroff state |= KVM_XICS_QUEUED; 256229e16fdSSam Bobroff } 25711ad93f6SDavid Gibson 25852b43881SCédric Le Goater ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, 2596cead90cSGreg Kurz srcno + ics->offset, &state, true, &local_err); 260bf358b54SCédric Le Goater if (local_err) { 26152b43881SCédric Le Goater error_report_err(local_err); 26211ad93f6SDavid Gibson return ret; 26311ad93f6SDavid Gibson } 2646cead90cSGreg Kurz 2656cead90cSGreg Kurz return 0; 2666cead90cSGreg Kurz } 2676cead90cSGreg Kurz 2686cead90cSGreg Kurz int ics_set_kvm_state(ICSState *ics) 2696cead90cSGreg Kurz { 2706cead90cSGreg Kurz int i; 2716cead90cSGreg Kurz 2726cead90cSGreg Kurz for (i = 0; i < ics->nr_irqs; i++) { 2736cead90cSGreg Kurz int ret; 2746cead90cSGreg Kurz 2756cead90cSGreg Kurz ret = ics_set_kvm_state_one(ics, i); 2766cead90cSGreg Kurz if (ret) { 2776cead90cSGreg Kurz return ret; 2786cead90cSGreg Kurz } 27911ad93f6SDavid Gibson } 28011ad93f6SDavid Gibson 28111ad93f6SDavid Gibson return 0; 28211ad93f6SDavid Gibson } 28311ad93f6SDavid Gibson 284557b4567SGreg Kurz void ics_kvm_set_irq(ICSState *ics, int srcno, int val) 28511ad93f6SDavid Gibson { 28611ad93f6SDavid Gibson struct kvm_irq_level args; 28711ad93f6SDavid Gibson int rc; 28811ad93f6SDavid Gibson 28911ad93f6SDavid Gibson args.irq = srcno + ics->offset; 2904af88944SAlexey Kardashevskiy if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) { 29111ad93f6SDavid Gibson if (!val) { 29211ad93f6SDavid Gibson return; 29311ad93f6SDavid Gibson } 29411ad93f6SDavid Gibson args.level = KVM_INTERRUPT_SET; 29511ad93f6SDavid Gibson } else { 29611ad93f6SDavid Gibson args.level = val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; 29711ad93f6SDavid Gibson } 29811ad93f6SDavid Gibson rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args); 29911ad93f6SDavid Gibson if (rc < 0) { 30011ad93f6SDavid Gibson perror("kvm_irq_line"); 30111ad93f6SDavid Gibson } 30211ad93f6SDavid Gibson } 30311ad93f6SDavid Gibson 304ce2918cbSDavid Gibson static void rtas_dummy(PowerPCCPU *cpu, SpaprMachineState *spapr, 30511ad93f6SDavid Gibson uint32_t token, 30611ad93f6SDavid Gibson uint32_t nargs, target_ulong args, 30711ad93f6SDavid Gibson uint32_t nret, target_ulong rets) 30811ad93f6SDavid Gibson { 30911ad93f6SDavid Gibson error_report("pseries: %s must never be called for in-kernel XICS", 31011ad93f6SDavid Gibson __func__); 31111ad93f6SDavid Gibson } 31211ad93f6SDavid Gibson 313ce2918cbSDavid Gibson int xics_kvm_init(SpaprMachineState *spapr, Error **errp) 31411ad93f6SDavid Gibson { 315817bb6a4SCédric Le Goater int rc; 31611ad93f6SDavid Gibson 31711ad93f6SDavid Gibson if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) { 31811ad93f6SDavid Gibson error_setg(errp, 31911ad93f6SDavid Gibson "KVM and IRQ_XICS capability must be present for in-kernel XICS"); 32011ad93f6SDavid Gibson goto fail; 32111ad93f6SDavid Gibson } 32211ad93f6SDavid Gibson 3233a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_dummy); 3243a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_dummy); 3253a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_dummy); 3263a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_dummy); 32711ad93f6SDavid Gibson 3283a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive"); 32911ad93f6SDavid Gibson if (rc < 0) { 33011ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive"); 33111ad93f6SDavid Gibson goto fail; 33211ad93f6SDavid Gibson } 33311ad93f6SDavid Gibson 3343a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive"); 33511ad93f6SDavid Gibson if (rc < 0) { 33611ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive"); 33711ad93f6SDavid Gibson goto fail; 33811ad93f6SDavid Gibson } 33911ad93f6SDavid Gibson 3403a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on"); 34111ad93f6SDavid Gibson if (rc < 0) { 34211ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on"); 34311ad93f6SDavid Gibson goto fail; 34411ad93f6SDavid Gibson } 34511ad93f6SDavid Gibson 3463a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off"); 34711ad93f6SDavid Gibson if (rc < 0) { 34811ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off"); 34911ad93f6SDavid Gibson goto fail; 35011ad93f6SDavid Gibson } 35111ad93f6SDavid Gibson 352bf358b54SCédric Le Goater /* Create the KVM XICS device */ 353bf358b54SCédric Le Goater rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false); 35411ad93f6SDavid Gibson if (rc < 0) { 35511ad93f6SDavid Gibson error_setg_errno(errp, -rc, "Error on KVM_CREATE_DEVICE for XICS"); 35611ad93f6SDavid Gibson goto fail; 35711ad93f6SDavid Gibson } 35811ad93f6SDavid Gibson 359bf358b54SCédric Le Goater kernel_xics_fd = rc; 3609554233cSAlexey Kardashevskiy kvm_kernel_irqchip = true; 3619554233cSAlexey Kardashevskiy kvm_msi_via_irqfd_allowed = true; 3629554233cSAlexey Kardashevskiy kvm_gsi_direct_mapping = true; 3639554233cSAlexey Kardashevskiy 364bf358b54SCédric Le Goater return 0; 36511ad93f6SDavid Gibson 36611ad93f6SDavid Gibson fail: 36711ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); 36811ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); 36911ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); 37011ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); 3712192a930SCédric Le Goater return -1; 37211ad93f6SDavid Gibson } 373*56b11587SCédric Le Goater 374*56b11587SCédric Le Goater void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp) 375*56b11587SCédric Le Goater { 376*56b11587SCédric Le Goater /* The KVM XICS device is not in use */ 377*56b11587SCédric Le Goater if (kernel_xics_fd == -1) { 378*56b11587SCédric Le Goater return; 379*56b11587SCédric Le Goater } 380*56b11587SCédric Le Goater 381*56b11587SCédric Le Goater if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) { 382*56b11587SCédric Le Goater error_setg(errp, 383*56b11587SCédric Le Goater "KVM and IRQ_XICS capability must be present for KVM XICS device"); 384*56b11587SCédric Le Goater return; 385*56b11587SCédric Le Goater } 386*56b11587SCédric Le Goater 387*56b11587SCédric Le Goater /* 388*56b11587SCédric Le Goater * Only on P9 using the XICS-on XIVE KVM device: 389*56b11587SCédric Le Goater * 390*56b11587SCédric Le Goater * When the KVM device fd is closed, the device is destroyed and 391*56b11587SCédric Le Goater * removed from the list of devices of the VM. The VCPU presenters 392*56b11587SCédric Le Goater * are also detached from the device. 393*56b11587SCédric Le Goater */ 394*56b11587SCédric Le Goater close(kernel_xics_fd); 395*56b11587SCédric Le Goater kernel_xics_fd = -1; 396*56b11587SCédric Le Goater 397*56b11587SCédric Le Goater spapr_rtas_unregister(RTAS_IBM_SET_XIVE); 398*56b11587SCédric Le Goater spapr_rtas_unregister(RTAS_IBM_GET_XIVE); 399*56b11587SCédric Le Goater spapr_rtas_unregister(RTAS_IBM_INT_OFF); 400*56b11587SCédric Le Goater spapr_rtas_unregister(RTAS_IBM_INT_ON); 401*56b11587SCédric Le Goater 402*56b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); 403*56b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); 404*56b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); 405*56b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); 406*56b11587SCédric Le Goater 407*56b11587SCédric Le Goater kvm_kernel_irqchip = false; 408*56b11587SCédric Le Goater kvm_msi_via_irqfd_allowed = false; 409*56b11587SCédric Le Goater kvm_gsi_direct_mapping = false; 410*56b11587SCédric Le Goater 411*56b11587SCédric Le Goater /* Clear the presenter from the VCPUs */ 412*56b11587SCédric Le Goater kvm_disable_icps(); 413*56b11587SCédric Le Goater } 414