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" 3011ad93f6SDavid Gibson #include "trace.h" 31*32cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h" 3211ad93f6SDavid Gibson #include "hw/ppc/spapr.h" 333f777abcSCédric Le Goater #include "hw/ppc/spapr_cpu_core.h" 3411ad93f6SDavid Gibson #include "hw/ppc/xics.h" 35a51d5afcSThomas Huth #include "hw/ppc/xics_spapr.h" 3611ad93f6SDavid Gibson #include "kvm_ppc.h" 3711ad93f6SDavid Gibson #include "qemu/config-file.h" 3811ad93f6SDavid Gibson #include "qemu/error-report.h" 3911ad93f6SDavid Gibson 4011ad93f6SDavid Gibson #include <sys/ioctl.h> 4111ad93f6SDavid Gibson 42729f8a4fSCédric Le Goater static int kernel_xics_fd = -1; 43729f8a4fSCédric Le Goater 44de86ecccSGreg Kurz typedef struct KVMEnabledICP { 45de86ecccSGreg Kurz unsigned long vcpu_id; 46de86ecccSGreg Kurz QLIST_ENTRY(KVMEnabledICP) node; 47de86ecccSGreg Kurz } KVMEnabledICP; 48de86ecccSGreg Kurz 49de86ecccSGreg Kurz static QLIST_HEAD(, KVMEnabledICP) 50de86ecccSGreg Kurz kvm_enabled_icps = QLIST_HEAD_INITIALIZER(&kvm_enabled_icps); 51de86ecccSGreg Kurz 5256b11587SCédric Le Goater static void kvm_disable_icps(void) 5356b11587SCédric Le Goater { 5456b11587SCédric Le Goater KVMEnabledICP *enabled_icp, *next; 5556b11587SCédric Le Goater 5656b11587SCédric Le Goater QLIST_FOREACH_SAFE(enabled_icp, &kvm_enabled_icps, node, next) { 5756b11587SCédric Le Goater QLIST_REMOVE(enabled_icp, node); 5856b11587SCédric Le Goater g_free(enabled_icp); 5956b11587SCédric Le Goater } 6056b11587SCédric Le Goater } 6156b11587SCédric Le Goater 6211ad93f6SDavid Gibson /* 6311ad93f6SDavid Gibson * ICP-KVM 6411ad93f6SDavid Gibson */ 650e5c7fadSGreg Kurz void icp_get_kvm_state(ICPState *icp) 6611ad93f6SDavid Gibson { 6711ad93f6SDavid Gibson uint64_t state; 6811ad93f6SDavid Gibson int ret; 6911ad93f6SDavid Gibson 703bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 713bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 723bf84e99SCédric Le Goater return; 733bf84e99SCédric Le Goater } 743bf84e99SCédric Le Goater 7511ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 768e4fba20SCédric Le Goater if (!icp->cs) { 7711ad93f6SDavid Gibson return; 7811ad93f6SDavid Gibson } 7911ad93f6SDavid Gibson 80bf358b54SCédric Le Goater ret = kvm_get_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state); 8111ad93f6SDavid Gibson if (ret != 0) { 8211ad93f6SDavid Gibson error_report("Unable to retrieve KVM interrupt controller state" 838e4fba20SCédric Le Goater " for CPU %ld: %s", kvm_arch_vcpu_id(icp->cs), strerror(errno)); 8411ad93f6SDavid Gibson exit(1); 8511ad93f6SDavid Gibson } 8611ad93f6SDavid Gibson 878e4fba20SCédric Le Goater icp->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT; 888e4fba20SCédric Le Goater icp->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT) 8911ad93f6SDavid Gibson & KVM_REG_PPC_ICP_MFRR_MASK; 908e4fba20SCédric Le Goater icp->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT) 9111ad93f6SDavid Gibson & KVM_REG_PPC_ICP_PPRI_MASK; 9211ad93f6SDavid Gibson } 9311ad93f6SDavid Gibson 94dcb556fcSGreg Kurz static void do_icp_synchronize_state(CPUState *cpu, run_on_cpu_data arg) 95dcb556fcSGreg Kurz { 96dcb556fcSGreg Kurz icp_get_kvm_state(arg.host_ptr); 97dcb556fcSGreg Kurz } 98dcb556fcSGreg Kurz 990e5c7fadSGreg Kurz void icp_synchronize_state(ICPState *icp) 100dcb556fcSGreg Kurz { 101dcb556fcSGreg Kurz if (icp->cs) { 102dcb556fcSGreg Kurz run_on_cpu(icp->cs, do_icp_synchronize_state, RUN_ON_CPU_HOST_PTR(icp)); 103dcb556fcSGreg Kurz } 104dcb556fcSGreg Kurz } 105dcb556fcSGreg Kurz 106330a21e3SGreg Kurz int icp_set_kvm_state(ICPState *icp, Error **errp) 10711ad93f6SDavid Gibson { 10811ad93f6SDavid Gibson uint64_t state; 10911ad93f6SDavid Gibson int ret; 11011ad93f6SDavid Gibson 1113bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 1123bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 1133bf84e99SCédric Le Goater return 0; 1143bf84e99SCédric Le Goater } 1153bf84e99SCédric Le Goater 11611ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 1178e4fba20SCédric Le Goater if (!icp->cs) { 11811ad93f6SDavid Gibson return 0; 11911ad93f6SDavid Gibson } 12011ad93f6SDavid Gibson 1218e4fba20SCédric Le Goater state = ((uint64_t)icp->xirr << KVM_REG_PPC_ICP_XISR_SHIFT) 1228e4fba20SCédric Le Goater | ((uint64_t)icp->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) 1238e4fba20SCédric Le Goater | ((uint64_t)icp->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT); 12411ad93f6SDavid Gibson 125bf358b54SCédric Le Goater ret = kvm_set_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state); 126330a21e3SGreg Kurz if (ret < 0) { 127330a21e3SGreg Kurz error_setg_errno(errp, -ret, 128330a21e3SGreg Kurz "Unable to restore KVM interrupt controller state (0x%" 129330a21e3SGreg Kurz PRIx64 ") for CPU %ld", state, 130330a21e3SGreg Kurz kvm_arch_vcpu_id(icp->cs)); 13111ad93f6SDavid Gibson return ret; 13211ad93f6SDavid Gibson } 13311ad93f6SDavid Gibson 13411ad93f6SDavid Gibson return 0; 13511ad93f6SDavid Gibson } 13611ad93f6SDavid Gibson 1378e6e6efeSGreg Kurz void icp_kvm_realize(DeviceState *dev, Error **errp) 138f0232434SCédric Le Goater { 139a028dd42SCédric Le Goater ICPState *icp = ICP(dev); 140a028dd42SCédric Le Goater CPUState *cs; 141de86ecccSGreg Kurz KVMEnabledICP *enabled_icp; 142a028dd42SCédric Le Goater unsigned long vcpu_id; 143f0232434SCédric Le Goater int ret; 144f0232434SCédric Le Goater 1453bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 146f0232434SCédric Le Goater if (kernel_xics_fd == -1) { 1473bf84e99SCédric Le Goater return; 148f0232434SCédric Le Goater } 149f0232434SCédric Le Goater 150a028dd42SCédric Le Goater cs = icp->cs; 151a028dd42SCédric Le Goater vcpu_id = kvm_arch_vcpu_id(cs); 152a028dd42SCédric Le Goater 153f0232434SCédric Le Goater /* 154f0232434SCédric Le Goater * If we are reusing a parked vCPU fd corresponding to the CPU 155f0232434SCédric Le Goater * which was hot-removed earlier we don't have to renable 156f0232434SCédric Le Goater * KVM_CAP_IRQ_XICS capability again. 157f0232434SCédric Le Goater */ 158de86ecccSGreg Kurz QLIST_FOREACH(enabled_icp, &kvm_enabled_icps, node) { 159de86ecccSGreg Kurz if (enabled_icp->vcpu_id == vcpu_id) { 160f0232434SCédric Le Goater return; 161f0232434SCédric Le Goater } 162de86ecccSGreg Kurz } 163f0232434SCédric Le Goater 164de86ecccSGreg Kurz ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, kernel_xics_fd, vcpu_id); 165f0232434SCédric Le Goater if (ret < 0) { 166894ea3ecSGreg Kurz Error *local_err = NULL; 167894ea3ecSGreg Kurz 168894ea3ecSGreg Kurz error_setg(&local_err, "Unable to connect CPU%ld to kernel XICS: %s", 169894ea3ecSGreg Kurz vcpu_id, strerror(errno)); 170894ea3ecSGreg Kurz if (errno == ENOSPC) { 171894ea3ecSGreg Kurz error_append_hint(&local_err, "Try -smp maxcpus=N with N < %u\n", 172894ea3ecSGreg Kurz MACHINE(qdev_get_machine())->smp.max_cpus); 173894ea3ecSGreg Kurz } 174894ea3ecSGreg Kurz error_propagate(errp, local_err); 175b1fd36c3SGreg Kurz return; 176f0232434SCédric Le Goater } 177de86ecccSGreg Kurz enabled_icp = g_malloc(sizeof(*enabled_icp)); 178de86ecccSGreg Kurz enabled_icp->vcpu_id = vcpu_id; 179de86ecccSGreg Kurz QLIST_INSERT_HEAD(&kvm_enabled_icps, enabled_icp, node); 180f0232434SCédric Le Goater } 181f0232434SCédric Le Goater 18211ad93f6SDavid Gibson /* 18311ad93f6SDavid Gibson * ICS-KVM 18411ad93f6SDavid Gibson */ 185d80b2ccfSGreg Kurz void ics_get_kvm_state(ICSState *ics) 18611ad93f6SDavid Gibson { 18711ad93f6SDavid Gibson uint64_t state; 18811ad93f6SDavid Gibson int i; 18911ad93f6SDavid Gibson 1903bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 1913bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 1923bf84e99SCédric Le Goater return; 1933bf84e99SCédric Le Goater } 1943bf84e99SCédric Le Goater 19511ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 19611ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 19711ad93f6SDavid Gibson 1984c3539d4SCédric Le Goater if (ics_irq_free(ics, i)) { 1994c3539d4SCédric Le Goater continue; 2004c3539d4SCédric Le Goater } 2014c3539d4SCédric Le Goater 202bf358b54SCédric Le Goater kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, 20350beeb68SMarkus Armbruster i + ics->offset, &state, false, &error_fatal); 20411ad93f6SDavid Gibson 20511ad93f6SDavid Gibson irq->server = state & KVM_XICS_DESTINATION_MASK; 20611ad93f6SDavid Gibson irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT) 20711ad93f6SDavid Gibson & KVM_XICS_PRIORITY_MASK; 20811ad93f6SDavid Gibson /* 20911ad93f6SDavid Gibson * To be consistent with the software emulation in xics.c, we 21011ad93f6SDavid Gibson * split out the masked state + priority that we get from the 21111ad93f6SDavid Gibson * kernel into 'current priority' (0xff if masked) and 21211ad93f6SDavid Gibson * 'saved priority' (if masked, this is the priority the 21311ad93f6SDavid Gibson * interrupt had before it was masked). Masking and unmasking 21411ad93f6SDavid Gibson * are done with the ibm,int-off and ibm,int-on RTAS calls. 21511ad93f6SDavid Gibson */ 21611ad93f6SDavid Gibson if (state & KVM_XICS_MASKED) { 21711ad93f6SDavid Gibson irq->priority = 0xff; 21811ad93f6SDavid Gibson } else { 21911ad93f6SDavid Gibson irq->priority = irq->saved_priority; 22011ad93f6SDavid Gibson } 22111ad93f6SDavid Gibson 222063cb7cbSSam Bobroff irq->status = 0; 22311ad93f6SDavid Gibson if (state & KVM_XICS_PENDING) { 22411ad93f6SDavid Gibson if (state & KVM_XICS_LEVEL_SENSITIVE) { 22511ad93f6SDavid Gibson irq->status |= XICS_STATUS_ASSERTED; 22611ad93f6SDavid Gibson } else { 22711ad93f6SDavid Gibson /* 22811ad93f6SDavid Gibson * A pending edge-triggered interrupt (or MSI) 22911ad93f6SDavid Gibson * must have been rejected previously when we 23011ad93f6SDavid Gibson * first detected it and tried to deliver it, 23111ad93f6SDavid Gibson * so mark it as pending and previously rejected 23211ad93f6SDavid Gibson * for consistency with how xics.c works. 23311ad93f6SDavid Gibson */ 23411ad93f6SDavid Gibson irq->status |= XICS_STATUS_MASKED_PENDING 23511ad93f6SDavid Gibson | XICS_STATUS_REJECTED; 23611ad93f6SDavid Gibson } 23711ad93f6SDavid Gibson } 238229e16fdSSam Bobroff if (state & KVM_XICS_PRESENTED) { 239229e16fdSSam Bobroff irq->status |= XICS_STATUS_PRESENTED; 240229e16fdSSam Bobroff } 241229e16fdSSam Bobroff if (state & KVM_XICS_QUEUED) { 242229e16fdSSam Bobroff irq->status |= XICS_STATUS_QUEUED; 243229e16fdSSam Bobroff } 24411ad93f6SDavid Gibson } 24511ad93f6SDavid Gibson } 24611ad93f6SDavid Gibson 247d80b2ccfSGreg Kurz void ics_synchronize_state(ICSState *ics) 248dcb556fcSGreg Kurz { 249dcb556fcSGreg Kurz ics_get_kvm_state(ics); 250dcb556fcSGreg Kurz } 251dcb556fcSGreg Kurz 252330a21e3SGreg Kurz int ics_set_kvm_state_one(ICSState *ics, int srcno, Error **errp) 25311ad93f6SDavid Gibson { 25411ad93f6SDavid Gibson uint64_t state; 2556cead90cSGreg Kurz ICSIRQState *irq = &ics->irqs[srcno]; 25611ad93f6SDavid Gibson int ret; 25711ad93f6SDavid Gibson 2583bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 2593bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 2603bf84e99SCédric Le Goater return 0; 2613bf84e99SCédric Le Goater } 2623bf84e99SCédric Le Goater 26311ad93f6SDavid Gibson state = irq->server; 26411ad93f6SDavid Gibson state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK) 26511ad93f6SDavid Gibson << KVM_XICS_PRIORITY_SHIFT; 26611ad93f6SDavid Gibson if (irq->priority != irq->saved_priority) { 26711ad93f6SDavid Gibson assert(irq->priority == 0xff); 26838298611SGreg Kurz } 26938298611SGreg Kurz 27038298611SGreg Kurz if (irq->priority == 0xff) { 27111ad93f6SDavid Gibson state |= KVM_XICS_MASKED; 27211ad93f6SDavid Gibson } 27311ad93f6SDavid Gibson 2746cead90cSGreg Kurz if (irq->flags & XICS_FLAGS_IRQ_LSI) { 27511ad93f6SDavid Gibson state |= KVM_XICS_LEVEL_SENSITIVE; 27611ad93f6SDavid Gibson if (irq->status & XICS_STATUS_ASSERTED) { 27711ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 27811ad93f6SDavid Gibson } 27911ad93f6SDavid Gibson } else { 28011ad93f6SDavid Gibson if (irq->status & XICS_STATUS_MASKED_PENDING) { 28111ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 28211ad93f6SDavid Gibson } 28311ad93f6SDavid Gibson } 284229e16fdSSam Bobroff if (irq->status & XICS_STATUS_PRESENTED) { 285229e16fdSSam Bobroff state |= KVM_XICS_PRESENTED; 286229e16fdSSam Bobroff } 287229e16fdSSam Bobroff if (irq->status & XICS_STATUS_QUEUED) { 288229e16fdSSam Bobroff state |= KVM_XICS_QUEUED; 289229e16fdSSam Bobroff } 29011ad93f6SDavid Gibson 29152b43881SCédric Le Goater ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, 292330a21e3SGreg Kurz srcno + ics->offset, &state, true, errp); 293330a21e3SGreg Kurz if (ret < 0) { 29411ad93f6SDavid Gibson return ret; 29511ad93f6SDavid Gibson } 2966cead90cSGreg Kurz 2976cead90cSGreg Kurz return 0; 2986cead90cSGreg Kurz } 2996cead90cSGreg Kurz 300330a21e3SGreg Kurz int ics_set_kvm_state(ICSState *ics, Error **errp) 3016cead90cSGreg Kurz { 3026cead90cSGreg Kurz int i; 3036cead90cSGreg Kurz 3043bf84e99SCédric Le Goater /* The KVM XICS device is not in use */ 3053bf84e99SCédric Le Goater if (kernel_xics_fd == -1) { 3063bf84e99SCédric Le Goater return 0; 3073bf84e99SCédric Le Goater } 3083bf84e99SCédric Le Goater 3096cead90cSGreg Kurz for (i = 0; i < ics->nr_irqs; i++) { 3106cead90cSGreg Kurz int ret; 3116cead90cSGreg Kurz 3124c3539d4SCédric Le Goater if (ics_irq_free(ics, i)) { 3134c3539d4SCédric Le Goater continue; 3144c3539d4SCédric Le Goater } 3154c3539d4SCédric Le Goater 316668f62ecSMarkus Armbruster ret = ics_set_kvm_state_one(ics, i, errp); 317330a21e3SGreg Kurz if (ret < 0) { 3186cead90cSGreg Kurz return ret; 3196cead90cSGreg Kurz } 32011ad93f6SDavid Gibson } 32111ad93f6SDavid Gibson 32211ad93f6SDavid Gibson return 0; 32311ad93f6SDavid Gibson } 32411ad93f6SDavid Gibson 325557b4567SGreg Kurz void ics_kvm_set_irq(ICSState *ics, int srcno, int val) 32611ad93f6SDavid Gibson { 32711ad93f6SDavid Gibson struct kvm_irq_level args; 32811ad93f6SDavid Gibson int rc; 32911ad93f6SDavid Gibson 3303bf84e99SCédric Le Goater /* The KVM XICS device should be in use */ 3313bf84e99SCédric Le Goater assert(kernel_xics_fd != -1); 3323bf84e99SCédric Le Goater 33311ad93f6SDavid Gibson args.irq = srcno + ics->offset; 3344af88944SAlexey Kardashevskiy if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MSI) { 33511ad93f6SDavid Gibson if (!val) { 33611ad93f6SDavid Gibson return; 33711ad93f6SDavid Gibson } 33811ad93f6SDavid Gibson args.level = KVM_INTERRUPT_SET; 33911ad93f6SDavid Gibson } else { 34011ad93f6SDavid Gibson args.level = val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; 34111ad93f6SDavid Gibson } 34211ad93f6SDavid Gibson rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args); 34311ad93f6SDavid Gibson if (rc < 0) { 34411ad93f6SDavid Gibson perror("kvm_irq_line"); 34511ad93f6SDavid Gibson } 34611ad93f6SDavid Gibson } 34711ad93f6SDavid Gibson 3484ffb7496SGreg Kurz int xics_kvm_connect(SpaprInterruptController *intc, uint32_t nr_servers, 3494ffb7496SGreg Kurz Error **errp) 35011ad93f6SDavid Gibson { 35198a39a79SDavid Gibson ICSState *ics = ICS_SPAPR(intc); 352817bb6a4SCédric Le Goater int rc; 3533f777abcSCédric Le Goater CPUState *cs; 3543f777abcSCédric Le Goater Error *local_err = NULL; 3553f777abcSCédric Le Goater 3563f777abcSCédric Le Goater /* 3573f777abcSCédric Le Goater * The KVM XICS device already in use. This is the case when 3583f777abcSCédric Le Goater * rebooting under the XICS-only interrupt mode. 3593f777abcSCédric Le Goater */ 3603f777abcSCédric Le Goater if (kernel_xics_fd != -1) { 3613f777abcSCédric Le Goater return 0; 3623f777abcSCédric Le Goater } 36311ad93f6SDavid Gibson 36411ad93f6SDavid Gibson if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) { 36511ad93f6SDavid Gibson error_setg(errp, 36611ad93f6SDavid Gibson "KVM and IRQ_XICS capability must be present for in-kernel XICS"); 36764fb9621SGreg Kurz return -1; 36811ad93f6SDavid Gibson } 36911ad93f6SDavid Gibson 3703a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_SET_XIVE, "ibm,set-xive"); 37111ad93f6SDavid Gibson if (rc < 0) { 372ab3d15faSGreg Kurz error_setg_errno(&local_err, -rc, 373ab3d15faSGreg Kurz "kvmppc_define_rtas_kernel_token: ibm,set-xive"); 37411ad93f6SDavid Gibson goto fail; 37511ad93f6SDavid Gibson } 37611ad93f6SDavid Gibson 3773a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_GET_XIVE, "ibm,get-xive"); 37811ad93f6SDavid Gibson if (rc < 0) { 379ab3d15faSGreg Kurz error_setg_errno(&local_err, -rc, 380ab3d15faSGreg Kurz "kvmppc_define_rtas_kernel_token: ibm,get-xive"); 38111ad93f6SDavid Gibson goto fail; 38211ad93f6SDavid Gibson } 38311ad93f6SDavid Gibson 3843a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_ON, "ibm,int-on"); 38511ad93f6SDavid Gibson if (rc < 0) { 386ab3d15faSGreg Kurz error_setg_errno(&local_err, -rc, 387ab3d15faSGreg Kurz "kvmppc_define_rtas_kernel_token: ibm,int-on"); 38811ad93f6SDavid Gibson goto fail; 38911ad93f6SDavid Gibson } 39011ad93f6SDavid Gibson 3913a3b8502SAlexey Kardashevskiy rc = kvmppc_define_rtas_kernel_token(RTAS_IBM_INT_OFF, "ibm,int-off"); 39211ad93f6SDavid Gibson if (rc < 0) { 393ab3d15faSGreg Kurz error_setg_errno(&local_err, -rc, 394ab3d15faSGreg Kurz "kvmppc_define_rtas_kernel_token: ibm,int-off"); 39511ad93f6SDavid Gibson goto fail; 39611ad93f6SDavid Gibson } 39711ad93f6SDavid Gibson 398bf358b54SCédric Le Goater /* Create the KVM XICS device */ 399bf358b54SCédric Le Goater rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false); 40011ad93f6SDavid Gibson if (rc < 0) { 401ab3d15faSGreg Kurz error_setg_errno(&local_err, -rc, "Error on KVM_CREATE_DEVICE for XICS"); 40211ad93f6SDavid Gibson goto fail; 40311ad93f6SDavid Gibson } 40411ad93f6SDavid Gibson 405894ea3ecSGreg Kurz /* Tell KVM about the # of VCPUs we may have (POWER9 and newer only) */ 406894ea3ecSGreg Kurz if (kvm_device_check_attr(rc, KVM_DEV_XICS_GRP_CTRL, 407894ea3ecSGreg Kurz KVM_DEV_XICS_NR_SERVERS)) { 408894ea3ecSGreg Kurz if (kvm_device_access(rc, KVM_DEV_XICS_GRP_CTRL, 409894ea3ecSGreg Kurz KVM_DEV_XICS_NR_SERVERS, &nr_servers, true, 410894ea3ecSGreg Kurz &local_err)) { 411894ea3ecSGreg Kurz goto fail; 412894ea3ecSGreg Kurz } 413894ea3ecSGreg Kurz } 414894ea3ecSGreg Kurz 415bf358b54SCédric Le Goater kernel_xics_fd = rc; 4169554233cSAlexey Kardashevskiy kvm_kernel_irqchip = true; 4179554233cSAlexey Kardashevskiy kvm_msi_via_irqfd_allowed = true; 4189554233cSAlexey Kardashevskiy kvm_gsi_direct_mapping = true; 4199554233cSAlexey Kardashevskiy 4203f777abcSCédric Le Goater /* Create the presenters */ 4213f777abcSCédric Le Goater CPU_FOREACH(cs) { 4223f777abcSCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 4233f777abcSCédric Le Goater 4243f777abcSCédric Le Goater icp_kvm_realize(DEVICE(spapr_cpu_state(cpu)->icp), &local_err); 4253f777abcSCédric Le Goater if (local_err) { 4263f777abcSCédric Le Goater goto fail; 4273f777abcSCédric Le Goater } 4283f777abcSCédric Le Goater } 4293f777abcSCédric Le Goater 4303f777abcSCédric Le Goater /* Update the KVM sources */ 43198a39a79SDavid Gibson ics_set_kvm_state(ics, &local_err); 432330a21e3SGreg Kurz if (local_err) { 433330a21e3SGreg Kurz goto fail; 434330a21e3SGreg Kurz } 4353f777abcSCédric Le Goater 4363f777abcSCédric Le Goater /* Connect the presenters to the initial VCPUs of the machine */ 4373f777abcSCédric Le Goater CPU_FOREACH(cs) { 4383f777abcSCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 439330a21e3SGreg Kurz icp_set_kvm_state(spapr_cpu_state(cpu)->icp, &local_err); 440330a21e3SGreg Kurz if (local_err) { 441330a21e3SGreg Kurz goto fail; 442330a21e3SGreg Kurz } 4433f777abcSCédric Le Goater } 4443f777abcSCédric Le Goater 445bf358b54SCédric Le Goater return 0; 44611ad93f6SDavid Gibson 44711ad93f6SDavid Gibson fail: 448ab3d15faSGreg Kurz error_propagate(errp, local_err); 44998a39a79SDavid Gibson xics_kvm_disconnect(intc); 4502192a930SCédric Le Goater return -1; 45111ad93f6SDavid Gibson } 45256b11587SCédric Le Goater 45398a39a79SDavid Gibson void xics_kvm_disconnect(SpaprInterruptController *intc) 45456b11587SCédric Le Goater { 45556b11587SCédric Le Goater /* 45656b11587SCédric Le Goater * Only on P9 using the XICS-on XIVE KVM device: 45756b11587SCédric Le Goater * 45856b11587SCédric Le Goater * When the KVM device fd is closed, the device is destroyed and 45956b11587SCédric Le Goater * removed from the list of devices of the VM. The VCPU presenters 46056b11587SCédric Le Goater * are also detached from the device. 46156b11587SCédric Le Goater */ 4624812f261SGreg Kurz if (kernel_xics_fd != -1) { 46356b11587SCédric Le Goater close(kernel_xics_fd); 46456b11587SCédric Le Goater kernel_xics_fd = -1; 4654812f261SGreg Kurz } 46656b11587SCédric Le Goater 46756b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); 46856b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); 46956b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); 47056b11587SCédric Le Goater kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); 47156b11587SCédric Le Goater 47256b11587SCédric Le Goater kvm_kernel_irqchip = false; 47356b11587SCédric Le Goater kvm_msi_via_irqfd_allowed = false; 47456b11587SCédric Le Goater kvm_gsi_direct_mapping = false; 47556b11587SCédric Le Goater 47656b11587SCédric Le Goater /* Clear the presenter from the VCPUs */ 47756b11587SCédric Le Goater kvm_disable_icps(); 47856b11587SCédric Le Goater } 4797abc0c6dSGreg Kurz 4807abc0c6dSGreg Kurz /* 4817abc0c6dSGreg Kurz * This is a heuristic to detect older KVMs on POWER9 hosts that don't 4827abc0c6dSGreg Kurz * support destruction of a KVM XICS device while the VM is running. 4837abc0c6dSGreg Kurz * Required to start a spapr machine with ic-mode=dual,kernel-irqchip=on. 4847abc0c6dSGreg Kurz */ 4850b66209dSGreg Kurz bool xics_kvm_has_broken_disconnect(void) 4867abc0c6dSGreg Kurz { 4877abc0c6dSGreg Kurz int rc; 4887abc0c6dSGreg Kurz 4897abc0c6dSGreg Kurz rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false); 4907abc0c6dSGreg Kurz if (rc < 0) { 4917abc0c6dSGreg Kurz /* 4927abc0c6dSGreg Kurz * The error is ignored on purpose. The KVM XICS setup code 4937abc0c6dSGreg Kurz * will catch it again anyway. The goal here is to see if 4947abc0c6dSGreg Kurz * close() actually destroys the device or not. 4957abc0c6dSGreg Kurz */ 4967abc0c6dSGreg Kurz return false; 4977abc0c6dSGreg Kurz } 4987abc0c6dSGreg Kurz 4997abc0c6dSGreg Kurz close(rc); 5007abc0c6dSGreg Kurz 5017abc0c6dSGreg Kurz rc = kvm_create_device(kvm_state, KVM_DEV_TYPE_XICS, false); 5027abc0c6dSGreg Kurz if (rc >= 0) { 5037abc0c6dSGreg Kurz close(rc); 5047abc0c6dSGreg Kurz return false; 5057abc0c6dSGreg Kurz } 5067abc0c6dSGreg Kurz 5077abc0c6dSGreg Kurz return errno == EEXIST; 5087abc0c6dSGreg Kurz } 509