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 2811ad93f6SDavid Gibson #include "hw/hw.h" 2911ad93f6SDavid Gibson #include "trace.h" 3011ad93f6SDavid Gibson #include "hw/ppc/spapr.h" 3111ad93f6SDavid Gibson #include "hw/ppc/xics.h" 3211ad93f6SDavid Gibson #include "kvm_ppc.h" 3311ad93f6SDavid Gibson #include "qemu/config-file.h" 3411ad93f6SDavid Gibson #include "qemu/error-report.h" 3511ad93f6SDavid Gibson 3611ad93f6SDavid Gibson #include <sys/ioctl.h> 3711ad93f6SDavid Gibson 3811ad93f6SDavid Gibson typedef struct KVMXICSState { 3911ad93f6SDavid Gibson XICSState parent_obj; 4011ad93f6SDavid Gibson 4111ad93f6SDavid Gibson uint32_t set_xive_token; 4211ad93f6SDavid Gibson uint32_t get_xive_token; 4311ad93f6SDavid Gibson uint32_t int_off_token; 4411ad93f6SDavid Gibson uint32_t int_on_token; 4511ad93f6SDavid Gibson int kernel_xics_fd; 4611ad93f6SDavid Gibson } KVMXICSState; 4711ad93f6SDavid Gibson 4811ad93f6SDavid Gibson /* 4911ad93f6SDavid Gibson * ICP-KVM 5011ad93f6SDavid Gibson */ 5111ad93f6SDavid Gibson static void icp_get_kvm_state(ICPState *ss) 5211ad93f6SDavid Gibson { 5311ad93f6SDavid Gibson uint64_t state; 5411ad93f6SDavid Gibson struct kvm_one_reg reg = { 5511ad93f6SDavid Gibson .id = KVM_REG_PPC_ICP_STATE, 5611ad93f6SDavid Gibson .addr = (uintptr_t)&state, 5711ad93f6SDavid Gibson }; 5811ad93f6SDavid Gibson int ret; 5911ad93f6SDavid Gibson 6011ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 6111ad93f6SDavid Gibson if (!ss->cs) { 6211ad93f6SDavid Gibson return; 6311ad93f6SDavid Gibson } 6411ad93f6SDavid Gibson 6511ad93f6SDavid Gibson ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, ®); 6611ad93f6SDavid Gibson if (ret != 0) { 6711ad93f6SDavid Gibson error_report("Unable to retrieve KVM interrupt controller state" 68*0f20ba62SAlexey Kardashevskiy " for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno)); 6911ad93f6SDavid Gibson exit(1); 7011ad93f6SDavid Gibson } 7111ad93f6SDavid Gibson 7211ad93f6SDavid Gibson ss->xirr = state >> KVM_REG_PPC_ICP_XISR_SHIFT; 7311ad93f6SDavid Gibson ss->mfrr = (state >> KVM_REG_PPC_ICP_MFRR_SHIFT) 7411ad93f6SDavid Gibson & KVM_REG_PPC_ICP_MFRR_MASK; 7511ad93f6SDavid Gibson ss->pending_priority = (state >> KVM_REG_PPC_ICP_PPRI_SHIFT) 7611ad93f6SDavid Gibson & KVM_REG_PPC_ICP_PPRI_MASK; 7711ad93f6SDavid Gibson } 7811ad93f6SDavid Gibson 7911ad93f6SDavid Gibson static int icp_set_kvm_state(ICPState *ss, int version_id) 8011ad93f6SDavid Gibson { 8111ad93f6SDavid Gibson uint64_t state; 8211ad93f6SDavid Gibson struct kvm_one_reg reg = { 8311ad93f6SDavid Gibson .id = KVM_REG_PPC_ICP_STATE, 8411ad93f6SDavid Gibson .addr = (uintptr_t)&state, 8511ad93f6SDavid Gibson }; 8611ad93f6SDavid Gibson int ret; 8711ad93f6SDavid Gibson 8811ad93f6SDavid Gibson /* ICP for this CPU thread is not in use, exiting */ 8911ad93f6SDavid Gibson if (!ss->cs) { 9011ad93f6SDavid Gibson return 0; 9111ad93f6SDavid Gibson } 9211ad93f6SDavid Gibson 9311ad93f6SDavid Gibson state = ((uint64_t)ss->xirr << KVM_REG_PPC_ICP_XISR_SHIFT) 9411ad93f6SDavid Gibson | ((uint64_t)ss->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) 9511ad93f6SDavid Gibson | ((uint64_t)ss->pending_priority << KVM_REG_PPC_ICP_PPRI_SHIFT); 9611ad93f6SDavid Gibson 9711ad93f6SDavid Gibson ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, ®); 9811ad93f6SDavid Gibson if (ret != 0) { 9911ad93f6SDavid Gibson error_report("Unable to restore KVM interrupt controller state (0x%" 100*0f20ba62SAlexey Kardashevskiy PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs), 10111ad93f6SDavid Gibson strerror(errno)); 10211ad93f6SDavid Gibson return ret; 10311ad93f6SDavid Gibson } 10411ad93f6SDavid Gibson 10511ad93f6SDavid Gibson return 0; 10611ad93f6SDavid Gibson } 10711ad93f6SDavid Gibson 10811ad93f6SDavid Gibson static void icp_kvm_reset(DeviceState *dev) 10911ad93f6SDavid Gibson { 11011ad93f6SDavid Gibson ICPState *icp = ICP(dev); 11111ad93f6SDavid Gibson 11211ad93f6SDavid Gibson icp->xirr = 0; 11311ad93f6SDavid Gibson icp->pending_priority = 0xff; 11411ad93f6SDavid Gibson icp->mfrr = 0xff; 11511ad93f6SDavid Gibson 11611ad93f6SDavid Gibson /* Make all outputs are deasserted */ 11711ad93f6SDavid Gibson qemu_set_irq(icp->output, 0); 11811ad93f6SDavid Gibson 11911ad93f6SDavid Gibson icp_set_kvm_state(icp, 1); 12011ad93f6SDavid Gibson } 12111ad93f6SDavid Gibson 12211ad93f6SDavid Gibson static void icp_kvm_class_init(ObjectClass *klass, void *data) 12311ad93f6SDavid Gibson { 12411ad93f6SDavid Gibson DeviceClass *dc = DEVICE_CLASS(klass); 12511ad93f6SDavid Gibson ICPStateClass *icpc = ICP_CLASS(klass); 12611ad93f6SDavid Gibson 12711ad93f6SDavid Gibson dc->reset = icp_kvm_reset; 12811ad93f6SDavid Gibson icpc->pre_save = icp_get_kvm_state; 12911ad93f6SDavid Gibson icpc->post_load = icp_set_kvm_state; 13011ad93f6SDavid Gibson } 13111ad93f6SDavid Gibson 13211ad93f6SDavid Gibson static const TypeInfo icp_kvm_info = { 13311ad93f6SDavid Gibson .name = TYPE_KVM_ICP, 13411ad93f6SDavid Gibson .parent = TYPE_ICP, 13511ad93f6SDavid Gibson .instance_size = sizeof(ICPState), 13611ad93f6SDavid Gibson .class_init = icp_kvm_class_init, 13711ad93f6SDavid Gibson .class_size = sizeof(ICPStateClass), 13811ad93f6SDavid Gibson }; 13911ad93f6SDavid Gibson 14011ad93f6SDavid Gibson /* 14111ad93f6SDavid Gibson * ICS-KVM 14211ad93f6SDavid Gibson */ 14311ad93f6SDavid Gibson static void ics_get_kvm_state(ICSState *ics) 14411ad93f6SDavid Gibson { 14511ad93f6SDavid Gibson KVMXICSState *icpkvm = KVM_XICS(ics->icp); 14611ad93f6SDavid Gibson uint64_t state; 14711ad93f6SDavid Gibson struct kvm_device_attr attr = { 14811ad93f6SDavid Gibson .flags = 0, 14911ad93f6SDavid Gibson .group = KVM_DEV_XICS_GRP_SOURCES, 15011ad93f6SDavid Gibson .addr = (uint64_t)(uintptr_t)&state, 15111ad93f6SDavid Gibson }; 15211ad93f6SDavid Gibson int i; 15311ad93f6SDavid Gibson 15411ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 15511ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 15611ad93f6SDavid Gibson int ret; 15711ad93f6SDavid Gibson 15811ad93f6SDavid Gibson attr.attr = i + ics->offset; 15911ad93f6SDavid Gibson 16011ad93f6SDavid Gibson ret = ioctl(icpkvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr); 16111ad93f6SDavid Gibson if (ret != 0) { 16211ad93f6SDavid Gibson error_report("Unable to retrieve KVM interrupt controller state" 16311ad93f6SDavid Gibson " for IRQ %d: %s", i + ics->offset, strerror(errno)); 16411ad93f6SDavid Gibson exit(1); 16511ad93f6SDavid Gibson } 16611ad93f6SDavid Gibson 16711ad93f6SDavid Gibson irq->server = state & KVM_XICS_DESTINATION_MASK; 16811ad93f6SDavid Gibson irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT) 16911ad93f6SDavid Gibson & KVM_XICS_PRIORITY_MASK; 17011ad93f6SDavid Gibson /* 17111ad93f6SDavid Gibson * To be consistent with the software emulation in xics.c, we 17211ad93f6SDavid Gibson * split out the masked state + priority that we get from the 17311ad93f6SDavid Gibson * kernel into 'current priority' (0xff if masked) and 17411ad93f6SDavid Gibson * 'saved priority' (if masked, this is the priority the 17511ad93f6SDavid Gibson * interrupt had before it was masked). Masking and unmasking 17611ad93f6SDavid Gibson * are done with the ibm,int-off and ibm,int-on RTAS calls. 17711ad93f6SDavid Gibson */ 17811ad93f6SDavid Gibson if (state & KVM_XICS_MASKED) { 17911ad93f6SDavid Gibson irq->priority = 0xff; 18011ad93f6SDavid Gibson } else { 18111ad93f6SDavid Gibson irq->priority = irq->saved_priority; 18211ad93f6SDavid Gibson } 18311ad93f6SDavid Gibson 18411ad93f6SDavid Gibson if (state & KVM_XICS_PENDING) { 18511ad93f6SDavid Gibson if (state & KVM_XICS_LEVEL_SENSITIVE) { 18611ad93f6SDavid Gibson irq->status |= XICS_STATUS_ASSERTED; 18711ad93f6SDavid Gibson } else { 18811ad93f6SDavid Gibson /* 18911ad93f6SDavid Gibson * A pending edge-triggered interrupt (or MSI) 19011ad93f6SDavid Gibson * must have been rejected previously when we 19111ad93f6SDavid Gibson * first detected it and tried to deliver it, 19211ad93f6SDavid Gibson * so mark it as pending and previously rejected 19311ad93f6SDavid Gibson * for consistency with how xics.c works. 19411ad93f6SDavid Gibson */ 19511ad93f6SDavid Gibson irq->status |= XICS_STATUS_MASKED_PENDING 19611ad93f6SDavid Gibson | XICS_STATUS_REJECTED; 19711ad93f6SDavid Gibson } 19811ad93f6SDavid Gibson } 19911ad93f6SDavid Gibson } 20011ad93f6SDavid Gibson } 20111ad93f6SDavid Gibson 20211ad93f6SDavid Gibson static int ics_set_kvm_state(ICSState *ics, int version_id) 20311ad93f6SDavid Gibson { 20411ad93f6SDavid Gibson KVMXICSState *icpkvm = KVM_XICS(ics->icp); 20511ad93f6SDavid Gibson uint64_t state; 20611ad93f6SDavid Gibson struct kvm_device_attr attr = { 20711ad93f6SDavid Gibson .flags = 0, 20811ad93f6SDavid Gibson .group = KVM_DEV_XICS_GRP_SOURCES, 20911ad93f6SDavid Gibson .addr = (uint64_t)(uintptr_t)&state, 21011ad93f6SDavid Gibson }; 21111ad93f6SDavid Gibson int i; 21211ad93f6SDavid Gibson 21311ad93f6SDavid Gibson for (i = 0; i < ics->nr_irqs; i++) { 21411ad93f6SDavid Gibson ICSIRQState *irq = &ics->irqs[i]; 21511ad93f6SDavid Gibson int ret; 21611ad93f6SDavid Gibson 21711ad93f6SDavid Gibson attr.attr = i + ics->offset; 21811ad93f6SDavid Gibson 21911ad93f6SDavid Gibson state = irq->server; 22011ad93f6SDavid Gibson state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK) 22111ad93f6SDavid Gibson << KVM_XICS_PRIORITY_SHIFT; 22211ad93f6SDavid Gibson if (irq->priority != irq->saved_priority) { 22311ad93f6SDavid Gibson assert(irq->priority == 0xff); 22411ad93f6SDavid Gibson state |= KVM_XICS_MASKED; 22511ad93f6SDavid Gibson } 22611ad93f6SDavid Gibson 22711ad93f6SDavid Gibson if (ics->islsi[i]) { 22811ad93f6SDavid Gibson state |= KVM_XICS_LEVEL_SENSITIVE; 22911ad93f6SDavid Gibson if (irq->status & XICS_STATUS_ASSERTED) { 23011ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 23111ad93f6SDavid Gibson } 23211ad93f6SDavid Gibson } else { 23311ad93f6SDavid Gibson if (irq->status & XICS_STATUS_MASKED_PENDING) { 23411ad93f6SDavid Gibson state |= KVM_XICS_PENDING; 23511ad93f6SDavid Gibson } 23611ad93f6SDavid Gibson } 23711ad93f6SDavid Gibson 23811ad93f6SDavid Gibson ret = ioctl(icpkvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); 23911ad93f6SDavid Gibson if (ret != 0) { 24011ad93f6SDavid Gibson error_report("Unable to restore KVM interrupt controller state" 24111ad93f6SDavid Gibson " for IRQs %d: %s", i + ics->offset, strerror(errno)); 24211ad93f6SDavid Gibson return ret; 24311ad93f6SDavid Gibson } 24411ad93f6SDavid Gibson } 24511ad93f6SDavid Gibson 24611ad93f6SDavid Gibson return 0; 24711ad93f6SDavid Gibson } 24811ad93f6SDavid Gibson 24911ad93f6SDavid Gibson static void ics_kvm_set_irq(void *opaque, int srcno, int val) 25011ad93f6SDavid Gibson { 25111ad93f6SDavid Gibson ICSState *ics = opaque; 25211ad93f6SDavid Gibson struct kvm_irq_level args; 25311ad93f6SDavid Gibson int rc; 25411ad93f6SDavid Gibson 25511ad93f6SDavid Gibson args.irq = srcno + ics->offset; 25611ad93f6SDavid Gibson if (!ics->islsi[srcno]) { 25711ad93f6SDavid Gibson if (!val) { 25811ad93f6SDavid Gibson return; 25911ad93f6SDavid Gibson } 26011ad93f6SDavid Gibson args.level = KVM_INTERRUPT_SET; 26111ad93f6SDavid Gibson } else { 26211ad93f6SDavid Gibson args.level = val ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; 26311ad93f6SDavid Gibson } 26411ad93f6SDavid Gibson rc = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE, &args); 26511ad93f6SDavid Gibson if (rc < 0) { 26611ad93f6SDavid Gibson perror("kvm_irq_line"); 26711ad93f6SDavid Gibson } 26811ad93f6SDavid Gibson } 26911ad93f6SDavid Gibson 27011ad93f6SDavid Gibson static void ics_kvm_reset(DeviceState *dev) 27111ad93f6SDavid Gibson { 27211ad93f6SDavid Gibson ics_set_kvm_state(ICS(dev), 1); 27311ad93f6SDavid Gibson } 27411ad93f6SDavid Gibson 27511ad93f6SDavid Gibson static void ics_kvm_realize(DeviceState *dev, Error **errp) 27611ad93f6SDavid Gibson { 27711ad93f6SDavid Gibson ICSState *ics = ICS(dev); 27811ad93f6SDavid Gibson 27911ad93f6SDavid Gibson if (!ics->nr_irqs) { 28011ad93f6SDavid Gibson error_setg(errp, "Number of interrupts needs to be greater 0"); 28111ad93f6SDavid Gibson return; 28211ad93f6SDavid Gibson } 28311ad93f6SDavid Gibson ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); 28411ad93f6SDavid Gibson ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool)); 28511ad93f6SDavid Gibson ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs); 28611ad93f6SDavid Gibson } 28711ad93f6SDavid Gibson 28811ad93f6SDavid Gibson static void ics_kvm_class_init(ObjectClass *klass, void *data) 28911ad93f6SDavid Gibson { 29011ad93f6SDavid Gibson DeviceClass *dc = DEVICE_CLASS(klass); 29111ad93f6SDavid Gibson ICSStateClass *icsc = ICS_CLASS(klass); 29211ad93f6SDavid Gibson 29311ad93f6SDavid Gibson dc->realize = ics_kvm_realize; 29411ad93f6SDavid Gibson dc->reset = ics_kvm_reset; 29511ad93f6SDavid Gibson icsc->pre_save = ics_get_kvm_state; 29611ad93f6SDavid Gibson icsc->post_load = ics_set_kvm_state; 29711ad93f6SDavid Gibson } 29811ad93f6SDavid Gibson 29911ad93f6SDavid Gibson static const TypeInfo ics_kvm_info = { 30011ad93f6SDavid Gibson .name = TYPE_KVM_ICS, 30111ad93f6SDavid Gibson .parent = TYPE_ICS, 30211ad93f6SDavid Gibson .instance_size = sizeof(ICSState), 30311ad93f6SDavid Gibson .class_init = ics_kvm_class_init, 30411ad93f6SDavid Gibson }; 30511ad93f6SDavid Gibson 30611ad93f6SDavid Gibson /* 30711ad93f6SDavid Gibson * XICS-KVM 30811ad93f6SDavid Gibson */ 30911ad93f6SDavid Gibson static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) 31011ad93f6SDavid Gibson { 31111ad93f6SDavid Gibson CPUState *cs; 31211ad93f6SDavid Gibson ICPState *ss; 31311ad93f6SDavid Gibson KVMXICSState *icpkvm = KVM_XICS(icp); 31411ad93f6SDavid Gibson 31511ad93f6SDavid Gibson cs = CPU(cpu); 31611ad93f6SDavid Gibson ss = &icp->ss[cs->cpu_index]; 31711ad93f6SDavid Gibson 31811ad93f6SDavid Gibson assert(cs->cpu_index < icp->nr_servers); 31911ad93f6SDavid Gibson if (icpkvm->kernel_xics_fd == -1) { 32011ad93f6SDavid Gibson abort(); 32111ad93f6SDavid Gibson } 32211ad93f6SDavid Gibson 32311ad93f6SDavid Gibson if (icpkvm->kernel_xics_fd != -1) { 32411ad93f6SDavid Gibson int ret; 32511ad93f6SDavid Gibson struct kvm_enable_cap xics_enable_cap = { 32611ad93f6SDavid Gibson .cap = KVM_CAP_IRQ_XICS, 32711ad93f6SDavid Gibson .flags = 0, 328*0f20ba62SAlexey Kardashevskiy .args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0}, 32911ad93f6SDavid Gibson }; 33011ad93f6SDavid Gibson 33111ad93f6SDavid Gibson ss->cs = cs; 33211ad93f6SDavid Gibson 33311ad93f6SDavid Gibson ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap); 33411ad93f6SDavid Gibson if (ret < 0) { 335*0f20ba62SAlexey Kardashevskiy error_report("Unable to connect CPU%ld to kernel XICS: %s", 336*0f20ba62SAlexey Kardashevskiy kvm_arch_vcpu_id(cs), strerror(errno)); 33711ad93f6SDavid Gibson exit(1); 33811ad93f6SDavid Gibson } 33911ad93f6SDavid Gibson } 34011ad93f6SDavid Gibson } 34111ad93f6SDavid Gibson 34211ad93f6SDavid Gibson static void xics_kvm_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp) 34311ad93f6SDavid Gibson { 34411ad93f6SDavid Gibson icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; 34511ad93f6SDavid Gibson } 34611ad93f6SDavid Gibson 34711ad93f6SDavid Gibson static void xics_kvm_set_nr_servers(XICSState *icp, uint32_t nr_servers, 34811ad93f6SDavid Gibson Error **errp) 34911ad93f6SDavid Gibson { 35011ad93f6SDavid Gibson int i; 35111ad93f6SDavid Gibson 35211ad93f6SDavid Gibson icp->nr_servers = nr_servers; 35311ad93f6SDavid Gibson 35411ad93f6SDavid Gibson icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); 35511ad93f6SDavid Gibson for (i = 0; i < icp->nr_servers; i++) { 35611ad93f6SDavid Gibson char buffer[32]; 35711ad93f6SDavid Gibson object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_KVM_ICP); 35811ad93f6SDavid Gibson snprintf(buffer, sizeof(buffer), "icp[%d]", i); 35911ad93f6SDavid Gibson object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), 36011ad93f6SDavid Gibson errp); 36111ad93f6SDavid Gibson } 36211ad93f6SDavid Gibson } 36311ad93f6SDavid Gibson 36411ad93f6SDavid Gibson static void rtas_dummy(PowerPCCPU *cpu, sPAPREnvironment *spapr, 36511ad93f6SDavid Gibson uint32_t token, 36611ad93f6SDavid Gibson uint32_t nargs, target_ulong args, 36711ad93f6SDavid Gibson uint32_t nret, target_ulong rets) 36811ad93f6SDavid Gibson { 36911ad93f6SDavid Gibson error_report("pseries: %s must never be called for in-kernel XICS", 37011ad93f6SDavid Gibson __func__); 37111ad93f6SDavid Gibson } 37211ad93f6SDavid Gibson 37311ad93f6SDavid Gibson static void xics_kvm_realize(DeviceState *dev, Error **errp) 37411ad93f6SDavid Gibson { 37511ad93f6SDavid Gibson KVMXICSState *icpkvm = KVM_XICS(dev); 37611ad93f6SDavid Gibson XICSState *icp = XICS_COMMON(dev); 37711ad93f6SDavid Gibson int i, rc; 37811ad93f6SDavid Gibson Error *error = NULL; 37911ad93f6SDavid Gibson struct kvm_create_device xics_create_device = { 38011ad93f6SDavid Gibson .type = KVM_DEV_TYPE_XICS, 38111ad93f6SDavid Gibson .flags = 0, 38211ad93f6SDavid Gibson }; 38311ad93f6SDavid Gibson 38411ad93f6SDavid Gibson if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_IRQ_XICS)) { 38511ad93f6SDavid Gibson error_setg(errp, 38611ad93f6SDavid Gibson "KVM and IRQ_XICS capability must be present for in-kernel XICS"); 38711ad93f6SDavid Gibson goto fail; 38811ad93f6SDavid Gibson } 38911ad93f6SDavid Gibson 39011ad93f6SDavid Gibson icpkvm->set_xive_token = spapr_rtas_register("ibm,set-xive", rtas_dummy); 39111ad93f6SDavid Gibson icpkvm->get_xive_token = spapr_rtas_register("ibm,get-xive", rtas_dummy); 39211ad93f6SDavid Gibson icpkvm->int_off_token = spapr_rtas_register("ibm,int-off", rtas_dummy); 39311ad93f6SDavid Gibson icpkvm->int_on_token = spapr_rtas_register("ibm,int-on", rtas_dummy); 39411ad93f6SDavid Gibson 39511ad93f6SDavid Gibson rc = kvmppc_define_rtas_kernel_token(icpkvm->set_xive_token, 39611ad93f6SDavid Gibson "ibm,set-xive"); 39711ad93f6SDavid Gibson if (rc < 0) { 39811ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,set-xive"); 39911ad93f6SDavid Gibson goto fail; 40011ad93f6SDavid Gibson } 40111ad93f6SDavid Gibson 40211ad93f6SDavid Gibson rc = kvmppc_define_rtas_kernel_token(icpkvm->get_xive_token, 40311ad93f6SDavid Gibson "ibm,get-xive"); 40411ad93f6SDavid Gibson if (rc < 0) { 40511ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,get-xive"); 40611ad93f6SDavid Gibson goto fail; 40711ad93f6SDavid Gibson } 40811ad93f6SDavid Gibson 40911ad93f6SDavid Gibson rc = kvmppc_define_rtas_kernel_token(icpkvm->int_on_token, "ibm,int-on"); 41011ad93f6SDavid Gibson if (rc < 0) { 41111ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-on"); 41211ad93f6SDavid Gibson goto fail; 41311ad93f6SDavid Gibson } 41411ad93f6SDavid Gibson 41511ad93f6SDavid Gibson rc = kvmppc_define_rtas_kernel_token(icpkvm->int_off_token, "ibm,int-off"); 41611ad93f6SDavid Gibson if (rc < 0) { 41711ad93f6SDavid Gibson error_setg(errp, "kvmppc_define_rtas_kernel_token: ibm,int-off"); 41811ad93f6SDavid Gibson goto fail; 41911ad93f6SDavid Gibson } 42011ad93f6SDavid Gibson 42111ad93f6SDavid Gibson /* Create the kernel ICP */ 42211ad93f6SDavid Gibson rc = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &xics_create_device); 42311ad93f6SDavid Gibson if (rc < 0) { 42411ad93f6SDavid Gibson error_setg_errno(errp, -rc, "Error on KVM_CREATE_DEVICE for XICS"); 42511ad93f6SDavid Gibson goto fail; 42611ad93f6SDavid Gibson } 42711ad93f6SDavid Gibson 42811ad93f6SDavid Gibson icpkvm->kernel_xics_fd = xics_create_device.fd; 42911ad93f6SDavid Gibson 43011ad93f6SDavid Gibson object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); 43111ad93f6SDavid Gibson if (error) { 43211ad93f6SDavid Gibson error_propagate(errp, error); 43311ad93f6SDavid Gibson goto fail; 43411ad93f6SDavid Gibson } 43511ad93f6SDavid Gibson 43611ad93f6SDavid Gibson assert(icp->nr_servers); 43711ad93f6SDavid Gibson for (i = 0; i < icp->nr_servers; i++) { 43811ad93f6SDavid Gibson object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); 43911ad93f6SDavid Gibson if (error) { 44011ad93f6SDavid Gibson error_propagate(errp, error); 44111ad93f6SDavid Gibson goto fail; 44211ad93f6SDavid Gibson } 44311ad93f6SDavid Gibson } 4449554233cSAlexey Kardashevskiy 4459554233cSAlexey Kardashevskiy kvm_kernel_irqchip = true; 4469554233cSAlexey Kardashevskiy kvm_irqfds_allowed = true; 4479554233cSAlexey Kardashevskiy kvm_msi_via_irqfd_allowed = true; 4489554233cSAlexey Kardashevskiy kvm_gsi_direct_mapping = true; 4499554233cSAlexey Kardashevskiy 45011ad93f6SDavid Gibson return; 45111ad93f6SDavid Gibson 45211ad93f6SDavid Gibson fail: 45311ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,set-xive"); 45411ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,get-xive"); 45511ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-on"); 45611ad93f6SDavid Gibson kvmppc_define_rtas_kernel_token(0, "ibm,int-off"); 45711ad93f6SDavid Gibson } 45811ad93f6SDavid Gibson 45911ad93f6SDavid Gibson static void xics_kvm_initfn(Object *obj) 46011ad93f6SDavid Gibson { 46111ad93f6SDavid Gibson XICSState *xics = XICS_COMMON(obj); 46211ad93f6SDavid Gibson 46311ad93f6SDavid Gibson xics->ics = ICS(object_new(TYPE_KVM_ICS)); 46411ad93f6SDavid Gibson object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); 46511ad93f6SDavid Gibson xics->ics->icp = xics; 46611ad93f6SDavid Gibson } 46711ad93f6SDavid Gibson 46811ad93f6SDavid Gibson static void xics_kvm_class_init(ObjectClass *oc, void *data) 46911ad93f6SDavid Gibson { 47011ad93f6SDavid Gibson DeviceClass *dc = DEVICE_CLASS(oc); 47111ad93f6SDavid Gibson XICSStateClass *xsc = XICS_COMMON_CLASS(oc); 47211ad93f6SDavid Gibson 47311ad93f6SDavid Gibson dc->realize = xics_kvm_realize; 47411ad93f6SDavid Gibson xsc->cpu_setup = xics_kvm_cpu_setup; 47511ad93f6SDavid Gibson xsc->set_nr_irqs = xics_kvm_set_nr_irqs; 47611ad93f6SDavid Gibson xsc->set_nr_servers = xics_kvm_set_nr_servers; 47711ad93f6SDavid Gibson } 47811ad93f6SDavid Gibson 47911ad93f6SDavid Gibson static const TypeInfo xics_kvm_info = { 48011ad93f6SDavid Gibson .name = TYPE_KVM_XICS, 48111ad93f6SDavid Gibson .parent = TYPE_XICS_COMMON, 48211ad93f6SDavid Gibson .instance_size = sizeof(KVMXICSState), 48311ad93f6SDavid Gibson .class_init = xics_kvm_class_init, 48411ad93f6SDavid Gibson .instance_init = xics_kvm_initfn, 48511ad93f6SDavid Gibson }; 48611ad93f6SDavid Gibson 48711ad93f6SDavid Gibson static void xics_kvm_register_types(void) 48811ad93f6SDavid Gibson { 48911ad93f6SDavid Gibson type_register_static(&xics_kvm_info); 49011ad93f6SDavid Gibson type_register_static(&ics_kvm_info); 49111ad93f6SDavid Gibson type_register_static(&icp_kvm_info); 49211ad93f6SDavid Gibson } 49311ad93f6SDavid Gibson 49411ad93f6SDavid Gibson type_init(xics_kvm_register_types) 495