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: vgic: Split out mapping IRQs and setting irq_ops

Prior to this change, the act of mapping a virtual IRQ to a physical
one also set the irq_ops. Unmapping then reset the irq_ops to NULL. So
far, this has been fine and hasn't caused any major issues.

Now, however, as GICv5 support is being added to KVM, it has become
apparent that conflating mapping/unmapping IRQs and setting/clearing
irq_ops can cause issues. The reason is that the upcoming GICv5
support introduces a set of default irq_ops for PPIs, and removing
this when unmapping will cause things to break rather horribly.

Split out the mapping/unmapping of IRQs from the setting/clearing of
irq_ops. The arch timer code is updated to set the irq_ops following a
successful map. The irq_ops are intentionally not removed again on an
unmap as the only irq_op introduced by the arch timer only takes
effect if the hw bit in struct vgic_irq is set. Therefore, it is safe
to leave this in place, and it avoids additional complexity when GICv5
support is introduced.

Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
Link: https://patch.msgid.link/20260319154937.3619520-6-sascha.bischoff@arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>

authored by

Sascha Bischoff and committed by
Marc Zyngier
663594aa cbd8c958

+36 -18
+11 -11
arch/arm64/kvm/arch_timer.c
··· 740 740 741 741 ret = kvm_vgic_map_phys_irq(vcpu, 742 742 map->direct_vtimer->host_timer_irq, 743 - timer_irq(map->direct_vtimer), 744 - &arch_timer_irq_ops); 743 + timer_irq(map->direct_vtimer)); 745 744 WARN_ON_ONCE(ret); 746 745 ret = kvm_vgic_map_phys_irq(vcpu, 747 746 map->direct_ptimer->host_timer_irq, 748 - timer_irq(map->direct_ptimer), 749 - &arch_timer_irq_ops); 747 + timer_irq(map->direct_ptimer)); 750 748 WARN_ON_ONCE(ret); 751 749 } 752 750 } ··· 1541 1543 { 1542 1544 struct arch_timer_cpu *timer = vcpu_timer(vcpu); 1543 1545 struct timer_map map; 1546 + struct irq_ops *ops; 1544 1547 int ret; 1545 1548 1546 1549 if (timer->enabled) ··· 1562 1563 1563 1564 get_timer_map(vcpu, &map); 1564 1565 1566 + ops = &arch_timer_irq_ops; 1567 + 1568 + for (int i = 0; i < nr_timers(vcpu); i++) 1569 + kvm_vgic_set_irq_ops(vcpu, timer_irq(vcpu_get_timer(vcpu, i)), ops); 1570 + 1565 1571 ret = kvm_vgic_map_phys_irq(vcpu, 1566 1572 map.direct_vtimer->host_timer_irq, 1567 - timer_irq(map.direct_vtimer), 1568 - &arch_timer_irq_ops); 1573 + timer_irq(map.direct_vtimer)); 1569 1574 if (ret) 1570 1575 return ret; 1571 1576 1572 - if (map.direct_ptimer) { 1577 + if (map.direct_ptimer) 1573 1578 ret = kvm_vgic_map_phys_irq(vcpu, 1574 1579 map.direct_ptimer->host_timer_irq, 1575 - timer_irq(map.direct_ptimer), 1576 - &arch_timer_irq_ops); 1577 - } 1578 - 1580 + timer_irq(map.direct_ptimer)); 1579 1581 if (ret) 1580 1582 return ret; 1581 1583
+21 -6
arch/arm64/kvm/vgic/vgic.c
··· 553 553 return 0; 554 554 } 555 555 556 + void kvm_vgic_set_irq_ops(struct kvm_vcpu *vcpu, u32 vintid, 557 + struct irq_ops *ops) 558 + { 559 + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, vintid); 560 + 561 + BUG_ON(!irq); 562 + 563 + scoped_guard(raw_spinlock_irqsave, &irq->irq_lock) 564 + irq->ops = ops; 565 + 566 + vgic_put_irq(vcpu->kvm, irq); 567 + } 568 + 569 + void kvm_vgic_clear_irq_ops(struct kvm_vcpu *vcpu, u32 vintid) 570 + { 571 + kvm_vgic_set_irq_ops(vcpu, vintid, NULL); 572 + } 573 + 556 574 /* @irq->irq_lock must be held */ 557 575 static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq, 558 - unsigned int host_irq, 559 - struct irq_ops *ops) 576 + unsigned int host_irq) 560 577 { 561 578 struct irq_desc *desc; 562 579 struct irq_data *data; ··· 593 576 irq->hw = true; 594 577 irq->host_irq = host_irq; 595 578 irq->hwintid = data->hwirq; 596 - irq->ops = ops; 597 579 return 0; 598 580 } 599 581 ··· 601 585 { 602 586 irq->hw = false; 603 587 irq->hwintid = 0; 604 - irq->ops = NULL; 605 588 } 606 589 607 590 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq, 608 - u32 vintid, struct irq_ops *ops) 591 + u32 vintid) 609 592 { 610 593 struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, vintid); 611 594 unsigned long flags; ··· 613 598 BUG_ON(!irq); 614 599 615 600 raw_spin_lock_irqsave(&irq->irq_lock, flags); 616 - ret = kvm_vgic_map_irq(vcpu, irq, host_irq, ops); 601 + ret = kvm_vgic_map_irq(vcpu, irq, host_irq); 617 602 raw_spin_unlock_irqrestore(&irq->irq_lock, flags); 618 603 vgic_put_irq(vcpu->kvm, irq); 619 604
+4 -1
include/kvm/arm_vgic.h
··· 397 397 398 398 int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu, 399 399 unsigned int intid, bool level, void *owner); 400 + void kvm_vgic_set_irq_ops(struct kvm_vcpu *vcpu, u32 vintid, 401 + struct irq_ops *ops); 402 + void kvm_vgic_clear_irq_ops(struct kvm_vcpu *vcpu, u32 vintid); 400 403 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq, 401 - u32 vintid, struct irq_ops *ops); 404 + u32 vintid); 402 405 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid); 403 406 int kvm_vgic_get_map(struct kvm_vcpu *vcpu, unsigned int vintid); 404 407 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);