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" 363f777abcSCédric Le Goater #include "hw/ppc/spapr_cpu_core.h" 3711ad93f6SDavid Gibson #include "hw/ppc/xics.h" 38a51d5afcSThomas Huth #include "hw/ppc/xics_spapr.h" 3911ad93f6SDavid Gibson #include "kvm_ppc.h" 4011ad93f6SDavid Gibson #include "qemu/config-file.h" 4111ad93f6SDavid Gibson #include "qemu/error-report.h" 4211ad93f6SDavid Gibson 4311ad93f6SDavid Gibson #include <sys/ioctl.h> 4411ad93f6SDavid Gibson 45729f8a4fSCédric Le Goater static int kernel_xics_fd = -1; 46729f8a4fSCédric Le Goater 47de86ecccSGreg Kurz typedef struct KVMEnabledICP { 48de86ecccSGreg Kurz unsigned long vcpu_id; 49de86ecccSGreg Kurz QLIST_ENTRY(KVMEnabledICP) node; 50de86ecccSGreg Kurz } KVMEnabledICP; 51de86ecccSGreg Kurz 52de86ecccSGreg Kurz static QLIST_HEAD(, KVMEnabledICP) 53de86ecccSGreg Kurz kvm_enabled_icps = QLIST_HEAD_INITIALIZER(&kvm_enabled_icps); 54de86ecccSGreg Kurz 5556b11587SCédric Le Goater static void kvm_disable_icps(void) 5656b11587SCédric Le Goater { 5756b11587SCédric Le Goater KVMEnabledICP *enabled_icp, *next; 5856b11587SCédric Le Goater 5956b11587SCédric Le Goater QLIST_FOREACH_SAFE(enabled_icp, &kvm_enabled_icps, node, next) { 6056b11587SCédric Le Goater QLIST_REMOVE(enabled_icp, node); 6156b11587SCédric Le Goater g_free(enabled_icp); 6256b11587SCédric Le Goater } 6356b11587SCédric Le Goater } 6456b11587SCédric Le Goater 6511ad93f6SDavid Gibson /* 6611ad93f6SDavid Gibson * ICP-KVM 6711ad93f6SDavid Gibson */ 680e5c7fadSGreg Kurz void icp_get_kvm_state(ICPState *icp) 6911ad93f6SDavid Gibson { 7011ad93f6SDavid Gibson uint64_t state; 7111ad93f6SDavid Gibson int ret; 7211ad93f6SDavid Gibson 733bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 743bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 753bf84e99SCédric Le Goater return; 763bf84e99SCédric Le Goater } 773bf84e99SCédric Le Goater 7811ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 798e4fba20SCédric Le Goater if (!icp->cs) { 8011ad93f6SDavid Gibson return; 8111ad93f6SDavid Gibson } 8211ad93f6SDavid Gibson 83bf358b54SCédric Le Goater ret = kvm_get_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state); 8411ad93f6SDavid Gibson if (ret != 0) { 8511ad93f6SDavid Gibson error_report("Unable to retrieve KVM interrupt controller state" 868e4fba20SCédric Le Goater " for CPU %ld: %s", kvm_arch_vcpu_id(icp->cs), strerror(errno)); 8711ad93f6SDavid Gibson exit(1); 8811ad93f6SDavid Gibson } 8911ad93f6SDavid Gibson 908e4fba20SCédric Le Goater icp->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT; 918e4fba20SCédric Le Goater icp->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT) 9211ad93f6SDavid Gibson & KVM_REG_PPC_ICP_MFRR_MASK; 938e4fba20SCédric Le Goater icp->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT) 9411ad93f6SDavid Gibson & KVM_REG_PPC_ICP_PPRI_MASK; 9511ad93f6SDavid Gibson } 9611ad93f6SDavid Gibson 97dcb556fcSGreg Kurz static void do_icp_synchronize_state(CPUState *cpu, run_on_cpu_data arg) 98dcb556fcSGreg Kurz { 99dcb556fcSGreg Kurz icp_get_kvm_state(arg.host_ptr); 100dcb556fcSGreg Kurz } 101dcb556fcSGreg Kurz 1020e5c7fadSGreg Kurz void icp_synchronize_state(ICPState *icp) 103dcb556fcSGreg Kurz { 104dcb556fcSGreg Kurz if (icp->cs) { 105dcb556fcSGreg Kurz run_on_cpu(icp->cs, do_icp_synchronize_state, RUN_ON_CPU_HOST_PTR(icp)); 106dcb556fcSGreg Kurz } 107dcb556fcSGreg Kurz } 108dcb556fcSGreg Kurz 1090e5c7fadSGreg Kurz int icp_set_kvm_state(ICPState *icp) 11011ad93f6SDavid Gibson { 11111ad93f6SDavid Gibson uint64_t state; 11211ad93f6SDavid Gibson int ret; 11311ad93f6SDavid Gibson 1143bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 1153bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 1163bf84e99SCédric Le Goater return 0; 1173bf84e99SCédric Le Goater } 1183bf84e99SCédric Le Goater 11911ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 1208e4fba20SCédric Le Goater if (!icp->cs) { 12111ad93f6SDavid Gibson return 0; 12211ad93f6SDavid Gibson } 12311ad93f6SDavid Gibson 1248e4fba20SCédric Le Goater state = ((uint64_t)icp->xirr << KVM_REG_PPC_ICP_XISR_SHIFT) 1258e4fba20SCédric Le Goater | ((uint64_t)icp->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) 1268e4fba20SCédric Le Goater | ((uint64_t)icp->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT); 12711ad93f6SDavid Gibson 128bf358b54SCédric Le Goater ret = kvm_set_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state); 12911ad93f6SDavid Gibson if (ret != 0) { 13011ad93f6SDavid Gibson error_report("Unable to restore KVM interrupt controller state (0x%" 1318e4fba20SCédric Le Goater PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(icp->cs), 13211ad93f6SDavid Gibson strerror(errno)); 13311ad93f6SDavid Gibson return ret; 13411ad93f6SDavid Gibson } 13511ad93f6SDavid Gibson 13611ad93f6SDavid Gibson return 0; 13711ad93f6SDavid Gibson } 13811ad93f6SDavid Gibson 1398e6e6efeSGreg Kurz void icp_kvm_realize(DeviceState *dev, Error **errp) 140f0232434SCédric Le Goater { 141a028dd42SCédric Le Goater ICPState *icp = ICP(dev); 142a028dd42SCédric Le Goater CPUState *cs; 143de86ecccSGreg Kurz KVMEnabledICP *enabled_icp; 144a028dd42SCédric Le Goater unsigned long vcpu_id; 145f0232434SCédric Le Goater int ret; 146f0232434SCédric Le Goater 1473bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 148f0232434SCédric Le Goater if (kernel_xics_fd == -1) { 1493bf84e99SCédric Le Goater return; 150f0232434SCédric Le Goater } 151f0232434SCédric Le Goater 152a028dd42SCédric Le Goater cs = icp->cs; 153a028dd42SCédric Le Goater vcpu_id = kvm_arch_vcpu_id(cs); 154a028dd42SCédric Le Goater 155f0232434SCédric Le Goater /* 156f0232434SCédric Le Goater * If we are reusing a parked vCPU fd corresponding to the CPU 157f0232434SCédric Le Goater * which was hot-removed earlier we don't have to renable 158f0232434SCédric Le Goater * KVM_CAP_IRQ_XICS capability again. 159f0232434SCédric Le Goater */ 160de86ecccSGreg Kurz QLIST_FOREACH(enabled_icp, &kvm_enabled_icps, node) { 161de86ecccSGreg Kurz if (enabled_icp->vcpu_id == vcpu_id) { 162f0232434SCédric Le Goater return; 163f0232434SCédric Le Goater } 164de86ecccSGreg Kurz } 165f0232434SCédric Le Goater 166de86ecccSGreg Kurz ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, vcpu_id); 167f0232434SCédric Le Goater if (ret < 0) { 168b1fd36c3SGreg Kurz error_setg(errp, "Unable to connect CPU%ld to kernel XICS: %s", vcpu_id, 169de86ecccSGreg Kurz strerror(errno)); 170b1fd36c3SGreg Kurz return; 171f0232434SCédric Le Goater } 172de86ecccSGreg Kurz enabled_icp = g_malloc(sizeof(*enabled_icp)); 173de86ecccSGreg Kurz enabled_icp->vcpu_id = vcpu_id; 174de86ecccSGreg Kurz QLIST_INSERT_HEAD(&kvm_enabled_icps, enabled_icp, node); 175f0232434SCédric Le Goater } 176f0232434SCédric Le Goater 17711ad93f6SDavid Gibson /* 17811ad93f6SDavid Gibson * ICS-KVM 17911ad93f6SDavid Gibson */ 180d80b2ccfSGreg Kurz void ics_get_kvm_state(ICSState *ics) 18111ad93f6SDavid Gibson { 18211ad93f6SDavid Gibson uint64_t state; 18311ad93f6SDavid Gibson int i; 18411ad93f6SDavid Gibson 1853bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 1863bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 1873bf84e99SCédric Le Goater return; 1883bf84e99SCédric Le Goater } 1893bf84e99SCédric Le Goater 19011ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 19111ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 19211ad93f6SDavid Gibson 193bf358b54SCédric Le Goater kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, 19450beeb68SMarkus Armbruster i + ics->offset, &state, false, &error_fatal); 19511ad93f6SDavid Gibson 19611ad93f6SDavid Gibson irq->server = state & KVM_XICS_DESTINATION_MASK; 19711ad93f6SDavid Gibson irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT) 19811ad93f6SDavid Gibson & KVM_XICS_PRIORITY_MASK; 19911ad93f6SDavid Gibson /* 20011ad93f6SDavid Gibson * To be consistent with the software emulation in xics.c, we 20111ad93f6SDavid Gibson * split out the masked state + priority that we get from the 20211ad93f6SDavid Gibson * kernel into 'current priority' (0xff if masked) and 20311ad93f6SDavid Gibson * 'saved priority' (if masked, this is the priority the 20411ad93f6SDavid Gibson * interrupt had before it was masked). Masking and unmasking 20511ad93f6SDavid Gibson * are done with the ibm,int-off and ibm,int-on RTAS calls. 20611ad93f6SDavid Gibson */ 20711ad93f6SDavid Gibson if (state & KVM_XICS_MASKED) { 20811ad93f6SDavid Gibson irq->priority = 0xff; 20911ad93f6SDavid Gibson } else { 21011ad93f6SDavid Gibson irq->priority = irq->saved_priority; 21111ad93f6SDavid Gibson } 21211ad93f6SDavid Gibson 213063cb7cbSSam Bobroff irq->status = 0; 21411ad93f6SDavid Gibson if (state & KVM_XICS_PENDING) { 21511ad93f6SDavid Gibson if (state & KVM_XICS_LEVEL_SENSITIVE) { 21611ad93f6SDavid Gibson irq->status |= XICS_STATUS_ASSERTED; 21711ad93f6SDavid Gibson } else { 21811ad93f6SDavid Gibson /* 21911ad93f6SDavid Gibson * A pending edge-triggered interrupt (or MSI) 22011ad93f6SDavid Gibson * must have been rejected previously when we 22111ad93f6SDavid Gibson * first detected it and tried to deliver it, 22211ad93f6SDavid Gibson * so mark it as pending and previously rejected 22311ad93f6SDavid Gibson * for consistency with how xics.c works. 22411ad93f6SDavid Gibson */ 22511ad93f6SDavid Gibson irq->status |= XICS_STATUS_MASKED_PENDING 22611ad93f6SDavid Gibson | XICS_STATUS_REJECTED; 22711ad93f6SDavid Gibson } 22811ad93f6SDavid Gibson } 229229e16fdSSam Bobroff if (state & KVM_XICS_PRESENTED) { 230229e16fdSSam Bobroff irq->status |= XICS_STATUS_PRESENTED; 231229e16fdSSam Bobroff } 232229e16fdSSam Bobroff if (state & KVM_XICS_QUEUED) { 233229e16fdSSam Bobroff irq->status |= XICS_STATUS_QUEUED; 234229e16fdSSam Bobroff } 23511ad93f6SDavid Gibson } 23611ad93f6SDavid Gibson } 23711ad93f6SDavid Gibson 238d80b2ccfSGreg Kurz void ics_synchronize_state(ICSState *ics) 239dcb556fcSGreg Kurz { 240dcb556fcSGreg Kurz ics_get_kvm_state(ics); 241dcb556fcSGreg Kurz } 242dcb556fcSGreg Kurz 2436cead90cSGreg Kurz int ics_set_kvm_state_one(ICSState *ics, int srcno) 24411ad93f6SDavid Gibson { 24511ad93f6SDavid Gibson uint64_t state; 246bf358b54SCédric Le Goater Error *local_err = NULL; 2476cead90cSGreg Kurz ICSIRQState *irq = &ics->irqs[srcno]; 24811ad93f6SDavid Gibson int ret; 24911ad93f6SDavid Gibson 2503bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 2513bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 2523bf84e99SCédric Le Goater return 0; 2533bf84e99SCédric Le Goater } 2543bf84e99SCédric Le Goater 25511ad93f6SDavid Gibson state = irq->server; 25611ad93f6SDavid Gibson state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK) 25711ad93f6SDavid Gibson << KVM_XICS_PRIORITY_SHIFT; 25811ad93f6SDavid Gibson if (irq->priority != irq->saved_priority) { 25911ad93f6SDavid Gibson assert(irq->priority == 0xff); 26011ad93f6SDavid Gibson state |= KVM_XICS_MASKED; 26111ad93f6SDavid Gibson } 26211ad93f6SDavid Gibson 2636cead90cSGreg Kurz if (irq->flags & XICS_FLAGS_IRQ_LSI) { 26411ad93f6SDavid Gibson state |= KVM_XICS_LEVEL_SENSITIVE; 26511ad93f6SDavid Gibson if (irq->status & XICS_STATUS_ASSERTED) { 26611ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 26711ad93f6SDavid Gibson } 26811ad93f6SDavid Gibson } else { 26911ad93f6SDavid Gibson if (irq->status & XICS_STATUS_MASKED_PENDING) { 27011ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 27111ad93f6SDavid Gibson } 27211ad93f6SDavid Gibson } 273229e16fdSSam Bobroff if (irq->status & XICS_STATUS_PRESENTED) { 274229e16fdSSam Bobroff state |= KVM_XICS_PRESENTED; 275229e16fdSSam Bobroff } 276229e16fdSSam Bobroff if (irq->status & XICS_STATUS_QUEUED) { 277229e16fdSSam Bobroff state |= KVM_XICS_QUEUED; 278229e16fdSSam Bobroff } 27911ad93f6SDavid Gibson 28052b43881SCédric Le Goater ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, 2816cead90cSGreg Kurz srcno + ics->offset, &state, true, &local_err); 282bf358b54SCédric Le Goater if (local_err) { 28352b43881SCédric Le Goater error_report_err(local_err); 28411ad93f6SDavid Gibson return ret; 28511ad93f6SDavid Gibson } 2866cead90cSGreg Kurz 2876cead90cSGreg Kurz return 0; 2886cead90cSGreg Kurz } 2896cead90cSGreg Kurz 2906cead90cSGreg Kurz int ics_set_kvm_state(ICSState *ics) 2916cead90cSGreg Kurz { 2926cead90cSGreg Kurz int i; 2936cead90cSGreg Kurz 2943bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 2953bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 2963bf84e99SCédric Le Goater return 0; 2973bf84e99SCédric Le Goater } 2983bf84e99SCédric Le Goater 2996cead90cSGreg Kurz for (i = 0; i < ics->nr_irqs; i++) { 3006cead90cSGreg Kurz int ret; 3016cead90cSGreg Kurz 3026cead90cSGreg Kurz ret = ics_set_kvm_state_one(ics, i); 3036cead90cSGreg Kurz if (ret) { 3046cead90cSGreg Kurz return ret; 3056cead90cSGreg Kurz } 30611ad93f6SDavid Gibson } 30711ad93f6SDavid Gibson 30811ad93f6SDavid Gibson return 0; 30911ad93f6SDavid Gibson } 31011ad93f6SDavid Gibson 311557b4567SGreg Kurz void ics_kvm_set_irq(ICSState *ics, int srcno, int val) 31211ad93f6SDavid Gibson { 31311ad93f6SDavid Gibson struct kvm_irq_level args; 31411ad93f6SDavid Gibson int rc; 31511ad93f6SDavid Gibson 3163bf84e99SCédric Le Goater /* The KVM XICS device should be in use */ 3173bf84e99SCédric Le Goater assert(kernel_xics_fd != -1); 3183bf84e99SCédric Le Goater 31911ad93f6SDavid Gibson args.irq = srcno + ics->offset; 3204af88944SAlexey Kardashevskiy if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) { 32111ad93f6SDavid Gibson if (!val) { 32211ad93f6SDavid Gibson return; 32311ad93f6SDavid Gibson } 32411ad93f6SDavid Gibson args.level = KVM_INTERRUPT_SET; 32511ad93f6SDavid Gibson } else { 32611ad93f6SDavid Gibson args.level = val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; 32711ad93f6SDavid Gibson } 32811ad93f6SDavid Gibson rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args); 32911ad93f6SDavid Gibson if (rc < 0) { 33011ad93f6SDavid Gibson perror("kvm_irq_line"); 33111ad93f6SDavid Gibson } 33211ad93f6SDavid Gibson } 33311ad93f6SDavid Gibson 334eab9f191SGreg Kurz int xics_kvm_connect(SpaprMachineState *spapr, Error **errp) 33511ad93f6SDavid Gibson { 336817bb6a4SCédric Le Goater int rc; 3373f777abcSCédric Le Goater CPUState *cs; 3383f777abcSCédric Le Goater Error *local_err = NULL; 3393f777abcSCédric Le Goater 3403f777abcSCédric Le Goater /* 3413f777abcSCédric Le Goater * The KVM XICS device already in use. This is the case when 3423f777abcSCédric Le Goater * rebooting under the XICS-only interrupt mode. 3433f777abcSCédric Le Goater */ 3443f777abcSCédric Le Goater if (kernel_xics_fd != -1) { 3453f777abcSCédric Le Goater return 0; 3463f777abcSCédric Le Goater } 34711ad93f6SDavid Gibson 34811ad93f6SDavid Gibson if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) { 34911ad93f6SDavid Gibson error_setg(errp, 35011ad93f6SDavid Gibson "KVM and IRQ_XICS capability must be present for in-kernel XICS"); 351*64fb9621SGreg Kurz return -1; 35211ad93f6SDavid Gibson } 35311ad93f6SDavid Gibson 3543a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive"); 35511ad93f6SDavid Gibson if (rc < 0) { 35611ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive"); 35711ad93f6SDavid Gibson goto fail; 35811ad93f6SDavid Gibson } 35911ad93f6SDavid Gibson 3603a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive"); 36111ad93f6SDavid Gibson if (rc < 0) { 36211ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive"); 36311ad93f6SDavid Gibson goto fail; 36411ad93f6SDavid Gibson } 36511ad93f6SDavid Gibson 3663a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on"); 36711ad93f6SDavid Gibson if (rc < 0) { 36811ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on"); 36911ad93f6SDavid Gibson goto fail; 37011ad93f6SDavid Gibson } 37111ad93f6SDavid Gibson 3723a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off"); 37311ad93f6SDavid Gibson if (rc < 0) { 37411ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off"); 37511ad93f6SDavid Gibson goto fail; 37611ad93f6SDavid Gibson } 37711ad93f6SDavid Gibson 378bf358b54SCédric Le Goater /* Create the KVM XICS device */ 379bf358b54SCédric Le Goater rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false); 38011ad93f6SDavid Gibson if (rc < 0) { 38111ad93f6SDavid Gibson error_setg_errno(errp, -rc, "Error on KVM_CREATE_DEVICE for XICS"); 38211ad93f6SDavid Gibson goto fail; 38311ad93f6SDavid Gibson } 38411ad93f6SDavid Gibson 385bf358b54SCédric Le Goater kernel_xics_fd = rc; 3869554233cSAlexey Kardashevskiy kvm_kernel_irqchip = true; 3879554233cSAlexey Kardashevskiy kvm_msi_via_irqfd_allowed = true; 3889554233cSAlexey Kardashevskiy kvm_gsi_direct_mapping = true; 3899554233cSAlexey Kardashevskiy 3903f777abcSCédric Le Goater /* Create the presenters */ 3913f777abcSCédric Le Goater CPU_FOREACH(cs) { 3923f777abcSCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 3933f777abcSCédric Le Goater 3943f777abcSCédric Le Goater icp_kvm_realize(DEVICE(spapr_cpu_state(cpu)->icp), &local_err); 3953f777abcSCédric Le Goater if (local_err) { 3963f777abcSCédric Le Goater error_propagate(errp, local_err); 3973f777abcSCédric Le Goater goto fail; 3983f777abcSCédric Le Goater } 3993f777abcSCédric Le Goater } 4003f777abcSCédric Le Goater 4013f777abcSCédric Le Goater /* Update the KVM sources */ 4023f777abcSCédric Le Goater ics_set_kvm_state(spapr->ics); 4033f777abcSCédric Le Goater 4043f777abcSCédric Le Goater /* Connect the presenters to the initial VCPUs of the machine */ 4053f777abcSCédric Le Goater CPU_FOREACH(cs) { 4063f777abcSCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 4073f777abcSCédric Le Goater icp_set_kvm_state(spapr_cpu_state(cpu)->icp); 4083f777abcSCédric Le Goater } 4093f777abcSCédric Le Goater 410bf358b54SCédric Le Goater return 0; 41111ad93f6SDavid Gibson 41211ad93f6SDavid Gibson fail: 41311ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); 41411ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); 41511ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); 41611ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); 4172192a930SCédric Le Goater return -1; 41811ad93f6SDavid Gibson } 41956b11587SCédric Le Goater 42056b11587SCédric Le Goater void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp) 42156b11587SCédric Le Goater { 42256b11587SCédric Le Goater /* The KVM XICS device is not in use */ 42356b11587SCédric Le Goater if (kernel_xics_fd == -1) { 42456b11587SCédric Le Goater return; 42556b11587SCédric Le Goater } 42656b11587SCédric Le Goater 42756b11587SCédric Le Goater if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) { 42856b11587SCédric Le Goater error_setg(errp, 42956b11587SCédric Le Goater "KVM and IRQ_XICS capability must be present for KVM XICS device"); 43056b11587SCédric Le Goater return; 43156b11587SCédric Le Goater } 43256b11587SCédric Le Goater 43356b11587SCédric Le Goater /* 43456b11587SCédric Le Goater * Only on P9 using the XICS-on XIVE KVM device: 43556b11587SCédric Le Goater * 43656b11587SCédric Le Goater * When the KVM device fd is closed, the device is destroyed and 43756b11587SCédric Le Goater * removed from the list of devices of the VM. The VCPU presenters 43856b11587SCédric Le Goater * are also detached from the device. 43956b11587SCédric Le Goater */ 44056b11587SCédric Le Goater close(kernel_xics_fd); 44156b11587SCédric Le Goater kernel_xics_fd = -1; 44256b11587SCédric Le Goater 44356b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); 44456b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); 44556b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); 44656b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); 44756b11587SCédric Le Goater 44856b11587SCédric Le Goater kvm_kernel_irqchip = false; 44956b11587SCédric Le Goater kvm_msi_via_irqfd_allowed = false; 45056b11587SCédric Le Goater kvm_gsi_direct_mapping = false; 45156b11587SCédric Le Goater 45256b11587SCédric Le Goater /* Clear the presenter from the VCPUs */ 45356b11587SCédric Le Goater kvm_disable_icps(); 45456b11587SCédric Le Goater } 4557abc0c6dSGreg Kurz 4567abc0c6dSGreg Kurz /* 4577abc0c6dSGreg Kurz * This is a heuristic to detect older KVMs on POWER9 hosts that don't 4587abc0c6dSGreg Kurz * support destruction of a KVM XICS device while the VM is running. 4597abc0c6dSGreg Kurz * Required to start a spapr machine with ic-mode=dual,kernel-irqchip=on. 4607abc0c6dSGreg Kurz */ 4617abc0c6dSGreg Kurz bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr) 4627abc0c6dSGreg Kurz { 4637abc0c6dSGreg Kurz int rc; 4647abc0c6dSGreg Kurz 4657abc0c6dSGreg Kurz rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false); 4667abc0c6dSGreg Kurz if (rc < 0) { 4677abc0c6dSGreg Kurz /* 4687abc0c6dSGreg Kurz * The error is ignored on purpose. The KVM XICS setup code 4697abc0c6dSGreg Kurz * will catch it again anyway. The goal here is to see if 4707abc0c6dSGreg Kurz * close() actually destroys the device or not. 4717abc0c6dSGreg Kurz */ 4727abc0c6dSGreg Kurz return false; 4737abc0c6dSGreg Kurz } 4747abc0c6dSGreg Kurz 4757abc0c6dSGreg Kurz close(rc); 4767abc0c6dSGreg Kurz 4777abc0c6dSGreg Kurz rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false); 4787abc0c6dSGreg Kurz if (rc >= 0) { 4797abc0c6dSGreg Kurz close(rc); 4807abc0c6dSGreg Kurz return false; 4817abc0c6dSGreg Kurz } 4827abc0c6dSGreg Kurz 4837abc0c6dSGreg Kurz return errno == EEXIST; 4847abc0c6dSGreg Kurz } 485