mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-27 22:24:11 +08:00
KVM: arm64: vgic: Implement SW-driven deactivation
In order to deal with these systems that do not offer HW-based deactivation of interrupts, let implement a SW-based approach: - When the irq is queued into a LR, treat it as a pure virtual interrupt and set the EOI flag in the LR. - When the interrupt state is read back from the LR, force a deactivation when the state is invalid (neither active nor pending) Interrupts requiring such treatment get the VGIC_SW_RESAMPLE flag. Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
parent
db75f1a33f
commit
354920e794
@ -108,11 +108,22 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
* If this causes us to lower the level, we have to also clear
|
||||
* the physical active state, since we will otherwise never be
|
||||
* told when the interrupt becomes asserted again.
|
||||
*
|
||||
* Another case is when the interrupt requires a helping hand
|
||||
* on deactivation (no HW deactivation, for example).
|
||||
*/
|
||||
if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
|
||||
irq->line_level = vgic_get_phys_line_level(irq);
|
||||
if (vgic_irq_is_mapped_level(irq)) {
|
||||
bool resample = false;
|
||||
|
||||
if (!irq->line_level)
|
||||
if (val & GICH_LR_PENDING_BIT) {
|
||||
irq->line_level = vgic_get_phys_line_level(irq);
|
||||
resample = !irq->line_level;
|
||||
} else if (vgic_irq_needs_resampling(irq) &&
|
||||
!(irq->active || irq->pending_latch)) {
|
||||
resample = true;
|
||||
}
|
||||
|
||||
if (resample)
|
||||
vgic_irq_set_phys_active(irq, false);
|
||||
}
|
||||
|
||||
@ -152,7 +163,7 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
|
||||
if (irq->group)
|
||||
val |= GICH_LR_GROUP1;
|
||||
|
||||
if (irq->hw) {
|
||||
if (irq->hw && !vgic_irq_needs_resampling(irq)) {
|
||||
val |= GICH_LR_HW;
|
||||
val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
|
||||
/*
|
||||
|
@ -101,11 +101,22 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
* If this causes us to lower the level, we have to also clear
|
||||
* the physical active state, since we will otherwise never be
|
||||
* told when the interrupt becomes asserted again.
|
||||
*
|
||||
* Another case is when the interrupt requires a helping hand
|
||||
* on deactivation (no HW deactivation, for example).
|
||||
*/
|
||||
if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
|
||||
irq->line_level = vgic_get_phys_line_level(irq);
|
||||
if (vgic_irq_is_mapped_level(irq)) {
|
||||
bool resample = false;
|
||||
|
||||
if (!irq->line_level)
|
||||
if (val & ICH_LR_PENDING_BIT) {
|
||||
irq->line_level = vgic_get_phys_line_level(irq);
|
||||
resample = !irq->line_level;
|
||||
} else if (vgic_irq_needs_resampling(irq) &&
|
||||
!(irq->active || irq->pending_latch)) {
|
||||
resample = true;
|
||||
}
|
||||
|
||||
if (resample)
|
||||
vgic_irq_set_phys_active(irq, false);
|
||||
}
|
||||
|
||||
@ -136,7 +147,7 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
|
||||
}
|
||||
}
|
||||
|
||||
if (irq->hw) {
|
||||
if (irq->hw && !vgic_irq_needs_resampling(irq)) {
|
||||
val |= ICH_LR_HW;
|
||||
val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
|
||||
/*
|
||||
|
@ -99,6 +99,11 @@ enum vgic_irq_config {
|
||||
* kvm_arm_get_running_vcpu() to get the vcpu pointer for private IRQs.
|
||||
*/
|
||||
struct irq_ops {
|
||||
/* Per interrupt flags for special-cased interrupts */
|
||||
unsigned long flags;
|
||||
|
||||
#define VGIC_IRQ_SW_RESAMPLE BIT(0) /* Clear the active state for resampling */
|
||||
|
||||
/*
|
||||
* Callback function pointer to in-kernel devices that can tell us the
|
||||
* state of the input level of mapped level-triggered IRQ faster than
|
||||
@ -150,6 +155,11 @@ struct vgic_irq {
|
||||
for in-kernel devices. */
|
||||
};
|
||||
|
||||
static inline bool vgic_irq_needs_resampling(struct vgic_irq *irq)
|
||||
{
|
||||
return irq->ops && (irq->ops->flags & VGIC_IRQ_SW_RESAMPLE);
|
||||
}
|
||||
|
||||
struct vgic_register_region;
|
||||
struct vgic_its;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user