summaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/arm/vgic.c37
1 files changed, 10 insertions, 27 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 265a41035728..96e45f3da534 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -105,7 +105,7 @@
105#include "vgic.h" 105#include "vgic.h"
106 106
107static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu); 107static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
108static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu); 108static void vgic_retire_lr(int lr_nr, struct kvm_vcpu *vcpu);
109static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr); 109static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr);
110static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc); 110static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc);
111static u64 vgic_get_elrsr(struct kvm_vcpu *vcpu); 111static u64 vgic_get_elrsr(struct kvm_vcpu *vcpu);
@@ -717,30 +717,14 @@ void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
717 * interrupt then move the active state to the 717 * interrupt then move the active state to the
718 * distributor tracking bit. 718 * distributor tracking bit.
719 */ 719 */
720 if (lr.state & LR_STATE_ACTIVE) { 720 if (lr.state & LR_STATE_ACTIVE)
721 vgic_irq_set_active(vcpu, lr.irq); 721 vgic_irq_set_active(vcpu, lr.irq);
722 lr.state &= ~LR_STATE_ACTIVE;
723 }
724 722
725 /* 723 /*
726 * Reestablish the pending state on the distributor and the 724 * Reestablish the pending state on the distributor and the
727 * CPU interface. It may have already been pending, but that 725 * CPU interface and mark the LR as free for other use.
728 * is fine, then we are only setting a few bits that were
729 * already set.
730 */ 726 */
731 if (lr.state & LR_STATE_PENDING) { 727 vgic_retire_lr(i, vcpu);
732 vgic_dist_irq_set_pending(vcpu, lr.irq);
733 lr.state &= ~LR_STATE_PENDING;
734 }
735
736 vgic_set_lr(vcpu, i, lr);
737
738 /*
739 * Mark the LR as free for other use.
740 */
741 BUG_ON(lr.state & LR_STATE_MASK);
742 vgic_retire_lr(i, lr.irq, vcpu);
743 vgic_irq_clear_queued(vcpu, lr.irq);
744 728
745 /* Finally update the VGIC state. */ 729 /* Finally update the VGIC state. */
746 vgic_update_state(vcpu->kvm); 730 vgic_update_state(vcpu->kvm);
@@ -1099,16 +1083,18 @@ static inline void vgic_enable(struct kvm_vcpu *vcpu)
1099 vgic_ops->enable(vcpu); 1083 vgic_ops->enable(vcpu);
1100} 1084}
1101 1085
1102static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu) 1086static void vgic_retire_lr(int lr_nr, struct kvm_vcpu *vcpu)
1103{ 1087{
1104 struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr); 1088 struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
1105 1089
1090 vgic_irq_clear_queued(vcpu, vlr.irq);
1091
1106 /* 1092 /*
1107 * We must transfer the pending state back to the distributor before 1093 * We must transfer the pending state back to the distributor before
1108 * retiring the LR, otherwise we may loose edge-triggered interrupts. 1094 * retiring the LR, otherwise we may loose edge-triggered interrupts.
1109 */ 1095 */
1110 if (vlr.state & LR_STATE_PENDING) { 1096 if (vlr.state & LR_STATE_PENDING) {
1111 vgic_dist_irq_set_pending(vcpu, irq); 1097 vgic_dist_irq_set_pending(vcpu, vlr.irq);
1112 vlr.hwirq = 0; 1098 vlr.hwirq = 0;
1113 } 1099 }
1114 1100
@@ -1135,11 +1121,8 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
1135 for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) { 1121 for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
1136 struct vgic_lr vlr = vgic_get_lr(vcpu, lr); 1122 struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
1137 1123
1138 if (!vgic_irq_is_enabled(vcpu, vlr.irq)) { 1124 if (!vgic_irq_is_enabled(vcpu, vlr.irq))
1139 vgic_retire_lr(lr, vlr.irq, vcpu); 1125 vgic_retire_lr(lr, vcpu);
1140 if (vgic_irq_is_queued(vcpu, vlr.irq))
1141 vgic_irq_clear_queued(vcpu, vlr.irq);
1142 }
1143 } 1126 }
1144} 1127}
1145 1128