Re: [PATCH 1/3] ARM: KVM: make vgic_inject_irq() compute only one IRQ

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Sep 11, 2012 at 2:50 PM, Marc Zyngier <marc.zyngier@xxxxxxx> wrote:
> Recomputing the whole GIC state when injecting a single interrupt
> is a tiny bit silly.
>
> Instead, just computing the new state for this particular IRQ saves
> a bit of processing and makes things noticeably faster.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx>
> ---
>  arch/arm/include/asm/kvm_vgic.h |  1 +
>  arch/arm/kvm/vgic.c             | 51 +++++++++++++++++++++++++++++++++--------
>  2 files changed, 42 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h
> index 5efc94d..84a3177 100644
> --- a/arch/arm/include/asm/kvm_vgic.h
> +++ b/arch/arm/include/asm/kvm_vgic.h
> @@ -183,6 +183,7 @@ struct vgic_dist {
>         u8                      irq_sgi_sources[VGIC_MAX_CPUS][16];
>
>         /* Target CPU for each IRQ */
> +       u8                      irq_spi_cpu[VGIC_NR_SHARED_IRQS];
>         struct vgic_bitmap      irq_spi_target[VGIC_MAX_CPUS];
>
>         /* Bitmap indicating which CPU has something pending */
> diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
> index 6581ad0..fd8865d 100644
> --- a/arch/arm/kvm/vgic.c
> +++ b/arch/arm/kvm/vgic.c
> @@ -47,6 +47,9 @@
>   *     registers, stored on each vcpu. We only keep one bit of
>   *     information per interrupt, making sure that only one vcpu can
>   *     accept the interrupt.
> + *   The same is true when injecting an interrupt, except that we only
> + *   consider a single interrupt at a time. The irq_spi_cpu array
> + *   contains the target CPU for each SPI.
>   *
>   * The handling of level interrupts adds some extra complexity. We
>   * need to track when the interrupt has been EOIed, so we can sample
> @@ -313,6 +316,7 @@ static void vgic_set_target_reg(struct kvm *kvm, u32 val, int irq)
>                 int shift = i * 8;
>                 target = ffs((val >> shift) & 0xffU);
>                 target = target ? (target - 1) : 0;
> +               dist->irq_spi_cpu[irq + i] = target;
>                 kvm_for_each_vcpu(c, vcpu, kvm) {
>                         bmap = vgic_bitmap_get_shared_map(&dist->irq_spi_target[c]);
>                         if (c == target)
> @@ -866,15 +870,17 @@ static void vgic_kick_vcpus(struct kvm *kvm)
>         }
>  }
>
> -int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
> -                       bool level)
> +static bool vgic_update_irq_state(struct kvm *kvm, int cpuid,
> +                                 unsigned int irq_num, bool level)
>  {
>         struct vgic_dist *dist = &kvm->arch.vgic;
> +       struct kvm_vcpu *vcpu;
>         int is_edge, state;
> +       int pend, enabled;
>         unsigned long flags;
> -       bool updated_state = false;
>
>         spin_lock_irqsave(&dist->lock, flags);
> +
>         is_edge = vgic_irq_is_edge(dist, irq_num);
>         state = vgic_bitmap_get_irq_val(&dist->irq_state, cpuid, irq_num);
>
> @@ -883,16 +889,41 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
>          * - level triggered and we change level
>          * - edge triggered and we have a rising edge
>          */
> -       if ((!is_edge && (state ^ level)) ||
> -           (is_edge && !state && level)) {
> -               vgic_bitmap_set_irq_val(&dist->irq_state, cpuid,
> -                                       irq_num, level);
> -               vgic_update_state(kvm);
> -               updated_state = true;
> +       if (!((!is_edge && (state ^ level)) ||
> +             (is_edge && !state && level))) {
> +               spin_unlock_irqrestore(&dist->lock, flags);
> +               return false;
>         }

this really needs to be more readable, but I'll change it.

> +
> +       vgic_bitmap_set_irq_val(&dist->irq_state, cpuid, irq_num, level);
> +
> +       enabled = vgic_bitmap_get_irq_val(&dist->irq_enabled, cpuid, irq_num);
> +       pend = level && enabled;
> +
> +       if (irq_num >= 32) {
> +               cpuid = dist->irq_spi_cpu[irq_num - 32];
> +               pend &= vgic_bitmap_get_irq_val(&dist->irq_spi_target[cpuid],
> +                                               0, irq_num);
> +       }
> +
> +       kvm_debug("Inject IRQ%d level %d CPU%d\n", irq_num, level, cpuid);
> +
> +       vcpu = kvm_get_vcpu(kvm, cpuid);
> +       if (pend) {
> +               set_bit(irq_num, vcpu->arch.vgic_cpu.pending);
> +               set_bit(cpuid, &dist->irq_pending_on_cpu);
> +       } else
> +               clear_bit(irq_num, vcpu->arch.vgic_cpu.pending);
> +
>         spin_unlock_irqrestore(&dist->lock, flags);
>
> -       if (updated_state)
> +       return true;
> +}
> +
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
> +                       bool level)
> +{
> +       if (vgic_update_irq_state(kvm, cpuid, irq_num, level))
>                 vgic_kick_vcpus(kvm);
>
>         return 0;
> --
> 1.7.12
>

thanks, applied (with updated logic statement)

-Christoffer
_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm


[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux