Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: arm64: Revamp vgic maintenance interrupt configuration

We currently don't use the maintenance interrupt very much, apart
from EOI on level interrupts, and for LR underflow in limited cases.

However, as we are moving toward a setup where active interrupts
can live outside of the LRs, we need to use the MIs in a more
diverse set of cases.

Add a new helper that produces a digest of the ap_list, and use
that summary to set the various control bits as required.

This slightly changes the way v2 SGIs are handled, as they used to
count for more than one interrupt, but not anymore.

Tested-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://msgid.link/20251120172540.2267180-22-maz@kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>

authored by

Marc Zyngier and committed by
Oliver Upton
6780a756 cf72ee63

+74 -66
+10 -2
arch/arm64/kvm/vgic/vgic-v2.c
··· 26 26 vgic_v2_write_lr(i, 0); 27 27 } 28 28 29 - void vgic_v2_set_underflow(struct kvm_vcpu *vcpu) 29 + void vgic_v2_configure_hcr(struct kvm_vcpu *vcpu, 30 + struct ap_list_summary *als) 30 31 { 31 32 struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2; 32 33 33 - cpuif->vgic_hcr |= GICH_HCR_UIE; 34 + cpuif->vgic_hcr = GICH_HCR_EN; 35 + 36 + if (irqs_pending_outside_lrs(als)) 37 + cpuif->vgic_hcr |= GICH_HCR_NPIE; 38 + if (irqs_active_outside_lrs(als)) 39 + cpuif->vgic_hcr |= GICH_HCR_LRENPIE; 40 + if (irqs_outside_lrs(als)) 41 + cpuif->vgic_hcr |= GICH_HCR_UIE; 34 42 } 35 43 36 44 static bool lr_signals_eoi_mi(u32 lr_val)
+16 -2
arch/arm64/kvm/vgic/vgic-v3.c
··· 20 20 static bool dir_trap; 21 21 static bool gicv4_enable; 22 22 23 - void vgic_v3_set_underflow(struct kvm_vcpu *vcpu) 23 + void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, 24 + struct ap_list_summary *als) 24 25 { 25 26 struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3; 26 27 27 - cpuif->vgic_hcr |= ICH_HCR_EL2_UIE; 28 + if (!irqchip_in_kernel(vcpu->kvm)) 29 + return; 30 + 31 + cpuif->vgic_hcr = ICH_HCR_EL2_En; 32 + 33 + if (irqs_pending_outside_lrs(als)) 34 + cpuif->vgic_hcr |= ICH_HCR_EL2_NPIE; 35 + if (irqs_active_outside_lrs(als)) 36 + cpuif->vgic_hcr |= ICH_HCR_EL2_LRENPIE; 37 + if (irqs_outside_lrs(als)) 38 + cpuif->vgic_hcr |= ICH_HCR_EL2_UIE; 39 + 40 + if (!als->nr_sgi) 41 + cpuif->vgic_hcr |= ICH_HCR_EL2_vSGIEOICount; 28 42 } 29 43 30 44 static bool lr_signals_eoi_mi(u64 lr_val)
+31 -60
arch/arm64/kvm/vgic/vgic.c
··· 791 791 vgic_v3_clear_lr(vcpu, lr); 792 792 } 793 793 794 - static inline void vgic_set_underflow(struct kvm_vcpu *vcpu) 795 - { 796 - if (kvm_vgic_global_state.type == VGIC_V2) 797 - vgic_v2_set_underflow(vcpu); 798 - else 799 - vgic_v3_set_underflow(vcpu); 800 - } 801 - 802 - /* Requires the ap_list_lock to be held. */ 803 - static int compute_ap_list_depth(struct kvm_vcpu *vcpu, 804 - bool *multi_sgi) 794 + static void summarize_ap_list(struct kvm_vcpu *vcpu, 795 + struct ap_list_summary *als) 805 796 { 806 797 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 807 798 struct vgic_irq *irq; 808 - int count = 0; 809 - 810 - *multi_sgi = false; 811 799 812 800 lockdep_assert_held(&vgic_cpu->ap_list_lock); 813 801 802 + *als = (typeof(*als)){}; 803 + 814 804 list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) { 815 - int w; 805 + guard(raw_spinlock)(&irq->irq_lock); 816 806 817 - raw_spin_lock(&irq->irq_lock); 818 - /* GICv2 SGIs can count for more than one... */ 819 - w = vgic_irq_get_lr_count(irq); 820 - raw_spin_unlock(&irq->irq_lock); 807 + if (unlikely(vgic_target_oracle(irq) != vcpu)) 808 + continue; 821 809 822 - count += w; 823 - *multi_sgi |= (w > 1); 810 + if (!irq->active) 811 + als->nr_pend++; 812 + else 813 + als->nr_act++; 814 + 815 + if (irq->intid < VGIC_NR_SGIS) 816 + als->nr_sgi++; 824 817 } 825 - return count; 826 818 } 827 819 828 820 /* ··· 900 908 static void vgic_flush_lr_state(struct kvm_vcpu *vcpu) 901 909 { 902 910 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 911 + struct ap_list_summary als; 903 912 struct vgic_irq *irq; 904 - int count; 905 - bool multi_sgi; 906 - u8 prio = 0xff; 907 - int i = 0; 913 + int count = 0; 908 914 909 915 lockdep_assert_held(&vgic_cpu->ap_list_lock); 910 916 911 - count = compute_ap_list_depth(vcpu, &multi_sgi); 912 - if (count > kvm_vgic_global_state.nr_lr || multi_sgi) 917 + summarize_ap_list(vcpu, &als); 918 + 919 + if (irqs_outside_lrs(&als)) 913 920 vgic_sort_ap_list(vcpu); 914 921 915 - count = 0; 916 - 917 922 list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) { 918 - raw_spin_lock(&irq->irq_lock); 923 + scoped_guard(raw_spinlock, &irq->irq_lock) { 924 + if (likely(vgic_target_oracle(irq) == vcpu)) { 925 + vgic_populate_lr(vcpu, irq, count++); 926 + } 927 + } 919 928 920 - /* 921 - * If we have multi-SGIs in the pipeline, we need to 922 - * guarantee that they are all seen before any IRQ of 923 - * lower priority. In that case, we need to filter out 924 - * these interrupts by exiting early. This is easy as 925 - * the AP list has been sorted already. 926 - */ 927 - if (multi_sgi && irq->priority > prio) { 928 - raw_spin_unlock(&irq->irq_lock); 929 + if (count == kvm_vgic_global_state.nr_lr) 929 930 break; 930 - } 931 - 932 - if (likely(vgic_target_oracle(irq) == vcpu)) { 933 - vgic_populate_lr(vcpu, irq, count++); 934 - 935 - if (irq->source) 936 - prio = irq->priority; 937 - } 938 - 939 - raw_spin_unlock(&irq->irq_lock); 940 - 941 - if (count == kvm_vgic_global_state.nr_lr) { 942 - if (!list_is_last(&irq->ap_list, 943 - &vgic_cpu->ap_list_head)) 944 - vgic_set_underflow(vcpu); 945 - break; 946 - } 947 931 } 948 932 949 933 /* Nuke remaining LRs */ 950 - for (i = count ; i < kvm_vgic_global_state.nr_lr; i++) 934 + for (int i = count ; i < kvm_vgic_global_state.nr_lr; i++) 951 935 vgic_clear_lr(vcpu, i); 952 936 953 - if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) 937 + if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) { 954 938 vcpu->arch.vgic_cpu.vgic_v2.used_lrs = count; 955 - else 939 + vgic_v2_configure_hcr(vcpu, &als); 940 + } else { 956 941 vcpu->arch.vgic_cpu.vgic_v3.used_lrs = count; 942 + vgic_v3_configure_hcr(vcpu, &als); 943 + } 957 944 } 958 945 959 946 static inline bool can_access_vgic_from_kernel(void)
+17 -2
arch/arm64/kvm/vgic/vgic.h
··· 236 236 u32 event_id; 237 237 }; 238 238 239 + struct ap_list_summary { 240 + unsigned int nr_pend; /* purely pending, not active */ 241 + unsigned int nr_act; /* active, or active+pending */ 242 + unsigned int nr_sgi; /* any SGI */ 243 + }; 244 + 245 + #define irqs_outside_lrs(s) \ 246 + (((s)->nr_pend + (s)->nr_act) > kvm_vgic_global_state.nr_lr) 247 + 248 + #define irqs_pending_outside_lrs(s) \ 249 + ((s)->nr_pend > kvm_vgic_global_state.nr_lr) 250 + 251 + #define irqs_active_outside_lrs(s) \ 252 + ((s)->nr_act && irqs_outside_lrs(s)) 253 + 239 254 int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, 240 255 struct vgic_reg_attr *reg_attr); 241 256 int vgic_v2_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, ··· 277 262 void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu); 278 263 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr); 279 264 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr); 280 - void vgic_v2_set_underflow(struct kvm_vcpu *vcpu); 265 + void vgic_v2_configure_hcr(struct kvm_vcpu *vcpu, struct ap_list_summary *als); 281 266 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr); 282 267 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write, 283 268 int offset, u32 *val); ··· 317 302 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu); 318 303 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr); 319 304 void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr); 320 - void vgic_v3_set_underflow(struct kvm_vcpu *vcpu); 305 + void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, struct ap_list_summary *als); 321 306 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr); 322 307 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr); 323 308 void vgic_v3_enable(struct kvm_vcpu *vcpu);