KVM: PPC: Book3S: Add support for ibm,int-on/off RTAS calls

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@samba.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Paul Mackerras 2013-04-17 20:32:04 +00:00 committed by Alexander Graf
parent 4619ac88b7
commit d19bd86204
4 changed files with 113 additions and 15 deletions

View File

@ -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.

View File

@ -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
};

View File

@ -123,6 +123,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.xics;
@ -130,7 +152,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;
@ -144,23 +165,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;
@ -189,6 +198,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.xics;
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.xics;
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,

View File

@ -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 */