From 21d79055a3bfbe29b260ea7a986701d3d6db32be Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Thu, 2 May 2013 13:08:46 -0500 Subject: KVM: PPC: revert the MPIC and irqfd patches There are important bug fixes in the upstream patches that got applied. This revert commit removes the old patches to prepare for the new set. ------------------------------------------------------------------ Revert "KVM: PPC: MPIC: Restrict to e500 platforms" This reverts commit 540983d28a0dbe60b8bd08d96448b6544ad60293. Revert "KVM: PPC: MPIC: Add support for KVM_IRQ_LINE" This reverts commit ce5692ad437dfa0e7eb35918c40cdbd119b50909. Revert "KVM: PPC: Support irq routing and irqfd for in-kernel MPIC" This reverts commit 4ad8621c44d1420090241eaa8d5594e72ae6e05f. Revert "KVM: Move irqfd resample cap handling to generic code" This reverts commit e5557be2f787cff8f4daab4b39d38b5822f41390. Revert "KVM: Move irq routing setup to irqchip.c" This reverts commit 4486cf9a7a4d823c43b54e1b6280f41bcc59022d. Revert "KVM: Extract generic irqchip logic into irqchip.c" This reverts commit 0028971f3b4251cc231989dd9570f426d8472a2b. Revert "KVM: Move irq routing to generic code" This reverts commit e144029a9451b391afcbe123d1895523654e2bc5. Revert "KVM: Remove kvm_get_intr_delivery_bitmask" This reverts commit a7e10a68a247bbcde502947cf2fd4a7722c30512. Revert "KVM: Drop __KVM_HAVE_IOAPIC condition on irq routing" This reverts commit 38deef57a0eef339636c8fb8b8207a5a24e241ad. Revert "KVM: Introduce CONFIG_HAVE_KVM_IRQ_ROUTING" This reverts commit 3b196a30f460bf0f1bd6737266ed479a597a5b58. Revert "KVM: Add KVM_IRQCHIP_NUM_PINS in addition to KVM_IOAPIC_NUM_PINS" This reverts commit 40602a78a8a12d17ca895ea0a2721441c155801f. Revert "kvm/ppc/mpic: add KVM_CAP_IRQ_MPIC" This reverts commit 36e75cd4b65376dbee78ad92b084f9428868fe29. Revert "kvm/ppc/mpic: in-kernel MPIC emulation" This reverts commit 13ded2807a22aceff940ca1e282897e36fb0ba47. Revert "kvm/ppc/mpic: adapt to kernel style and environment" This reverts commit ac811c14ba3229ecbd39f3dc0b7f4c43ded36308. Revert "kvm/ppc/mpic: remove some obviously unneeded code" This reverts commit a60b865ac8d5cf3bff1e4a7dd43b6d8aaed87391. Revert "kvm/ppc/mpic: import hw/openpic.c from QEMU" This reverts commit 256cdf3f6df0561883ce801fd29595ecd031209a. Revert "kvm: add device control API" This reverts commit 8c848b9ed8b15aaccfb54511b22b205afc14f2d6. ------------------------------------------------------------------ Signed-off-by: Stuart Yoder diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index da6b44a..f94e300 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2147,76 +2147,6 @@ header; first `n_valid' valid entries with contents from the data written, then `n_invalid' invalid entries, invalidating any previously valid entries found. -4.79 KVM_CREATE_DEVICE - -Capability: KVM_CAP_DEVICE_CTRL -Type: vm ioctl -Parameters: struct kvm_create_device (in/out) -Returns: 0 on success, -1 on error -Errors: - ENODEV: The device type is unknown or unsupported - EEXIST: Device already created, and this type of device may not - be instantiated multiple times - - Other error conditions may be defined by individual device types or - have their standard meanings. - -Creates an emulated device in the kernel. The file descriptor returned -in fd can be used with KVM_SET/GET/HAS_DEVICE_ATTR. - -If the KVM_CREATE_DEVICE_TEST flag is set, only test whether the -device type is supported (not necessarily whether it can be created -in the current vm). - -Individual devices should not define flags. Attributes should be used -for specifying any behavior that is not implied by the device type -number. - -struct kvm_create_device { - __u32 type; /* in: KVM_DEV_TYPE_xxx */ - __u32 fd; /* out: device handle */ - __u32 flags; /* in: KVM_CREATE_DEVICE_xxx */ -}; - -4.80 KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR - -Capability: KVM_CAP_DEVICE_CTRL -Type: device ioctl -Parameters: struct kvm_device_attr -Returns: 0 on success, -1 on error -Errors: - ENXIO: The group or attribute is unknown/unsupported for this device - EPERM: The attribute cannot (currently) be accessed this way - (e.g. read-only attribute, or attribute that only makes - sense when the device is in a different state) - - Other error conditions may be defined by individual device types. - -Gets/sets a specified piece of device configuration and/or state. The -semantics are device-specific. See individual device documentation in -the "devices" directory. As with ONE_REG, the size of the data -transferred is defined by the particular attribute. - -struct kvm_device_attr { - __u32 flags; /* no flags currently defined */ - __u32 group; /* device-defined */ - __u64 attr; /* group-defined */ - __u64 addr; /* userspace address of attr data */ -}; - -4.81 KVM_HAS_DEVICE_ATTR - -Capability: KVM_CAP_DEVICE_CTRL -Type: device ioctl -Parameters: struct kvm_device_attr -Returns: 0 on success, -1 on error -Errors: - ENXIO: The group or attribute is unknown/unsupported for this device - -Tests whether a device supports a particular attribute. A successful -return indicates the attribute is implemented. It does not necessarily -indicate that the attribute can be read or written in the device's -current state. "addr" is ignored. 5. The kvm_run structure ------------------------ @@ -2590,11 +2520,3 @@ to receive the topmost interrupt vector. When disabled (args[0] == 0), behavior is as if this facility is unsupported. When this capability is enabled, KVM_EXIT_EPR can occur. - -6.6 KVM_CAP_IRQ_MPIC - -Architectures: ppc -Parameters: args[0] is the MPIC device fd - args[1] is the MPIC CPU number for this vcpu - -This capability connects the vcpu to an in-kernel MPIC device. diff --git a/Documentation/virtual/kvm/devices/mpic.txt b/Documentation/virtual/kvm/devices/mpic.txt deleted file mode 100644 index ce98e32..0000000 --- a/Documentation/virtual/kvm/devices/mpic.txt +++ /dev/null @@ -1,37 +0,0 @@ -MPIC interrupt controller -========================= - -Device types supported: - KVM_DEV_TYPE_FSL_MPIC_20 Freescale MPIC v2.0 - KVM_DEV_TYPE_FSL_MPIC_42 Freescale MPIC v4.2 - -Only one MPIC instance, of any type, may be instantiated. The created -MPIC will act as the system interrupt controller, connecting to each -vcpu's interrupt inputs. - -Groups: - KVM_DEV_MPIC_GRP_MISC - Attributes: - KVM_DEV_MPIC_BASE_ADDR (rw, 64-bit) - Base address of the 256 KiB MPIC register space. Must be - naturally aligned. A value of zero disables the mapping. - Reset value is zero. - - KVM_DEV_MPIC_GRP_REGISTER (rw, 32-bit) - Access an MPIC register, as if the access were made from the guest. - "attr" is the byte offset into the MPIC register space. Accesses - must be 4-byte aligned. - - MSIs may be signaled by using this attribute group to write - to the relevant MSIIR. - - KVM_DEV_MPIC_GRP_IRQ_ACTIVE (rw, 32-bit) - IRQ input line for each standard openpic source. 0 is inactive and 1 - is active, regardless of interrupt sense. - - For edge-triggered interrupts: Writing 1 is considered an activating - edge, and writing 0 is ignored. Reading returns 1 if a previously - signaled edge has not been acknowledged, and 0 otherwise. - - "attr" is the IRQ number. IRQ numbers for standard sources are the - byte offset of the relevant IVPR from EIVPR0, divided by 32. diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 43ac154..19c8ac4 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -46,10 +46,6 @@ #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 #endif -/* These values are internal and can be increased later */ -#define KVM_NR_IRQCHIPS 1 -#define KVM_IRQCHIP_NUM_PINS 256 - #if !defined(CONFIG_KVM_440) #include @@ -267,9 +263,6 @@ struct kvm_arch { #ifdef CONFIG_PPC_BOOK3S_64 struct list_head spapr_tce_tables; #endif -#ifdef CONFIG_KVM_MPIC - void *mpic; -#endif }; /* @@ -373,11 +366,6 @@ struct kvmppc_slb { #define KVMPPC_BOOKE_MAX_IAC 4 #define KVMPPC_BOOKE_MAX_DAC 2 -/* KVMPPC_EPR_USER takes precedence over KVMPPC_EPR_KERNEL */ -#define KVMPPC_EPR_NONE 0 /* EPR not supported */ -#define KVMPPC_EPR_USER 1 /* exit to userspace to fill EPR */ -#define KVMPPC_EPR_KERNEL 2 /* in-kernel irqchip */ - struct kvmppc_booke_debug_reg { u32 dbcr0; u32 dbcr1; @@ -389,11 +377,6 @@ struct kvmppc_booke_debug_reg { u64 dac[KVMPPC_BOOKE_MAX_DAC]; }; -#define KVMPPC_IRQ_DEFAULT 0 -#define KVMPPC_IRQ_MPIC 1 - -struct openpic; - struct kvm_vcpu_arch { ulong host_stack; u32 host_pid; @@ -556,7 +539,7 @@ struct kvm_vcpu_arch { u8 sane; u8 cpu_type; u8 hcall_needed; - u8 epr_flags; /* KVMPPC_EPR_xxx */ + u8 epr_enabled; u8 epr_needed; u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ @@ -583,10 +566,6 @@ struct kvm_vcpu_arch { unsigned long magic_page_pa; /* phys addr to map the magic page to */ unsigned long magic_page_ea; /* effect. addr to map the magic page to */ - int irq_type; /* one of KVM_IRQ_* */ - int irq_cpu_id; - struct openpic *mpic; /* KVM_IRQ_MPIC */ - #ifdef CONFIG_KVM_BOOK3S_64_HV struct kvm_vcpu_arch_shared shregs; @@ -627,6 +606,5 @@ struct kvm_vcpu_arch { #define KVM_MMIO_REG_FQPR 0x0060 #define __KVM_HAVE_ARCH_WQP -#define __KVM_HAVE_CREATE_DEVICE #endif /* __POWERPC_KVM_HOST_H__ */ diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index f86b5a6..b20f580 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -164,8 +164,6 @@ extern int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu); extern int kvm_vm_ioctl_get_htab_fd(struct kvm *kvm, struct kvm_get_htab_fd *); -int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq); - /* * Cuts out inst bits with ordering according to spec. * That means the leftmost bit is zero. All given bits are included. @@ -247,8 +245,6 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *); void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid); -struct openpic; - #ifdef CONFIG_KVM_BOOK3S_64_HV static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) { @@ -274,11 +270,6 @@ static inline void kvmppc_set_epr(struct kvm_vcpu *vcpu, u32 epr) #endif } -void kvmppc_mpic_set_epr(struct kvm_vcpu *vcpu); -int kvmppc_mpic_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu, - u32 cpu); -void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, struct kvm_vcpu *vcpu); - int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu, struct kvm_config_tlb *cfg); int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu, diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index 449bad8..5aefeb9 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h @@ -25,8 +25,6 @@ /* Select powerpc specific features in */ #define __KVM_HAVE_SPAPR_TCE #define __KVM_HAVE_PPC_SMT -#define __KVM_HAVE_IRQCHIP -#define __KVM_HAVE_IRQ_LINE #define __KVM_HAVE_GUEST_DEBUG struct kvm_regs { @@ -487,11 +485,4 @@ struct kvm_get_htab_header { #define KVM_REG_PPC_TLB3PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9a) #define KVM_REG_PPC_EPTCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9b) -/* Device control API: PPC-specific devices */ -#define KVM_DEV_MPIC_GRP_MISC 1 -#define KVM_DEV_MPIC_BASE_ADDR 0 /* 64-bit */ - -#define KVM_DEV_MPIC_GRP_REGISTER 2 /* 32-bit */ -#define KVM_DEV_MPIC_GRP_IRQ_ACTIVE 3 /* 32-bit */ - #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index 656e0bc..4489520 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -151,18 +151,6 @@ config KVM_E500MC If unsure, say N. -config KVM_MPIC - bool "KVM in-kernel MPIC emulation" - depends on KVM && E500 - select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQ_ROUTING - select HAVE_KVM_MSI - help - Enable support for emulating MPIC devices inside the - host kernel, rather than relying on userspace to emulate. - Currently, support is limited to certain versions of - Freescale's MPIC implementation. - source drivers/vhost/Kconfig endif # VIRTUALIZATION diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index 4eada0c..b772ede 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile @@ -103,9 +103,6 @@ kvm-book3s_32-objs := \ book3s_32_mmu.o kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs) -kvm-objs-$(CONFIG_KVM_MPIC) += mpic.o -kvm-objs-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(addprefix ../../../virt/kvm/, irqchip.o) - kvm-objs := $(kvm-objs-m) $(kvm-objs-y) obj-$(CONFIG_KVM_440) += kvm.o diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 9731ad6..5d9383f 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -370,7 +370,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, keep_irq = true; } - if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_flags) + if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_enabled) update_epr = true; switch (priority) { @@ -451,16 +451,8 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, set_guest_esr(vcpu, vcpu->arch.queued_esr); if (update_dear == true) set_guest_dear(vcpu, vcpu->arch.queued_dear); - if (update_epr == true) { - if (vcpu->arch.epr_flags & KVMPPC_EPR_USER) - kvm_make_request(KVM_REQ_EPR_EXIT, vcpu); -#ifdef CONFIG_KVM_MPIC - else if (vcpu->arch.epr_flags & KVMPPC_EPR_KERNEL) { - BUG_ON(vcpu->arch.irq_type != KVMPPC_IRQ_MPIC); - kvmppc_mpic_set_epr(vcpu); - } -#endif - } + if (update_epr == true) + kvm_make_request(KVM_REQ_EPR_EXIT, vcpu); new_msr &= msr_mask; #if defined(CONFIG_64BIT) diff --git a/arch/powerpc/kvm/irq.h b/arch/powerpc/kvm/irq.h deleted file mode 100644 index f1e27fd..0000000 --- a/arch/powerpc/kvm/irq.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __IRQ_H -#define __IRQ_H - -#include - -static inline int irqchip_in_kernel(struct kvm *kvm) -{ - int ret = 0; - -#ifdef CONFIG_KVM_MPIC - ret = ret || (kvm->arch.mpic != NULL); -#endif - smp_rmb(); - return ret; -} - -#endif diff --git a/arch/powerpc/kvm/mpic.c b/arch/powerpc/kvm/mpic.c deleted file mode 100644 index 475a98b..0000000 --- a/arch/powerpc/kvm/mpic.c +++ /dev/null @@ -1,1863 +0,0 @@ -/* - * OpenPIC emulation - * - * Copyright (c) 2004 Jocelyn Mayer - * 2011 Alexander Graf - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iodev.h" - -#define MAX_CPU 32 -#define MAX_SRC 256 -#define MAX_TMR 4 -#define MAX_IPI 4 -#define MAX_MSI 8 -#define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR) -#define VID 0x03 /* MPIC version ID */ - -/* OpenPIC capability flags */ -#define OPENPIC_FLAG_IDR_CRIT (1 << 0) -#define OPENPIC_FLAG_ILR (2 << 0) - -/* OpenPIC address map */ -#define OPENPIC_REG_SIZE 0x40000 -#define OPENPIC_GLB_REG_START 0x0 -#define OPENPIC_GLB_REG_SIZE 0x10F0 -#define OPENPIC_TMR_REG_START 0x10F0 -#define OPENPIC_TMR_REG_SIZE 0x220 -#define OPENPIC_MSI_REG_START 0x1600 -#define OPENPIC_MSI_REG_SIZE 0x200 -#define OPENPIC_SUMMARY_REG_START 0x3800 -#define OPENPIC_SUMMARY_REG_SIZE 0x800 -#define OPENPIC_SRC_REG_START 0x10000 -#define OPENPIC_SRC_REG_SIZE (MAX_SRC * 0x20) -#define OPENPIC_CPU_REG_START 0x20000 -#define OPENPIC_CPU_REG_SIZE (0x100 + ((MAX_CPU - 1) * 0x1000)) - -struct fsl_mpic_info { - int max_ext; -}; - -static struct fsl_mpic_info fsl_mpic_20 = { - .max_ext = 12, -}; - -static struct fsl_mpic_info fsl_mpic_42 = { - .max_ext = 12, -}; - -#define FRR_NIRQ_SHIFT 16 -#define FRR_NCPU_SHIFT 8 -#define FRR_VID_SHIFT 0 - -#define VID_REVISION_1_2 2 -#define VID_REVISION_1_3 3 - -#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ - -#define GCR_RESET 0x80000000 -#define GCR_MODE_PASS 0x00000000 -#define GCR_MODE_MIXED 0x20000000 -#define GCR_MODE_PROXY 0x60000000 - -#define TBCR_CI 0x80000000 /* count inhibit */ -#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ - -#define IDR_EP_SHIFT 31 -#define IDR_EP_MASK (1 << IDR_EP_SHIFT) -#define IDR_CI0_SHIFT 30 -#define IDR_CI1_SHIFT 29 -#define IDR_P1_SHIFT 1 -#define IDR_P0_SHIFT 0 - -#define ILR_INTTGT_MASK 0x000000ff -#define ILR_INTTGT_INT 0x00 -#define ILR_INTTGT_CINT 0x01 /* critical */ -#define ILR_INTTGT_MCP 0x02 /* machine check */ -#define NUM_OUTPUTS 3 - -#define MSIIR_OFFSET 0x140 -#define MSIIR_SRS_SHIFT 29 -#define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) -#define MSIIR_IBS_SHIFT 24 -#define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) - -static int get_current_cpu(void) -{ - struct kvm_vcpu *vcpu = current->thread.kvm_vcpu; - return vcpu ? vcpu->arch.irq_cpu_id : -1; -} - -static int openpic_cpu_write_internal(void *opaque, gpa_t addr, - u32 val, int idx); -static int openpic_cpu_read_internal(void *opaque, gpa_t addr, - u32 *ptr, int idx); - -enum irq_type { - IRQ_TYPE_NORMAL = 0, - IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ - IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ -}; - -struct irq_queue { - /* Round up to the nearest 64 IRQs so that the queue length - * won't change when moving between 32 and 64 bit hosts. - */ - unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)]; - int next; - int priority; -}; - -struct irq_source { - uint32_t ivpr; /* IRQ vector/priority register */ - uint32_t idr; /* IRQ destination register */ - uint32_t destmask; /* bitmap of CPU destinations */ - int last_cpu; - int output; /* IRQ level, e.g. ILR_INTTGT_INT */ - int pending; /* TRUE if IRQ is pending */ - enum irq_type type; - bool level:1; /* level-triggered */ - bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ -}; - -#define IVPR_MASK_SHIFT 31 -#define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT) -#define IVPR_ACTIVITY_SHIFT 30 -#define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT) -#define IVPR_MODE_SHIFT 29 -#define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT) -#define IVPR_POLARITY_SHIFT 23 -#define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT) -#define IVPR_SENSE_SHIFT 22 -#define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT) - -#define IVPR_PRIORITY_MASK (0xF << 16) -#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) -#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) - -/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ -#define IDR_EP 0x80000000 /* external pin */ -#define IDR_CI 0x40000000 /* critical interrupt */ - -struct irq_dest { - struct kvm_vcpu *vcpu; - - int32_t ctpr; /* CPU current task priority */ - struct irq_queue raised; - struct irq_queue servicing; - - /* Count of IRQ sources asserting on non-INT outputs */ - uint32_t outputs_active[NUM_OUTPUTS]; -}; - -struct openpic { - struct kvm *kvm; - struct kvm_device *dev; - struct kvm_io_device mmio; - struct list_head mmio_regions; - atomic_t users; - bool mmio_mapped; - - gpa_t reg_base; - spinlock_t lock; - - /* Behavior control */ - struct fsl_mpic_info *fsl; - uint32_t model; - uint32_t flags; - uint32_t nb_irqs; - uint32_t vid; - uint32_t vir; /* Vendor identification register */ - uint32_t vector_mask; - uint32_t tfrr_reset; - uint32_t ivpr_reset; - uint32_t idr_reset; - uint32_t brr1; - uint32_t mpic_mode_mask; - - /* Global registers */ - uint32_t frr; /* Feature reporting register */ - uint32_t gcr; /* Global configuration register */ - uint32_t pir; /* Processor initialization register */ - uint32_t spve; /* Spurious vector register */ - uint32_t tfrr; /* Timer frequency reporting register */ - /* Source registers */ - struct irq_source src[MAX_IRQ]; - /* Local registers per output pin */ - struct irq_dest dst[MAX_CPU]; - uint32_t nb_cpus; - /* Timer registers */ - struct { - uint32_t tccr; /* Global timer current count register */ - uint32_t tbcr; /* Global timer base count register */ - } timers[MAX_TMR]; - /* Shared MSI registers */ - struct { - uint32_t msir; /* Shared Message Signaled Interrupt Register */ - } msi[MAX_MSI]; - uint32_t max_irq; - uint32_t irq_ipi0; - uint32_t irq_tim0; - uint32_t irq_msi; -}; - - -static void mpic_irq_raise(struct openpic *opp, struct irq_dest *dst, - int output) -{ - struct kvm_interrupt irq = { - .irq = KVM_INTERRUPT_SET_LEVEL, - }; - - if (!dst->vcpu) { - pr_debug("%s: destination cpu %td does not exist\n", - __func__, dst - &opp->dst[0]); - return; - } - - pr_debug("%s: cpu %d output %d\n", __func__, dst->vcpu->arch.irq_cpu_id, - output); - - if (output != ILR_INTTGT_INT) /* TODO */ - return; - - kvm_vcpu_ioctl_interrupt(dst->vcpu, &irq); -} - -static void mpic_irq_lower(struct openpic *opp, struct irq_dest *dst, - int output) -{ - if (!dst->vcpu) { - pr_debug("%s: destination cpu %td does not exist\n", - __func__, dst - &opp->dst[0]); - return; - } - - pr_debug("%s: cpu %d output %d\n", __func__, dst->vcpu->arch.irq_cpu_id, - output); - - if (output != ILR_INTTGT_INT) /* TODO */ - return; - - kvmppc_core_dequeue_external(dst->vcpu); -} - -static inline void IRQ_setbit(struct irq_queue *q, int n_IRQ) -{ - set_bit(n_IRQ, q->queue); -} - -static inline void IRQ_resetbit(struct irq_queue *q, int n_IRQ) -{ - clear_bit(n_IRQ, q->queue); -} - -static inline int IRQ_testbit(struct irq_queue *q, int n_IRQ) -{ - return test_bit(n_IRQ, q->queue); -} - -static void IRQ_check(struct openpic *opp, struct irq_queue *q) -{ - int irq = -1; - int next = -1; - int priority = -1; - - for (;;) { - irq = find_next_bit(q->queue, opp->max_irq, irq + 1); - if (irq == opp->max_irq) - break; - - pr_debug("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", - irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); - - if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { - next = irq; - priority = IVPR_PRIORITY(opp->src[irq].ivpr); - } - } - - q->next = next; - q->priority = priority; -} - -static int IRQ_get_next(struct openpic *opp, struct irq_queue *q) -{ - /* XXX: optimize */ - IRQ_check(opp, q); - - return q->next; -} - -static void IRQ_local_pipe(struct openpic *opp, int n_CPU, int n_IRQ, - bool active, bool was_active) -{ - struct irq_dest *dst; - struct irq_source *src; - int priority; - - dst = &opp->dst[n_CPU]; - src = &opp->src[n_IRQ]; - - pr_debug("%s: IRQ %d active %d was %d\n", - __func__, n_IRQ, active, was_active); - - if (src->output != ILR_INTTGT_INT) { - pr_debug("%s: output %d irq %d active %d was %d count %d\n", - __func__, src->output, n_IRQ, active, was_active, - dst->outputs_active[src->output]); - - /* On Freescale MPIC, critical interrupts ignore priority, - * IACK, EOI, etc. Before MPIC v4.1 they also ignore - * masking. - */ - if (active) { - if (!was_active && - dst->outputs_active[src->output]++ == 0) { - pr_debug("%s: Raise OpenPIC output %d cpu %d irq %d\n", - __func__, src->output, n_CPU, n_IRQ); - mpic_irq_raise(opp, dst, src->output); - } - } else { - if (was_active && - --dst->outputs_active[src->output] == 0) { - pr_debug("%s: Lower OpenPIC output %d cpu %d irq %d\n", - __func__, src->output, n_CPU, n_IRQ); - mpic_irq_lower(opp, dst, src->output); - } - } - - return; - } - - priority = IVPR_PRIORITY(src->ivpr); - - /* Even if the interrupt doesn't have enough priority, - * it is still raised, in case ctpr is lowered later. - */ - if (active) - IRQ_setbit(&dst->raised, n_IRQ); - else - IRQ_resetbit(&dst->raised, n_IRQ); - - IRQ_check(opp, &dst->raised); - - if (active && priority <= dst->ctpr) { - pr_debug("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", - __func__, n_IRQ, priority, dst->ctpr, n_CPU); - active = 0; - } - - if (active) { - if (IRQ_get_next(opp, &dst->servicing) >= 0 && - priority <= dst->servicing.priority) { - pr_debug("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", - __func__, n_IRQ, dst->servicing.next, n_CPU); - } else { - pr_debug("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", - __func__, n_CPU, n_IRQ, dst->raised.next); - mpic_irq_raise(opp, dst, ILR_INTTGT_INT); - } - } else { - IRQ_get_next(opp, &dst->servicing); - if (dst->raised.priority > dst->ctpr && - dst->raised.priority > dst->servicing.priority) { - pr_debug("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", - __func__, n_IRQ, dst->raised.next, - dst->raised.priority, dst->ctpr, - dst->servicing.priority, n_CPU); - /* IRQ line stays asserted */ - } else { - pr_debug("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", - __func__, n_IRQ, dst->ctpr, - dst->servicing.priority, n_CPU); - mpic_irq_lower(opp, dst, ILR_INTTGT_INT); - } - } -} - -/* update pic state because registers for n_IRQ have changed value */ -static void openpic_update_irq(struct openpic *opp, int n_IRQ) -{ - struct irq_source *src; - bool active, was_active; - int i; - - src = &opp->src[n_IRQ]; - active = src->pending; - - if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { - /* Interrupt source is disabled */ - pr_debug("%s: IRQ %d is disabled\n", __func__, n_IRQ); - active = false; - } - - was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); - - /* - * We don't have a similar check for already-active because - * ctpr may have changed and we need to withdraw the interrupt. - */ - if (!active && !was_active) { - pr_debug("%s: IRQ %d is already inactive\n", __func__, n_IRQ); - return; - } - - if (active) - src->ivpr |= IVPR_ACTIVITY_MASK; - else - src->ivpr &= ~IVPR_ACTIVITY_MASK; - - if (src->destmask == 0) { - /* No target */ - pr_debug("%s: IRQ %d has no target\n", __func__, n_IRQ); - return; - } - - if (src->destmask == (1 << src->last_cpu)) { - /* Only one CPU is allowed to receive this IRQ */ - IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); - } else if (!(src->ivpr & IVPR_MODE_MASK)) { - /* Directed delivery mode */ - for (i = 0; i < opp->nb_cpus; i++) { - if (src->destmask & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ, active, - was_active); - } - } - } else { - /* Distributed delivery mode */ - for (i = src->last_cpu + 1; i != src->last_cpu; i++) { - if (i == opp->nb_cpus) - i = 0; - - if (src->destmask & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ, active, - was_active); - src->last_cpu = i; - break; - } - } - } -} - -static void openpic_set_irq(void *opaque, int n_IRQ, int level) -{ - struct openpic *opp = opaque; - struct irq_source *src; - - if (n_IRQ >= MAX_IRQ) { - WARN_ONCE(1, "%s: IRQ %d out of range\n", __func__, n_IRQ); - return; - } - - src = &opp->src[n_IRQ]; - pr_debug("openpic: set irq %d = %d ivpr=0x%08x\n", - n_IRQ, level, src->ivpr); - if (src->level) { - /* level-sensitive irq */ - src->pending = level; - openpic_update_irq(opp, n_IRQ); - } else { - /* edge-sensitive irq */ - if (level) { - src->pending = 1; - openpic_update_irq(opp, n_IRQ); - } - - if (src->output != ILR_INTTGT_INT) { - /* Edge-triggered interrupts shouldn't be used - * with non-INT delivery, but just in case, - * try to make it do something sane rather than - * cause an interrupt storm. This is close to - * what you'd probably see happen in real hardware. - */ - src->pending = 0; - openpic_update_irq(opp, n_IRQ); - } - } -} - -static void openpic_reset(struct openpic *opp) -{ - int i; - - opp->gcr = GCR_RESET; - /* Initialise controller registers */ - opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) | - (opp->vid << FRR_VID_SHIFT); - - opp->pir = 0; - opp->spve = -1 & opp->vector_mask; - opp->tfrr = opp->tfrr_reset; - /* Initialise IRQ sources */ - for (i = 0; i < opp->max_irq; i++) { - opp->src[i].ivpr = opp->ivpr_reset; - opp->src[i].idr = opp->idr_reset; - - switch (opp->src[i].type) { - case IRQ_TYPE_NORMAL: - opp->src[i].level = - !!(opp->ivpr_reset & IVPR_SENSE_MASK); - break; - - case IRQ_TYPE_FSLINT: - opp->src[i].ivpr |= IVPR_POLARITY_MASK; - break; - - case IRQ_TYPE_FSLSPECIAL: - break; - } - } - /* Initialise IRQ destinations */ - for (i = 0; i < MAX_CPU; i++) { - opp->dst[i].ctpr = 15; - memset(&opp->dst[i].raised, 0, sizeof(struct irq_queue)); - opp->dst[i].raised.next = -1; - memset(&opp->dst[i].servicing, 0, sizeof(struct irq_queue)); - opp->dst[i].servicing.next = -1; - } - /* Initialise timers */ - for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].tccr = 0; - opp->timers[i].tbcr = TBCR_CI; - } - /* Go out of RESET state */ - opp->gcr = 0; -} - -static inline uint32_t read_IRQreg_idr(struct openpic *opp, int n_IRQ) -{ - return opp->src[n_IRQ].idr; -} - -static inline uint32_t read_IRQreg_ilr(struct openpic *opp, int n_IRQ) -{ - if (opp->flags & OPENPIC_FLAG_ILR) - return opp->src[n_IRQ].output; - - return 0xffffffff; -} - -static inline uint32_t read_IRQreg_ivpr(struct openpic *opp, int n_IRQ) -{ - return opp->src[n_IRQ].ivpr; -} - -static inline void write_IRQreg_idr(struct openpic *opp, int n_IRQ, - uint32_t val) -{ - struct irq_source *src = &opp->src[n_IRQ]; - uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; - uint32_t crit_mask = 0; - uint32_t mask = normal_mask; - int crit_shift = IDR_EP_SHIFT - opp->nb_cpus; - int i; - - if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { - crit_mask = mask << crit_shift; - mask |= crit_mask | IDR_EP; - } - - src->idr = val & mask; - pr_debug("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); - - if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { - if (src->idr & crit_mask) { - if (src->idr & normal_mask) { - pr_debug("%s: IRQ configured for multiple output types, using critical\n", - __func__); - } - - src->output = ILR_INTTGT_CINT; - src->nomask = true; - src->destmask = 0; - - for (i = 0; i < opp->nb_cpus; i++) { - int n_ci = IDR_CI0_SHIFT - i; - - if (src->idr & (1UL << n_ci)) - src->destmask |= 1UL << i; - } - } else { - src->output = ILR_INTTGT_INT; - src->nomask = false; - src->destmask = src->idr & normal_mask; - } - } else { - src->destmask = src->idr; - } -} - -static inline void write_IRQreg_ilr(struct openpic *opp, int n_IRQ, - uint32_t val) -{ - if (opp->flags & OPENPIC_FLAG_ILR) { - struct irq_source *src = &opp->src[n_IRQ]; - - src->output = val & ILR_INTTGT_MASK; - pr_debug("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr, - src->output); - - /* TODO: on MPIC v4.0 only, set nomask for non-INT */ - } -} - -static inline void write_IRQreg_ivpr(struct openpic *opp, int n_IRQ, - uint32_t val) -{ - uint32_t mask; - - /* NOTE when implementing newer FSL MPIC models: starting with v4.0, - * the polarity bit is read-only on internal interrupts. - */ - mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | - IVPR_POLARITY_MASK | opp->vector_mask; - - /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ivpr = - (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); - - /* For FSL internal interrupts, The sense bit is reserved and zero, - * and the interrupt is always level-triggered. Timers and IPIs - * have no sense or polarity bits, and are edge-triggered. - */ - switch (opp->src[n_IRQ].type) { - case IRQ_TYPE_NORMAL: - opp->src[n_IRQ].level = - !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); - break; - - case IRQ_TYPE_FSLINT: - opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; - break; - - case IRQ_TYPE_FSLSPECIAL: - opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); - break; - } - - openpic_update_irq(opp, n_IRQ); - pr_debug("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, - opp->src[n_IRQ].ivpr); -} - -static void openpic_gcr_write(struct openpic *opp, uint64_t val) -{ - if (val & GCR_RESET) { - openpic_reset(opp); - return; - } - - opp->gcr &= ~opp->mpic_mode_mask; - opp->gcr |= val & opp->mpic_mode_mask; -} - -static int openpic_gbl_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - int err = 0; - - pr_debug("%s: addr %#llx <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return 0; - - switch (addr) { - case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ - break; - case 0x40: - case 0x50: - case 0x60: - case 0x70: - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - err = openpic_cpu_write_internal(opp, addr, val, - get_current_cpu()); - break; - case 0x1000: /* FRR */ - break; - case 0x1020: /* GCR */ - openpic_gcr_write(opp, val); - break; - case 0x1080: /* VIR */ - break; - case 0x1090: /* PIR */ - /* - * This register is used to reset a CPU core -- - * let userspace handle it. - */ - err = -ENXIO; - break; - case 0x10A0: /* IPI_IVPR */ - case 0x10B0: - case 0x10C0: - case 0x10D0: { - int idx; - idx = (addr - 0x10A0) >> 4; - write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); - break; - } - case 0x10E0: /* SPVE */ - opp->spve = val & opp->vector_mask; - break; - default: - break; - } - - return err; -} - -static int openpic_gbl_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - u32 retval; - int err = 0; - - pr_debug("%s: addr %#llx\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - goto out; - - switch (addr) { - case 0x1000: /* FRR */ - retval = opp->frr; - retval |= (opp->nb_cpus - 1) << FRR_NCPU_SHIFT; - break; - case 0x1020: /* GCR */ - retval = opp->gcr; - break; - case 0x1080: /* VIR */ - retval = opp->vir; - break; - case 0x1090: /* PIR */ - retval = 0x00000000; - break; - case 0x00: /* Block Revision Register1 (BRR1) */ - retval = opp->brr1; - break; - case 0x40: - case 0x50: - case 0x60: - case 0x70: - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - err = openpic_cpu_read_internal(opp, addr, - &retval, get_current_cpu()); - break; - case 0x10A0: /* IPI_IVPR */ - case 0x10B0: - case 0x10C0: - case 0x10D0: - { - int idx; - idx = (addr - 0x10A0) >> 4; - retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx); - } - break; - case 0x10E0: /* SPVE */ - retval = opp->spve; - break; - default: - break; - } - -out: - pr_debug("%s: => 0x%08x\n", __func__, retval); - *ptr = retval; - return err; -} - -static int openpic_tmr_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - int idx; - - addr += 0x10f0; - - pr_debug("%s: addr %#llx <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return 0; - - if (addr == 0x10f0) { - /* TFRR */ - opp->tfrr = val; - return 0; - } - - idx = (addr >> 6) & 0x3; - addr = addr & 0x30; - - switch (addr & 0x30) { - case 0x00: /* TCCR */ - break; - case 0x10: /* TBCR */ - if ((opp->timers[idx].tccr & TCCR_TOG) != 0 && - (val & TBCR_CI) == 0 && - (opp->timers[idx].tbcr & TBCR_CI) != 0) - opp->timers[idx].tccr &= ~TCCR_TOG; - - opp->timers[idx].tbcr = val; - break; - case 0x20: /* TVPR */ - write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val); - break; - case 0x30: /* TDR */ - write_IRQreg_idr(opp, opp->irq_tim0 + idx, val); - break; - } - - return 0; -} - -static int openpic_tmr_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - uint32_t retval = -1; - int idx; - - pr_debug("%s: addr %#llx\n", __func__, addr); - if (addr & 0xF) - goto out; - - idx = (addr >> 6) & 0x3; - if (addr == 0x0) { - /* TFRR */ - retval = opp->tfrr; - goto out; - } - - switch (addr & 0x30) { - case 0x00: /* TCCR */ - retval = opp->timers[idx].tccr; - break; - case 0x10: /* TBCR */ - retval = opp->timers[idx].tbcr; - break; - case 0x20: /* TIPV */ - retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); - break; - case 0x30: /* TIDE (TIDR) */ - retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx); - break; - } - -out: - pr_debug("%s: => 0x%08x\n", __func__, retval); - *ptr = retval; - return 0; -} - -static int openpic_src_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - int idx; - - pr_debug("%s: addr %#llx <= %08x\n", __func__, addr, val); - - addr = addr & 0xffff; - idx = addr >> 5; - - switch (addr & 0x1f) { - case 0x00: - write_IRQreg_ivpr(opp, idx, val); - break; - case 0x10: - write_IRQreg_idr(opp, idx, val); - break; - case 0x18: - write_IRQreg_ilr(opp, idx, val); - break; - } - - return 0; -} - -static int openpic_src_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - uint32_t retval; - int idx; - - pr_debug("%s: addr %#llx\n", __func__, addr); - retval = 0xFFFFFFFF; - - addr = addr & 0xffff; - idx = addr >> 5; - - switch (addr & 0x1f) { - case 0x00: - retval = read_IRQreg_ivpr(opp, idx); - break; - case 0x10: - retval = read_IRQreg_idr(opp, idx); - break; - case 0x18: - retval = read_IRQreg_ilr(opp, idx); - break; - } - - pr_debug("%s: => 0x%08x\n", __func__, retval); - *ptr = retval; - return 0; -} - -static int openpic_msi_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - int idx = opp->irq_msi; - int srs, ibs; - - pr_debug("%s: addr %#llx <= 0x%08x\n", __func__, addr, val); - if (addr & 0xF) - return 0; - - switch (addr) { - case MSIIR_OFFSET: - srs = val >> MSIIR_SRS_SHIFT; - idx += srs; - ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT; - opp->msi[srs].msir |= 1 << ibs; - openpic_set_irq(opp, idx, 1); - break; - default: - /* most registers are read-only, thus ignored */ - break; - } - - return 0; -} - -static int openpic_msi_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - uint32_t r = 0; - int i, srs; - - pr_debug("%s: addr %#llx\n", __func__, addr); - if (addr & 0xF) - return -ENXIO; - - srs = addr >> 4; - - switch (addr) { - case 0x00: - case 0x10: - case 0x20: - case 0x30: - case 0x40: - case 0x50: - case 0x60: - case 0x70: /* MSIRs */ - r = opp->msi[srs].msir; - /* Clear on read */ - opp->msi[srs].msir = 0; - openpic_set_irq(opp, opp->irq_msi + srs, 0); - break; - case 0x120: /* MSISR */ - for (i = 0; i < MAX_MSI; i++) - r |= (opp->msi[i].msir ? 1 : 0) << i; - break; - } - - pr_debug("%s: => 0x%08x\n", __func__, r); - *ptr = r; - return 0; -} - -static int openpic_summary_read(void *opaque, gpa_t addr, u32 *ptr) -{ - uint32_t r = 0; - - pr_debug("%s: addr %#llx\n", __func__, addr); - - /* TODO: EISR/EIMR */ - - *ptr = r; - return 0; -} - -static int openpic_summary_write(void *opaque, gpa_t addr, u32 val) -{ - pr_debug("%s: addr %#llx <= 0x%08x\n", __func__, addr, val); - - /* TODO: EISR/EIMR */ - return 0; -} - -static int openpic_cpu_write_internal(void *opaque, gpa_t addr, - u32 val, int idx) -{ - struct openpic *opp = opaque; - struct irq_source *src; - struct irq_dest *dst; - int s_IRQ, n_IRQ; - - pr_debug("%s: cpu %d addr %#llx <= 0x%08x\n", __func__, idx, - addr, val); - - if (idx < 0) - return 0; - - if (addr & 0xF) - return 0; - - dst = &opp->dst[idx]; - addr &= 0xFF0; - switch (addr) { - case 0x40: /* IPIDR */ - case 0x50: - case 0x60: - case 0x70: - idx = (addr - 0x40) >> 4; - /* we use IDE as mask which CPUs to deliver the IPI to still. */ - opp->src[opp->irq_ipi0 + idx].destmask |= val; - openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); - openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); - break; - case 0x80: /* CTPR */ - dst->ctpr = val & 0x0000000F; - - pr_debug("%s: set CPU %d ctpr to %d, raised %d servicing %d\n", - __func__, idx, dst->ctpr, dst->raised.priority, - dst->servicing.priority); - - if (dst->raised.priority <= dst->ctpr) { - pr_debug("%s: Lower OpenPIC INT output cpu %d due to ctpr\n", - __func__, idx); - mpic_irq_lower(opp, dst, ILR_INTTGT_INT); - } else if (dst->raised.priority > dst->servicing.priority) { - pr_debug("%s: Raise OpenPIC INT output cpu %d irq %d\n", - __func__, idx, dst->raised.next); - mpic_irq_raise(opp, dst, ILR_INTTGT_INT); - } - - break; - case 0x90: /* WHOAMI */ - /* Read-only register */ - break; - case 0xA0: /* IACK */ - /* Read-only register */ - break; - case 0xB0: /* EOI */ - pr_debug("EOI\n"); - s_IRQ = IRQ_get_next(opp, &dst->servicing); - - if (s_IRQ < 0) { - pr_debug("%s: EOI with no interrupt in service\n", - __func__); - break; - } - - IRQ_resetbit(&dst->servicing, s_IRQ); - /* Notify listeners that the IRQ is over */ - kvm_notify_acked_irq(opp->kvm, 0, s_IRQ); - /* Set up next servicing IRQ */ - s_IRQ = IRQ_get_next(opp, &dst->servicing); - /* Check queued interrupts. */ - n_IRQ = IRQ_get_next(opp, &dst->raised); - src = &opp->src[n_IRQ]; - if (n_IRQ != -1 && - (s_IRQ == -1 || - IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { - pr_debug("Raise OpenPIC INT output cpu %d irq %d\n", - idx, n_IRQ); - mpic_irq_raise(opp, dst, ILR_INTTGT_INT); - } - break; - default: - break; - } - - return 0; -} - -static int openpic_cpu_write(void *opaque, gpa_t addr, u32 val) -{ - struct openpic *opp = opaque; - - return openpic_cpu_write_internal(opp, addr, val, - (addr & 0x1f000) >> 12); -} - -static uint32_t openpic_iack(struct openpic *opp, struct irq_dest *dst, - int cpu) -{ - struct irq_source *src; - int retval, irq; - - pr_debug("Lower OpenPIC INT output\n"); - mpic_irq_lower(opp, dst, ILR_INTTGT_INT); - - irq = IRQ_get_next(opp, &dst->raised); - pr_debug("IACK: irq=%d\n", irq); - - if (irq == -1) - /* No more interrupt pending */ - return opp->spve; - - src = &opp->src[irq]; - if (!(src->ivpr & IVPR_ACTIVITY_MASK) || - !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { - pr_err("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n", - __func__, irq, dst->ctpr, src->ivpr); - openpic_update_irq(opp, irq); - retval = opp->spve; - } else { - /* IRQ enter servicing state */ - IRQ_setbit(&dst->servicing, irq); - retval = IVPR_VECTOR(opp, src->ivpr); - } - - if (!src->level) { - /* edge-sensitive IRQ */ - src->ivpr &= ~IVPR_ACTIVITY_MASK; - src->pending = 0; - IRQ_resetbit(&dst->raised, irq); - } - - if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { - src->destmask &= ~(1 << cpu); - if (src->destmask && !src->level) { - /* trigger on CPUs that didn't know about it yet */ - openpic_set_irq(opp, irq, 1); - openpic_set_irq(opp, irq, 0); - /* if all CPUs knew about it, set active bit again */ - src->ivpr |= IVPR_ACTIVITY_MASK; - } - } - - return retval; -} - -void kvmppc_mpic_set_epr(struct kvm_vcpu *vcpu) -{ - struct openpic *opp = vcpu->arch.mpic; - int cpu = vcpu->arch.irq_cpu_id; - unsigned long flags; - - spin_lock_irqsave(&opp->lock, flags); - - if ((opp->gcr & opp->mpic_mode_mask) == GCR_MODE_PROXY) - kvmppc_set_epr(vcpu, openpic_iack(opp, &opp->dst[cpu], cpu)); - - spin_unlock_irqrestore(&opp->lock, flags); -} - -static int openpic_cpu_read_internal(void *opaque, gpa_t addr, - u32 *ptr, int idx) -{ - struct openpic *opp = opaque; - struct irq_dest *dst; - uint32_t retval; - - pr_debug("%s: cpu %d addr %#llx\n", __func__, idx, addr); - retval = 0xFFFFFFFF; - - if (idx < 0) - goto out; - - if (addr & 0xF) - goto out; - - dst = &opp->dst[idx]; - addr &= 0xFF0; - switch (addr) { - case 0x80: /* CTPR */ - retval = dst->ctpr; - break; - case 0x90: /* WHOAMI */ - retval = idx; - break; - case 0xA0: /* IACK */ - retval = openpic_iack(opp, dst, idx); - break; - case 0xB0: /* EOI */ - retval = 0; - break; - default: - break; - } - pr_debug("%s: => 0x%08x\n", __func__, retval); - -out: - *ptr = retval; - return 0; -} - -static int openpic_cpu_read(void *opaque, gpa_t addr, u32 *ptr) -{ - struct openpic *opp = opaque; - - return openpic_cpu_read_internal(opp, addr, ptr, - (addr & 0x1f000) >> 12); -} - -struct mem_reg { - struct list_head list; - int (*read)(void *opaque, gpa_t addr, u32 *ptr); - int (*write)(void *opaque, gpa_t addr, u32 val); - gpa_t start_addr; - int size; -}; - -static struct mem_reg openpic_gbl_mmio = { - .write = openpic_gbl_write, - .read = openpic_gbl_read, - .start_addr = OPENPIC_GLB_REG_START, - .size = OPENPIC_GLB_REG_SIZE, -}; - -static struct mem_reg openpic_tmr_mmio = { - .write = openpic_tmr_write, - .read = openpic_tmr_read, - .start_addr = OPENPIC_TMR_REG_START, - .size = OPENPIC_TMR_REG_SIZE, -}; - -static struct mem_reg openpic_cpu_mmio = { - .write = openpic_cpu_write, - .read = openpic_cpu_read, - .start_addr = OPENPIC_CPU_REG_START, - .size = OPENPIC_CPU_REG_SIZE, -}; - -static struct mem_reg openpic_src_mmio = { - .write = openpic_src_write, - .read = openpic_src_read, - .start_addr = OPENPIC_SRC_REG_START, - .size = OPENPIC_SRC_REG_SIZE, -}; - -static struct mem_reg openpic_msi_mmio = { - .read = openpic_msi_read, - .write = openpic_msi_write, - .start_addr = OPENPIC_MSI_REG_START, - .size = OPENPIC_MSI_REG_SIZE, -}; - -static struct mem_reg openpic_summary_mmio = { - .read = openpic_summary_read, - .write = openpic_summary_write, - .start_addr = OPENPIC_SUMMARY_REG_START, - .size = OPENPIC_SUMMARY_REG_SIZE, -}; - -static void fsl_common_init(struct openpic *opp) -{ - int i; - int virq = MAX_SRC; - - list_add(&openpic_msi_mmio.list, &opp->mmio_regions); - list_add(&openpic_summary_mmio.list, &opp->mmio_regions); - - opp->vid = VID_REVISION_1_2; - opp->vir = VIR_GENERIC; - opp->vector_mask = 0xFFFF; - opp->tfrr_reset = 0; - opp->ivpr_reset = IVPR_MASK_MASK; - opp->idr_reset = 1 << 0; - opp->max_irq = MAX_IRQ; - - opp->irq_ipi0 = virq; - virq += MAX_IPI; - opp->irq_tim0 = virq; - virq += MAX_TMR; - - BUG_ON(virq > MAX_IRQ); - - opp->irq_msi = 224; - - for (i = 0; i < opp->fsl->max_ext; i++) - opp->src[i].level = false; - - /* Internal interrupts, including message and MSI */ - for (i = 16; i < MAX_SRC; i++) { - opp->src[i].type = IRQ_TYPE_FSLINT; - opp->src[i].level = true; - } - - /* timers and IPIs */ - for (i = MAX_SRC; i < virq; i++) { - opp->src[i].type = IRQ_TYPE_FSLSPECIAL; - opp->src[i].level = false; - } -} - -static int kvm_mpic_read_internal(struct openpic *opp, gpa_t addr, u32 *ptr) -{ - struct list_head *node; - - list_for_each(node, &opp->mmio_regions) { - struct mem_reg *mr = list_entry(node, struct mem_reg, list); - - if (mr->start_addr > addr || addr >= mr->start_addr + mr->size) - continue; - - return mr->read(opp, addr - mr->start_addr, ptr); - } - - return -ENXIO; -} - -static int kvm_mpic_write_internal(struct openpic *opp, gpa_t addr, u32 val) -{ - struct list_head *node; - - list_for_each(node, &opp->mmio_regions) { - struct mem_reg *mr = list_entry(node, struct mem_reg, list); - - if (mr->start_addr > addr || addr >= mr->start_addr + mr->size) - continue; - - return mr->write(opp, addr - mr->start_addr, val); - } - - return -ENXIO; -} - -static int kvm_mpic_read(struct kvm_io_device *this, gpa_t addr, - int len, void *ptr) -{ - struct openpic *opp = container_of(this, struct openpic, mmio); - int ret; - union { - u32 val; - u8 bytes[4]; - } u; - - if (addr & (len - 1)) { - pr_debug("%s: bad alignment %llx/%d\n", - __func__, addr, len); - return -EINVAL; - } - - spin_lock_irq(&opp->lock); - ret = kvm_mpic_read_internal(opp, addr - opp->reg_base, &u.val); - spin_unlock_irq(&opp->lock); - - /* - * Technically only 32-bit accesses are allowed, but be nice to - * people dumping registers a byte at a time -- it works in real - * hardware (reads only, not writes). - */ - if (len == 4) { - *(u32 *)ptr = u.val; - pr_debug("%s: addr %llx ret %d len 4 val %x\n", - __func__, addr, ret, u.val); - } else if (len == 1) { - *(u8 *)ptr = u.bytes[addr & 3]; - pr_debug("%s: addr %llx ret %d len 1 val %x\n", - __func__, addr, ret, u.bytes[addr & 3]); - } else { - pr_debug("%s: bad length %d\n", __func__, len); - return -EINVAL; - } - - return ret; -} - -static int kvm_mpic_write(struct kvm_io_device *this, gpa_t addr, - int len, const void *ptr) -{ - struct openpic *opp = container_of(this, struct openpic, mmio); - int ret; - - if (len != 4) { - pr_debug("%s: bad length %d\n", __func__, len); - return -EOPNOTSUPP; - } - if (addr & 3) { - pr_debug("%s: bad alignment %llx/%d\n", __func__, addr, len); - return -EOPNOTSUPP; - } - - spin_lock_irq(&opp->lock); - ret = kvm_mpic_write_internal(opp, addr - opp->reg_base, - *(const u32 *)ptr); - spin_unlock_irq(&opp->lock); - - pr_debug("%s: addr %llx ret %d val %x\n", - __func__, addr, ret, *(const u32 *)ptr); - - return ret; -} - -static void kvm_mpic_dtor(struct kvm_io_device *this) -{ - struct openpic *opp = container_of(this, struct openpic, mmio); - - opp->mmio_mapped = false; -} - -static const struct kvm_io_device_ops mpic_mmio_ops = { - .read = kvm_mpic_read, - .write = kvm_mpic_write, - .destructor = kvm_mpic_dtor, -}; - -static void map_mmio(struct openpic *opp) -{ - BUG_ON(opp->mmio_mapped); - opp->mmio_mapped = true; - - kvm_iodevice_init(&opp->mmio, &mpic_mmio_ops); - - kvm_io_bus_register_dev(opp->kvm, KVM_MMIO_BUS, - opp->reg_base, OPENPIC_REG_SIZE, - &opp->mmio); -} - -static void unmap_mmio(struct openpic *opp) -{ - if (opp->mmio_mapped) { - opp->mmio_mapped = false; - kvm_io_bus_unregister_dev(opp->kvm, KVM_MMIO_BUS, &opp->mmio); - } -} - -static int set_base_addr(struct openpic *opp, struct kvm_device_attr *attr) -{ - u64 base; - - if (copy_from_user(&base, (u64 __user *)(long)attr->addr, sizeof(u64))) - return -EFAULT; - - if (base & 0x3ffff) { - pr_debug("kvm mpic %s: KVM_DEV_MPIC_BASE_ADDR %08llx not aligned\n", - __func__, base); - return -EINVAL; - } - - if (base == opp->reg_base) - return 0; - - mutex_lock(&opp->kvm->slots_lock); - - unmap_mmio(opp); - opp->reg_base = base; - - pr_debug("kvm mpic %s: KVM_DEV_MPIC_BASE_ADDR %08llx\n", - __func__, base); - - if (base == 0) - goto out; - - map_mmio(opp); - - mutex_unlock(&opp->kvm->slots_lock); -out: - return 0; -} - -#define ATTR_SET 0 -#define ATTR_GET 1 - -static int access_reg(struct openpic *opp, gpa_t addr, u32 *val, int type) -{ - int ret; - - if (addr & 3) - return -ENXIO; - - spin_lock_irq(&opp->lock); - - if (type == ATTR_SET) - ret = kvm_mpic_write_internal(opp, addr, *val); - else - ret = kvm_mpic_read_internal(opp, addr, val); - - spin_unlock_irq(&opp->lock); - - pr_debug("%s: type %d addr %llx val %x\n", __func__, type, addr, *val); - - return ret; -} - -static int mpic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - struct openpic *opp = dev->private; - u32 attr32; - - switch (attr->group) { - case KVM_DEV_MPIC_GRP_MISC: - switch (attr->attr) { - case KVM_DEV_MPIC_BASE_ADDR: - return set_base_addr(opp, attr); - } - - break; - - case KVM_DEV_MPIC_GRP_REGISTER: - if (get_user(attr32, (u32 __user *)(long)attr->addr)) - return -EFAULT; - - return access_reg(opp, attr->attr, &attr32, ATTR_SET); - - case KVM_DEV_MPIC_GRP_IRQ_ACTIVE: - if (attr->attr > MAX_SRC) - return -EINVAL; - - if (get_user(attr32, (u32 __user *)(long)attr->addr)) - return -EFAULT; - - if (attr32 != 0 && attr32 != 1) - return -EINVAL; - - spin_lock_irq(&opp->lock); - openpic_set_irq(opp, attr->attr, attr32); - spin_unlock_irq(&opp->lock); - return 0; - } - - return -ENXIO; -} - -static int mpic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - struct openpic *opp = dev->private; - u64 attr64; - u32 attr32; - int ret; - - switch (attr->group) { - case KVM_DEV_MPIC_GRP_MISC: - switch (attr->attr) { - case KVM_DEV_MPIC_BASE_ADDR: - mutex_lock(&opp->kvm->slots_lock); - attr64 = opp->reg_base; - mutex_unlock(&opp->kvm->slots_lock); - - if (copy_to_user((u64 __user *)(long)attr->addr, - &attr64, sizeof(u64))) - return -EFAULT; - - return 0; - } - - break; - - case KVM_DEV_MPIC_GRP_REGISTER: - ret = access_reg(opp, attr->attr, &attr32, ATTR_GET); - if (ret) - return ret; - - if (put_user(attr32, (u32 __user *)(long)attr->addr)) - return -EFAULT; - - return 0; - - case KVM_DEV_MPIC_GRP_IRQ_ACTIVE: - if (attr->attr > MAX_SRC) - return -EINVAL; - - spin_lock_irq(&opp->lock); - attr32 = opp->src[attr->attr].pending; - spin_unlock_irq(&opp->lock); - - if (put_user(attr32, (u32 __user *)(long)attr->addr)) - return -EFAULT; - - return 0; - } - - return -ENXIO; -} - -static int mpic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) -{ - switch (attr->group) { - case KVM_DEV_MPIC_GRP_MISC: - switch (attr->attr) { - case KVM_DEV_MPIC_BASE_ADDR: - return 0; - } - - break; - - case KVM_DEV_MPIC_GRP_REGISTER: - return 0; - - case KVM_DEV_MPIC_GRP_IRQ_ACTIVE: - if (attr->attr > MAX_SRC) - break; - - return 0; - } - - return -ENXIO; -} - -static void mpic_destroy(struct kvm_device *dev) -{ - struct openpic *opp = dev->private; - - if (opp->mmio_mapped) { - /* - * Normally we get unmapped by kvm_io_bus_destroy(), - * which happens before the VCPUs release their references. - * - * Thus, we should only get here if no VCPUs took a reference - * to us in the first place. - */ - WARN_ON(opp->nb_cpus != 0); - unmap_mmio(opp); - } - - dev->kvm->arch.mpic = NULL; - kfree(opp); -} - -static int mpic_set_default_irq_routing(struct openpic *opp) -{ - int i; - struct kvm_irq_routing_entry *routing; - - /* XXX be more dynamic if we ever want to support multiple MPIC chips */ - routing = kzalloc((sizeof(*routing) * opp->nb_irqs), GFP_KERNEL); - if (!routing) - return -ENOMEM; - - for (i = 0; i < opp->nb_irqs; i++) { - routing[i].gsi = i; - routing[i].type = KVM_IRQ_ROUTING_IRQCHIP; - routing[i].u.irqchip.irqchip = 0; - routing[i].u.irqchip.pin = i; - } - - kvm_set_irq_routing(opp->kvm, routing, opp->nb_irqs, 0); - - kfree(routing); - return 0; -} - -static int mpic_create(struct kvm_device *dev, u32 type) -{ - struct openpic *opp; - int ret; - - /* We only support one MPIC at a time for now */ - if (dev->kvm->arch.mpic) - return -EINVAL; - - opp = kzalloc(sizeof(struct openpic), GFP_KERNEL); - if (!opp) - return -ENOMEM; - - dev->private = opp; - opp->kvm = dev->kvm; - opp->dev = dev; - opp->model = type; - spin_lock_init(&opp->lock); - - INIT_LIST_HEAD(&opp->mmio_regions); - list_add(&openpic_gbl_mmio.list, &opp->mmio_regions); - list_add(&openpic_tmr_mmio.list, &opp->mmio_regions); - list_add(&openpic_src_mmio.list, &opp->mmio_regions); - list_add(&openpic_cpu_mmio.list, &opp->mmio_regions); - - switch (opp->model) { - case KVM_DEV_TYPE_FSL_MPIC_20: - opp->fsl = &fsl_mpic_20; - opp->brr1 = 0x00400200; - opp->flags |= OPENPIC_FLAG_IDR_CRIT; - opp->nb_irqs = 80; - opp->mpic_mode_mask = GCR_MODE_MIXED; - - fsl_common_init(opp); - - break; - - case KVM_DEV_TYPE_FSL_MPIC_42: - opp->fsl = &fsl_mpic_42; - opp->brr1 = 0x00400402; - opp->flags |= OPENPIC_FLAG_ILR; - opp->nb_irqs = 196; - opp->mpic_mode_mask = GCR_MODE_PROXY; - - fsl_common_init(opp); - - break; - - default: - ret = -ENODEV; - goto err; - } - - dev->kvm->arch.mpic = opp; - - ret = mpic_set_default_irq_routing(opp); - if (ret) - goto err; - - openpic_reset(opp); - - return 0; - -err: - dev->kvm->arch.mpic = NULL; - kfree(opp); - return ret; -} - -struct kvm_device_ops kvm_mpic_ops = { - .name = "kvm-mpic", - .create = mpic_create, - .destroy = mpic_destroy, - .set_attr = mpic_set_attr, - .get_attr = mpic_get_attr, - .has_attr = mpic_has_attr, -}; - -int kvmppc_mpic_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu, - u32 cpu) -{ - struct openpic *opp = dev->private; - int ret = 0; - - if (dev->ops != &kvm_mpic_ops) - return -EPERM; - if (opp->kvm != vcpu->kvm) - return -EPERM; - if (cpu < 0 || cpu >= MAX_CPU) - return -EPERM; - - spin_lock_irq(&opp->lock); - - if (opp->dst[cpu].vcpu) { - ret = -EEXIST; - goto out; - } - if (vcpu->arch.irq_type) { - ret = -EBUSY; - goto out; - } - - opp->dst[cpu].vcpu = vcpu; - opp->nb_cpus = max(opp->nb_cpus, cpu + 1); - - vcpu->arch.mpic = opp; - vcpu->arch.irq_cpu_id = cpu; - vcpu->arch.irq_type = KVMPPC_IRQ_MPIC; - - /* This might need to be changed if GCR gets extended */ - if (opp->mpic_mode_mask == GCR_MODE_PROXY) - vcpu->arch.epr_flags |= KVMPPC_EPR_KERNEL; - - kvm_device_get(dev); -out: - spin_unlock_irq(&opp->lock); - return ret; -} - -/* - * This should only happen immediately before the mpic is destroyed, - * so we shouldn't need to worry about anything still trying to - * access the vcpu pointer. - */ -void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, struct kvm_vcpu *vcpu) -{ - BUG_ON(!opp->dst[vcpu->arch.irq_cpu_id].vcpu); - - opp->dst[vcpu->arch.irq_cpu_id].vcpu = NULL; - kvm_device_put(opp->dev); -} - -/* - * Return value: - * < 0 Interrupt was ignored (masked or not delivered for other reasons) - * = 0 Interrupt was coalesced (previous irq is still pending) - * > 0 Number of CPUs interrupt was delivered to - */ -static int mpic_set_irq(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level) -{ - u32 irq = e->irqchip.pin; - struct openpic *opp = kvm->arch.mpic; - - spin_lock_irq(&opp->lock); - openpic_set_irq(opp, irq, level); - spin_unlock_irq(&opp->lock); - - /* All code paths we care about don't check for the return value */ - return 0; -} - -int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, int level) -{ - struct openpic *opp = kvm->arch.mpic; - spin_lock_irq(&opp->lock); - - /* - * XXX We ignore the target address for now, as we only support - * a single MSI bank. - */ - openpic_msi_write(kvm->arch.mpic, MSIIR_OFFSET, e->msi.data); - spin_unlock_irq(&opp->lock); - - /* All code paths we care about don't check for the return value */ - return 0; -} - -int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, - struct kvm_kernel_irq_routing_entry *e, - const struct kvm_irq_routing_entry *ue) -{ - int r = -EINVAL; - - switch (ue->type) { - case KVM_IRQ_ROUTING_IRQCHIP: - e->set = mpic_set_irq; - e->irqchip.irqchip = ue->u.irqchip.irqchip; - e->irqchip.pin = ue->u.irqchip.pin; - if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) - goto out; - rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi; - break; - case KVM_IRQ_ROUTING_MSI: - e->set = kvm_set_msi; - e->msi.address_lo = ue->u.msi.address_lo; - e->msi.address_hi = ue->u.msi.address_hi; - e->msi.data = ue->u.msi.data; - break; - default: - goto out; - } - - r = 0; -out: - return r; -} diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 990e24a..4bf74d4 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -33,7 +32,6 @@ #include #include #include "timing.h" -#include "irq.h" #include "../mm/mmu_decl.h" #define CREATE_TRACE_POINTS @@ -319,7 +317,6 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_ENABLE_CAP: case KVM_CAP_ONE_REG: case KVM_CAP_IOEVENTFD: - case KVM_CAP_DEVICE_CTRL: r = 1; break; #ifndef CONFIG_KVM_BOOK3S_64_HV @@ -329,9 +326,6 @@ int kvm_dev_ioctl_check_extension(long ext) #if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) case KVM_CAP_SW_TLB: #endif -#ifdef CONFIG_KVM_MPIC - case KVM_CAP_IRQ_MPIC: -#endif r = 1; break; case KVM_CAP_COALESCED_MMIO: @@ -466,15 +460,6 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu) tasklet_kill(&vcpu->arch.tasklet); kvmppc_remove_vcpu_debugfs(vcpu); - - switch (vcpu->arch.irq_type) { -#ifdef CONFIG_KVM_MPIC - case KVMPPC_IRQ_MPIC: - kvmppc_mpic_disconnect_vcpu(vcpu->arch.mpic, vcpu); - break; -#endif - } - kvmppc_core_vcpu_free(vcpu); } @@ -778,10 +763,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, break; case KVM_CAP_PPC_EPR: r = 0; - if (cap->args[0]) - vcpu->arch.epr_flags |= KVMPPC_EPR_USER; - else - vcpu->arch.epr_flags &= ~KVMPPC_EPR_USER; + vcpu->arch.epr_enabled = cap->args[0]; break; #ifdef CONFIG_BOOKE case KVM_CAP_PPC_BOOKE_WATCHDOG: @@ -802,25 +784,6 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, break; } #endif -#ifdef CONFIG_KVM_MPIC - case KVM_CAP_IRQ_MPIC: { - struct file *filp; - struct kvm_device *dev; - - r = -EBADF; - filp = fget(cap->args[0]); - if (!filp) - break; - - r = -EPERM; - dev = kvm_device_from_filp(filp); - if (dev) - r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); - - fput(filp); - break; - } -#endif default: r = -EINVAL; break; @@ -943,20 +906,9 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo) return 0; } -int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event) -{ - if (!irqchip_in_kernel(kvm)) - return -ENXIO; - - irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, - irq_event->irq, irq_event->level); - return 0; -} - long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { - struct kvm *kvm __maybe_unused = filp->private_data; void __user *argp = (void __user *)arg; long r; @@ -975,6 +927,7 @@ long kvm_arch_vm_ioctl(struct file *filp, #ifdef CONFIG_PPC_BOOK3S_64 case KVM_CREATE_SPAPR_TCE: { struct kvm_create_spapr_tce create_tce; + struct kvm *kvm = filp->private_data; r = -EFAULT; if (copy_from_user(&create_tce, argp, sizeof(create_tce))) @@ -986,6 +939,7 @@ long kvm_arch_vm_ioctl(struct file *filp, #ifdef CONFIG_KVM_BOOK3S_64_HV case KVM_ALLOCATE_RMA: { + struct kvm *kvm = filp->private_data; struct kvm_allocate_rma rma; r = kvm_vm_ioctl_allocate_rma(kvm, &rma); @@ -995,6 +949,7 @@ long kvm_arch_vm_ioctl(struct file *filp, } case KVM_PPC_ALLOCATE_HTAB: { + struct kvm *kvm = filp->private_data; u32 htab_order; r = -EFAULT; @@ -1011,6 +966,7 @@ long kvm_arch_vm_ioctl(struct file *filp, } case KVM_PPC_GET_HTAB_FD: { + struct kvm *kvm = filp->private_data; struct kvm_get_htab_fd ghf; r = -EFAULT; @@ -1023,6 +979,7 @@ long kvm_arch_vm_ioctl(struct file *filp, #ifdef CONFIG_PPC_BOOK3S_64 case KVM_PPC_GET_SMMU_INFO: { + struct kvm *kvm = filp->private_data; struct kvm_ppc_smmu_info info; memset(&info, 0, sizeof(info)); diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index ff691d6..85039f9 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -43,8 +43,6 @@ #define KVM_PIO_PAGE_OFFSET 1 #define KVM_COALESCED_MMIO_PAGE_OFFSET 2 -#define KVM_IRQCHIP_NUM_PINS KVM_IOAPIC_NUM_PINS - #define CR0_RESERVED_BITS \ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \ | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \ diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 9d50efd..586f000 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -29,7 +29,6 @@ config KVM select MMU_NOTIFIER select ANON_INODES select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_EVENTFD select KVM_APIC_ARCHITECTURE select KVM_ASYNC_PF diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index a797b8e..04d3040 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -7,7 +7,7 @@ CFLAGS_vmx.o := -I. kvm-y += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \ coalesced_mmio.o irq_comm.o eventfd.o \ - assigned-dev.o irqchip.o) + assigned-dev.o) kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o) kvm-$(CONFIG_KVM_ASYNC_PF) += $(addprefix ../../../virt/kvm/, async_pf.o) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3dd9625..fb485ba 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2500,6 +2500,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_PCI_2_3: case KVM_CAP_KVMCLOCK_CTRL: case KVM_CAP_READONLY_MEM: + case KVM_CAP_IRQFD_RESAMPLE: r = 1; break; case KVM_CAP_COALESCED_MMIO: diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 226d10b..3fd7b15 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -295,10 +295,10 @@ struct kvm_kernel_irq_routing_entry { struct hlist_node link; }; -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC struct kvm_irq_routing_table { - int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS]; + int chip[KVM_NR_IRQCHIPS][KVM_IOAPIC_NUM_PINS]; struct kvm_kernel_irq_routing_entry *rt_entries; u32 nr_rt_entries; /* @@ -419,7 +419,7 @@ void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); int __must_check vcpu_load(struct kvm_vcpu *vcpu); void vcpu_put(struct kvm_vcpu *vcpu); -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC int kvm_irqfd_init(void); void kvm_irqfd_exit(void); #else @@ -690,6 +690,11 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq, void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin, bool mask); +#ifdef __KVM_HAVE_IOAPIC +void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic, + union kvm_ioapic_redirect_entry *entry, + unsigned long *deliver_bitmask); +#endif int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level); int kvm_set_irq_inatomic(struct kvm *kvm, int irq_source_id, u32 irq, int level); int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm, @@ -885,7 +890,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq) } #endif -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef KVM_CAP_IRQ_ROUTING #define KVM_MAX_IRQ_ROUTES 1024 @@ -894,9 +899,6 @@ int kvm_set_irq_routing(struct kvm *kvm, const struct kvm_irq_routing_entry *entries, unsigned nr, unsigned flags); -int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, - struct kvm_kernel_irq_routing_entry *e, - const struct kvm_irq_routing_entry *ue); void kvm_free_irq_routing(struct kvm *kvm); int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi); @@ -995,43 +997,6 @@ static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu) } } -struct kvm_device_ops; - -struct kvm_device { - struct kvm_device_ops *ops; - struct kvm *kvm; - atomic_t users; - void *private; -}; - -/* create, destroy, and name are mandatory */ -struct kvm_device_ops { - const char *name; - int (*create)(struct kvm_device *dev, u32 type); - - /* - * Destroy is responsible for freeing dev. - * - * Destroy may be called before or after destructors are called - * on emulated I/O regions, depending on whether a reference is - * held by a vcpu or other kvm component that gets destroyed - * after the emulated I/O. - */ - void (*destroy)(struct kvm_device *dev); - - int (*set_attr)(struct kvm_device *dev, struct kvm_device_attr *attr); - int (*get_attr)(struct kvm_device *dev, struct kvm_device_attr *attr); - int (*has_attr)(struct kvm_device *dev, struct kvm_device_attr *attr); - long (*ioctl)(struct kvm_device *dev, unsigned int ioctl, - unsigned long arg); -}; - -void kvm_device_get(struct kvm_device *dev); -void kvm_device_put(struct kvm_device *dev); -struct kvm_device *kvm_device_from_filp(struct file *filp); - -extern struct kvm_device_ops kvm_mpic_ops; - #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val) diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h index 85422a8..7ef9e75 100644 --- a/include/trace/events/kvm.h +++ b/include/trace/events/kvm.h @@ -37,7 +37,7 @@ TRACE_EVENT(kvm_userspace_exit, __entry->errno < 0 ? -__entry->errno : __entry->reason) ); -#if defined(CONFIG_HAVE_KVM_IRQCHIP) +#if defined(__KVM_HAVE_IRQ_LINE) TRACE_EVENT(kvm_set_irq, TP_PROTO(unsigned int gsi, int level, int irq_source_id), TP_ARGS(gsi, level, irq_source_id), @@ -122,10 +122,6 @@ TRACE_EVENT(kvm_msi_set_irq, {KVM_IRQCHIP_PIC_SLAVE, "PIC slave"}, \ {KVM_IRQCHIP_IOAPIC, "IOAPIC"} -#endif /* defined(__KVM_HAVE_IOAPIC) */ - -#if defined(CONFIG_HAVE_KVM_IRQCHIP) - TRACE_EVENT(kvm_ack_irq, TP_PROTO(unsigned int irqchip, unsigned int pin), TP_ARGS(irqchip, pin), @@ -140,18 +136,14 @@ TRACE_EVENT(kvm_ack_irq, __entry->pin = pin; ), -#ifdef kvm_irqchips TP_printk("irqchip %s pin %u", __print_symbolic(__entry->irqchip, kvm_irqchips), __entry->pin) -#else - TP_printk("irqchip %d pin %u", __entry->irqchip, __entry->pin) -#endif ); -#endif /* defined(CONFIG_HAVE_KVM_IRQCHIP) */ +#endif /* defined(__KVM_HAVE_IOAPIC) */ #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 #define KVM_TRACE_MMIO_READ 1 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 7a7a3c3..710634c 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -555,7 +555,9 @@ struct kvm_ppc_smmu_info { #ifdef __KVM_HAVE_PIT #define KVM_CAP_REINJECT_CONTROL 24 #endif +#ifdef __KVM_HAVE_IOAPIC #define KVM_CAP_IRQ_ROUTING 25 +#endif #define KVM_CAP_IRQ_INJECT_STATUS 26 #ifdef __KVM_HAVE_DEVICE_ASSIGNMENT #define KVM_CAP_DEVICE_DEASSIGNMENT 27 @@ -639,8 +641,6 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_BOOKE_WATCHDOG 83 #define KVM_CAP_PPC_HTAB_FD 84 #define KVM_CAP_PPC_EPR 86 -#define KVM_CAP_DEVICE_CTRL 89 -#define KVM_CAP_IRQ_MPIC 90 #ifdef KVM_CAP_IRQ_ROUTING @@ -870,35 +870,6 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd) /* - * Device control API, available with KVM_CAP_DEVICE_CTRL - */ -#define KVM_CREATE_DEVICE_TEST 1 - -struct kvm_create_device { - __u32 type; /* in: KVM_DEV_TYPE_xxx */ - __u32 fd; /* out: device handle */ - __u32 flags; /* in: KVM_CREATE_DEVICE_xxx */ -}; - -struct kvm_device_attr { - __u32 flags; /* no flags currently defined */ - __u32 group; /* device-defined */ - __u64 attr; /* group-defined */ - __u64 addr; /* userspace address of attr data */ -}; - -#define KVM_DEV_TYPE_FSL_MPIC_20 1 -#define KVM_DEV_TYPE_FSL_MPIC_42 2 - -/* ioctl for vm fd */ -#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device) - -/* ioctls for fds returned by KVM_CREATE_DEVICE */ -#define KVM_SET_DEVICE_ATTR _IOW(KVMIO, 0xe1, struct kvm_device_attr) -#define KVM_GET_DEVICE_ATTR _IOW(KVMIO, 0xe2, struct kvm_device_attr) -#define KVM_HAS_DEVICE_ATTR _IOW(KVMIO, 0xe3, struct kvm_device_attr) - -/* * ioctls for vcpu fds */ #define KVM_RUN _IO(KVMIO, 0x80) diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 779262f..d01b24b 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -6,9 +6,6 @@ config HAVE_KVM config HAVE_KVM_IRQCHIP bool -config HAVE_KVM_IRQ_ROUTING - bool - config HAVE_KVM_EVENTFD bool select EVENTFD diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c index 468c05d..3642239 100644 --- a/virt/kvm/assigned-dev.c +++ b/virt/kvm/assigned-dev.c @@ -982,6 +982,36 @@ long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl, goto out; break; } +#ifdef KVM_CAP_IRQ_ROUTING + case KVM_SET_GSI_ROUTING: { + struct kvm_irq_routing routing; + struct kvm_irq_routing __user *urouting; + struct kvm_irq_routing_entry *entries; + + r = -EFAULT; + if (copy_from_user(&routing, argp, sizeof(routing))) + goto out; + r = -EINVAL; + if (routing.nr >= KVM_MAX_IRQ_ROUTES) + goto out; + if (routing.flags) + goto out; + r = -ENOMEM; + entries = vmalloc(routing.nr * sizeof(*entries)); + if (!entries) + goto out; + r = -EFAULT; + urouting = argp; + if (copy_from_user(entries, urouting->entries, + routing.nr * sizeof(*entries))) + goto out_free_irq_routing; + r = kvm_set_irq_routing(kvm, entries, routing.nr, + routing.flags); + out_free_irq_routing: + vfree(entries); + break; + } +#endif /* KVM_CAP_IRQ_ROUTING */ #ifdef __KVM_HAVE_MSIX case KVM_ASSIGN_SET_MSIX_NR: { struct kvm_assigned_msix_nr entry_nr; diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index c95a075..f0ced1a 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -35,7 +35,7 @@ #include "iodev.h" -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC /* * -------------------------------------------------------------------- * irqfd: Allows an fd to be used to inject an interrupt to the guest @@ -431,7 +431,7 @@ fail: void kvm_eventfd_init(struct kvm *kvm) { -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC spin_lock_init(&kvm->irqfds.lock); INIT_LIST_HEAD(&kvm->irqfds.items); INIT_LIST_HEAD(&kvm->irqfds.resampler_list); @@ -440,7 +440,7 @@ kvm_eventfd_init(struct kvm *kvm) INIT_LIST_HEAD(&kvm->ioeventfds); } -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef __KVM_HAVE_IOAPIC /* * shutdown any irqfd's that match fd+gsi */ diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index c62509d..656fa45 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -147,6 +147,58 @@ static int kvm_set_msi_inatomic(struct kvm_kernel_irq_routing_entry *e, return -EWOULDBLOCK; } +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) +{ + struct kvm_kernel_irq_routing_entry route; + + if (!irqchip_in_kernel(kvm) || msi->flags != 0) + return -EINVAL; + + route.msi.address_lo = msi->address_lo; + route.msi.address_hi = msi->address_hi; + route.msi.data = msi->data; + + return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1); +} + +/* + * Return value: + * < 0 Interrupt was ignored (masked or not delivered for other reasons) + * = 0 Interrupt was coalesced (previous irq is still pending) + * > 0 Number of CPUs interrupt was delivered to + */ +int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level) +{ + struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS]; + int ret = -1, i = 0; + struct kvm_irq_routing_table *irq_rt; + struct hlist_node *n; + + trace_kvm_set_irq(irq, level, irq_source_id); + + /* Not possible to detect if the guest uses the PIC or the + * IOAPIC. So set the bit in both. The guest will ignore + * writes to the unused one. + */ + rcu_read_lock(); + irq_rt = rcu_dereference(kvm->irq_routing); + if (irq < irq_rt->nr_rt_entries) + hlist_for_each_entry(e, n, &irq_rt->map[irq], link) + irq_set[i++] = *e; + rcu_read_unlock(); + + while(i--) { + int r; + r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level); + if (r < 0) + continue; + + ret = r + ((ret < 0) ? 0 : ret); + } + + return ret; +} + /* * Deliver an IRQ in an atomic context if we can, or return a failure, * user can retry in a process context. @@ -185,6 +237,41 @@ int kvm_set_irq_inatomic(struct kvm *kvm, int irq_source_id, u32 irq, int level) return ret; } +void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) +{ + struct kvm_irq_ack_notifier *kian; + struct hlist_node *n; + int gsi; + + trace_kvm_ack_irq(irqchip, pin); + + rcu_read_lock(); + gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; + if (gsi != -1) + hlist_for_each_entry_rcu(kian, n, &kvm->irq_ack_notifier_list, + link) + if (kian->gsi == gsi) + kian->irq_acked(kian); + rcu_read_unlock(); +} + +void kvm_register_irq_ack_notifier(struct kvm *kvm, + struct kvm_irq_ack_notifier *kian) +{ + mutex_lock(&kvm->irq_lock); + hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list); + mutex_unlock(&kvm->irq_lock); +} + +void kvm_unregister_irq_ack_notifier(struct kvm *kvm, + struct kvm_irq_ack_notifier *kian) +{ + mutex_lock(&kvm->irq_lock); + hlist_del_init_rcu(&kian->link); + mutex_unlock(&kvm->irq_lock); + synchronize_rcu(); +} + int kvm_request_irq_source_id(struct kvm *kvm) { unsigned long *bitmap = &kvm->arch.irq_sources_bitmap; @@ -269,14 +356,35 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin, rcu_read_unlock(); } -int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, - struct kvm_kernel_irq_routing_entry *e, - const struct kvm_irq_routing_entry *ue) +void kvm_free_irq_routing(struct kvm *kvm) +{ + /* Called only during vm destruction. Nobody can use the pointer + at this stage */ + kfree(kvm->irq_routing); +} + +static int setup_routing_entry(struct kvm_irq_routing_table *rt, + struct kvm_kernel_irq_routing_entry *e, + const struct kvm_irq_routing_entry *ue) { int r = -EINVAL; int delta; unsigned max_pin; + struct kvm_kernel_irq_routing_entry *ei; + struct hlist_node *n; + /* + * Do not allow GSI to be mapped to the same irqchip more than once. + * Allow only one to one mapping between GSI and MSI. + */ + hlist_for_each_entry(ei, n, &rt->map[ue->gsi], link) + if (ei->type == KVM_IRQ_ROUTING_MSI || + ue->type == KVM_IRQ_ROUTING_MSI || + ue->u.irqchip.irqchip == ei->irqchip.irqchip) + return r; + + e->gsi = ue->gsi; + e->type = ue->type; switch (ue->type) { case KVM_IRQ_ROUTING_IRQCHIP: delta = 0; @@ -319,6 +427,63 @@ out: return r; } + +int kvm_set_irq_routing(struct kvm *kvm, + const struct kvm_irq_routing_entry *ue, + unsigned nr, + unsigned flags) +{ + struct kvm_irq_routing_table *new, *old; + u32 i, j, nr_rt_entries = 0; + int r; + + for (i = 0; i < nr; ++i) { + if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES) + return -EINVAL; + nr_rt_entries = max(nr_rt_entries, ue[i].gsi); + } + + nr_rt_entries += 1; + + new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head)) + + (nr * sizeof(struct kvm_kernel_irq_routing_entry)), + GFP_KERNEL); + + if (!new) + return -ENOMEM; + + new->rt_entries = (void *)&new->map[nr_rt_entries]; + + new->nr_rt_entries = nr_rt_entries; + for (i = 0; i < 3; i++) + for (j = 0; j < KVM_IOAPIC_NUM_PINS; j++) + new->chip[i][j] = -1; + + for (i = 0; i < nr; ++i) { + r = -EINVAL; + if (ue->flags) + goto out; + r = setup_routing_entry(new, &new->rt_entries[i], ue); + if (r) + goto out; + ++ue; + } + + mutex_lock(&kvm->irq_lock); + old = kvm->irq_routing; + kvm_irq_routing_update(kvm, new); + mutex_unlock(&kvm->irq_lock); + + synchronize_rcu(); + + new = old; + r = 0; + +out: + kfree(new); + return r; +} + #define IOAPIC_ROUTING_ENTRY(irq) \ { .gsi = irq, .type = KVM_IRQ_ROUTING_IRQCHIP, \ .u.irqchip.irqchip = KVM_IRQCHIP_IOAPIC, .u.irqchip.pin = (irq) } diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c deleted file mode 100644 index f1a4add..0000000 --- a/virt/kvm/irqchip.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * irqchip.c: Common API for in kernel interrupt controllers - * Copyright (c) 2007, Intel Corporation. - * Copyright 2010 Red Hat, Inc. and/or its affiliates. - * Copyright (c) 2013, Alexander Graf - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - * - * This file is derived from virt/kvm/irq_comm.c. - * - * Authors: - * Yaozu (Eddie) Dong - * Alexander Graf - */ - -#include -#include -#include -#include -#include "irq.h" - -void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) -{ - struct kvm_irq_ack_notifier *kian; - struct hlist_node *n; - int gsi; - - trace_kvm_ack_irq(irqchip, pin); - - rcu_read_lock(); - gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; - if (gsi != -1) - hlist_for_each_entry_rcu(kian, n, &kvm->irq_ack_notifier_list, - link) - if (kian->gsi == gsi) - kian->irq_acked(kian); - rcu_read_unlock(); -} - -void kvm_register_irq_ack_notifier(struct kvm *kvm, - struct kvm_irq_ack_notifier *kian) -{ - mutex_lock(&kvm->irq_lock); - hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list); - mutex_unlock(&kvm->irq_lock); -} - -void kvm_unregister_irq_ack_notifier(struct kvm *kvm, - struct kvm_irq_ack_notifier *kian) -{ - mutex_lock(&kvm->irq_lock); - hlist_del_init_rcu(&kian->link); - mutex_unlock(&kvm->irq_lock); - synchronize_rcu(); -} - -int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) -{ - struct kvm_kernel_irq_routing_entry route; - - if (!irqchip_in_kernel(kvm) || msi->flags != 0) - return -EINVAL; - - route.msi.address_lo = msi->address_lo; - route.msi.address_hi = msi->address_hi; - route.msi.data = msi->data; - - return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1); -} - -/* - * Return value: - * < 0 Interrupt was ignored (masked or not delivered for other reasons) - * = 0 Interrupt was coalesced (previous irq is still pending) - * > 0 Number of CPUs interrupt was delivered to - */ -int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level) -{ - struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS]; - int ret = -1, i = 0; - struct kvm_irq_routing_table *irq_rt; - struct hlist_node *n; - - trace_kvm_set_irq(irq, level, irq_source_id); - - /* Not possible to detect if the guest uses the PIC or the - * IOAPIC. So set the bit in both. The guest will ignore - * writes to the unused one. - */ - rcu_read_lock(); - irq_rt = rcu_dereference(kvm->irq_routing); - if (irq < irq_rt->nr_rt_entries) - hlist_for_each_entry(e, n, &irq_rt->map[irq], link) - irq_set[i++] = *e; - rcu_read_unlock(); - - while(i--) { - int r; - r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level); - if (r < 0) - continue; - - ret = r + ((ret < 0) ? 0 : ret); - } - - return ret; -} - -void kvm_free_irq_routing(struct kvm *kvm) -{ - /* Called only during vm destruction. Nobody can use the pointer - at this stage */ - kfree(kvm->irq_routing); -} - -static int setup_routing_entry(struct kvm_irq_routing_table *rt, - struct kvm_kernel_irq_routing_entry *e, - const struct kvm_irq_routing_entry *ue) -{ - int r = -EINVAL; - struct kvm_kernel_irq_routing_entry *ei; - struct hlist_node *n; - - /* - * Do not allow GSI to be mapped to the same irqchip more than once. - * Allow only one to one mapping between GSI and MSI. - */ - hlist_for_each_entry(ei, n, &rt->map[ue->gsi], link) - if (ei->type == KVM_IRQ_ROUTING_MSI || - ue->type == KVM_IRQ_ROUTING_MSI || - ue->u.irqchip.irqchip == ei->irqchip.irqchip) - return r; - - e->gsi = ue->gsi; - e->type = ue->type; - r = kvm_set_routing_entry(rt, e, ue); - if (r) - goto out; - - hlist_add_head(&e->link, &rt->map[e->gsi]); - r = 0; -out: - return r; -} - -int kvm_set_irq_routing(struct kvm *kvm, - const struct kvm_irq_routing_entry *ue, - unsigned nr, - unsigned flags) -{ - struct kvm_irq_routing_table *new, *old; - u32 i, j, nr_rt_entries = 0; - int r; - - for (i = 0; i < nr; ++i) { - if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES) - return -EINVAL; - nr_rt_entries = max(nr_rt_entries, ue[i].gsi); - } - - nr_rt_entries += 1; - - new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head)) - + (nr * sizeof(struct kvm_kernel_irq_routing_entry)), - GFP_KERNEL); - - if (!new) - return -ENOMEM; - - new->rt_entries = (void *)&new->map[nr_rt_entries]; - - new->nr_rt_entries = nr_rt_entries; - for (i = 0; i < KVM_NR_IRQCHIPS; i++) - for (j = 0; j < KVM_IRQCHIP_NUM_PINS; j++) - new->chip[i][j] = -1; - - for (i = 0; i < nr; ++i) { - r = -EINVAL; - if (ue->flags) - goto out; - r = setup_routing_entry(new, &new->rt_entries[i], ue); - if (r) - goto out; - ++ue; - } - - mutex_lock(&kvm->irq_lock); - old = kvm->irq_routing; - kvm_irq_routing_update(kvm, new); - mutex_unlock(&kvm->irq_lock); - - synchronize_rcu(); - - new = old; - r = 0; - -out: - kfree(new); - return r; -} diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 60ac292..5ff30ca 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2133,123 +2133,6 @@ out: } #endif -static int kvm_device_ioctl_attr(struct kvm_device *dev, - int (*accessor)(struct kvm_device *dev, - struct kvm_device_attr *attr), - unsigned long arg) -{ - struct kvm_device_attr attr; - - if (!accessor) - return -EPERM; - - if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) - return -EFAULT; - - return accessor(dev, &attr); -} - -static long kvm_device_ioctl(struct file *filp, unsigned int ioctl, - unsigned long arg) -{ - struct kvm_device *dev = filp->private_data; - - switch (ioctl) { - case KVM_SET_DEVICE_ATTR: - return kvm_device_ioctl_attr(dev, dev->ops->set_attr, arg); - case KVM_GET_DEVICE_ATTR: - return kvm_device_ioctl_attr(dev, dev->ops->get_attr, arg); - case KVM_HAS_DEVICE_ATTR: - return kvm_device_ioctl_attr(dev, dev->ops->has_attr, arg); - default: - if (dev->ops->ioctl) - return dev->ops->ioctl(dev, ioctl, arg); - - return -ENOTTY; - } -} - -void kvm_device_get(struct kvm_device *dev) -{ - atomic_inc(&dev->users); -} - -void kvm_device_put(struct kvm_device *dev) -{ - if (atomic_dec_and_test(&dev->users)) - dev->ops->destroy(dev); -} - -static int kvm_device_release(struct inode *inode, struct file *filp) -{ - struct kvm_device *dev = filp->private_data; - struct kvm *kvm = dev->kvm; - - kvm_device_put(dev); - kvm_put_kvm(kvm); - return 0; -} - -static const struct file_operations kvm_device_fops = { - .unlocked_ioctl = kvm_device_ioctl, - .release = kvm_device_release, -}; - -struct kvm_device *kvm_device_from_filp(struct file *filp) -{ - if (filp->f_op != &kvm_device_fops) - return NULL; - - return filp->private_data; -} - -static int kvm_ioctl_create_device(struct kvm *kvm, - struct kvm_create_device *cd) -{ - struct kvm_device_ops *ops = NULL; - struct kvm_device *dev; - bool test = cd->flags & KVM_CREATE_DEVICE_TEST; - int ret; - - switch (cd->type) { -#ifdef CONFIG_KVM_MPIC - case KVM_DEV_TYPE_FSL_MPIC_20: - case KVM_DEV_TYPE_FSL_MPIC_42: - ops = &kvm_mpic_ops; - break; -#endif - default: - return -ENODEV; - } - - if (test) - return 0; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dev->ops = ops; - dev->kvm = kvm; - atomic_set(&dev->users, 1); - - ret = ops->create(dev, cd->type); - if (ret < 0) { - kfree(dev); - return ret; - } - - ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR); - if (ret < 0) { - ops->destroy(dev); - return ret; - } - - kvm_get_kvm(kvm); - cd->fd = ret; - return 0; -} - static long kvm_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2364,54 +2247,6 @@ static long kvm_vm_ioctl(struct file *filp, break; } #endif -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING - case KVM_SET_GSI_ROUTING: { - struct kvm_irq_routing routing; - struct kvm_irq_routing __user *urouting; - struct kvm_irq_routing_entry *entries; - - r = -EFAULT; - if (copy_from_user(&routing, argp, sizeof(routing))) - goto out; - r = -EINVAL; - if (routing.nr >= KVM_MAX_IRQ_ROUTES) - goto out; - if (routing.flags) - goto out; - r = -ENOMEM; - entries = vmalloc(routing.nr * sizeof(*entries)); - if (!entries) - goto out; - r = -EFAULT; - urouting = argp; - if (copy_from_user(entries, urouting->entries, - routing.nr * sizeof(*entries))) - goto out_free_irq_routing; - r = kvm_set_irq_routing(kvm, entries, routing.nr, - routing.flags); - out_free_irq_routing: - vfree(entries); - break; - } -#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */ - case KVM_CREATE_DEVICE: { - struct kvm_create_device cd; - - r = -EFAULT; - if (copy_from_user(&cd, argp, sizeof(cd))) - goto out; - - r = kvm_ioctl_create_device(kvm, &cd); - if (r) - goto out; - - r = -EFAULT; - if (copy_to_user(argp, &cd, sizeof(cd))) - goto out; - - r = 0; - break; - } default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); if (r == -ENOTTY) @@ -2541,11 +2376,8 @@ static long kvm_dev_ioctl_check_extension_generic(long arg) #ifdef CONFIG_HAVE_KVM_MSI case KVM_CAP_SIGNAL_MSI: #endif -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING - case KVM_CAP_IRQFD_RESAMPLE: -#endif return 1; -#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +#ifdef KVM_CAP_IRQ_ROUTING case KVM_CAP_IRQ_ROUTING: return KVM_MAX_IRQ_ROUTES; #endif -- cgit v0.10.2