mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
kvm/ppc/mpic: in-kernel MPIC emulation
Hook the MPIC code up to the KVM interfaces, add locking, etc. Signed-off-by: Scott Wood <scottwood@freescale.com> [agraf: add stub function for kvmppc_mpic_set_epr, non-booke, 64bit] Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
f0f5c481a9
commit
5df554ad5b
37
Documentation/virtual/kvm/devices/mpic.txt
Normal file
37
Documentation/virtual/kvm/devices/mpic.txt
Normal file
@ -0,0 +1,37 @@
|
||||
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.
|
@ -361,6 +361,11 @@ 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;
|
||||
@ -526,7 +531,7 @@ struct kvm_vcpu_arch {
|
||||
u8 sane;
|
||||
u8 cpu_type;
|
||||
u8 hcall_needed;
|
||||
u8 epr_enabled;
|
||||
u8 epr_flags; /* KVMPPC_EPR_xxx */
|
||||
u8 epr_needed;
|
||||
|
||||
u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
|
||||
@ -593,5 +598,6 @@ 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__ */
|
||||
|
@ -164,6 +164,8 @@ 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.
|
||||
@ -245,6 +247,9 @@ 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;
|
||||
void kvmppc_mpic_put(struct openpic *opp);
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_64_HV
|
||||
static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
|
||||
{
|
||||
@ -270,6 +275,18 @@ static inline void kvmppc_set_epr(struct kvm_vcpu *vcpu, u32 epr)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KVM_MPIC
|
||||
|
||||
void kvmppc_mpic_set_epr(struct kvm_vcpu *vcpu);
|
||||
|
||||
#else
|
||||
|
||||
static inline void kvmppc_mpic_set_epr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_KVM_MPIC */
|
||||
|
||||
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,
|
||||
|
@ -382,6 +382,14 @@ struct kvm_get_htab_header {
|
||||
__u16 n_invalid;
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* One-Reg API: PPC-specific registers */
|
||||
#define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
|
||||
#define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2)
|
||||
#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3)
|
||||
|
@ -151,6 +151,15 @@ config KVM_E500MC
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config KVM_MPIC
|
||||
bool "KVM in-kernel MPIC emulation"
|
||||
depends on KVM
|
||||
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
|
||||
|
@ -103,6 +103,8 @@ 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 := $(kvm-objs-m) $(kvm-objs-y)
|
||||
|
||||
obj-$(CONFIG_KVM_440) += kvm.o
|
||||
|
@ -346,7 +346,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
|
||||
keep_irq = true;
|
||||
}
|
||||
|
||||
if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_enabled)
|
||||
if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_flags)
|
||||
update_epr = true;
|
||||
|
||||
switch (priority) {
|
||||
@ -427,8 +427,10 @@ 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)
|
||||
kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
|
||||
if (update_epr == true) {
|
||||
if (vcpu->arch.epr_flags & KVMPPC_EPR_USER)
|
||||
kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
|
||||
}
|
||||
|
||||
new_msr &= msr_mask;
|
||||
#if defined(CONFIG_64BIT)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -317,6 +317,7 @@ 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
|
||||
@ -762,7 +763,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
|
||||
break;
|
||||
case KVM_CAP_PPC_EPR:
|
||||
r = 0;
|
||||
vcpu->arch.epr_enabled = cap->args[0];
|
||||
if (cap->args[0])
|
||||
vcpu->arch.epr_flags |= KVMPPC_EPR_USER;
|
||||
else
|
||||
vcpu->arch.epr_flags &= ~KVMPPC_EPR_USER;
|
||||
break;
|
||||
#ifdef CONFIG_BOOKE
|
||||
case KVM_CAP_PPC_BOOKE_WATCHDOG:
|
||||
@ -908,6 +912,7 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
|
||||
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;
|
||||
|
||||
@ -926,7 +931,6 @@ 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)))
|
||||
@ -938,7 +942,6 @@ 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);
|
||||
@ -948,7 +951,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
||||
}
|
||||
|
||||
case KVM_PPC_ALLOCATE_HTAB: {
|
||||
struct kvm *kvm = filp->private_data;
|
||||
u32 htab_order;
|
||||
|
||||
r = -EFAULT;
|
||||
@ -965,7 +967,6 @@ 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;
|
||||
@ -978,7 +979,6 @@ 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));
|
||||
|
@ -1099,6 +1099,8 @@ 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)
|
||||
|
@ -837,6 +837,9 @@ struct kvm_device_attr {
|
||||
__u64 addr; /* userspace address of attr data */
|
||||
};
|
||||
|
||||
#define KVM_DEV_TYPE_FSL_MPIC_20 1
|
||||
#define KVM_DEV_TYPE_FSL_MPIC_42 2
|
||||
|
||||
/*
|
||||
* ioctls for VM fds
|
||||
*/
|
||||
|
@ -2238,6 +2238,12 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user