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:

committed by
Alexander Graf

parent
4619ac88b7
commit
d19bd86204
@@ -174,6 +174,8 @@ extern int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server,
|
|||||||
u32 priority);
|
u32 priority);
|
||||||
extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server,
|
extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server,
|
||||||
u32 *priority);
|
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.
|
* Cuts out inst bits with ordering according to spec.
|
||||||
|
@@ -63,6 +63,44 @@ static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
|||||||
out:
|
out:
|
||||||
args->rets[0] = rc;
|
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 */
|
#endif /* CONFIG_KVM_XICS */
|
||||||
|
|
||||||
struct rtas_handler {
|
struct rtas_handler {
|
||||||
@@ -74,6 +112,8 @@ static struct rtas_handler rtas_handlers[] = {
|
|||||||
#ifdef CONFIG_KVM_XICS
|
#ifdef CONFIG_KVM_XICS
|
||||||
{ .name = "ibm,set-xive", .handler = kvm_rtas_set_xive },
|
{ .name = "ibm,set-xive", .handler = kvm_rtas_set_xive },
|
||||||
{ .name = "ibm,get-xive", .handler = kvm_rtas_get_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
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -123,6 +123,28 @@ static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
|
|||||||
mutex_unlock(&ics->lock);
|
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)
|
int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority)
|
||||||
{
|
{
|
||||||
struct kvmppc_xics *xics = kvm->arch.xics;
|
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 kvmppc_ics *ics;
|
||||||
struct ics_irq_state *state;
|
struct ics_irq_state *state;
|
||||||
u16 src;
|
u16 src;
|
||||||
bool deliver;
|
|
||||||
|
|
||||||
if (!xics)
|
if (!xics)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -144,23 +165,11 @@ int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority)
|
|||||||
if (!icp)
|
if (!icp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&ics->lock);
|
|
||||||
|
|
||||||
XICS_DBG("set_xive %#x server %#x prio %#x MP:%d RS:%d\n",
|
XICS_DBG("set_xive %#x server %#x prio %#x MP:%d RS:%d\n",
|
||||||
irq, server, priority,
|
irq, server, priority,
|
||||||
state->masked_pending, state->resend);
|
state->masked_pending, state->resend);
|
||||||
|
|
||||||
state->server = server;
|
if (write_xive(xics, ics, state, server, priority, priority))
|
||||||
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)
|
|
||||||
icp_deliver_irq(xics, icp, irq);
|
icp_deliver_irq(xics, icp, irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -189,6 +198,53 @@ int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority)
|
|||||||
return 0;
|
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 -- */
|
/* -- ICP routines, including hcalls -- */
|
||||||
|
|
||||||
static inline bool icp_try_update(struct kvmppc_icp *icp,
|
static inline bool icp_try_update(struct kvmppc_icp *icp,
|
||||||
|
@@ -36,7 +36,7 @@ struct ics_irq_state {
|
|||||||
u32 number;
|
u32 number;
|
||||||
u32 server;
|
u32 server;
|
||||||
u8 priority;
|
u8 priority;
|
||||||
u8 saved_priority; /* currently unused */
|
u8 saved_priority;
|
||||||
u8 resend;
|
u8 resend;
|
||||||
u8 masked_pending;
|
u8 masked_pending;
|
||||||
u8 asserted; /* Only for LSI */
|
u8 asserted; /* Only for LSI */
|
||||||
|
Reference in New Issue
Block a user