xref: /qemu/hw/intc/xics_kvm.c (revision 56b11587dfc79dc6453d857159801dcc38f24d0c)
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