In-kernel XICS interrupt controller emulation
Subsystems (4)
v5 cover In-kernel XICS interrupt controller emulation
This is a repost of my patch series implementing in-kernel emulation of the XICS interrupt controller architecture defined in PAPR (Power Architecture Platform Requirements, the document that defines IBM's pSeries platform architecture). This version of the patch series uses the latest device API as posted by Scott Wood, that is, i.e., the version where the core device code provides the file descriptor and ioctl handler. I have structured the series so that the API is added by the last two patches, so as to be able to accommodate any future revisions to the device API with minimal changes.
The series is based on Alex Graf's kvm-ppc-queue branch with Scott Wood's recent patch series applied on top, together with the patch below to allow it to build with CONFIG_KVM_MPIC=n.
The API defined here uses KVM_CREATE_DEVICE to create the XICS, KVM_DEVICE_SET_ATTR/KVM_DEVICE_GET_ATTR to manipulate the interrupt sources (for initialization and migration), a new KVM_CAP_IRQ_XICS capability to connect vcpus to the XICS, a new identifier KVM_REG_PPC_ICP_STATE for the one-reg interface to get and set per-vcpu state, and the existing KVM_IRQ_LINE ioctl to assert and deassert interrupt sources.
This version also cleans up some checkpatch.pl errors and clarifies the lifetime rules for the various objects. There are two checkpatch warnings for long lines, but they are long because they have long strings in them, and if I break the strings over two lines then checkpatch warns about that.
Paul.
arch/powerpc/kvm/powerpc.c +2 -0
@@ -466,9 +466,11 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)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);
PATCH v5 1/8 KVM: PPC: Book3S: Add infrastructure to implement kernel-side RTAS calls
From: Michael Ellerman <[email protected]>
For pseries machine emulation, in order to move the interrupt controller code to the kernel, we need to intercept some RTAS calls in the kernel itself. This adds an infrastructure to allow in-kernel handlers to be registered for RTAS services by name. A new ioctl, KVM_PPC_RTAS_DEFINE_TOKEN, then allows userspace to associate token values with those service names. Then, when the guest requests an RTAS service with one of those token values, it will be handled by the relevant in-kernel handler rather than being passed up to userspace as at present.
--- Documentation/virtual/kvm/api.txt | 19 ++++ arch/powerpc/include/asm/hvcall.h | 3 + arch/powerpc/include/asm/kvm_host.h | 1 + arch/powerpc/include/asm/kvm_ppc.h | 4 + arch/powerpc/include/uapi/asm/kvm.h | 6 ++ arch/powerpc/kvm/Makefile | 1 + arch/powerpc/kvm/book3s_hv.c | 18 +++- arch/powerpc/kvm/book3s_pr.c | 1 + arch/powerpc/kvm/book3s_pr_papr.c | 7 ++ arch/powerpc/kvm/book3s_rtas.c | 182 +++++++++++++++++++++++++++++++++++ arch/powerpc/kvm/powerpc.c | 8 ++ include/uapi/linux/kvm.h | 3 + 12 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/kvm/book3s_rtas.c
Documentation/virtual/kvm/api.txt +19 -0
@@ -2325,6 +2325,25 @@ and distributor interface, the ioctl must be called after calling KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the base addresses will return -EEXIST. +4.82 KVM_PPC_RTAS_DEFINE_TOKEN + +Capability: KVM_CAP_PPC_RTAS +Architectures: ppc +Type: vm ioctl +Parameters: struct kvm_rtas_token_args +Returns: 0 on success, -1 on error + +Defines a token value for a RTAS (Run Time Abstraction Services) +service in order to allow it to be handled in the kernel. The +argument struct gives the name of the service, which must be the name +of a service that has a kernel-side implementation. If the token +value is non-zero, it will be associated with that service, and +subsequent RTAS calls by the guest specifying that token will be +handled by the kernel. If the token value is 0, then any token +associated with the service will be forgotten, and subsequent RTAS +calls by the guest for that service will be passed to userspace to be +handled. + 5. The kvm_run structure ------------------------
arch/powerpc/include/asm/hvcall.h +3 -0
@@ -270,6 +270,9 @@#define H_SET_MODE 0x31C#define MAX_HCALL_OPCODE H_SET_MODE +/* Platform specific hcalls, used by KVM */ +#define H_RTAS 0xf000 +#ifndef __ASSEMBLY__/**
arch/powerpc/include/asm/kvm_host.h +1 -0
@@ -255,6 +255,7 @@ struct kvm_arch {#endif /* CONFIG_KVM_BOOK3S_64_HV */ #ifdef CONFIG_PPC_BOOK3S_64 struct list_head spapr_tce_tables; +struct list_head rtas_tokens;#endif };
arch/powerpc/include/asm/kvm_ppc.h +4 -0
@@ -166,6 +166,10 @@ 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); +extern int kvm_vm_ioctl_rtas_define_token (struct kvm *kvm,void __user *argp); +extern int kvmppc_rtas_hcall (struct kvm_vcpu *vcpu); +extern void kvmppc_rtas_tokens_free (struct kvm *kvm); +/* * Cuts out inst bits with ordering according to spec. * That means the leftmost bit is zero. All given bits are included.
arch/powerpc/include/uapi/asm/kvm.h +6 -0
@@ -299,6 +299,12 @@ struct kvm_allocate_rma {__u64 rma_size; }; +/* for KVM_CAP_PPC_RTAS */ +struct kvm_rtas_token_args { +char name[120 ]; +__u64 token;/* Use a token of 0 to undefine a mapping */ +}; +struct kvm_book3e_206_tlb_entry {__u32 mas8;__u32 mas1;
arch/powerpc/kvm/Makefile +1 -0
@@ -86,6 +86,7 @@ kvm-book3s_64-module-objs := \ emulate.o \ book3s.o \ book3s_64_vio.o \ + book3s_rtas.o \ $(kvm-book3s_64-objs-y) kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-module-objs)
arch/powerpc/kvm/book3s_hv.c +17 -1
@@ -479,7 +479,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)unsigned long req =kvmppc_get_gpr (vcpu,3 );unsigned long target, ret =H_SUCCESS ;struct kvm_vcpu *tvcpu; -int idx; +int idx, rc;switch (req) {case H_ENTER :
@@ -515,6 +515,19 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)kvmppc_get_gpr (vcpu,5 ), kvmppc_get_gpr(vcpu, 6));break ; +case H_RTAS : +if (list_empty (&vcpu->kvm->arch.rtas_tokens)) +return RESUME_HOST ; + + rc =kvmppc_rtas_hcall (vcpu); + +if (rc = -ENOENT ) +return RESUME_HOST ; +else if (rc =0 ) +break ; + +/* Send the error out to userspace via KVM_RUN */ +return rc;default :return RESUME_HOST ; }
@@ -1821,6 +1834,7 @@ int kvmppc_core_init_vm(struct kvm *kvm)cpumask_setall (&kvm->arch.need_tlb_flush);INIT_LIST_HEAD (&kvm->arch.spapr_tce_tables); +INIT_LIST_HEAD (&kvm->arch.rtas_tokens); kvm->arch.rma =NULL ;
@@ -1866,6 +1880,8 @@ void kvmppc_core_destroy_vm(struct kvm *kvm) kvm->arch.rma =NULL ; } +kvmppc_rtas_tokens_free (kvm); +kvmppc_free_hpt (kvm);WARN_ON (!list_empty (&kvm->arch.spapr_tce_tables)); }
arch/powerpc/kvm/book3s_pr.c +1 -0
@@ -1298,6 +1298,7 @@ int kvmppc_core_init_vm(struct kvm *kvm) {#ifdef CONFIG_PPC64 INIT_LIST_HEAD (&kvm->arch.spapr_tce_tables); +INIT_LIST_HEAD (&kvm->arch.rtas_tokens);#endif if (firmware_has_feature (FW_FEATURE_SET_MODE )) {
arch/powerpc/kvm/book3s_pr_papr.c +7 -0
@@ -246,6 +246,13 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)clear_bit (KVM_REQ_UNHALT , &vcpu->requests); vcpu->stat.halt_wakeup++;return EMULATE_DONE ; +case H_RTAS : +if (list_empty (&vcpu->kvm->arch.rtas_tokens)) +return RESUME_HOST ; +if (kvmppc_rtas_hcall (vcpu)) +break ; +kvmppc_set_gpr (vcpu,3 ,0 ); +return EMULATE_DONE ; }return EMULATE_FAIL ;
arch/powerpc/kvm/book3s_rtas.c new file +182 -0
182 lines not on this page · raw message
arch/powerpc/kvm/powerpc.c +8 -0
@@ -340,6 +340,7 @@ int kvm_dev_ioctl_check_extension(long ext)#ifdef CONFIG_PPC_BOOK3S_64 case KVM_CAP_SPAPR_TCE :case KVM_CAP_PPC_ALLOC_HTAB : +case KVM_CAP_PPC_RTAS : r =1 ;break ;#endif /* CONFIG_PPC_BOOK3S_64 */
@@ -981,6 +982,7 @@ long kvm_arch_vm_ioctl(struct file *filp,#ifdef CONFIG_KVM_BOOK3S_64_HV case KVM_ALLOCATE_RMA : {struct kvm_allocate_rma rma; +struct kvm *kvm = filp->private_data; r =kvm_vm_ioctl_allocate_rma (kvm, &rma);if (r >=0 &©_to_user (argp, &rma,sizeof (rma)))
@@ -1025,6 +1027,12 @@ long kvm_arch_vm_ioctl(struct file *filp, r = -EFAULT ; break; } +case KVM_PPC_RTAS_DEFINE_TOKEN : { +struct kvm *kvm = filp->private_data; + + r =kvm_vm_ioctl_rtas_define_token (kvm, argp); +break ; + }#endif /* CONFIG_PPC_BOOK3S_64 */ default : r = -ENOTTY ;
include/uapi/linux/kvm.h +3 -0
@@ -670,6 +670,7 @@ struct kvm_ppc_smmu_info {#define KVM_CAP_ARM_SET_DEVICE_ADDR 88#define KVM_CAP_DEVICE_CTRL 89#define KVM_CAP_IRQ_MPIC 90 +#define KVM_CAP_PPC_RTAS 91#ifdef KVM_CAP_IRQ_ROUTING
@@ -909,6 +910,8 @@ struct kvm_s390_ucas_mapping {#define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd)/* Available with KVM_CAP_ARM_SET_DEVICE_ADDR */ #define KVM_ARM_SET_DEVICE_ADDR _IOW(KVMIO, 0xab, struct kvm_arm_device_addr) +/* Available with KVM_CAP_PPC_RTAS */ +#define KVM_PPC_RTAS_DEFINE_TOKEN _IOW(KVMIO, 0xac, struct kvm_rtas_token_args)/* * Device control API, available with KVM_CAP_DEVICE_CTRL
Signature · 1 line
1.7.10.4
PATCH v5 2/8 KVM: PPC: Book3S: Add kernel emulation for the XICS interrupt controller
In reply to Paul MackerrasFrom: Benjamin Herrenschmidt <[email protected]>
This adds in-kernel emulation of the XICS (eXternal Interrupt Controller Specification) interrupt controller specified by PAPR, for both HV and PR KVM guests.
The XICS emulation supports up to 1048560 interrupt sources. Interrupt source numbers below 16 are reserved; 0 is used to mean no interrupt and 2 is used for IPIs. Internally these are represented in blocks of 1024, called ICS (interrupt controller source) entities, but that is not visible to userspace.
Each vcpu gets one ICP (interrupt controller presentation) entity, used to store the per-vcpu state such as vcpu priority, pending interrupt state, IPI request, etc.
This does not include any API or any way to connect vcpus to their ICP state; that will be added in later patches.
This is based on an initial implementation by Michael Ellerman <[email protected]> reworked by Benjamin Herrenschmidt and Paul Mackerras.
--- arch/powerpc/include/asm/kvm_book3s.h | 2 + arch/powerpc/include/asm/kvm_host.h | 11 + arch/powerpc/include/asm/kvm_ppc.h | 29 + arch/powerpc/kvm/Kconfig | 8 + arch/powerpc/kvm/Makefile | 3 + arch/powerpc/kvm/book3s.c | 2 +- arch/powerpc/kvm/book3s_hv.c | 9 + arch/powerpc/kvm/book3s_pr_papr.c | 14 + arch/powerpc/kvm/book3s_rtas.c | 54 +- arch/powerpc/kvm/book3s_xics.c | 946 +++++++++++++++++++++++++++++++++ arch/powerpc/kvm/book3s_xics.h | 113 ++++ arch/powerpc/kvm/powerpc.c | 3 + 12 files changed, 1192 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/kvm/book3s_xics.c create mode 100644 arch/powerpc/kvm/book3s_xics.h
arch/powerpc/include/asm/kvm_book3s.h +2 -0
@@ -142,6 +142,8 @@ extern int kvmppc_mmu_hv_init(void);extern int kvmppc_ld (struct kvm_vcpu *vcpu,ulong *eaddr,int size,void *ptr,bool data);extern int kvmppc_st (struct kvm_vcpu *vcpu,ulong *eaddr,int size,void *ptr,bool data);extern void kvmppc_book3s_queue_irqprio (struct kvm_vcpu *vcpu,unsigned int vec); +extern void kvmppc_book3s_dequeue_irqprio (struct kvm_vcpu *vcpu, +unsigned int vec);extern void kvmppc_inject_interrupt (struct kvm_vcpu *vcpu,int vec,u64 flags);extern void kvmppc_set_bat (struct kvm_vcpu *vcpu,struct kvmppc_bat *bat,bool upper,u32 val);
arch/powerpc/include/asm/kvm_host.h +11 -0
@@ -188,6 +188,10 @@ struct kvmppc_linear_info {int type; }; +/* XICS components, defined in boo3s_xics.c */ +struct kvmppc_xics ; +struct kvmppc_icp ; +/* * The reverse mapping array has one entry for each HPTE, * which stores the guest's view of the second word of the HPTE
@@ -257,6 +261,9 @@ struct kvm_arch {struct list_head spapr_tce_tables;struct list_head rtas_tokens;#endif +#ifdef CONFIG_KVM_XICS +struct kvmppc_xics *xics; +#endif };/*
@@ -378,6 +385,7 @@ struct kvmppc_booke_debug_reg {#define KVMPPC_IRQ_DEFAULT 0#define KVMPPC_IRQ_MPIC 1 +#define KVMPPC_IRQ_XICS 2struct openpic ;
@@ -563,6 +571,9 @@ struct kvm_vcpu_arch {int irq_type;/* one of KVM_IRQ_* */ int irq_cpu_id;struct openpic *mpic;/* KVM_IRQ_MPIC */ +#ifdef CONFIG_KVM_XICS +struct kvmppc_icp *icp;/* XICS presentation controller */ +#endif #ifdef CONFIG_KVM_BOOK3S_64_HV struct kvm_vcpu_arch_shared shregs;
arch/powerpc/include/asm/kvm_ppc.h +29 -0
@@ -130,6 +130,7 @@ extern long kvmppc_prepare_vrma(struct kvm *kvm,extern void kvmppc_map_vrma (struct kvm_vcpu *vcpu,struct kvm_memory_slot *memslot,unsigned long porder);extern int kvmppc_pseries_do_hcall (struct kvm_vcpu *vcpu); +extern long kvm_vm_ioctl_create_spapr_tce (struct kvm *kvm,struct kvm_create_spapr_tce *args); extern long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
@@ -169,6 +170,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);extern int kvm_vm_ioctl_rtas_define_token (struct kvm *kvm,void __user *argp);extern int kvmppc_rtas_hcall (struct kvm_vcpu *vcpu);extern void kvmppc_rtas_tokens_free (struct kvm *kvm); +extern int kvmppc_xics_set_xive (struct kvm *kvm,u32 irq,u32 server, +u32 priority); +extern int kvmppc_xics_get_xive (struct kvm *kvm,u32 irq,u32 *server, +u32 *priority);/* * Cuts out inst bits with ordering according to spec.
@@ -267,6 +272,30 @@ static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)static inline void kvm_linear_init (void ) {} + +#endif + +#ifdef CONFIG_KVM_XICS +static inline int kvmppc_xics_enabled (struct kvm_vcpu *vcpu) +{ +return vcpu->arch.irq_type =KVMPPC_IRQ_XICS ; +} +extern void kvmppc_xics_free_icp (struct kvm_vcpu *vcpu); +extern int kvmppc_xics_create_icp (struct kvm_vcpu *vcpu,unsigned long server); +extern int kvm_vm_ioctl_xics_irq (struct kvm *kvm,struct kvm_irq_level *args); +extern int kvmppc_xics_hcall (struct kvm_vcpu *vcpu,u32 cmd); +#else +static inline int kvmppc_xics_enabled (struct kvm_vcpu *vcpu) + {return 0 ; } +static inline void kvmppc_xics_free_icp (struct kvm_vcpu *vcpu) { } +static inline int kvmppc_xics_create_icp (struct kvm_vcpu *vcpu, +unsigned long server) + {return -EINVAL ; } +static inline int kvm_vm_ioctl_xics_irq (struct kvm *kvm, +struct kvm_irq_level *args) + {return -ENOTTY ; } +static inline int kvmppc_xics_hcall (struct kvm_vcpu *vcpu,u32 cmd) + {return 0 ; }#endif static inline void kvmppc_set_epr (struct kvm_vcpu *vcpu,u32 epr)
arch/powerpc/kvm/Kconfig +8 -0
@@ -160,6 +160,14 @@ config KVM_MPIC Currently, support is limited to certain versions of Freescale's MPIC implementation. +config KVM_XICS + bool "KVM in-kernel XICS emulation" + depends on KVM_BOOK3S_64 + ---help--- + Include support for the XICS (eXternal Interrupt Controller + Specification) interrupt controller architecture used on + IBM POWER (pSeries) servers. + source drivers/vhost/Kconfig endif # VIRTUALIZATION
arch/powerpc/kvm/Makefile +3 -0
@@ -79,6 +79,9 @@ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ book3s_hv_ras.o \ book3s_hv_builtin.o +kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \ + book3s_xics.o + kvm-book3s_64-module-objs := \ ../../../virt/kvm/kvm_main.o \ ../../../virt/kvm/eventfd.o \
arch/powerpc/kvm/book3s.c +1 -1
@@ -104,7 +104,7 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec)return prio; } -static void kvmppc_book3s_dequeue_irqprio (struct kvm_vcpu *vcpu, +void kvmppc_book3s_dequeue_irqprio (struct kvm_vcpu *vcpu,unsigned int vec) {unsigned long old_pending = vcpu->arch.pending_exceptions;
arch/powerpc/kvm/book3s_hv.c +9 -0
@@ -528,6 +528,15 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)/* Send the error out to userspace via KVM_RUN */ return rc; + +case H_XIRR : +case H_CPPR : +case H_EOI : +case H_IPI : +if (kvmppc_xics_enabled (vcpu)) { + ret =kvmppc_xics_hcall (vcpu, req); +break ; + }/* fallthrough */ default :return RESUME_HOST ; }
arch/powerpc/kvm/book3s_pr_papr.c +14 -0
@@ -227,6 +227,13 @@ static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu)return EMULATE_DONE ; } +static int kvmppc_h_pr_xics_hcall (struct kvm_vcpu *vcpu,u32 cmd) +{ +long rc =kvmppc_xics_hcall (vcpu, cmd); +kvmppc_set_gpr (vcpu,3 , rc); +return EMULATE_DONE ; +} +int kvmppc_h_pr (struct kvm_vcpu *vcpu,unsigned long cmd) {switch (cmd) {
@@ -246,6 +253,13 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)clear_bit (KVM_REQ_UNHALT , &vcpu->requests); vcpu->stat.halt_wakeup++;return EMULATE_DONE ; +case H_XIRR : +case H_CPPR : +case H_EOI : +case H_IPI : +if (kvmppc_xics_enabled (vcpu)) +return kvmppc_h_pr_xics_hcall (vcpu, cmd); +break ;case H_RTAS :if (list_empty (&vcpu->kvm->arch.rtas_tokens))return RESUME_HOST ;
arch/powerpc/kvm/book3s_rtas.c +53 -1
66 lines not on this page · raw message
arch/powerpc/kvm/book3s_xics.c new file +945 -0
945 lines not on this page · raw message
arch/powerpc/kvm/book3s_xics.h new file +113 -0
113 lines not on this page · raw message
arch/powerpc/kvm/powerpc.c +3 -0
@@ -472,6 +472,9 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)kvmppc_mpic_disconnect_vcpu (vcpu->arch.mpic, vcpu);break ;#endif +case KVMPPC_IRQ_XICS : +kvmppc_xics_free_icp (vcpu); +break ; }kvmppc_core_vcpu_free (vcpu);
Signature · 1 line
1.7.10.4
PATCH v5 3/8 KVM: PPC: Book3S HV: Speed up wakeups of CPUs on HV KVM
In reply to Paul MackerrasFrom: Benjamin Herrenschmidt <[email protected]>
Currently, we wake up a CPU by sending a host IPI with smp_send_reschedule() to thread 0 of that core, which will take all threads out of the guest, and cause them to re-evaluate their interrupt status on the way back in.
This adds a mechanism to differentiate real host IPIs from IPIs sent by KVM for guest threads to poke each other, in order to target the guest threads precisely when possible and avoid that global switch of the core to host state.
We then use this new facility in the in-kernel XICS code.
--- arch/powerpc/include/asm/kvm_book3s_asm.h | 8 ++- arch/powerpc/include/asm/kvm_ppc.h | 29 ++++++++ arch/powerpc/kernel/asm-offsets.c | 2 + arch/powerpc/kvm/book3s_hv.c | 26 +++++++- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 102 ++++++++++++++++++++++++----- arch/powerpc/kvm/book3s_xics.c | 2 +- arch/powerpc/sysdev/xics/icp-native.c | 8 +++ 7 files changed, 158 insertions(+), 19 deletions(-)
arch/powerpc/include/asm/kvm_book3s_asm.h +7 -1
@@ -20,6 +20,11 @@#ifndef __ASM_KVM_BOOK3S_ASM_H__#define __ASM_KVM_BOOK3S_ASM_H__ +/* XICS ICP register offsets */ +#define XICS_XIRR 4 +#define XICS_MFRR 0xc +#define XICS_IPI 2/* interrupt source # for IPIs */ +#ifdef __ASSEMBLY__#ifdef CONFIG_KVM_BOOK3S_HANDLER
@@ -81,10 +86,11 @@ struct kvmppc_host_state {#ifdef CONFIG_KVM_BOOK3S_64_HV u8 hwthread_req;u8 hwthread_state; - +u8 host_ipi;struct kvm_vcpu *kvm_vcpu;struct kvmppc_vcore *kvm_vcore;unsigned long xics_phys; +u32 saved_xirr;u64 dabr;u64 host_mmcr[3 ];u32 host_pmc[8 ];
arch/powerpc/include/asm/kvm_ppc.h +29 -0
@@ -264,6 +264,21 @@ static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) paca[cpu].kvm_hstate.xics_phys = addr; } +static inline u32 kvmppc_get_xics_latch (void ) +{ +u32 xirr =get_paca ()->kvm_hstate.saved_xirr; + +get_paca ()->kvm_hstate.saved_xirr =0 ; + +return xirr; +} + +static inline void kvmppc_set_host_ipi (int cpu,u8 host_ipi) +{ + paca[cpu].kvm_hstate.host_ipi = host_ipi; +} + +extern void kvmppc_fast_vcpu_kick (struct kvm_vcpu *vcpu);extern void kvm_linear_init (void );#else
@@ -273,6 +288,18 @@ static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)static inline void kvm_linear_init (void ) {} +static inline u32 kvmppc_get_xics_latch (void ) +{ +return 0 ; +} + +static inline void kvmppc_set_host_ipi (int cpu,u8 host_ipi) +{} + +static inline void kvmppc_fast_vcpu_kick (struct kvm_vcpu *vcpu) +{ +kvm_vcpu_kick (vcpu); +}#endif #ifdef CONFIG_KVM_XICS
@@ -365,4 +392,6 @@ static inline ulong kvmppc_get_ea_indexed(struct kvm_vcpu *vcpu, int ra, int rb) return ea; } +extern void xics_wake_cpu (int cpu); +#endif /* __POWERPC_KVM_PPC_H__ */
arch/powerpc/kernel/asm-offsets.c +2 -0
@@ -573,6 +573,8 @@ int main(void)HSTATE_FIELD (HSTATE_KVM_VCPU , kvm_vcpu);HSTATE_FIELD (HSTATE_KVM_VCORE , kvm_vcore);HSTATE_FIELD (HSTATE_XICS_PHYS , xics_phys); +HSTATE_FIELD (HSTATE_SAVED_XIRR , saved_xirr); +HSTATE_FIELD (HSTATE_HOST_IPI , host_ipi);HSTATE_FIELD (HSTATE_MMCR , host_mmcr);HSTATE_FIELD (HSTATE_PMC , host_pmc);HSTATE_FIELD (HSTATE_PURR , host_purr);
arch/powerpc/kvm/book3s_hv.c +25 -1
@@ -66,6 +66,31 @@static void kvmppc_end_cede (struct kvm_vcpu *vcpu);static int kvmppc_hv_setup_htab_rma (struct kvm_vcpu *vcpu); +void kvmppc_fast_vcpu_kick (struct kvm_vcpu *vcpu) +{ +int me; +int cpu = vcpu->cpu; +wait_queue_head_t *wqp; + + wqp =kvm_arch_vcpu_wq (vcpu); +if (waitqueue_active (wqp)) { +wake_up_interruptible (wqp); + ++vcpu->stat.halt_wakeup; + } + + me =get_cpu (); + +/* CPU points to the first thread of the core */ +if (cpu != me && cpu >=0 && cpu < nr_cpu_ids) { +int real_cpu = cpu + vcpu->arch.ptid; +if (paca[real_cpu].kvm_hstate.xics_phys) +xics_wake_cpu (real_cpu); +else if (cpu_online (cpu)) +smp_send_reschedule (cpu); + } +put_cpu (); +} +/* * We use the vcpu_load/put functions to measure stolen time. * Stolen time is counted as time when either the vcpu is able to
@@ -977,7 +1002,6 @@ static void kvmppc_end_cede(struct kvm_vcpu *vcpu) }extern int __kvmppc_vcore_entry (struct kvm_run *kvm_run,struct kvm_vcpu *vcpu); -extern void xics_wake_cpu (int cpu);static void kvmppc_remove_runnable (struct kvmppc_vcore *vc,struct kvm_vcpu *vcpu)
arch/powerpc/kvm/book3s_hv_rmhandlers.S +86 -16
134 lines not on this page · raw message
arch/powerpc/kvm/book3s_xics.c +1 -1
@@ -227,7 +227,7 @@ static inline bool icp_try_update(struct kvmppc_icp *icp,kvmppc_book3s_queue_irqprio (icp->vcpu,BOOK3S_INTERRUPT_EXTERNAL_LEVEL );if (!change_self) -kvm_vcpu_kick (icp->vcpu); +kvmppc_fast_vcpu_kick (icp->vcpu); } bail:return success;
arch/powerpc/sysdev/xics/icp-native.c +8 -0
@@ -51,6 +51,12 @@ static struct icp_ipl __iomem *icp_native_regs[NR_CPUS];static inline unsigned int icp_native_get_xirr (void ) {int cpu =smp_processor_id (); +unsigned int xirr; + +/* Handled an interrupt latched by KVM */ + xirr =kvmppc_get_xics_latch (); +if (xirr) +return xirr;return in_be32 (&icp_native_regs[cpu]->xirr.word); }
@@ -138,6 +144,7 @@ static unsigned int icp_native_get_irq(void)static void icp_native_cause_ipi (int cpu,unsigned long data) { +kvmppc_set_host_ipi (cpu,1 );icp_native_set_qirr (cpu,IPI_PRIORITY ); }
@@ -151,6 +158,7 @@ static irqreturn_t icp_native_ipi_action(int irq, void *dev_id) {int cpu =smp_processor_id (); +kvmppc_set_host_ipi (cpu,0 );icp_native_set_qirr (cpu,0xff );return smp_ipi_demux ();
Signature · 1 line
1.7.10.4
PATCH v5 4/8 KVM: PPC: Book3S HV: Add support for real mode ICP in XICS emulation
In reply to Paul MackerrasFrom: Benjamin Herrenschmidt <[email protected]>
This adds an implementation of the XICS hypercalls in real mode for HV KVM, which allows us to avoid exiting the guest MMU context on all threads for a variety of operations such as fetching a pending interrupt, EOI of messages, IPIs, etc.
--- arch/powerpc/kvm/Makefile | 5 +- arch/powerpc/kvm/book3s_hv_rm_xics.c | 406 +++++++++++++++++++++++++++++++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 18 +- arch/powerpc/kvm/book3s_xics.c | 64 ++++- arch/powerpc/kvm/book3s_xics.h | 16 ++ 5 files changed, 490 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/kvm/book3s_hv_rm_xics.c
arch/powerpc/kvm/Makefile +4 -1
@@ -72,12 +72,15 @@ kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ book3s_hv.o \ book3s_hv_interrupts.o \ book3s_64_mmu_hv.o +kvm-book3s_64-builtin-xics-objs-$(CONFIG_KVM_XICS) := \ + book3s_hv_rm_xics.o kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ book3s_hv_rmhandlers.o \ book3s_hv_rm_mmu.o \ book3s_64_vio_hv.o \ book3s_hv_ras.o \ - book3s_hv_builtin.o + book3s_hv_builtin.o \ + $(kvm-book3s_64-builtin-xics-objs-y) kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \ book3s_xics.o
arch/powerpc/kvm/book3s_hv_rm_xics.c new file +406 -0
406 lines not on this page · raw message
arch/powerpc/kvm/book3s_hv_rmhandlers.S +13 -5
@@ -1420,11 +1420,19 @@ hcall_real_table: .long 0 /* 0x58 */ .long 0 /* 0x5c */ .long 0 /* 0x60 */ - .long 0 /* 0x64 */ - .long 0 /* 0x68 */ - .long 0 /* 0x6c */ - .long 0 /* 0x70 */ - .long 0 /* 0x74 */ +#ifdef CONFIG_KVM_XICS + .long .kvmppc_rm_h_eoi - hcall_real_table + .long .kvmppc_rm_h_cppr - hcall_real_table + .long .kvmppc_rm_h_ipi - hcall_real_table + .long 0 /* 0x70 - H_IPOLL */ + .long .kvmppc_rm_h_xirr - hcall_real_table +#else + .long 0 /* 0x64 - H_EOI */ + .long 0 /* 0x68 - H_CPPR */ + .long 0 /* 0x6c - H_IPI */ + .long 0 /* 0x70 - H_IPOLL */ + .long 0 /* 0x74 - H_XIRR */ +#endif .long 0 /* 0x78 */ .long 0 /* 0x7c */ .long 0 /* 0x80 */
arch/powerpc/kvm/book3s_xics.c +3 -0
@@ -30,6 +30,9 @@ #define XICS_DBG(fmt...) trace_printk(fmt)#endif +#define ENABLE_REALMODE true +#define DEBUG_REALMODE false +/* * LOCKING * ===@@ -220,8 +223,10 @@ static inline bool icp_try_update(struct kvmppc_icp *icp,
* in Accept (H_XIRR) and Up_Cppr (H_XPPR).
*
* We also do not try to figure out whether the EE state has changed,
- * we unconditionally set it if the new state calls for it for the
- * same reason.
+ * we unconditionally set it if the new state calls for it. The reason
+ * for that is that we opportunistically remove the pending interrupt
+ * flag when raising CPPR, so we need to set it back here if an
+ * interrupt is still pending.
*/
if (new.out_ee) {
kvmppc_book3s_queue_irqprio(icp->vcpu,
@@ -483,7 +488,7 @@ static void icp_down_cppr(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
icp_check_resend(xics, icp);
}
-static noinline unsigned long h_xirr(struct kvm_vcpu *vcpu) +static noinline unsigned long kvmppc_h_xirr(struct kvm_vcpu *vcpu)
{
union kvmppc_icp_state old_state, new_state;
struct kvmppc_icp *icp = vcpu->arch.icp;
@@ -517,8 +522,8 @@ static noinline unsigned long h_xirr(struct kvm_vcpu *vcpu)
return xirr;
}
-static noinline int h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
- unsigned long mfrr)
+static noinline int kvmppc_h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
+ unsigned long mfrr)
{
union kvmppc_icp_state old_state, new_state;
struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
@@ -586,7 +591,7 @@ static noinline int h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
return H_SUCCESS;
}
-static noinline void h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr) +static noinline void kvmppc_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr)
{
union kvmppc_icp_state old_state, new_state;
struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
@@ -643,7 +648,7 @@ static noinline void h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr)
icp_deliver_irq(xics, icp, reject);
}
-static noinline int h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) +static noinline int kvmppc_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
{
struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
struct kvmppc_icp *icp = vcpu->arch.icp;
@@ -693,29 +698,54 @@ static noinline int h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
return H_SUCCESS;
}
+static noinline int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall) +{
+ struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
+ struct kvmppc_icp *icp = vcpu->arch.icp;
+
+ XICS_DBG("XICS_RM: H_%x completing, act: %x state: %lx tgt: %p\n",
+ hcall, icp->rm_action, icp->rm_dbgstate.raw, icp->rm_dbgtgt);
+
+ if (icp->rm_action & XICS_RM_KICK_VCPU)
+ kvmppc_fast_vcpu_kick(icp->rm_kick_target);
+ if (icp->rm_action & XICS_RM_CHECK_RESEND)
+ icp_check_resend(xics, icp);
+ if (icp->rm_action & XICS_RM_REJECT)
+ icp_deliver_irq(xics, icp, icp->rm_reject);
+
+ icp->rm_action = 0;
+
+ return H_SUCCESS;
+}
+
int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 req)
{
+ struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
unsigned long res;
int rc = H_SUCCESS;
/* Check if we have an ICP */
- if (!vcpu->arch.icp || !vcpu->kvm->arch.xics)
+ if (!xics || !vcpu->arch.icp)
return H_HARDWARE;
+ /* Check for real mode returning too hard */
+ if (xics->real_mode)
+ return kvmppc_xics_rm_complete(vcpu, req);
+
switch (req) {
case H_XIRR:
- res = h_xirr(vcpu);
+ res = kvmppc_h_xirr(vcpu);
kvmppc_set_gpr(vcpu, 4, res);
break;
case H_CPPR:
- h_cppr(vcpu, kvmppc_get_gpr(vcpu, 4));
+ kvmppc_h_cppr(vcpu, kvmppc_get_gpr(vcpu, 4));
break;
case H_EOI:
- rc = h_eoi(vcpu, kvmppc_get_gpr(vcpu, 4));
+ rc = kvmppc_h_eoi(vcpu, kvmppc_get_gpr(vcpu, 4));
break;
case H_IPI:
- rc = h_ipi(vcpu, kvmppc_get_gpr(vcpu, 4),
- kvmppc_get_gpr(vcpu, 5));
+ rc = kvmppc_h_ipi(vcpu, kvmppc_get_gpr(vcpu, 4),
+ kvmppc_get_gpr(vcpu, 5));
break;
}
@@ -933,6 +963,14 @@ int kvm_xics_create(struct kvm *kvm, u32 type)
xics_debugfs_init(xics);
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+ if (cpu_has_feature(CPU_FTR_ARCH_206)) {
+ /* Enable real mode support */
+ xics->real_mode = ENABLE_REALMODE;
+ xics->real_mode_dbg = DEBUG_REALMODE;
+ }
+#endif /* CONFIG_KVM_BOOK3S_64_HV */
+
return 0;
}
arch/powerpc/kvm/book3s_xics.h +16 -0
@@ -64,6 +64,20 @@ struct kvmppc_icp {unsigned long server_num;union kvmppc_icp_state state;unsigned long resend_map[ICP_RESEND_MAP_SIZE ]; + +/* Real mode might find something too hard, here's the action +* it might request from virtual mode +*/ +#define XICS_RM_KICK_VCPU 0x1 +#define XICS_RM_CHECK_RESEND 0x2 +#define XICS_RM_REJECT 0x4 +u32 rm_action; +struct kvm_vcpu *rm_kick_target; +u32 rm_reject; + +/* Debug stuff for real mode */ +union kvmppc_icp_state rm_dbgstate; +struct kvm_vcpu *rm_dbgtgt; };struct kvmppc_ics {
@@ -76,6 +90,8 @@ struct kvmppc_xics {struct kvm *kvm;struct dentry *dentry;u32 max_icsid; +bool real_mode; +bool real_mode_dbg;struct kvmppc_ics *ics[KVMPPC_XICS_MAX_ICS_ID +1 ]; };
Signature · 1 line
1.7.10.4
PATCH v5 5/8 KVM: PPC: Book3S HV: Improve real-mode handling of external interrupts
In reply to Paul MackerrasThis streamlines our handling of external interrupts that come in while we're in the guest. First, when waking up a hardware thread that was napping, we split off the "napping due to H_CEDE" case earlier, and use the code that handles an external interrupt (0x500) in the guest to handle that too. Secondly, the code that handles those external interrupts now checks if any other thread is exiting to the host before bouncing an external interrupt to the guest, and also checks that there is actually an external interrupt pending for the guest before setting the LPCR MER bit (mediated external request).
This also makes sure that we clear the "ceded" flag when we handle a wakeup from cede in real mode, and fixes a potential infinite loop in kvmppc_run_vcpu() which can occur if we ever end up with the ceded flag set but MSR[EE] off.
--- arch/powerpc/include/asm/reg.h | 1 + arch/powerpc/kvm/book3s_hv.c | 5 +- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 138 +++++++++++++++++-------------- 3 files changed, 80 insertions(+), 64 deletions(-)
arch/powerpc/include/asm/reg.h +1 -0
@@ -290,6 +290,7 @@#define LPCR_PECE1 0x00002000/* decrementer can cause exit */ #define LPCR_PECE2 0x00001000/* machine check etc can cause exit */ #define LPCR_MER 0x00000800/* Mediated External Exception */ +#define LPCR_MER_SH 11#define LPCR_LPES 0x0000000c#define LPCR_LPES0 0x00000008/* LPAR Env selector 0 */ #define LPCR_LPES1 0x00000004/* LPAR Env selector 1 */
arch/powerpc/kvm/book3s_hv.c +4 -1
@@ -1376,9 +1376,12 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)break ; vc->runner = vcpu; n_ceded =0 ; -list_for_each_entry (v, &vc->runnable_threads, arch.run_list) +list_for_each_entry (v, &vc->runnable_threads, arch.run_list) {if (!v->arch.pending_exceptions) n_ceded += v->arch.ceded; +else + v->arch.ceded =0 ; + }if (n_ceded = vc->n_runnable)kvmppc_vcore_blocked (vc);else
arch/powerpc/kvm/book3s_hv_rmhandlers.S +75 -63
231 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v5 6/8 KVM: PPC: Book3S: Add support for ibm,int-on/off RTAS calls
In reply to Paul MackerrasThis adds support for the ibm,int-on and ibm,int-off RTAS calls to the in-kernel XICS emulation and corrects the handling of the saved priority by the ibm,set-xive RTAS call. With this, ibm,int-off sets the specified interrupt's priority in its saved_priority field and sets the priority to 0xff (the least favoured value). ibm,int-on restores the saved_priority to the priority field, and ibm,set-xive sets both the priority and the saved_priority to the specified priority value.
--- arch/powerpc/include/asm/kvm_ppc.h | 2 + arch/powerpc/kvm/book3s_rtas.c | 40 +++++++++++++++++ arch/powerpc/kvm/book3s_xics.c | 84 ++++++++++++++++++++++++++++++------ arch/powerpc/kvm/book3s_xics.h | 2 +- 4 files changed, 113 insertions(+), 15 deletions(-)
arch/powerpc/include/asm/kvm_ppc.h +2 -0
@@ -174,6 +174,8 @@ extern int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority);extern int kvmppc_xics_get_xive (struct kvm *kvm,u32 irq,u32 *server,u32 *priority); +extern int kvmppc_xics_int_on (struct kvm *kvm,u32 irq); +extern int kvmppc_xics_int_off (struct kvm *kvm,u32 irq);/* * Cuts out inst bits with ordering according to spec.
arch/powerpc/kvm/book3s_rtas.c +40 -0
@@ -63,6 +63,44 @@ static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args) out: args->rets[0 ] = rc; } + +static void kvm_rtas_int_off (struct kvm_vcpu *vcpu,struct rtas_args *args) +{ +u32 irq; +int rc; + +if (args->nargs !=1 || args->nret !=1 ) { + rc =-3 ; + goto out; + } + + irq = args->args[0 ]; + + rc =kvmppc_xics_int_off (vcpu->kvm, irq); +if (rc) + rc =-3 ; +out: + args->rets[0 ] = rc; +} + +static void kvm_rtas_int_on (struct kvm_vcpu *vcpu,struct rtas_args *args) +{ +u32 irq; +int rc; + +if (args->nargs !=1 || args->nret !=1 ) { + rc =-3 ; + goto out; + } + + irq = args->args[0 ]; + + rc =kvmppc_xics_int_on (vcpu->kvm, irq); +if (rc) + rc =-3 ; +out: + args->rets[0 ] = rc; +}#endif /* CONFIG_KVM_XICS */ struct rtas_handler {
@@ -74,6 +112,8 @@ static struct rtas_handler rtas_handlers[] = {#ifdef CONFIG_KVM_XICS { .name = "ibm,set-xive", .handler = kvm_rtas_set_xive }, { .name = "ibm,get-xive", .handler = kvm_rtas_get_xive }, + { .name = "ibm,int-off", .handler = kvm_rtas_int_off }, + { .name = "ibm,int-on", .handler = kvm_rtas_int_on },#endif };
arch/powerpc/kvm/book3s_xics.c +70 -14
112 lines not on this page · raw message
arch/powerpc/kvm/book3s_xics.h +1 -1
@@ -36,7 +36,7 @@ struct ics_irq_state {u32 number;u32 server;u8 priority; -u8 saved_priority;/* currently unused */ +u8 saved_priority;u8 resend;u8 masked_pending;u8 asserted;/* Only for LSI */
Signature · 1 line
1.7.10.4
PATCH v5 7/8 KVM: PPC: Book3S: Facilities to save/restore XICS presentation ctrler state
In reply to Paul MackerrasThis adds the ability for userspace to save and restore the state of the XICS interrupt presentation controllers (ICPs) via the KVM_GET/SET_ONE_REG interface. Since there is one ICP per vcpu, we simply define a new 64-bit register in the ONE_REG space for the ICP state. The state includes the CPU priority setting, the pending IPI priority, and the priority and source number of any pending external interrupt.
--- Documentation/virtual/kvm/api.txt | 1 + arch/powerpc/include/asm/kvm_ppc.h | 2 + arch/powerpc/include/uapi/asm/kvm.h | 12 +++++ arch/powerpc/kvm/book3s.c | 19 ++++++++ arch/powerpc/kvm/book3s_xics.c | 90 +++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+)
Documentation/virtual/kvm/api.txt +1 -0
@@ -1792,6 +1792,7 @@ registers, find a list below: PPC | KVM_REG_PPC_TSR | 32 PPC | KVM_REG_PPC_OR_TSR | 32 PPC | KVM_REG_PPC_CLEAR_TSR | 32 + PPC | KVM_REG_PPC_ICP_STATE | 64 ARM registers are mapped using the lower 32 bits. The upper 16 of that is the register group type, or coprocessor number:
arch/powerpc/include/asm/kvm_ppc.h +2 -0
@@ -313,6 +313,8 @@ extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);extern int kvmppc_xics_create_icp (struct kvm_vcpu *vcpu,unsigned long server);extern int kvm_vm_ioctl_xics_irq (struct kvm *kvm,struct kvm_irq_level *args);extern int kvmppc_xics_hcall (struct kvm_vcpu *vcpu,u32 cmd); +extern u64 kvmppc_xics_get_icp (struct kvm_vcpu *vcpu); +extern int kvmppc_xics_set_icp (struct kvm_vcpu *vcpu,u64 icpval);#else static inline int kvmppc_xics_enabled (struct kvm_vcpu *vcpu) {return 0 ; }
arch/powerpc/include/uapi/asm/kvm.h +12 -0
@@ -432,6 +432,18 @@ struct kvm_get_htab_header {/* Debugging: Special instruction for software breakpoint */ #define KVM_REG_PPC_DEBUG_INST (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8b) +/* Per-vcpu XICS interrupt controller state */ +#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c) + +#define KVM_REG_PPC_ICP_CPPR_SHIFT 56/* current proc priority */ +#define KVM_REG_PPC_ICP_CPPR_MASK 0xff +#define KVM_REG_PPC_ICP_XISR_SHIFT 32/* interrupt status field */ +#define KVM_REG_PPC_ICP_XISR_MASK 0xffffff +#define KVM_REG_PPC_ICP_MFRR_SHIFT 24/* pending IPI priority */ +#define KVM_REG_PPC_ICP_MFRR_MASK 0xff +#define KVM_REG_PPC_ICP_PPRI_SHIFT 16/* pending irq priority */ +#define KVM_REG_PPC_ICP_PPRI_MASK 0xff +/* Device control API: PPC-specific devices */ #define KVM_DEV_MPIC_GRP_MISC 1#define KVM_DEV_MPIC_BASE_ADDR 0/* 64-bit */
arch/powerpc/kvm/book3s.c +19 -0
@@ -535,6 +535,15 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) &opcode, sizeof(u32));break ; } +#ifdef CONFIG_KVM_XICS +case KVM_REG_PPC_ICP_STATE : +if (!vcpu->arch.icp) { + r = -ENXIO ; +break ; + } + val =get_reg_val (reg->id,kvmppc_xics_get_icp (vcpu)); +break ; +#endif /* CONFIG_KVM_XICS */ default : r = -EINVAL ;break ;
@@ -597,6 +606,16 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) vcpu->arch.vscr.u[3 ] =set_reg_val (reg->id, val);break ;#endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_KVM_XICS +case KVM_REG_PPC_ICP_STATE : +if (!vcpu->arch.icp) { + r = -ENXIO ; +break ; + } + r =kvmppc_xics_set_icp (vcpu, +set_reg_val (reg->id, val)); +break ; +#endif /* CONFIG_KVM_XICS */ default : r = -EINVAL ;break ;
arch/powerpc/kvm/book3s_xics.c +90 -0
96 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v5 8/8 KVM: PPC: Book 3S: Add API for in-kernel XICS emulation
In reply to Paul MackerrasThis adds the API for userspace to instantiate an XICS device in a VM and connect VCPUs to it. The API consists of a new device type for the KVM_CREATE_DEVICE ioctl, a new capability KVM_CAP_IRQ_XICS, which functions similarly to KVM_CAP_IRQ_MPIC, and the KVM_IRQ_LINE ioctl, which is used to assert and deassert interrupt inputs of the XICS.
The XICS device has one attribute group, KVM_DEV_XICS_GRP_SOURCES. Each attribute within this group corresponds to the state of one interrupt source. The attribute number is the same as the interrupt source number.
--- Documentation/virtual/kvm/api.txt | 8 ++ Documentation/virtual/kvm/devices/xics.txt | 66 +++++++++ arch/powerpc/include/asm/kvm_ppc.h | 2 + arch/powerpc/include/uapi/asm/kvm.h | 12 ++ arch/powerpc/kvm/book3s_xics.c | 211 ++++++++++++++++++++++++++-- arch/powerpc/kvm/book3s_xics.h | 6 + arch/powerpc/kvm/powerpc.c | 35 +++++ include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 2 + virt/kvm/kvm_main.c | 5 + 10 files changed, 339 insertions(+), 9 deletions(-) create mode 100644 Documentation/virtual/kvm/devices/xics.txt
Documentation/virtual/kvm/api.txt +8 -0
@@ -2756,3 +2756,11 @@ 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. + +6.7 KVM_CAP_IRQ_XICS + +Architectures: ppc +Parameters: args[0] is the XICS device fd + args[1] is the XICS CPU number (server ID) for this vcpu + +This capability connects the vcpu to an in-kernel XICS device.
Documentation/virtual/kvm/devices/xics.txt new file +66 -0
66 lines not on this page · raw message
arch/powerpc/include/asm/kvm_ppc.h +2 -0
@@ -315,6 +315,8 @@ extern int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args);extern int kvmppc_xics_hcall (struct kvm_vcpu *vcpu,u32 cmd);extern u64 kvmppc_xics_get_icp (struct kvm_vcpu *vcpu);extern int kvmppc_xics_set_icp (struct kvm_vcpu *vcpu,u64 icpval); +extern int kvmppc_xics_connect_vcpu (struct kvm_device *dev, +struct kvm_vcpu *vcpu,u32 cpu);#else static inline int kvmppc_xics_enabled (struct kvm_vcpu *vcpu) {return 0 ; }
arch/powerpc/include/uapi/asm/kvm.h +12 -0
@@ -451,4 +451,16 @@ struct kvm_get_htab_header {#define KVM_DEV_MPIC_GRP_REGISTER 2/* 32-bit */ #define KVM_DEV_MPIC_GRP_IRQ_ACTIVE 3/* 32-bit */ +/* PPC64 eXternal Interrupt Controller Specification */ +#define KVM_DEV_XICS_GRP_SOURCES 1/* 64-bit source attributes */ + +/* Layout of 64-bit source attribute values */ +#define KVM_XICS_DESTINATION_SHIFT 0 +#define KVM_XICS_DESTINATION_MASK 0xffffffffULL +#define KVM_XICS_PRIORITY_SHIFT 32 +#define KVM_XICS_PRIORITY_MASK 0xff +#define KVM_XICS_LEVEL_SENSITIVE (1ULL << 40) +#define KVM_XICS_MASKED (1ULL << 41) +#define KVM_XICS_PENDING (1ULL << 42) +#endif /* __LINUX_KVM_POWERPC_H */
arch/powerpc/kvm/book3s_xics.c +201 -9
285 lines not on this page · raw message
arch/powerpc/kvm/book3s_xics.h +6 -0
@@ -10,6 +10,9 @@#ifndef _KVM_PPC_BOOK3S_XICS_H#define _KVM_PPC_BOOK3S_XICS_H +#include <linux/types.h> +#include <linux/rcupdate.h> +/* * We use a two-level tree to store interrupt source information. * There are up to 1024 ICS nodes, each of which can represent
@@ -83,12 +86,15 @@ struct kvmppc_icp {struct kvmppc_ics {struct mutex lock;u16 icsid; +struct rcu_head rhead;struct ics_irq_state irq_state[KVMPPC_XICS_IRQ_PER_ICS ]; };struct kvmppc_xics {struct kvm *kvm; +struct kvm_device *dev;struct dentry *dentry; +struct rcu_head rhead;u32 max_icsid;bool real_mode;bool real_mode_dbg;
arch/powerpc/kvm/powerpc.c +35 -0
@@ -341,6 +341,9 @@ int kvm_dev_ioctl_check_extension(long ext)case KVM_CAP_SPAPR_TCE :case KVM_CAP_PPC_ALLOC_HTAB :case KVM_CAP_PPC_RTAS : +#ifdef CONFIG_KVM_XICS +case KVM_CAP_IRQ_XICS : +#endif r =1 ;break ;#endif /* CONFIG_PPC_BOOK3S_64 */
@@ -829,6 +832,25 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, break; }#endif +#ifdef CONFIG_KVM_XICS +case KVM_CAP_IRQ_XICS : { +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_xics_connect_vcpu (dev, vcpu, cap->args[1 ]); + +fput (filp); +break ; + } +#endif /* CONFIG_KVM_XICS */ default : r = -EINVAL ;break ;
@@ -1037,6 +1059,19 @@ long kvm_arch_vm_ioctl(struct file *filp, break; }#endif /* CONFIG_PPC_BOOK3S_64 */ + +case KVM_IRQ_LINE : { +struct kvm *kvm = filp->private_data; +struct kvm_irq_level args; + + r = -EFAULT ; +if (copy_from_user (&args, argp,sizeof (args))) +break ; + +/* Call all the interrupt controllers */ + r =kvm_vm_ioctl_xics_irq (kvm, &args); +break ; + }default : r = -ENOTTY ; }
include/linux/kvm_host.h +1 -0
@@ -1102,6 +1102,7 @@ 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; +extern struct kvm_device_ops kvm_xics_ops;#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
include/uapi/linux/kvm.h +2 -0
@@ -671,6 +671,7 @@ struct kvm_ppc_smmu_info {#define KVM_CAP_DEVICE_CTRL 89#define KVM_CAP_IRQ_MPIC 90#define KVM_CAP_PPC_RTAS 91 +#define KVM_CAP_IRQ_XICS 92#ifdef KVM_CAP_IRQ_ROUTING
@@ -933,6 +934,7 @@ struct kvm_device_attr {#define KVM_DEV_TYPE_FSL_MPIC_20 1#define KVM_DEV_TYPE_FSL_MPIC_42 2 +#define KVM_DEV_TYPE_XICS 3/* ioctl for vm fd */ #define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)
virt/kvm/kvm_main.c +5 -0
@@ -2244,6 +2244,11 @@ static int kvm_ioctl_create_device(struct kvm *kvm, ops = &kvm_mpic_ops;break ;#endif +#ifdef CONFIG_KVM_XICS +case KVM_DEV_TYPE_XICS : + ops = &kvm_xics_ops; +break ; +#endif default :return -ENODEV ; }
Signature · 1 line
1.7.10.4
Quoted 22 lines · Paul Mackerras
This is a repost of my patch series implementing in-kernel emulation of the XICS interrupt controller architecture defined in PAPR (Power Architecture Platform Requirements, the document that defines IBM's pSeries platform architecture). This version of the patch series uses the latest device API as posted by Scott Wood, that is, i.e., the version where the core device code provides the file descriptor and ioctl handler. I have structured the series so that the API is added by the last two patches, so as to be able to accommodate any future revisions to the device API with minimal changes.
The series is based on Alex Graf's kvm-ppc-queue branch with Scott Wood's recent patch series applied on top, together with the patch below to allow it to build with
CONFIG_KVM_MPIC=n.The API defined here uses
KVM_CREATE_DEVICEto create the XICS, KVM_DEVICE_SET_ATTR/KVM_DEVICE_GET_ATTR to manipulate the interrupt sources (for initialization and migration), a newKVM_CAP_IRQ_XICScapability to connect vcpus to the XICS, a new identifierKVM_REG_PPC_ICP_STATEfor the one-reg interface to get and set per-vcpu state, and the existingKVM_IRQ_LINEioctl to assert and deassert interrupt sources.
Quoted 5 lines
This version also cleans up some checkpatch.pl errors and clarifies the lifetime rules for the various objects. There are two checkpatch warnings for long lines, but they are long because they have long strings in them, and if I break the strings over two lines then checkpatch warns about that.
Very nice patch set. I've applie 1-7 of it to kvm-ppc-queue. So they will hopefully make it to 3.10.
Please check for 8/8 whether
a) You want to have a released kernel version without irq routing (irqfd) support. It makes user space's life harder, because you need to maintain backwards compatibility.
b) Please rebase on top of the current state of things, especially the changed lifecycle assumptions. Devices should now just live until the vm gets destroyed. It gives me way less headaches.
Alex
Quoted 39 lines · Alexander Graf
Quoted 4 lines · Paul Mackerras
This is a repost of my patch series implementing in-kernel emulation of the XICS interrupt controller architecture defined in PAPR (Power Architecture Platform Requirements, the document that defines IBM's pSeries platform architecture). This version of the patch series
uses
Quoted 3 lines
the latest device API as posted by Scott Wood, that is, i.e., the version where the core device code provides the file descriptor and ioctl handler. I have structured the series so that the API is
added
Quoted 15 lines
by the last two patches, so as to be able to accommodate any future revisions to the device API with minimal changes.
The series is based on Alex Graf's kvm-ppc-queue branch with Scott Wood's recent patch series applied on top, together with the patch below to allow it to build with
CONFIG_KVM_MPIC=n.The API defined here uses
KVM_CREATE_DEVICEto create the XICS, KVM_DEVICE_SET_ATTR/KVM_DEVICE_GET_ATTR to manipulate the interrupt sources (for initialization and migration), a newKVM_CAP_IRQ_XICScapability to connect vcpus to the XICS, a new identifierKVM_REG_PPC_ICP_STATEfor the one-reg interface to get and set per-vcpu state, and the existingKVM_IRQ_LINEioctl to assert and deassert interrupt sources.Quoted 2 lines
This version also cleans up some checkpatch.pl errors and clarifies the lifetime rules for the various objects. There are two
checkpatch
Quoted 3 lines
warnings for long lines, but they are long because they have long strings in them, and if I break the strings over two lines then checkpatch warns about that.
Very nice patch set. I've applie 1-7 of it to kvm-ppc-queue. So they will hopefully make it to 3.10.
Please check for 8/8 whether
Quoted 7 lines
a) You want to have a released kernel version without irq routing
(irqfd) support. It makes user space's life harder, because you need to maintain backwards compatibility.b) Please rebase on top of the current state of things, especially
the changed lifecycle assumptions. Devices should now just live until the vm gets destroyed. It gives me way less headaches.
Also please note that we no longer hold kvm->lock during device creation, so your EEXIST check looks racy.
-Scott
Quoted 2 lines · Scott Wood
Also please note that we no longer hold
kvm->lockduring device creation, so your EEXIST check looks racy.
Huh? Patch 2/8 adds this code:
+ mutex_lock(&kvm->lock);
+ if (kvm->arch.xics)
+ ret = -EEXIST;
+ else
+ kvm->arch.xics = xics;
+ mutex_unlock(&kvm->lock);
How is that racy?
Paul.
Quoted 14 lines · Paul Mackerras
Quoted 2 lines · Scott Wood
Also please note that we no longer hold
kvm->lockduring device creation, so your EEXIST check looks racy.Huh? Patch 2/8 adds this code:
(quoted diff) +6
-0+ mutex_lock(&kvm->lock); + if (kvm->arch.xics) + ret = -EEXIST; + else + kvm->arch.xics = xics; + mutex_unlock(&kvm->lock);
Quoted 1 line
How is that racy?
Sorry, it's not -- I must have been looking at the previous version of the patchset by mistake. :-(
-Scott
Quoted 5 lines · Alexander Graf
Very nice patch set. I've applie 1-7 of it to kvm-ppc-queue. So they will hopefully make it to 3.10.
Please check for 8/8 whether
a) You want to have a released kernel version without irq routing (irqfd) support. It makes user space's life harder, because you need to maintain backwards compatibility.
If we do a version without irq routing and later add it, old userspace should still work, since KVM_IRQ_LINE still works, right? New userspace on an old kernel can test the KVM_CAP_IRQ_ROUTING capability to see if it can use irqfd. So on the whole, I would like to get it in, provided of course I can get it tested and sent out before the window closes.
Quoted 1 line
b) Please rebase on top of the current state of things, especially the changed lifecycle assumptions. Devices should now just live until the vm gets destroyed. It gives me way less headaches.
OK, I've done that, but I need to grab David Gibson to get a qemu that knows about the new API so I can test it.
Regards,
Paul.
Quoted 11 lines · Paul Mackerras
Quoted 5 lines · Alexander Graf
Very nice patch set. I've applie 1-7 of it to kvm-ppc-queue. So they will hopefully make it to 3.10.
Please check for 8/8 whether
a) You want to have a released kernel version without irq routing (irqfd) support. It makes user space's life harder, because you need to maintain backwards compatibility.
If we do a version without irq routing and later add it, old userspace should still work, since
KVM_IRQ_LINEstill works, right? New userspace on an old kernel can test theKVM_CAP_IRQ_ROUTINGcapability to see if it can use irqfd. So on the whole, I would like to get it
User space would have to know about 2 different ways of setting interrupts, one through IRQ_LINE and one through whatever XICS device specific ioctl you create :).
This really depends on how quickly you think you could have irqfd support working. If you think it's ready for 3.11, I'd be inclined to say that it's easier for everyone if we don't have to provide any backwards compatibility at all. Then QEMU doesn't need to learn about the irq line setting path that is only ever available on 3.10.
Quoted 7 lines
in, provided of course I can get it tested and sent out before the window closes.
Quoted 1 line
b) Please rebase on top of the current state of things, especially the changed lifecycle assumptions. Devices should now just live until the vm gets destroyed. It gives me way less headaches.
OK, I've done that, but I need to grab David Gibson to get a qemu that knows about the new API so I can test it.
Yeah, please sync with him on this whole thing too. Someone will have to write the compat code ;).
Alex
Quoted 8 lines · Alexander Graf
Quoted 5 lines · Paul Mackerras
Quoted 4 lines · Alexander Graf
Very nice patch set. I've applie 1-7 of it to kvm-ppc-queue. So they will hopefully make it to 3.10.
Please check for 8/8 whether
Quoted 8 lines
Quoted 6 lines
Quoted 1 line
a) You want to have a released kernel version without irq routing (irqfd) support. It makes user space's life harder, because you need to maintain backwards compatibility.
If we do a version without irq routing and later add it, old userspace should still work, since
KVM_IRQ_LINEstill works, right? New userspace on an old kernel can test theKVM_CAP_IRQ_ROUTINGcapability to see if it can use irqfd. So on the whole, I would like to get itUser space would have to know about 2 different ways of setting interrupts, one through
IRQ_LINEand one through whatever XICS device specific ioctl you create :).
Ummm, no, userspace uses KVM_IRQ_LINE either way. Since I don't define CONFIG_HAVE_KVM_IRQCHIP or CONFIG_HAVE_KVM_IRQ_ROUTING, we don't compile in virt/kvm/irqchip.c and thus we don't get a definition of kvm_set_irq() (note that in your tree as it stands, it's only by grace of gcc's optimizations that we don't get a link error when CONFIG_KVM_MPIC=n, since we have the code in arch/powerpc/kvm/powerpc.c that calls kvm_set_irq() unconditionally).
So I added a definition of kvm_set_irq() to book3s_xics.c in the patch I posted recently, meaning that userspace can in fact use KVM_IRQ_LINE even though I don't yet support irqfd or irq routing.
Quoted 4 lines
Quoted 2 lines
OK, I've done that, but I need to grab David Gibson to get a qemu that knows about the new API so I can test it.
Yeah, please sync with him on this whole thing too. Someone will have to write the compat code ;).
I have a version of qemu from him that uses KVM_CREATE_DEVICE to create the XICS and KVM_IRQ_LINE to control the interrupt inputs, and it all works just fine.
Regards,
Paul.
Quoted 26 lines · Paul Mackerras
Quoted 8 lines · Alexander Graf
Quoted 5 lines · Paul Mackerras
Quoted 4 lines · Alexander Graf
Very nice patch set. I've applie 1-7 of it to kvm-ppc-queue. So they will hopefully make it to 3.10.
Please check for 8/8 whether
Quoted 8 lines
Quoted 6 lines
Quoted 1 line
a) You want to have a released kernel version without irq routing (irqfd) support. It makes user space's life harder, because you need to maintain backwards compatibility.
If we do a version without irq routing and later add it, old userspace should still work, since
KVM_IRQ_LINEstill works, right? New userspace on an old kernel can test theKVM_CAP_IRQ_ROUTINGcapability to see if it can use irqfd. So on the whole, I would like to get itUser space would have to know about 2 different ways of setting interrupts, one through
IRQ_LINEand one through whatever XICS device specific ioctl you create :).Ummm, no, userspace uses
KVM_IRQ_LINEeither way. Since I don't defineCONFIG_HAVE_KVM_IRQCHIPorCONFIG_HAVE_KVM_IRQ_ROUTING, we don't compile invirt/kvm/irqchip.cand thus we don't get a definition ofkvm_set_irq()(note that in your tree as it stands, it's only by grace of gcc's optimizations that we don't get a link error whenCONFIG_KVM_MPIC=n, since we have the code inarch/powerpc/kvm/powerpc.cthat callskvm_set_irq()unconditionally).
Quoted 3 lines
So I added a definition of
kvm_set_irq()tobook3s_xics.cin the patch I posted recently, meaning that userspace can in fact useKVM_IRQ_LINEeven though I don't yet support irqfd or irq routing.
That means you'll have to make your default map compatible with what you expose there now.
Quoted 9 lines
Quoted 5 lines
Quoted 3 lines
OK, I've done that, but I need to grab David Gibson to get a qemu that knows about the new API so I can test it.
Yeah, please sync with him on this whole thing too. Someone will have to write the compat code ;).
I have a version of qemu from him that uses
KVM_CREATE_DEVICEto create the XICS andKVM_IRQ_LINEto control the interrupt inputs, and it all works just fine.
Please get him to ack the approach of getting 2 interfaces later. Of course what you wrote now works. I'm not concerned about that. I'm concerned about tomorrow :).
Alex