This 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. Signed-off-by: Paul Mackerras <paulus@xxxxxxxxx> --- arch/powerpc/include/asm/kvm_ppc.h | 2 + arch/powerpc/kvm/book3s_rtas.c | 40 ++++++++++++++ arch/powerpc/kvm/book3s_xics.c | 101 +++++++++++++++++++++++++++++------- arch/powerpc/kvm/book3s_xics.h | 2 +- 4 files changed, 125 insertions(+), 20 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index f371af8a..dd7c1fc 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -171,6 +171,8 @@ 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); +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. diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c index 6a6c1fe..fc1a749 100644 --- a/arch/powerpc/kvm/book3s_rtas.c +++ b/arch/powerpc/kvm/book3s_rtas.c @@ -64,6 +64,44 @@ 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; +} + struct rtas_handler { void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args); char *name; @@ -72,6 +110,8 @@ struct rtas_handler { static struct rtas_handler rtas_handlers[] = { { .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 }, }; struct rtas_token_definition { diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index abd2dde..665777e 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -116,6 +116,28 @@ static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics, mutex_unlock(&ics->lock); } +static bool write_xive(struct kvmppc_xics *xics, struct kvmppc_ics *ics, + struct ics_irq_state *state, + u32 server, u32 priority, u32 saved_priority) +{ + bool deliver; + + mutex_lock(&ics->lock); + + state->server = server; + state->priority = priority; + state->saved_priority = saved_priority; + deliver = false; + if ((state->masked_pending || state->resend) && priority != MASKED) { + state->masked_pending = 0; + deliver = true; + } + + mutex_unlock(&ics->lock); + + return deliver; +} + int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) { struct kvmppc_xics *xics = kvm->arch.irq_ctrler_private; @@ -123,7 +145,6 @@ int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) struct kvmppc_ics *ics; struct ics_irq_state *state; u16 src; - bool deliver; if (!xics) return -ENODEV; @@ -137,23 +158,11 @@ int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) if (!icp) return -EINVAL; - mutex_lock(&ics->lock); - XICS_DBG("set_xive %#x server %#x prio %#x MP:%d RS:%d\n", irq, server, priority, state->masked_pending, state->resend); - state->server = server; - state->priority = priority; - deliver = false; - if ((state->masked_pending || state->resend) && priority != MASKED) { - state->masked_pending = 0; - deliver = true; - } - - mutex_unlock(&ics->lock); - - if (deliver) + if (write_xive(xics, ics, state, server, priority, priority)) icp_deliver_irq(xics, icp, irq); return 0; @@ -182,6 +191,53 @@ int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority) return 0; } +int kvmppc_xics_int_on(struct kvm *kvm, u32 irq) +{ + struct kvmppc_xics *xics = kvm->arch.irq_ctrler_private; + struct kvmppc_icp *icp; + struct kvmppc_ics *ics; + struct ics_irq_state *state; + u16 src; + + if (!xics) + return -ENODEV; + + ics = kvmppc_xics_find_ics(xics, irq, &src); + if (!ics) + return -EINVAL; + state = &ics->irq_state[src]; + + icp = kvmppc_xics_find_server(kvm, state->server); + if (!icp) + return -EINVAL; + + if (write_xive(xics, ics, state, state->server, state->saved_priority, + state->saved_priority)) + icp_deliver_irq(xics, icp, irq); + + return 0; +} + +int kvmppc_xics_int_off(struct kvm *kvm, u32 irq) +{ + struct kvmppc_xics *xics = kvm->arch.irq_ctrler_private; + struct kvmppc_ics *ics; + struct ics_irq_state *state; + u16 src; + + if (!xics) + return -ENODEV; + + ics = kvmppc_xics_find_ics(xics, irq, &src); + if (!ics) + return -EINVAL; + state = &ics->irq_state[src]; + + write_xive(xics, ics, state, state->server, MASKED, state->priority); + + return 0; +} + /* -- ICP routines, including hcalls -- */ static inline bool icp_try_update(struct kvmppc_icp *icp, @@ -576,7 +632,7 @@ static noinline int kvmppc_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, /* Handle reject */ if (reject && reject != XICS_IPI) icp_deliver_irq(xics, icp, reject); - + /* Handle resend */ if (resend) icp_check_resend(xics, icp); @@ -1016,7 +1072,7 @@ static int kvm_xics_get_sources(struct kvm *kvm, struct kvm_irq_sources *srcs) struct ics_irq_state *irqp; u64 __user *ubufp; u16 idx; - u64 val; + u64 val, prio; long int i, irq, nirq; irq = srcs->irq; @@ -1039,9 +1095,12 @@ static int kvm_xics_get_sources(struct kvm *kvm, struct kvm_irq_sources *srcs) if (!irqp->exists) break; val = irqp->server; - val |= ((u64)irqp->priority << KVM_IRQ_PRIORITY_SHIFT); - if (irqp->priority == MASKED) + prio = irqp->priority; + if (irqp->priority == MASKED) { val |= KVM_IRQ_MASKED; + prio = irqp->saved_priority; + } + val |= prio << KVM_IRQ_PRIORITY_SHIFT; if (irqp->asserted) val |= KVM_IRQ_LEVEL_SENSITIVE | KVM_IRQ_PENDING; @@ -1099,7 +1158,11 @@ static int kvm_xics_set_sources(struct kvm *kvm, struct kvm_irq_sources *srcs) mutex_lock(&ics->lock); irqp->server = val & KVM_IRQ_SERVER_MASK; - irqp->priority = val >> KVM_IRQ_PRIORITY_SHIFT; + irqp->saved_priority = val >> KVM_IRQ_PRIORITY_SHIFT; + if (val & KVM_IRQ_MASKED) + irqp->priority = MASKED; + else + irqp->priority = irqp->saved_priority; irqp->resend = 0; irqp->masked_pending = 0; irqp->asserted = 0; diff --git a/arch/powerpc/kvm/book3s_xics.h b/arch/powerpc/kvm/book3s_xics.h index 2da27d7..9c1f1bb 100644 --- a/arch/powerpc/kvm/book3s_xics.h +++ b/arch/powerpc/kvm/book3s_xics.h @@ -35,7 +35,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 */ -- 1.7.10.rc3.219.g53414 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html