Re: [PATCH 06/16] ARM: KVM: vgic: refactor level irq handling

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

 



On 13/12/12 21:52, Christoffer Dall wrote:
> 
> 
> On Thursday, December 6, 2012, Marc Zyngier wrote:
> 
>     Shuffle things around to make handling of level interrupts less
>     messy:
>     - encapsulate irq_active in accessors
>     - introduce vgic_queue_{sgi,hwirq} functions
>     - vgic_is_edge now takes a vcpu instrad of a distributor
> 
> 
> instead
>  
> 
> 
>     Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx <javascript:;>>
>     ---
>      arch/arm/kvm/vgic.c | 172
>     ++++++++++++++++++++++++++++++----------------------
>      1 file changed, 100 insertions(+), 72 deletions(-)
> 
>     diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
>     index 11a4416..d666df7 100644
>     --- a/arch/arm/kvm/vgic.c
>     +++ b/arch/arm/kvm/vgic.c
>     @@ -154,9 +154,11 @@ static u32 *vgic_bytemap_get_reg(struct
>     vgic_bytemap *x, int cpuid, u32 offset)
>      #define VGIC_CFG_LEVEL 0
>      #define VGIC_CFG_EDGE  1
> 
>     -static bool vgic_irq_is_edge(struct vgic_dist *dist, int irq)
>     +static bool vgic_irq_is_edge(struct kvm_vcpu *vcpu, int irq)
>      {
>     -       return vgic_bitmap_get_irq_val(&dist->irq_cfg, 0, irq) ==
>     VGIC_CFG_EDGE;
>     +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     +
>     +       return vgic_bitmap_get_irq_val(&dist->irq_cfg,
>     vcpu->vcpu_id, irq) == VGIC_CFG_EDGE;
>      }
> 
>      static int vgic_irq_is_enabled(struct kvm_vcpu *vcpu, int irq)
>     @@ -166,6 +168,31 @@ static int vgic_irq_is_enabled(struct kvm_vcpu
>     *vcpu, int irq)
>             return vgic_bitmap_get_irq_val(&dist->irq_enabled,
>     vcpu->vcpu_id, irq);
>      }
> 
>     +static int vgic_irq_is_active(struct kvm_vcpu *vcpu, int irq)
>     +{
>     +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     +
>     +       return vgic_bitmap_get_irq_val(&dist->irq_active,
>     vcpu->vcpu_id, irq);
>     +}
>     +
>     +static void vgic_irq_set_active(struct kvm_vcpu *vcpu, int irq)
>     +{
>     +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     +
>     +       vgic_bitmap_set_irq_val(&dist->irq_active, vcpu->vcpu_id,
>     irq, 1);
>     +       atomic_inc(&vcpu->arch.vgic_cpu.irq_active_count);
>     +       smp_mb__after_atomic_inc();
>     +}
>     +
>     +static void vgic_irq_clear_active(struct kvm_vcpu *vcpu, int irq)
>     +{
>     +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     +
>     +       vgic_bitmap_set_irq_val(&dist->irq_active, vcpu->vcpu_id,
>     irq, 0);
>     +       atomic_dec(&vcpu->arch.vgic_cpu.irq_active_count);
>     +       smp_mb__after_atomic_dec();
> 
> 
> uf, could we have a comment explaining these memory barriers?
> 
> Specifically, what is the change after the decrement, which must be
> perceived after the decrement from another cpu?

There is a long thread about this:
https://patchwork.kernel.org/patch/1724141/

and a subsequent patch removes completely the feature.

> 
>     +}
>     +
>      static void vgic_dist_irq_set(struct kvm_vcpu *vcpu, int irq)
>      {
>             struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     @@ -809,8 +836,7 @@ static void vgic_retire_disabled_irqs(struct
>     kvm_vcpu *vcpu)
>      static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id,
>     int irq)
>      {
>             struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>     -       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     -       int lr, is_level;
>     +       int lr;
> 
>             /* Sanitize the input... */
>             BUG_ON(sgi_source_id & ~7);
>     @@ -820,7 +846,6 @@ static bool vgic_queue_irq(struct kvm_vcpu
>     *vcpu, u8 sgi_source_id, int irq)
>             kvm_debug("Queue IRQ%d\n", irq);
> 
>             lr = vgic_cpu->vgic_irq_lr_map[irq];
>     -       is_level = !vgic_irq_is_edge(dist, irq);
> 
>             /* Do we have an active interrupt for the same CPUID? */
>             if (lr != LR_EMPTY &&
>     @@ -828,11 +853,8 @@ static bool vgic_queue_irq(struct kvm_vcpu
>     *vcpu, u8 sgi_source_id, int irq)
>                     kvm_debug("LR%d piggyback for IRQ%d %x\n", lr, irq,
>     vgic_cpu->vgic_lr[lr]);
>                     BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
>                     vgic_cpu->vgic_lr[lr] |= VGIC_LR_PENDING_BIT;
>     -               if (is_level) {
>     -                       vgic_cpu->vgic_lr[lr] |= VGIC_LR_EOI;
>     -                       atomic_inc(&vgic_cpu->irq_active_count);
>     -               }
>     -               return true;
> 
> 
> 
> why is this no longer necessary?

It is still mandatory, but the below "goto" should give you a clue.

> 
>     +
>     +               goto out;
>             }
> 
>             /* Try to use another LR for this interrupt */
>     @@ -843,17 +865,68 @@ static bool vgic_queue_irq(struct kvm_vcpu
>     *vcpu, u8 sgi_source_id, int irq)
> 
>             kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq,
>     sgi_source_id);
>             vgic_cpu->vgic_lr[lr] = MK_LR_PEND(sgi_source_id, irq);
>     -       if (is_level) {
>     -               vgic_cpu->vgic_lr[lr] |= VGIC_LR_EOI;
>     -               atomic_inc(&vgic_cpu->irq_active_count);
>     -       }
>     -
> 
> 
> and this, why can it just be removed?

