Skip to content

Commit

Permalink
KVM: PPC: Enable IRQFD support for the XICS interrupt controller
Browse files Browse the repository at this point in the history
This makes it possible to use IRQFDs on platforms that use the XICS
interrupt controller.  To do this we implement kvm_irq_map_gsi() and
kvm_irq_map_chip_pin() in book3s_xics.c, so as to provide a 1-1 mapping
between global interrupt numbers and XICS interrupt source numbers.
For now, all interrupts are mapped as "IRQCHIP" interrupts, and no
MSI support is provided.

This means that kvm_set_irq can now get called with level == 0 or 1
as well as the powerpc-specific values KVM_INTERRUPT_SET,
KVM_INTERRUPT_UNSET and KVM_INTERRUPT_SET_LEVEL.  We change
ics_deliver_irq() to accept all those values, and remove its
report_status argument, as it is always false, given that we don't
support KVM_IRQ_LINE_STATUS.

This also adds support for interrupt ack notifiers to the XICS code
so that the IRQFD resampler functionality can be supported.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Tested-by: Eric Auger <eric.auger@linaro.org>
Tested-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
Paul Mackerras authored and Paolo Bonzini committed Aug 5, 2014
1 parent 297e210 commit 25a2150
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 9 deletions.
2 changes: 2 additions & 0 deletions arch/powerpc/kvm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ config KVM_MPIC
config KVM_XICS
bool "KVM in-kernel XICS emulation"
depends on KVM_BOOK3S_64 && !KVM_MPIC
select HAVE_KVM_IRQCHIP
select HAVE_KVM_IRQFD
---help---
Include support for the XICS (eXternal Interrupt Controller
Specification) interrupt controller architecture used on
Expand Down
5 changes: 5 additions & 0 deletions arch/powerpc/kvm/book3s_hv_rm_xics.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,11 @@ int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
icp->rm_action |= XICS_RM_REJECT;
icp->rm_reject = irq;
}

if (!hlist_empty(&vcpu->kvm->irq_ack_notifier_list)) {
icp->rm_action |= XICS_RM_NOTIFY_EOI;
icp->rm_eoied_irq = irq;
}
bail:
return check_too_hard(xics, icp);
}
55 changes: 46 additions & 9 deletions arch/powerpc/kvm/book3s_xics.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@
static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
u32 new_irq);

static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level,
bool report_status)
/*
* Return value ideally indicates how the interrupt was handled, but no
* callers look at it (given that we don't implement KVM_IRQ_LINE_STATUS),
* so just return 0.
*/
static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level)
{
struct ics_irq_state *state;
struct kvmppc_ics *ics;
Expand All @@ -82,25 +86,22 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level,
if (!state->exists)
return -EINVAL;

if (report_status)
return state->asserted;

/*
* We set state->asserted locklessly. This should be fine as
* we are the only setter, thus concurrent access is undefined
* to begin with.
*/
if (level == KVM_INTERRUPT_SET_LEVEL)
if (level == 1 || level == KVM_INTERRUPT_SET_LEVEL)
state->asserted = 1;
else if (level == KVM_INTERRUPT_UNSET) {
else if (level == 0 || level == KVM_INTERRUPT_UNSET) {
state->asserted = 0;
return 0;
}

/* Attempt delivery */
icp_deliver_irq(xics, NULL, irq);

return state->asserted;
return 0;
}

static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
Expand Down Expand Up @@ -772,6 +773,8 @@ static noinline int kvmppc_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
if (state->asserted)
icp_deliver_irq(xics, icp, irq);

kvm_notify_acked_irq(vcpu->kvm, 0, irq);

return H_SUCCESS;
}

Expand All @@ -789,6 +792,8 @@ static noinline int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall)
icp_check_resend(xics, icp);
if (icp->rm_action & XICS_RM_REJECT)
icp_deliver_irq(xics, icp, icp->rm_reject);
if (icp->rm_action & XICS_RM_NOTIFY_EOI)
kvm_notify_acked_irq(vcpu->kvm, 0, icp->rm_eoied_irq);

icp->rm_action = 0;

Expand Down Expand Up @@ -1170,7 +1175,16 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
{
struct kvmppc_xics *xics = kvm->arch.xics;

return ics_deliver_irq(xics, irq, level, line_status);
return ics_deliver_irq(xics, irq, level);
}

int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm,
int irq_source_id, int level, bool line_status)
{
if (!level)
return -1;
return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi,
level, line_status);
}

static int xics_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
Expand Down Expand Up @@ -1301,3 +1315,26 @@ void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
vcpu->arch.icp = NULL;
vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
}

static int xics_set_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level,
bool line_status)
{
return kvm_set_irq(kvm, irq_source_id, e->gsi, level, line_status);
}

int kvm_irq_map_gsi(struct kvm *kvm,
struct kvm_kernel_irq_routing_entry *entries, int gsi)
{
entries->gsi = gsi;
entries->type = KVM_IRQ_ROUTING_IRQCHIP;
entries->set = xics_set_irq;
entries->irqchip.irqchip = 0;
entries->irqchip.pin = gsi;
return 1;
}

int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
{
return pin;
}
2 changes: 2 additions & 0 deletions arch/powerpc/kvm/book3s_xics.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ struct kvmppc_icp {
#define XICS_RM_KICK_VCPU 0x1
#define XICS_RM_CHECK_RESEND 0x2
#define XICS_RM_REJECT 0x4
#define XICS_RM_NOTIFY_EOI 0x8
u32 rm_action;
struct kvm_vcpu *rm_kick_target;
u32 rm_reject;
u32 rm_eoied_irq;

/* Debug stuff for real mode */
union kvmppc_icp_state rm_dbgstate;
Expand Down

0 comments on commit 25a2150

Please sign in to comment.