summaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorPavel Fedin <p.fedin@samsung.com>2015-10-27 04:37:29 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2015-11-04 09:29:49 -0500
commitc4cd4c168b81dad53e659d18cdae653bc0ec2384 (patch)
treefe519309bd917369e61cde515ebc7bc9915d9409 /virt
parent5fdf876d30ce7c9b63045b3db8374912ab9b262c (diff)
KVM: arm/arm64: Optimize away redundant LR tracking
Currently we use vgic_irq_lr_map in order to track which LRs hold which IRQs, and lr_used bitmap in order to track which LRs are used or free. vgic_irq_lr_map is actually used only for piggy-back optimization, and can be easily replaced by iteration over lr_used. This is good because in future, when LPI support is introduced, number of IRQs will grow up to at least 16384, while numbers from 1024 to 8192 are never going to be used. This would be a huge memory waste. In its turn, lr_used is also completely redundant since ae705930fca6322600690df9dc1c7d0516145a93 ("arm/arm64: KVM: Keep elrsr/aisr in sync with software model"), because together with lr_used we also update elrsr. This allows to easily replace lr_used with elrsr, inverting all conditions (because in elrsr '1' means 'free'). Signed-off-by: Pavel Fedin <p.fedin@samsung.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/arm/vgic-v2.c1
-rw-r--r--virt/kvm/arm/vgic-v3.c1
-rw-r--r--virt/kvm/arm/vgic.c53
3 files changed, 17 insertions, 38 deletions
diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
index 8d7b04db8471..c0f5d7fad9ea 100644
--- a/virt/kvm/arm/vgic-v2.c
+++ b/virt/kvm/arm/vgic-v2.c
@@ -158,6 +158,7 @@ static void vgic_v2_enable(struct kvm_vcpu *vcpu)
158 * anyway. 158 * anyway.
159 */ 159 */
160 vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0; 160 vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
161 vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr = ~0;
161 162
162 /* Get the show on the road... */ 163 /* Get the show on the road... */
163 vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN; 164 vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index 7dd5d62f10a1..92003cb61a0a 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -193,6 +193,7 @@ static void vgic_v3_enable(struct kvm_vcpu *vcpu)
193 * anyway. 193 * anyway.
194 */ 194 */
195 vgic_v3->vgic_vmcr = 0; 195 vgic_v3->vgic_vmcr = 0;
196 vgic_v3->vgic_elrsr = ~0;
196 197
197 /* 198 /*
198 * If we are emulating a GICv3, we do it in an non-GICv2-compatible 199 * If we are emulating a GICv3, we do it in an non-GICv2-compatible
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index d4669eb29b77..265a41035728 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -108,6 +108,7 @@ static 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, int irq, 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 struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu, 112static struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu,
112 int virt_irq); 113 int virt_irq);
113static int compute_pending_for_cpu(struct kvm_vcpu *vcpu); 114static int compute_pending_for_cpu(struct kvm_vcpu *vcpu);
@@ -691,9 +692,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
691void vgic_unqueue_irqs(struct kvm_vcpu *vcpu) 692void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
692{ 693{
693 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 694 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
695 u64 elrsr = vgic_get_elrsr(vcpu);
696 unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
694 int i; 697 int i;
695 698
696 for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) { 699 for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) {
697 struct vgic_lr lr = vgic_get_lr(vcpu, i); 700 struct vgic_lr lr = vgic_get_lr(vcpu, i);
698 701
699 /* 702 /*
@@ -1098,7 +1101,6 @@ static inline void vgic_enable(struct kvm_vcpu *vcpu)
1098 1101
1099static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu) 1102static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
1100{ 1103{
1101 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
1102 struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr); 1104 struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
1103 1105
1104 /* 1106 /*
@@ -1112,8 +1114,6 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
1112 1114
1113 vlr.state = 0; 1115 vlr.state = 0;
1114 vgic_set_lr(vcpu, lr_nr, vlr); 1116 vgic_set_lr(vcpu, lr_nr, vlr);
1115 clear_bit(lr_nr, vgic_cpu->lr_used);
1116 vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
1117 vgic_sync_lr_elrsr(vcpu, lr_nr, vlr); 1117 vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
1118} 1118}
1119 1119
@@ -1128,10 +1128,11 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
1128 */ 1128 */
1129static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu) 1129static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
1130{ 1130{
1131 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 1131 u64 elrsr = vgic_get_elrsr(vcpu);
1132 unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
1132 int lr; 1133 int lr;
1133 1134
1134 for_each_set_bit(lr, vgic_cpu->lr_used, vgic->nr_lr) { 1135 for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
1135 struct vgic_lr vlr = vgic_get_lr(vcpu, lr); 1136 struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
1136 1137
1137 if (!vgic_irq_is_enabled(vcpu, vlr.irq)) { 1138 if (!vgic_irq_is_enabled(vcpu, vlr.irq)) {
@@ -1188,8 +1189,9 @@ static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
1188 */ 1189 */
1189bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq) 1190bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
1190{ 1191{
1191 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
1192 struct vgic_dist *dist = &vcpu->kvm->arch.vgic; 1192 struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
1193 u64 elrsr = vgic_get_elrsr(vcpu);
1194 unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
1193 struct vgic_lr vlr; 1195 struct vgic_lr vlr;
1194 int lr; 1196 int lr;
1195 1197
@@ -1200,28 +1202,22 @@ bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
1200 1202
1201 kvm_debug("Queue IRQ%d\n", irq); 1203 kvm_debug("Queue IRQ%d\n", irq);
1202 1204
1203 lr = vgic_cpu->vgic_irq_lr_map[irq];
1204
1205 /* Do we have an active interrupt for the same CPUID? */ 1205 /* Do we have an active interrupt for the same CPUID? */
1206 if (lr != LR_EMPTY) { 1206 for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
1207 vlr = vgic_get_lr(vcpu, lr); 1207 vlr = vgic_get_lr(vcpu, lr);
1208 if (vlr.source == sgi_source_id) { 1208 if (vlr.irq == irq && vlr.source == sgi_source_id) {
1209 kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq); 1209 kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq);
1210 BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
1211 vgic_queue_irq_to_lr(vcpu, irq, lr, vlr); 1210 vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
1212 return true; 1211 return true;
1213 } 1212 }
1214 } 1213 }
1215 1214
1216 /* Try to use another LR for this interrupt */ 1215 /* Try to use another LR for this interrupt */
1217 lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used, 1216 lr = find_first_bit(elrsr_ptr, vgic->nr_lr);
1218 vgic->nr_lr);
1219 if (lr >= vgic->nr_lr) 1217 if (lr >= vgic->nr_lr)
1220 return false; 1218 return false;
1221 1219
1222 kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id); 1220 kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
1223 vgic_cpu->vgic_irq_lr_map[irq] = lr;
1224 set_bit(lr, vgic_cpu->lr_used);
1225 1221
1226 vlr.irq = irq; 1222 vlr.irq = irq;
1227 vlr.source = sgi_source_id; 1223 vlr.source = sgi_source_id;
@@ -1456,7 +1452,6 @@ static bool vgic_sync_hwirq(struct kvm_vcpu *vcpu, int lr, struct vgic_lr vlr)
1456/* Sync back the VGIC state after a guest run */ 1452/* Sync back the VGIC state after a guest run */
1457static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) 1453static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
1458{ 1454{
1459 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
1460 struct vgic_dist *dist = &vcpu->kvm->arch.vgic; 1455 struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
1461 u64 elrsr; 1456 u64 elrsr;
1462 unsigned long *elrsr_ptr; 1457 unsigned long *elrsr_ptr;
@@ -1469,22 +1464,10 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
1469 1464
1470 /* Deal with HW interrupts, and clear mappings for empty LRs */ 1465 /* Deal with HW interrupts, and clear mappings for empty LRs */
1471 for (lr = 0; lr < vgic->nr_lr; lr++) { 1466 for (lr = 0; lr < vgic->nr_lr; lr++) {
1472 struct vgic_lr vlr; 1467 struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
1473
1474 if (!test_bit(lr, vgic_cpu->lr_used))
1475 continue;
1476
1477 vlr = vgic_get_lr(vcpu, lr);
1478 if (vgic_sync_hwirq(vcpu, lr, vlr))
1479 level_pending = true;
1480
1481 if (!test_bit(lr, elrsr_ptr))
1482 continue;
1483
1484 clear_bit(lr, vgic_cpu->lr_used);
1485 1468
1469 level_pending |= vgic_sync_hwirq(vcpu, lr, vlr);
1486 BUG_ON(vlr.irq >= dist->nr_irqs); 1470 BUG_ON(vlr.irq >= dist->nr_irqs);
1487 vgic_cpu->vgic_irq_lr_map[vlr.irq] = LR_EMPTY;
1488 } 1471 }
1489 1472
1490 /* Check if we still have something up our sleeve... */ 1473 /* Check if we still have something up our sleeve... */
@@ -1912,12 +1895,10 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
1912 kfree(vgic_cpu->pending_shared); 1895 kfree(vgic_cpu->pending_shared);
1913 kfree(vgic_cpu->active_shared); 1896 kfree(vgic_cpu->active_shared);
1914 kfree(vgic_cpu->pend_act_shared); 1897 kfree(vgic_cpu->pend_act_shared);
1915 kfree(vgic_cpu->vgic_irq_lr_map);
1916 vgic_destroy_irq_phys_map(vcpu->kvm, &vgic_cpu->irq_phys_map_list); 1898 vgic_destroy_irq_phys_map(vcpu->kvm, &vgic_cpu->irq_phys_map_list);
1917 vgic_cpu->pending_shared = NULL; 1899 vgic_cpu->pending_shared = NULL;
1918 vgic_cpu->active_shared = NULL; 1900 vgic_cpu->active_shared = NULL;
1919 vgic_cpu->pend_act_shared = NULL; 1901 vgic_cpu->pend_act_shared = NULL;
1920 vgic_cpu->vgic_irq_lr_map = NULL;
1921} 1902}
1922 1903
1923static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs) 1904static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
@@ -1928,18 +1909,14 @@ static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
1928 vgic_cpu->pending_shared = kzalloc(sz, GFP_KERNEL); 1909 vgic_cpu->pending_shared = kzalloc(sz, GFP_KERNEL);
1929 vgic_cpu->active_shared = kzalloc(sz, GFP_KERNEL); 1910 vgic_cpu->active_shared = kzalloc(sz, GFP_KERNEL);
1930 vgic_cpu->pend_act_shared = kzalloc(sz, GFP_KERNEL); 1911 vgic_cpu->pend_act_shared = kzalloc(sz, GFP_KERNEL);
1931 vgic_cpu->vgic_irq_lr_map = kmalloc(nr_irqs, GFP_KERNEL);
1932 1912
1933 if (!vgic_cpu->pending_shared 1913 if (!vgic_cpu->pending_shared
1934 || !vgic_cpu->active_shared 1914 || !vgic_cpu->active_shared
1935 || !vgic_cpu->pend_act_shared 1915 || !vgic_cpu->pend_act_shared) {
1936 || !vgic_cpu->vgic_irq_lr_map) {
1937 kvm_vgic_vcpu_destroy(vcpu); 1916 kvm_vgic_vcpu_destroy(vcpu);
1938 return -ENOMEM; 1917 return -ENOMEM;
1939 } 1918 }
1940 1919
1941 memset(vgic_cpu->vgic_irq_lr_map, LR_EMPTY, nr_irqs);
1942
1943 /* 1920 /*
1944 * Store the number of LRs per vcpu, so we don't have to go 1921 * Store the number of LRs per vcpu, so we don't have to go
1945 * all the way to the distributor structure to find out. Only 1922 * all the way to the distributor structure to find out. Only