Same here.

>  
> 
>             vgic_cpu->vgic_irq_lr_map[irq] = lr;
>             set_bit(lr, vgic_cpu->lr_used);
> 
>     +out:
>     +       if (!vgic_irq_is_edge(vcpu, irq))
>     +               vgic_cpu->vgic_lr[lr] |= VGIC_LR_EOI;
>     +
>             return true;
>      }
> 
>     +static bool vgic_queue_sgi(struct kvm_vcpu *vcpu, int irq)
>     +{
>     +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     +       unsigned long sources;
>     +       int vcpu_id = vcpu->vcpu_id;
>     +       int c;
>     +
>     +       sources = dist->irq_sgi_sources[vcpu_id][irq];
>     +
>     +       for_each_set_bit(c, &sources, VGIC_MAX_CPUS) {
>     +               if (vgic_queue_irq(vcpu, c, irq))
>     +                       clear_bit(c, &sources);
>     +       }
>     +
>     +       dist->irq_sgi_sources[vcpu_id][irq] = sources;
>     +
>     +       /*
>     +        * If the sources bitmap has been cleared it means that we
>     +        * could queue all the SGIs onto link registers (see the
>     +        * clear_bit above), and therefore we are done with them in
>     +        * our emulated gic and can get rid of them.
>     +        */
>     +       if (!sources) {
>     +               vgic_dist_irq_clear(vcpu, irq);
>     +               vgic_cpu_irq_clear(vcpu, irq);
>     +               return true;
>     +       }
>     +
>     +       return false;
>     +}
>     +
>     +static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
>     +{
>     +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     +
>     +       if (vgic_bitmap_get_irq_val(&dist->irq_active,
>     vcpu->vcpu_id, irq))
>     +               return true; /* level interrupt, already queued */
>     +
>     +       if (vgic_queue_irq(vcpu, 0, irq)) {
>     +               if (vgic_irq_is_edge(vcpu, irq)) {
>     +                       vgic_dist_irq_clear(vcpu, irq);
>     +                       vgic_cpu_irq_clear(vcpu, irq);
>     +               } else {
>     +                       vgic_irq_set_active(vcpu, irq);
>     +               }
>     +
>     +               return true;
>     +       }
>     +
>     +       return false;
>     +}
>     +
>      /*
>       * Fill the list registers with pending interrupts before running the
>       * guest.
>     @@ -862,7 +935,7 @@ static void __kvm_vgic_sync_to_cpu(struct
>     kvm_vcpu *vcpu)
>      {
>             struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>             struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>     -       int i, c, vcpu_id;
>     +       int i, vcpu_id;
>             int overflow = 0;
> 
>             vcpu_id = vcpu->vcpu_id;
>     @@ -881,62 +954,20 @@ static void __kvm_vgic_sync_to_cpu(struct
>     kvm_vcpu *vcpu)
> 
>             /* SGIs */
>             for_each_set_bit(i, vgic_cpu->pending_percpu, VGIC_NR_SGIS) {
>     -               unsigned long sources;
>     -
>     -               sources = dist->irq_sgi_sources[vcpu_id][i];
>     -               for_each_set_bit(c, &sources, 8) {
>     -                       if (!vgic_queue_irq(vcpu, c, i)) {
>     -                               overflow = 1;
>     -                               continue;
>     -                       }
>     -
>     -                       clear_bit(c, &sources);
>     -               }
>     -
>     -               /*
>     -                * If the sources bitmap has been cleared it means
>     that we
>     -                * could queue all the SGIs onto link registers (see the
>     -                * clear_bit above), and therefore we are done with
>     them in
>     -                * our emulated gic and can get rid of them.
>     -                */
>     -               if (!sources) {
>     -                       vgic_dist_irq_clear(vcpu, i);
>     -                       vgic_cpu_irq_clear(vcpu, i);
>     -               }
>     -
>     -               dist->irq_sgi_sources[vcpu_id][i] = sources;
>     +               if (!vgic_queue_sgi(vcpu, i))
>     +                       overflow = 1;
>             }
> 
>             /* PPIs */
>             for_each_set_bit_from(i, vgic_cpu->pending_percpu,
>     VGIC_NR_PRIVATE_IRQS) {
>     -               if (!vgic_queue_irq(vcpu, 0, i)) {
>     +               if (!vgic_queue_hwirq(vcpu, i))
>                             overflow = 1;
>     -                       continue;
>     -               }
>     -
>     -               vgic_dist_irq_clear(vcpu, i);
>     -               vgic_cpu_irq_clear(vcpu, i);
>             }
> 
>     -
>             /* SPIs */
>             for_each_set_bit(i, vgic_cpu->pending_shared,
>     VGIC_NR_SHARED_IRQS) {
>     -               int irq = i + VGIC_NR_PRIVATE_IRQS;
>     -               if (vgic_bitmap_get_irq_val(&dist->irq_active, 0, irq))
>     -                       continue; /* level interrupt, already queued */
>     -
>     -               if (!vgic_queue_irq(vcpu, 0, irq)) {
>     +               if (!vgic_queue_hwirq(vcpu, i + VGIC_NR_PRIVATE_IRQS))
>                             overflow = 1;
>     -                       continue;
>     -               }
>     -
>     -               /* Immediate clear on edge, set active on level */
>     -               if (vgic_irq_is_edge(dist, irq)) {
>     -                       vgic_dist_irq_clear(vcpu, irq);
>     -                       vgic_cpu_irq_clear(vcpu, irq);
>     -               } else {
>     -                       vgic_bitmap_set_irq_val(&dist->irq_active,
>     0, irq, 1);
>     -               }
>             }
> 
>      epilog:
>     @@ -1044,7 +1075,8 @@ static bool vgic_update_irq_state(struct kvm
>     *kvm, int cpuid,
> 
>             spin_lock(&dist->lock);
> 
>     -       is_edge = vgic_irq_is_edge(dist, irq_num);
>     +       vcpu = kvm_get_vcpu(kvm, cpuid);
>     +       is_edge = vgic_irq_is_edge(vcpu, irq_num);
>             is_level = !is_edge;
>             state = vgic_bitmap_get_irq_val(&dist->irq_state, cpuid,
>     irq_num);
> 
>     @@ -1058,13 +1090,13 @@ static bool vgic_update_irq_state(struct kvm
>     *kvm, int cpuid,
>                     goto out;
>             }
> 
>     -       if (irq_num >= VGIC_NR_PRIVATE_IRQS)
>     +       if (irq_num >= VGIC_NR_PRIVATE_IRQS) {
>                     cpuid = dist->irq_spi_cpu[irq_num -
>     VGIC_NR_PRIVATE_IRQS];
>     +               vcpu = kvm_get_vcpu(kvm, cpuid);
>     +       }
> 
>             kvm_debug("Inject IRQ%d level %d CPU%d\n", irq_num, level,
>     cpuid);
> 
>     -       vcpu = kvm_get_vcpu(kvm, cpuid);
>     -
>             if (level)
>                     vgic_dist_irq_set(vcpu, irq_num);
>             else
>     @@ -1077,8 +1109,7 @@ static bool vgic_update_irq_state(struct kvm
>     *kvm, int cpuid,
>                     goto out;
>             }
> 
>     -       if (is_level && vgic_bitmap_get_irq_val(&dist->irq_active,
>     -                                               cpuid, irq_num)) {
>     +       if (is_level && vgic_irq_is_active(vcpu, irq_num)) {
>                     /*
>                      * Level interrupt in progress, will be picked up
>                      * when EOId.
>     @@ -1159,10 +1190,7 @@ static irqreturn_t
>     vgic_maintenance_handler(int irq, void *data)
>                                      vgic_cpu->nr_lr) {
>                             irq = vgic_cpu->vgic_lr[lr] & VGIC_LR_VIRTUALID;
> 
>     -                       vgic_bitmap_set_irq_val(&dist->irq_active,
>     -                                               vcpu->vcpu_id, irq, 0);
>     -                       atomic_dec(&vgic_cpu->irq_active_count);
>     -                       smp_mb();
>     +                       vgic_irq_clear_active(vcpu, irq);
>                             vgic_cpu->vgic_lr[lr] &= ~VGIC_LR_EOI;
>                             writel_relaxed(vgic_cpu->vgic_lr[lr],
>                                            dist->vctrl_base + GICH_LR0 +
>     (lr << 2));
>     --
>     1.8.0.1
> 
> 
> 
>     _______________________________________________
>     kvmarm mailing list
>     kvmarm@xxxxxxxxxxxxxxxxxxxxx <javascript:;>
>     https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm
> 


-- 
Jazz is not dead. It just smells funny...


_______________________________________________
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