diff options
author | Paul Mackerras <paulus@samba.org> | 2014-06-30 06:51:14 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-08-05 08:26:33 -0400 |
commit | 25a2150bee00b4d996487552948b9b3ba21d0257 (patch) | |
tree | 871ddff4f28387cd9c85ade7860c883da3660fbf /arch | |
parent | 297e21053a52f060944e9f0de4c64fad9bcd72fc (diff) |
KVM: PPC: Enable IRQFD support for the XICS interrupt controller
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kvm/Kconfig | 2 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rm_xics.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_xics.c | 55 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_xics.h | 2 |
4 files changed, 55 insertions, 9 deletions
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index d4741dba91af..602eb51d20bc 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig | |||
@@ -170,6 +170,8 @@ config KVM_MPIC | |||
170 | config KVM_XICS | 170 | config KVM_XICS |
171 | bool "KVM in-kernel XICS emulation" | 171 | bool "KVM in-kernel XICS emulation" |
172 | depends on KVM_BOOK3S_64 && !KVM_MPIC | 172 | depends on KVM_BOOK3S_64 && !KVM_MPIC |
173 | select HAVE_KVM_IRQCHIP | ||
174 | select HAVE_KVM_IRQFD | ||
173 | ---help--- | 175 | ---help--- |
174 | Include support for the XICS (eXternal Interrupt Controller | 176 | Include support for the XICS (eXternal Interrupt Controller |
175 | Specification) interrupt controller architecture used on | 177 | Specification) interrupt controller architecture used on |
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c index b4b0082f761c..3ee38e6e884f 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c | |||
@@ -401,6 +401,11 @@ int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) | |||
401 | icp->rm_action |= XICS_RM_REJECT; | 401 | icp->rm_action |= XICS_RM_REJECT; |
402 | icp->rm_reject = irq; | 402 | icp->rm_reject = irq; |
403 | } | 403 | } |
404 | |||
405 | if (!hlist_empty(&vcpu->kvm->irq_ack_notifier_list)) { | ||
406 | icp->rm_action |= XICS_RM_NOTIFY_EOI; | ||
407 | icp->rm_eoied_irq = irq; | ||
408 | } | ||
404 | bail: | 409 | bail: |
405 | return check_too_hard(xics, icp); | 410 | return check_too_hard(xics, icp); |
406 | } | 411 | } |
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index d1acd32a64c0..eaeb78047fb8 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c | |||
@@ -64,8 +64,12 @@ | |||
64 | static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, | 64 | static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, |
65 | u32 new_irq); | 65 | u32 new_irq); |
66 | 66 | ||
67 | static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level, | 67 | /* |
68 | bool report_status) | 68 | * Return value ideally indicates how the interrupt was handled, but no |
69 | * callers look at it (given that we don't implement KVM_IRQ_LINE_STATUS), | ||
70 | * so just return 0. | ||
71 | */ | ||
72 | static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level) | ||
69 | { | 73 | { |
70 | struct ics_irq_state *state; | 74 | struct ics_irq_state *state; |
71 | struct kvmppc_ics *ics; | 75 | struct kvmppc_ics *ics; |
@@ -82,17 +86,14 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level, | |||
82 | if (!state->exists) | 86 | if (!state->exists) |
83 | return -EINVAL; | 87 | return -EINVAL; |
84 | 88 | ||
85 | if (report_status) | ||
86 | return state->asserted; | ||
87 | |||
88 | /* | 89 | /* |
89 | * We set state->asserted locklessly. This should be fine as | 90 | * We set state->asserted locklessly. This should be fine as |
90 | * we are the only setter, thus concurrent access is undefined | 91 | * we are the only setter, thus concurrent access is undefined |
91 | * to begin with. | 92 | * to begin with. |
92 | */ | 93 | */ |
93 | if (level == KVM_INTERRUPT_SET_LEVEL) | 94 | if (level == 1 || level == KVM_INTERRUPT_SET_LEVEL) |
94 | state->asserted = 1; | 95 | state->asserted = 1; |
95 | else if (level == KVM_INTERRUPT_UNSET) { | 96 | else if (level == 0 || level == KVM_INTERRUPT_UNSET) { |
96 | state->asserted = 0; | 97 | state->asserted = 0; |
97 | return 0; | 98 | return 0; |
98 | } | 99 | } |
@@ -100,7 +101,7 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level, | |||
100 | /* Attempt delivery */ | 101 | /* Attempt delivery */ |
101 | icp_deliver_irq(xics, NULL, irq); | 102 | icp_deliver_irq(xics, NULL, irq); |
102 | 103 | ||
103 | return state->asserted; | 104 | return 0; |
104 | } | 105 | } |
105 | 106 | ||
106 | static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics, | 107 | static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics, |
@@ -772,6 +773,8 @@ static noinline int kvmppc_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) | |||
772 | if (state->asserted) | 773 | if (state->asserted) |
773 | icp_deliver_irq(xics, icp, irq); | 774 | icp_deliver_irq(xics, icp, irq); |
774 | 775 | ||
776 | kvm_notify_acked_irq(vcpu->kvm, 0, irq); | ||
777 | |||
775 | return H_SUCCESS; | 778 | return H_SUCCESS; |
776 | } | 779 | } |
777 | 780 | ||
@@ -789,6 +792,8 @@ static noinline int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall) | |||
789 | icp_check_resend(xics, icp); | 792 | icp_check_resend(xics, icp); |
790 | if (icp->rm_action & XICS_RM_REJECT) | 793 | if (icp->rm_action & XICS_RM_REJECT) |
791 | icp_deliver_irq(xics, icp, icp->rm_reject); | 794 | icp_deliver_irq(xics, icp, icp->rm_reject); |
795 | if (icp->rm_action & XICS_RM_NOTIFY_EOI) | ||
796 | kvm_notify_acked_irq(vcpu->kvm, 0, icp->rm_eoied_irq); | ||
792 | 797 | ||
793 | icp->rm_action = 0; | 798 | icp->rm_action = 0; |
794 | 799 | ||
@@ -1170,7 +1175,16 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, | |||
1170 | { | 1175 | { |
1171 | struct kvmppc_xics *xics = kvm->arch.xics; | 1176 | struct kvmppc_xics *xics = kvm->arch.xics; |
1172 | 1177 | ||
1173 | return ics_deliver_irq(xics, irq, level, line_status); | 1178 | return ics_deliver_irq(xics, irq, level); |
1179 | } | ||
1180 | |||
1181 | int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm, | ||
1182 | int irq_source_id, int level, bool line_status) | ||
1183 | { | ||
1184 | if (!level) | ||
1185 | return -1; | ||
1186 | return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi, | ||
1187 | level, line_status); | ||
1174 | } | 1188 | } |
1175 | 1189 | ||
1176 | static int xics_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) | 1190 | static int xics_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) |
@@ -1301,3 +1315,26 @@ void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) | |||
1301 | vcpu->arch.icp = NULL; | 1315 | vcpu->arch.icp = NULL; |
1302 | vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT; | 1316 | vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT; |
1303 | } | 1317 | } |
1318 | |||
1319 | static int xics_set_irq(struct kvm_kernel_irq_routing_entry *e, | ||
1320 | struct kvm *kvm, int irq_source_id, int level, | ||
1321 | bool line_status) | ||
1322 | { | ||
1323 | return kvm_set_irq(kvm, irq_source_id, e->gsi, level, line_status); | ||
1324 | } | ||
1325 | |||
1326 | int kvm_irq_map_gsi(struct kvm *kvm, | ||
1327 | struct kvm_kernel_irq_routing_entry *entries, int gsi) | ||
1328 | { | ||
1329 | entries->gsi = gsi; | ||
1330 | entries->type = KVM_IRQ_ROUTING_IRQCHIP; | ||
1331 | entries->set = xics_set_irq; | ||
1332 | entries->irqchip.irqchip = 0; | ||
1333 | entries->irqchip.pin = gsi; | ||
1334 | return 1; | ||
1335 | } | ||
1336 | |||
1337 | int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin) | ||
1338 | { | ||
1339 | return pin; | ||
1340 | } | ||
diff --git a/arch/powerpc/kvm/book3s_xics.h b/arch/powerpc/kvm/book3s_xics.h index dd9326c5c19b..e8aaa7a3f209 100644 --- a/arch/powerpc/kvm/book3s_xics.h +++ b/arch/powerpc/kvm/book3s_xics.h | |||
@@ -71,9 +71,11 @@ struct kvmppc_icp { | |||
71 | #define XICS_RM_KICK_VCPU 0x1 | 71 | #define XICS_RM_KICK_VCPU 0x1 |
72 | #define XICS_RM_CHECK_RESEND 0x2 | 72 | #define XICS_RM_CHECK_RESEND 0x2 |
73 | #define XICS_RM_REJECT 0x4 | 73 | #define XICS_RM_REJECT 0x4 |
74 | #define XICS_RM_NOTIFY_EOI 0x8 | ||
74 | u32 rm_action; | 75 | u32 rm_action; |
75 | struct kvm_vcpu *rm_kick_target; | 76 | struct kvm_vcpu *rm_kick_target; |
76 | u32 rm_reject; | 77 | u32 rm_reject; |
78 | u32 rm_eoied_irq; | ||
77 | 79 | ||
78 | /* Debug stuff for real mode */ | 80 | /* Debug stuff for real mode */ |
79 | union kvmppc_icp_state rm_dbgstate; | 81 | union kvmppc_icp_state rm_dbgstate; |