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:
committed by
Alexander Graf
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_IAC 4
|
||||||
#define KVMPPC_BOOKE_MAX_DAC 2
|
#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 {
|
struct kvmppc_booke_debug_reg {
|
||||||
u32 dbcr0;
|
u32 dbcr0;
|
||||||
u32 dbcr1;
|
u32 dbcr1;
|
||||||
@@ -526,7 +531,7 @@ struct kvm_vcpu_arch {
|
|||||||
u8 sane;
|
u8 sane;
|
||||||
u8 cpu_type;
|
u8 cpu_type;
|
||||||
u8 hcall_needed;
|
u8 hcall_needed;
|
||||||
u8 epr_enabled;
|
u8 epr_flags; /* KVMPPC_EPR_xxx */
|
||||||
u8 epr_needed;
|
u8 epr_needed;
|
||||||
|
|
||||||
u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
|
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_MMIO_REG_FQPR 0x0060
|
||||||
|
|
||||||
#define __KVM_HAVE_ARCH_WQP
|
#define __KVM_HAVE_ARCH_WQP
|
||||||
|
#define __KVM_HAVE_CREATE_DEVICE
|
||||||
|
|
||||||
#endif /* __POWERPC_KVM_HOST_H__ */
|
#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 *);
|
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.
|
* Cuts out inst bits with ordering according to spec.
|
||||||
* That means the leftmost bit is zero. All given bits are included.
|
* 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);
|
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
|
#ifdef CONFIG_KVM_BOOK3S_64_HV
|
||||||
static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
|
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
|
#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,
|
int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_config_tlb *cfg);
|
struct kvm_config_tlb *cfg);
|
||||||
int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
|
int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
|
||||||
|
@@ -382,6 +382,14 @@ struct kvm_get_htab_header {
|
|||||||
__u16 n_invalid;
|
__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_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_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2)
|
||||||
#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3)
|
#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3)
|
||||||
|
@@ -151,6 +151,15 @@ config KVM_E500MC
|
|||||||
|
|
||||||
If unsure, say N.
|
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
|
source drivers/vhost/Kconfig
|
||||||
|
|
||||||
endif # VIRTUALIZATION
|
endif # VIRTUALIZATION
|
||||||
|
@@ -103,6 +103,8 @@ kvm-book3s_32-objs := \
|
|||||||
book3s_32_mmu.o
|
book3s_32_mmu.o
|
||||||
kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs)
|
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)
|
kvm-objs := $(kvm-objs-m) $(kvm-objs-y)
|
||||||
|
|
||||||
obj-$(CONFIG_KVM_440) += kvm.o
|
obj-$(CONFIG_KVM_440) += kvm.o
|
||||||
|
@@ -346,7 +346,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
|
|||||||
keep_irq = true;
|
keep_irq = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_enabled)
|
if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_flags)
|
||||||
update_epr = true;
|
update_epr = true;
|
||||||
|
|
||||||
switch (priority) {
|
switch (priority) {
|
||||||
@@ -427,8 +427,10 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
|
|||||||
set_guest_esr(vcpu, vcpu->arch.queued_esr);
|
set_guest_esr(vcpu, vcpu->arch.queued_esr);
|
||||||
if (update_dear == true)
|
if (update_dear == true)
|
||||||
set_guest_dear(vcpu, vcpu->arch.queued_dear);
|
set_guest_dear(vcpu, vcpu->arch.queued_dear);
|
||||||
if (update_epr == true)
|
if (update_epr == true) {
|
||||||
kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
|
if (vcpu->arch.epr_flags & KVMPPC_EPR_USER)
|
||||||
|
kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
|
||||||
|
}
|
||||||
|
|
||||||
new_msr &= msr_mask;
|
new_msr &= msr_mask;
|
||||||
#if defined(CONFIG_64BIT)
|
#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_ENABLE_CAP:
|
||||||
case KVM_CAP_ONE_REG:
|
case KVM_CAP_ONE_REG:
|
||||||
case KVM_CAP_IOEVENTFD:
|
case KVM_CAP_IOEVENTFD:
|
||||||
|
case KVM_CAP_DEVICE_CTRL:
|
||||||
r = 1;
|
r = 1;
|
||||||
break;
|
break;
|
||||||
#ifndef CONFIG_KVM_BOOK3S_64_HV
|
#ifndef CONFIG_KVM_BOOK3S_64_HV
|
||||||
@@ -762,7 +763,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
|
|||||||
break;
|
break;
|
||||||
case KVM_CAP_PPC_EPR:
|
case KVM_CAP_PPC_EPR:
|
||||||
r = 0;
|
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;
|
break;
|
||||||
#ifdef CONFIG_BOOKE
|
#ifdef CONFIG_BOOKE
|
||||||
case KVM_CAP_PPC_BOOKE_WATCHDOG:
|
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,
|
long kvm_arch_vm_ioctl(struct file *filp,
|
||||||
unsigned int ioctl, unsigned long arg)
|
unsigned int ioctl, unsigned long arg)
|
||||||
{
|
{
|
||||||
|
struct kvm *kvm __maybe_unused = filp->private_data;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
long r;
|
long r;
|
||||||
|
|
||||||
@@ -926,7 +931,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|||||||
#ifdef CONFIG_PPC_BOOK3S_64
|
#ifdef CONFIG_PPC_BOOK3S_64
|
||||||
case KVM_CREATE_SPAPR_TCE: {
|
case KVM_CREATE_SPAPR_TCE: {
|
||||||
struct kvm_create_spapr_tce create_tce;
|
struct kvm_create_spapr_tce create_tce;
|
||||||
struct kvm *kvm = filp->private_data;
|
|
||||||
|
|
||||||
r = -EFAULT;
|
r = -EFAULT;
|
||||||
if (copy_from_user(&create_tce, argp, sizeof(create_tce)))
|
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
|
#ifdef CONFIG_KVM_BOOK3S_64_HV
|
||||||
case KVM_ALLOCATE_RMA: {
|
case KVM_ALLOCATE_RMA: {
|
||||||
struct kvm *kvm = filp->private_data;
|
|
||||||
struct kvm_allocate_rma rma;
|
struct kvm_allocate_rma rma;
|
||||||
|
|
||||||
r = kvm_vm_ioctl_allocate_rma(kvm, &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: {
|
case KVM_PPC_ALLOCATE_HTAB: {
|
||||||
struct kvm *kvm = filp->private_data;
|
|
||||||
u32 htab_order;
|
u32 htab_order;
|
||||||
|
|
||||||
r = -EFAULT;
|
r = -EFAULT;
|
||||||
@@ -965,7 +967,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case KVM_PPC_GET_HTAB_FD: {
|
case KVM_PPC_GET_HTAB_FD: {
|
||||||
struct kvm *kvm = filp->private_data;
|
|
||||||
struct kvm_get_htab_fd ghf;
|
struct kvm_get_htab_fd ghf;
|
||||||
|
|
||||||
r = -EFAULT;
|
r = -EFAULT;
|
||||||
@@ -978,7 +979,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|||||||
|
|
||||||
#ifdef CONFIG_PPC_BOOK3S_64
|
#ifdef CONFIG_PPC_BOOK3S_64
|
||||||
case KVM_PPC_GET_SMMU_INFO: {
|
case KVM_PPC_GET_SMMU_INFO: {
|
||||||
struct kvm *kvm = filp->private_data;
|
|
||||||
struct kvm_ppc_smmu_info info;
|
struct kvm_ppc_smmu_info info;
|
||||||
|
|
||||||
memset(&info, 0, sizeof(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);
|
void kvm_device_put(struct kvm_device *dev);
|
||||||
struct kvm_device *kvm_device_from_filp(struct file *filp);
|
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
|
#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
|
||||||
|
|
||||||
static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val)
|
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 */
|
__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
|
* ioctls for VM fds
|
||||||
*/
|
*/
|
||||||
|
@@ -2238,6 +2238,12 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (cd->type) {
|
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:
|
default:
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user