Commit 1c810636 authored by Alexander Graf's avatar Alexander Graf

KVM: PPC: BookE: Implement EPR exit

The External Proxy Facility in FSL BookE chips allows the interrupt
controller to automatically acknowledge an interrupt as soon as a
core gets its pending external interrupt delivered.

Today, user space implements the interrupt controller, so we need to
check on it during such a cycle.

This patch implements logic for user space to enable EPR exiting,
disable EPR exiting and EPR exiting itself, so that user space can
acknowledge an interrupt when an external interrupt has successfully
been delivered into the guest vcpu.
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent 37ecb257
...@@ -2246,8 +2246,8 @@ executed a memory-mapped I/O instruction which could not be satisfied ...@@ -2246,8 +2246,8 @@ executed a memory-mapped I/O instruction which could not be satisfied
by kvm. The 'data' member contains the written data if 'is_write' is by kvm. The 'data' member contains the written data if 'is_write' is
true, and should be filled by application code otherwise. true, and should be filled by application code otherwise.
NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_DCR NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_DCR,
and KVM_EXIT_PAPR the corresponding KVM_EXIT_PAPR and KVM_EXIT_EPR the corresponding
operations are complete (and guest state is consistent) only after userspace operations are complete (and guest state is consistent) only after userspace
has re-entered the kernel with KVM_RUN. The kernel side will first finish has re-entered the kernel with KVM_RUN. The kernel side will first finish
incomplete operations and then check for pending signals. Userspace incomplete operations and then check for pending signals. Userspace
...@@ -2366,6 +2366,25 @@ interrupt for the target subchannel has been dequeued and subchannel_id, ...@@ -2366,6 +2366,25 @@ interrupt for the target subchannel has been dequeued and subchannel_id,
subchannel_nr, io_int_parm and io_int_word contain the parameters for that subchannel_nr, io_int_parm and io_int_word contain the parameters for that
interrupt. ipb is needed for instruction parameter decoding. interrupt. ipb is needed for instruction parameter decoding.
/* KVM_EXIT_EPR */
struct {
__u32 epr;
} epr;
On FSL BookE PowerPC chips, the interrupt controller has a fast patch
interrupt acknowledge path to the core. When the core successfully
delivers an interrupt, it automatically populates the EPR register with
the interrupt vector number and acknowledges the interrupt inside
the interrupt controller.
In case the interrupt controller lives in user space, we need to do
the interrupt acknowledge cycle through it to fetch the next to be
delivered interrupt vector using this exit.
It gets triggered whenever both KVM_CAP_PPC_EPR are enabled and an
external interrupt has just been delivered into the guest. User space
should put the acknowledged interrupt vector into the 'epr' field.
/* Fix the size of the union. */ /* Fix the size of the union. */
char padding[256]; char padding[256];
}; };
...@@ -2501,3 +2520,20 @@ handled in-kernel, while the other I/O instructions are passed to userspace. ...@@ -2501,3 +2520,20 @@ handled in-kernel, while the other I/O instructions are passed to userspace.
When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST
SUBCHANNEL intercepts. SUBCHANNEL intercepts.
6.5 KVM_CAP_PPC_EPR
Architectures: ppc
Parameters: args[0] defines whether the proxy facility is active
Returns: 0 on success; -1 on error
This capability enables or disables the delivery of interrupts through the
external proxy facility.
When enabled (args[0] != 0), every time the guest gets an external interrupt
delivered, it automatically exits into user space with a KVM_EXIT_EPR exit
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.
...@@ -520,6 +520,8 @@ struct kvm_vcpu_arch { ...@@ -520,6 +520,8 @@ 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_needed;
u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
......
...@@ -264,6 +264,15 @@ static inline void kvm_linear_init(void) ...@@ -264,6 +264,15 @@ static inline void kvm_linear_init(void)
{} {}
#endif #endif
static inline void kvmppc_set_epr(struct kvm_vcpu *vcpu, u32 epr)
{
#ifdef CONFIG_KVM_BOOKE_HV
mtspr(SPRN_GEPR, epr);
#elif defined(CONFIG_BOOKE)
vcpu->arch.epr = epr;
#endif
}
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,
......
...@@ -306,7 +306,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, ...@@ -306,7 +306,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
{ {
int allowed = 0; int allowed = 0;
ulong msr_mask = 0; ulong msr_mask = 0;
bool update_esr = false, update_dear = false; bool update_esr = false, update_dear = false, update_epr = false;
ulong crit_raw = vcpu->arch.shared->critical; ulong crit_raw = vcpu->arch.shared->critical;
ulong crit_r1 = kvmppc_get_gpr(vcpu, 1); ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
bool crit; bool crit;
...@@ -330,6 +330,9 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, ...@@ -330,6 +330,9 @@ 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)
update_epr = true;
switch (priority) { switch (priority) {
case BOOKE_IRQPRIO_DTLB_MISS: case BOOKE_IRQPRIO_DTLB_MISS:
case BOOKE_IRQPRIO_DATA_STORAGE: case BOOKE_IRQPRIO_DATA_STORAGE:
...@@ -408,6 +411,8 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, ...@@ -408,6 +411,8 @@ 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)
kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
new_msr &= msr_mask; new_msr &= msr_mask;
#if defined(CONFIG_64BIT) #if defined(CONFIG_64BIT)
...@@ -615,6 +620,13 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu) ...@@ -615,6 +620,13 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
r = 0; r = 0;
} }
if (kvm_check_request(KVM_REQ_EPR_EXIT, vcpu)) {
vcpu->run->epr.epr = 0;
vcpu->arch.epr_needed = true;
vcpu->run->exit_reason = KVM_EXIT_EPR;
r = 0;
}
return r; return r;
} }
......
...@@ -306,6 +306,7 @@ int kvm_dev_ioctl_check_extension(long ext) ...@@ -306,6 +306,7 @@ int kvm_dev_ioctl_check_extension(long ext)
#ifdef CONFIG_BOOKE #ifdef CONFIG_BOOKE
case KVM_CAP_PPC_BOOKE_SREGS: case KVM_CAP_PPC_BOOKE_SREGS:
case KVM_CAP_PPC_BOOKE_WATCHDOG: case KVM_CAP_PPC_BOOKE_WATCHDOG:
case KVM_CAP_PPC_EPR:
#else #else
case KVM_CAP_PPC_SEGSTATE: case KVM_CAP_PPC_SEGSTATE:
case KVM_CAP_PPC_HIOR: case KVM_CAP_PPC_HIOR:
...@@ -721,6 +722,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) ...@@ -721,6 +722,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
for (i = 0; i < 9; ++i) for (i = 0; i < 9; ++i)
kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]); kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]);
vcpu->arch.hcall_needed = 0; vcpu->arch.hcall_needed = 0;
#ifdef CONFIG_BOOKE
} else if (vcpu->arch.epr_needed) {
kvmppc_set_epr(vcpu, run->epr.epr);
vcpu->arch.epr_needed = 0;
#endif
} }
r = kvmppc_vcpu_run(run, vcpu); r = kvmppc_vcpu_run(run, vcpu);
...@@ -762,6 +768,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, ...@@ -762,6 +768,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
r = 0; r = 0;
vcpu->arch.papr_enabled = true; vcpu->arch.papr_enabled = true;
break; break;
case KVM_CAP_PPC_EPR:
r = 0;
vcpu->arch.epr_enabled = cap->args[0];
break;
#ifdef CONFIG_BOOKE #ifdef CONFIG_BOOKE
case KVM_CAP_PPC_BOOKE_WATCHDOG: case KVM_CAP_PPC_BOOKE_WATCHDOG:
r = 0; r = 0;
......
...@@ -122,6 +122,7 @@ static inline bool is_error_page(struct page *page) ...@@ -122,6 +122,7 @@ static inline bool is_error_page(struct page *page)
#define KVM_REQ_WATCHDOG 18 #define KVM_REQ_WATCHDOG 18
#define KVM_REQ_MASTERCLOCK_UPDATE 19 #define KVM_REQ_MASTERCLOCK_UPDATE 19
#define KVM_REQ_MCLOCK_INPROGRESS 20 #define KVM_REQ_MCLOCK_INPROGRESS 20
#define KVM_REQ_EPR_EXIT 21
#define KVM_USERSPACE_IRQ_SOURCE_ID 0 #define KVM_USERSPACE_IRQ_SOURCE_ID 0
#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1
......
...@@ -169,6 +169,7 @@ struct kvm_pit_config { ...@@ -169,6 +169,7 @@ struct kvm_pit_config {
#define KVM_EXIT_S390_UCONTROL 20 #define KVM_EXIT_S390_UCONTROL 20
#define KVM_EXIT_WATCHDOG 21 #define KVM_EXIT_WATCHDOG 21
#define KVM_EXIT_S390_TSCH 22 #define KVM_EXIT_S390_TSCH 22
#define KVM_EXIT_EPR 23
/* For KVM_EXIT_INTERNAL_ERROR */ /* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */ /* Emulate instruction failed. */
...@@ -295,6 +296,10 @@ struct kvm_run { ...@@ -295,6 +296,10 @@ struct kvm_run {
__u32 ipb; __u32 ipb;
__u8 dequeued; __u8 dequeued;
} s390_tsch; } s390_tsch;
/* KVM_EXIT_EPR */
struct {
__u32 epr;
} epr;
/* Fix the size of the union. */ /* Fix the size of the union. */
char padding[256]; char padding[256];
}; };
...@@ -656,6 +661,7 @@ struct kvm_ppc_smmu_info { ...@@ -656,6 +661,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_PPC_BOOKE_WATCHDOG 83 #define KVM_CAP_PPC_BOOKE_WATCHDOG 83
#define KVM_CAP_PPC_HTAB_FD 84 #define KVM_CAP_PPC_HTAB_FD 84
#define KVM_CAP_S390_CSS_SUPPORT 85 #define KVM_CAP_S390_CSS_SUPPORT 85
#define KVM_CAP_PPC_EPR 86
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment