diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2013-06-03 10:55:02 -0400 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2014-07-11 07:57:31 -0400 |
commit | 8d5c6b06a5d5f8ebcf40558e566781d572920740 (patch) | |
tree | fa9d9631b9336ae2f1c4c061c2bfd6d2b2615f45 /virt | |
parent | eede821dbfd58df89edb072da64e006321eaef58 (diff) |
KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
In order to split the various register manipulation from the main vgic
code, introduce a vgic_ops structure, and start by abstracting the
LR manipulation code with a couple of accessors.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/arm/vgic.c | 162 |
1 files changed, 110 insertions, 52 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 0ba1ab0721fd..11408fee600e 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c | |||
@@ -94,9 +94,12 @@ static struct device_node *vgic_node; | |||
94 | #define ACCESS_WRITE_MASK(x) ((x) & (3 << 1)) | 94 | #define ACCESS_WRITE_MASK(x) ((x) & (3 << 1)) |
95 | 95 | ||
96 | static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu); | 96 | static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu); |
97 | static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu); | ||
97 | static void vgic_update_state(struct kvm *kvm); | 98 | static void vgic_update_state(struct kvm *kvm); |
98 | static void vgic_kick_vcpus(struct kvm *kvm); | 99 | static void vgic_kick_vcpus(struct kvm *kvm); |
99 | static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg); | 100 | static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg); |
101 | static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr); | ||
102 | static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc); | ||
100 | static u32 vgic_nr_lr; | 103 | static u32 vgic_nr_lr; |
101 | 104 | ||
102 | static unsigned int vgic_maint_irq; | 105 | static unsigned int vgic_maint_irq; |
@@ -593,18 +596,6 @@ static bool handle_mmio_sgi_reg(struct kvm_vcpu *vcpu, | |||
593 | return false; | 596 | return false; |
594 | } | 597 | } |
595 | 598 | ||
596 | #define LR_CPUID(lr) \ | ||
597 | (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT) | ||
598 | #define LR_IRQID(lr) \ | ||
599 | ((lr) & GICH_LR_VIRTUALID) | ||
600 | |||
601 | static void vgic_retire_lr(int lr_nr, int irq, struct vgic_cpu *vgic_cpu) | ||
602 | { | ||
603 | clear_bit(lr_nr, vgic_cpu->lr_used); | ||
604 | vgic_cpu->vgic_v2.vgic_lr[lr_nr] &= ~GICH_LR_STATE; | ||
605 | vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY; | ||
606 | } | ||
607 | |||
608 | /** | 599 | /** |
609 | * vgic_unqueue_irqs - move pending IRQs from LRs to the distributor | 600 | * vgic_unqueue_irqs - move pending IRQs from LRs to the distributor |
610 | * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs | 601 | * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs |
@@ -622,13 +613,10 @@ static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu) | |||
622 | struct vgic_dist *dist = &vcpu->kvm->arch.vgic; | 613 | struct vgic_dist *dist = &vcpu->kvm->arch.vgic; |
623 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; | 614 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; |
624 | int vcpu_id = vcpu->vcpu_id; | 615 | int vcpu_id = vcpu->vcpu_id; |
625 | int i, irq, source_cpu; | 616 | int i; |
626 | u32 *lr; | ||
627 | 617 | ||
628 | for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) { | 618 | for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) { |
629 | lr = &vgic_cpu->vgic_v2.vgic_lr[i]; | 619 | struct vgic_lr lr = vgic_get_lr(vcpu, i); |
630 | irq = LR_IRQID(*lr); | ||
631 | source_cpu = LR_CPUID(*lr); | ||
632 | 620 | ||
633 | /* | 621 | /* |
634 | * There are three options for the state bits: | 622 | * There are three options for the state bits: |
@@ -640,7 +628,7 @@ static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu) | |||
640 | * If the LR holds only an active interrupt (not pending) then | 628 | * If the LR holds only an active interrupt (not pending) then |
641 | * just leave it alone. | 629 | * just leave it alone. |
642 | */ | 630 | */ |
643 | if ((*lr & GICH_LR_STATE) == GICH_LR_ACTIVE_BIT) | 631 | if ((lr.state & LR_STATE_MASK) == LR_STATE_ACTIVE) |
644 | continue; | 632 | continue; |
645 | 633 | ||
646 | /* | 634 | /* |
@@ -649,18 +637,19 @@ static void vgic_unqueue_irqs(struct kvm_vcpu *vcpu) | |||
649 | * is fine, then we are only setting a few bits that were | 637 | * is fine, then we are only setting a few bits that were |
650 | * already set. | 638 | * already set. |
651 | */ | 639 | */ |
652 | vgic_dist_irq_set(vcpu, irq); | 640 | vgic_dist_irq_set(vcpu, lr.irq); |
653 | if (irq < VGIC_NR_SGIS) | 641 | if (lr.irq < VGIC_NR_SGIS) |
654 | dist->irq_sgi_sources[vcpu_id][irq] |= 1 << source_cpu; | 642 | dist->irq_sgi_sources[vcpu_id][lr.irq] |= 1 << lr.source; |
655 | *lr &= ~GICH_LR_PENDING_BIT; | 643 | lr.state &= ~LR_STATE_PENDING; |
644 | vgic_set_lr(vcpu, i, lr); | ||
656 | 645 | ||
657 | /* | 646 | /* |
658 | * If there's no state left on the LR (it could still be | 647 | * If there's no state left on the LR (it could still be |
659 | * active), then the LR does not hold any useful info and can | 648 | * active), then the LR does not hold any useful info and can |
660 | * be marked as free for other use. | 649 | * be marked as free for other use. |
661 | */ | 650 | */ |
662 | if (!(*lr & GICH_LR_STATE)) | 651 | if (!(lr.state & LR_STATE_MASK)) |
663 | vgic_retire_lr(i, irq, vgic_cpu); | 652 | vgic_retire_lr(i, lr.irq, vcpu); |
664 | 653 | ||
665 | /* Finally update the VGIC state. */ | 654 | /* Finally update the VGIC state. */ |
666 | vgic_update_state(vcpu->kvm); | 655 | vgic_update_state(vcpu->kvm); |
@@ -989,8 +978,69 @@ static void vgic_update_state(struct kvm *kvm) | |||
989 | } | 978 | } |
990 | } | 979 | } |
991 | 980 | ||
992 | #define MK_LR_PEND(src, irq) \ | 981 | static struct vgic_lr vgic_v2_get_lr(const struct kvm_vcpu *vcpu, int lr) |
993 | (GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) | (irq)) | 982 | { |
983 | struct vgic_lr lr_desc; | ||
984 | u32 val = vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr]; | ||
985 | |||
986 | lr_desc.irq = val & GICH_LR_VIRTUALID; | ||
987 | if (lr_desc.irq <= 15) | ||
988 | lr_desc.source = (val >> GICH_LR_PHYSID_CPUID_SHIFT) & 0x7; | ||
989 | else | ||
990 | lr_desc.source = 0; | ||
991 | lr_desc.state = 0; | ||
992 | |||
993 | if (val & GICH_LR_PENDING_BIT) | ||
994 | lr_desc.state |= LR_STATE_PENDING; | ||
995 | if (val & GICH_LR_ACTIVE_BIT) | ||
996 | lr_desc.state |= LR_STATE_ACTIVE; | ||
997 | if (val & GICH_LR_EOI) | ||
998 | lr_desc.state |= LR_EOI_INT; | ||
999 | |||
1000 | return lr_desc; | ||
1001 | } | ||
1002 | |||
1003 | static void vgic_v2_set_lr(struct kvm_vcpu *vcpu, int lr, | ||
1004 | struct vgic_lr lr_desc) | ||
1005 | { | ||
1006 | u32 lr_val = (lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT) | lr_desc.irq; | ||
1007 | |||
1008 | if (lr_desc.state & LR_STATE_PENDING) | ||
1009 | lr_val |= GICH_LR_PENDING_BIT; | ||
1010 | if (lr_desc.state & LR_STATE_ACTIVE) | ||
1011 | lr_val |= GICH_LR_ACTIVE_BIT; | ||
1012 | if (lr_desc.state & LR_EOI_INT) | ||
1013 | lr_val |= GICH_LR_EOI; | ||
1014 | |||
1015 | vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = lr_val; | ||
1016 | } | ||
1017 | |||
1018 | static const struct vgic_ops vgic_ops = { | ||
1019 | .get_lr = vgic_v2_get_lr, | ||
1020 | .set_lr = vgic_v2_set_lr, | ||
1021 | }; | ||
1022 | |||
1023 | static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr) | ||
1024 | { | ||
1025 | return vgic_ops.get_lr(vcpu, lr); | ||
1026 | } | ||
1027 | |||
1028 | static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, | ||
1029 | struct vgic_lr vlr) | ||
1030 | { | ||
1031 | vgic_ops.set_lr(vcpu, lr, vlr); | ||
1032 | } | ||
1033 | |||
1034 | static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu) | ||
1035 | { | ||
1036 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; | ||
1037 | struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr); | ||
1038 | |||
1039 | vlr.state = 0; | ||
1040 | vgic_set_lr(vcpu, lr_nr, vlr); | ||
1041 | clear_bit(lr_nr, vgic_cpu->lr_used); | ||
1042 | vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY; | ||
1043 | } | ||
994 | 1044 | ||
995 | /* | 1045 | /* |
996 | * An interrupt may have been disabled after being made pending on the | 1046 | * An interrupt may have been disabled after being made pending on the |
@@ -1007,12 +1057,12 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu) | |||
1007 | int lr; | 1057 | int lr; |
1008 | 1058 | ||
1009 | for_each_set_bit(lr, vgic_cpu->lr_used, vgic_cpu->nr_lr) { | 1059 | for_each_set_bit(lr, vgic_cpu->lr_used, vgic_cpu->nr_lr) { |
1010 | int irq = vgic_cpu->vgic_v2.vgic_lr[lr] & GICH_LR_VIRTUALID; | 1060 | struct vgic_lr vlr = vgic_get_lr(vcpu, lr); |
1011 | 1061 | ||
1012 | if (!vgic_irq_is_enabled(vcpu, irq)) { | 1062 | if (!vgic_irq_is_enabled(vcpu, vlr.irq)) { |
1013 | vgic_retire_lr(lr, irq, vgic_cpu); | 1063 | vgic_retire_lr(lr, vlr.irq, vcpu); |
1014 | if (vgic_irq_is_active(vcpu, irq)) | 1064 | if (vgic_irq_is_active(vcpu, vlr.irq)) |
1015 | vgic_irq_clear_active(vcpu, irq); | 1065 | vgic_irq_clear_active(vcpu, vlr.irq); |
1016 | } | 1066 | } |
1017 | } | 1067 | } |
1018 | } | 1068 | } |
@@ -1024,6 +1074,7 @@ static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu) | |||
1024 | static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) | 1074 | static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) |
1025 | { | 1075 | { |
1026 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; | 1076 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; |
1077 | struct vgic_lr vlr; | ||
1027 | int lr; | 1078 | int lr; |
1028 | 1079 | ||
1029 | /* Sanitize the input... */ | 1080 | /* Sanitize the input... */ |
@@ -1036,13 +1087,15 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) | |||
1036 | lr = vgic_cpu->vgic_irq_lr_map[irq]; | 1087 | lr = vgic_cpu->vgic_irq_lr_map[irq]; |
1037 | 1088 | ||
1038 | /* Do we have an active interrupt for the same CPUID? */ | 1089 | /* Do we have an active interrupt for the same CPUID? */ |
1039 | if (lr != LR_EMPTY && | 1090 | if (lr != LR_EMPTY) { |
1040 | (LR_CPUID(vgic_cpu->vgic_v2.vgic_lr[lr]) == sgi_source_id)) { | 1091 | vlr = vgic_get_lr(vcpu, lr); |
1041 | kvm_debug("LR%d piggyback for IRQ%d %x\n", | 1092 | if (vlr.source == sgi_source_id) { |
1042 | lr, irq, vgic_cpu->vgic_v2.vgic_lr[lr]); | 1093 | kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq); |
1043 | BUG_ON(!test_bit(lr, vgic_cpu->lr_used)); | 1094 | BUG_ON(!test_bit(lr, vgic_cpu->lr_used)); |
1044 | vgic_cpu->vgic_v2.vgic_lr[lr] |= GICH_LR_PENDING_BIT; | 1095 | vlr.state |= LR_STATE_PENDING; |
1045 | return true; | 1096 | vgic_set_lr(vcpu, lr, vlr); |
1097 | return true; | ||
1098 | } | ||
1046 | } | 1099 | } |
1047 | 1100 | ||
1048 | /* Try to use another LR for this interrupt */ | 1101 | /* Try to use another LR for this interrupt */ |
@@ -1052,12 +1105,16 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) | |||
1052 | return false; | 1105 | return false; |
1053 | 1106 | ||
1054 | kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id); | 1107 | kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id); |
1055 | vgic_cpu->vgic_v2.vgic_lr[lr] = MK_LR_PEND(sgi_source_id, irq); | ||
1056 | vgic_cpu->vgic_irq_lr_map[irq] = lr; | 1108 | vgic_cpu->vgic_irq_lr_map[irq] = lr; |
1057 | set_bit(lr, vgic_cpu->lr_used); | 1109 | set_bit(lr, vgic_cpu->lr_used); |
1058 | 1110 | ||
1111 | vlr.irq = irq; | ||
1112 | vlr.source = sgi_source_id; | ||
1113 | vlr.state = LR_STATE_PENDING; | ||
1059 | if (!vgic_irq_is_edge(vcpu, irq)) | 1114 | if (!vgic_irq_is_edge(vcpu, irq)) |
1060 | vgic_cpu->vgic_v2.vgic_lr[lr] |= GICH_LR_EOI; | 1115 | vlr.state |= LR_EOI_INT; |
1116 | |||
1117 | vgic_set_lr(vcpu, lr, vlr); | ||
1061 | 1118 | ||
1062 | return true; | 1119 | return true; |
1063 | } | 1120 | } |
@@ -1180,21 +1237,23 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) | |||
1180 | * Some level interrupts have been EOIed. Clear their | 1237 | * Some level interrupts have been EOIed. Clear their |
1181 | * active bit. | 1238 | * active bit. |
1182 | */ | 1239 | */ |
1183 | int lr, irq; | 1240 | int lr; |
1184 | 1241 | ||
1185 | for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_eisr, | 1242 | for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_eisr, |
1186 | vgic_cpu->nr_lr) { | 1243 | vgic_cpu->nr_lr) { |
1187 | irq = vgic_cpu->vgic_v2.vgic_lr[lr] & GICH_LR_VIRTUALID; | 1244 | struct vgic_lr vlr = vgic_get_lr(vcpu, lr); |
1188 | 1245 | ||
1189 | vgic_irq_clear_active(vcpu, irq); | 1246 | vgic_irq_clear_active(vcpu, vlr.irq); |
1190 | vgic_cpu->vgic_v2.vgic_lr[lr] &= ~GICH_LR_EOI; | 1247 | WARN_ON(vlr.state & LR_STATE_MASK); |
1248 | vlr.state = 0; | ||
1249 | vgic_set_lr(vcpu, lr, vlr); | ||
1191 | 1250 | ||
1192 | /* Any additional pending interrupt? */ | 1251 | /* Any additional pending interrupt? */ |
1193 | if (vgic_dist_irq_is_pending(vcpu, irq)) { | 1252 | if (vgic_dist_irq_is_pending(vcpu, vlr.irq)) { |
1194 | vgic_cpu_irq_set(vcpu, irq); | 1253 | vgic_cpu_irq_set(vcpu, vlr.irq); |
1195 | level_pending = true; | 1254 | level_pending = true; |
1196 | } else { | 1255 | } else { |
1197 | vgic_cpu_irq_clear(vcpu, irq); | 1256 | vgic_cpu_irq_clear(vcpu, vlr.irq); |
1198 | } | 1257 | } |
1199 | 1258 | ||
1200 | /* | 1259 | /* |
@@ -1202,7 +1261,6 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) | |||
1202 | * been marked as empty. | 1261 | * been marked as empty. |
1203 | */ | 1262 | */ |
1204 | set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr); | 1263 | set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr); |
1205 | vgic_cpu->vgic_v2.vgic_lr[lr] &= ~GICH_LR_ACTIVE_BIT; | ||
1206 | } | 1264 | } |
1207 | } | 1265 | } |
1208 | 1266 | ||
@@ -1228,15 +1286,15 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) | |||
1228 | /* Clear mappings for empty LRs */ | 1286 | /* Clear mappings for empty LRs */ |
1229 | for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr, | 1287 | for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr, |
1230 | vgic_cpu->nr_lr) { | 1288 | vgic_cpu->nr_lr) { |
1231 | int irq; | 1289 | struct vgic_lr vlr; |
1232 | 1290 | ||
1233 | if (!test_and_clear_bit(lr, vgic_cpu->lr_used)) | 1291 | if (!test_and_clear_bit(lr, vgic_cpu->lr_used)) |
1234 | continue; | 1292 | continue; |
1235 | 1293 | ||
1236 | irq = vgic_cpu->vgic_v2.vgic_lr[lr] & GICH_LR_VIRTUALID; | 1294 | vlr = vgic_get_lr(vcpu, lr); |
1237 | 1295 | ||
1238 | BUG_ON(irq >= VGIC_NR_IRQS); | 1296 | BUG_ON(vlr.irq >= VGIC_NR_IRQS); |
1239 | vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY; | 1297 | vgic_cpu->vgic_irq_lr_map[vlr.irq] = LR_EMPTY; |
1240 | } | 1298 | } |
1241 | 1299 | ||
1242 | /* Check if we still have something up our sleeve... */ | 1300 | /* Check if we still have something up our sleeve... */ |