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

Re: [Xen-devel] [RFC PATCH] xen/arm: Deliver interrupts to vcpu specified in IROUTER



The only additional info that Xen provides is via the CTRL-AAA menu.
Some details on the GIC are printed but nothing as well organized as
/proc/interrupts.

On Wed, 10 Sep 2014, Vijay Kilari wrote:
> Hi Stefano,
> 
>  Is there way to see irq stats at vcpu level for a domain similar to
> /proc/interrupts?
> 
> Regards
> Vijay
> 
> On Tue, Sep 9, 2014 at 4:52 AM, Stefano Stabellini
> <stefano.stabellini@xxxxxxxxxxxxx> wrote:
> > On Mon, 8 Sep 2014, Vijay Kilari wrote:
> >> Hi Stefano,
> >>
> >> On Sat, Sep 6, 2014 at 12:14 AM, Stefano Stabellini
> >> <stefano.stabellini@xxxxxxxxxxxxx> wrote:
> >> > On Fri, 5 Sep 2014, Vijay Kilari wrote:
> >> >> On Fri, Sep 5, 2014 at 4:59 AM, Stefano Stabellini
> >> >> <stefano.stabellini@xxxxxxxxxxxxx> wrote:
> >> >> > On Thu, 4 Sep 2014, vijay.kilari@xxxxxxxxx wrote:
> >> >> >> From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
> >> >> >>
> >> >> >> In GICv3 use IROUTER register contents to
> >> >> >> deliver irq to specified vcpu's.
> >> >> >>
> >> >> >> In error scenario fallback to vcpu 0.
> >> >> >>
> >> >> >> This patch is similar to Stefano's commit
> >> >> >> 5b3a817ea33b891caf7d7d788da9ce6deffa82a1 for GICv2
> >> >> >>
> >> >> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
> >> >> >> ---
> >> >> >>  xen/arch/arm/vgic-v3.c |  115 
> >> >> >> ++++++++++++++++++++++++++++++++++++++++++++----
> >> >> >>  1 file changed, 106 insertions(+), 9 deletions(-)
> >> >> >>
> >> >> >> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> >> >> >> index ecda672..b01a201 100644
> >> >> >> --- a/xen/arch/arm/vgic-v3.c
> >> >> >> +++ b/xen/arch/arm/vgic-v3.c
> >> >> >> @@ -45,6 +45,35 @@
> >> >> >>  #define GICV3_GICR_PIDR2  GICV3_GICD_PIDR2
> >> >> >>  #define GICV3_GICR_PIDR4  GICV3_GICD_PIDR4
> >> >> >>
> >> >> >> +static struct vcpu *vgicv3_irouter_to_vcpu(struct vcpu *v,
> >> >> >> +                                           uint64_t irouter_aff)
> >> >> >> +{
> >> >> >> +    int i;
> >> >> >> +    uint64_t cpu_affinity;
> >> >> >> +    struct vcpu *v_target = NULL;
> >> >> >> +
> >> >> >> +    /* If routing mode is set. Fallback to vcpu0 */
> >> >> >> +    if ( irouter_aff & GICD_IROUTER_SPI_MODE_ANY )
> >> >> >> +        return v->domain->vcpu[0];
> >> >> >> +
> >> >> >> +    for ( i = 0; i < v->domain->max_vcpus; i++ )
> >> >> >> +    {
> >> >> >> +        v_target = v->domain->vcpu[i];
> >> >> >> +        cpu_affinity = (MPIDR_AFFINITY_LEVEL(v_target->arch.vmpidr, 
> >> >> >> 3) << 32 |
> >> >> >> +                        MPIDR_AFFINITY_LEVEL(v_target->arch.vmpidr, 
> >> >> >> 2) << 16 |
> >> >> >> +                        MPIDR_AFFINITY_LEVEL(v_target->arch.vmpidr, 
> >> >> >> 1) << 8  |
> >> >> >> +                        MPIDR_AFFINITY_LEVEL(v_target->arch.vmpidr, 
> >> >> >> 0));
> >> >> >> +
> >> >> >> +        if ( irouter_aff == cpu_affinity )
> >> >> >> +            return v_target;
> >> >> >> +    }
> >> >> >
> >> >> > Using a loop is pretty bad. Couldn't you just calculate the lowest 
> >> >> > vcpu
> >> >> > number from irouter_aff (maybe using find_first_bit)?
> >> >>
> >> >> IMO,  If GICD_IROUTER_SPI_MODE_ANY bit is set, then it specifies any 
> >> >> cpu.
> >> >> If GICD_IROUTER_SPI_MODE_ANY is not set, it register specifies only
> >> >> one cpu number.
> >> >>
> >> >> So we cannot use find_first_bit() unlike GICv2 where ITARGET specifies
> >> >> irq affinity
> >> >> to more than one CPU.
> >> >>
> >> >> If at all we want to avoid this for loop, then we have to maintain one
> >> >> more variable for
> >> >> every IROUTERn and corresponding vpcu number, which is updated on
> >> >> IROUTERn update
> >> >
> >> > Given that at the moment AFF0 is just set to vcpu_id (see
> >> > vcpu_initialise), I would simply do a direct calculation, adding a TODO
> >> > comment so that we remember to fix this when we implement smarter mpidr
> >> > schemes.
> >>
> >> Instead of storing vcpu_id in AFF0 of vgic irouter[], we could rather
> >> store vcpu_id in irouter[]
> >> similar to v2. One bit per vcpu, though in v3 always only one bit is set.
> >>
> >> The conversion function irouter_to_vcpu & vcpu_to_irouter will manage
> >> mmio_{read,write}
> >> of IROUTER regs.
> >>
> >> Is this OK?
> >
> > Sounds good in principle, but of course I would need to see the code to
> > get a better idea.
> >
> >
> >> >
> >> > Even better you could introduce two simple functions that convert vmpidr
> >> > to vcpu_id and vice versa, so that we keep all the hacks in one place.
> >> >
> >> >
> >> >> >>      switch ( gicd_reg )
> >> >> >> @@ -804,16 +836,42 @@ static int vgic_v3_distr_mmio_write(struct 
> >> >> >> vcpu *v, mmio_info_t *info)
> >> >> >>          if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> >> >> >>          rank = vgic_rank_offset(v, 64, gicd_reg - GICD_IROUTER, 
> >> >> >> DABT_DOUBLE_WORD);
> >> >> >>          if ( rank == NULL) goto write_ignore_64;
> >> >> >> -        if ( *r )
> >> >> >> +        new_target = *r;
> >> >> >> +        vgic_lock_rank(v, rank, flags);
> >> >> >> +        old_target = rank->v3.irouter[REG_RANK_INDEX(64,
> >> >> >> +                              (gicd_reg - GICD_IROUTER), 
> >> >> >> DABT_DOUBLE_WORD)];
> >> >> >> +        if ( *r & GICD_IROUTER_SPI_MODE_ANY )
> >> >> >>          {
> >> >> >> -            /* TODO: Ignored. We don't support irq delivery for 
> >> >> >> vcpu != 0 */
> >> >> >> -            gdprintk(XENLOG_DEBUG,
> >> >> >> -                     "SPI delivery to secondary cpus not 
> >> >> >> supported\n");
> >> >> >> -            goto write_ignore_64;
> >> >> >> +            /*
> >> >> >> +             * IRQ routing mode set. Route any one processor in the 
> >> >> >> entire
> >> >> >> +             * system. We chose vcpu 0
> >> >> >> +             */
> >> >> >> +            rank->v3.irouter[REG_RANK_INDEX(64,
> >> >> >> +                     (gicd_reg - GICD_IROUTER), DABT_DOUBLE_WORD)] 
> >> >> >> = *r;
> >> >> >> +            vgic_unlock_rank(v, rank, flags);
> >> >> >> +            return 1;
> >> >> >>          }
> >> >> >> -        vgic_lock_rank(v, rank, flags);
> >> >> >> +        irq = (gicd_reg - GICD_IROUTER)/8;
> >> >> >> +        /* IROUTER now specifies only one cpu affinity for this irq 
> >> >> >> */
> >> >> >> +        /* Migrate from any core(vcpu0) to new_target */
> >> >> >> +        if ( (old_target & GICD_IROUTER_SPI_MODE_ANY) &&
> >> >> >> +             !(new_target & GICD_IROUTER_SPI_MODE_ANY) )
> >> >> >> +        {
> >> >> >> +            new_vcpu = vgicv3_irouter_to_vcpu(v, new_target);
> >> >> >> +            vgic_migrate_irq(v->domain->vcpu[0], new_vcpu, irq);
> >> >> >> +        }
> >> >> >> +        else
> >> >> >> +        {
> >> >> >> +            if ( old_target != new_target )
> >> >> >> +            {
> >> >> >> +                old_vcpu = vgicv3_irouter_to_vcpu(v, old_target);
> >> >> >> +                new_vcpu = vgicv3_irouter_to_vcpu(v, new_target);
> >> >> >> +                vgic_migrate_irq(old_vcpu, new_vcpu, irq);
> >> >> >> +            }
> >> >> >> +        }
> >> >> >
> >> >> > The issue is that if irouter is GICD_IROUTER_SPI_MODE_ANY, you always
> >> >> > return vcpu0 below.
> >> >> > So if the kernel:
> >> >> >
> >> >> > 1) move the irq to vcpu1
> >> >> > 2) set the irq as GICD_IROUTER_SPI_MODE_ANY
> >> >> >
> >> >> > you now have migrated the irq to vcpu1 but you are returning vcpu0 
> >> >> > from
> >> >> > vgicv3_get_target_vcpu.
> >> >> >
> >> >> > You can either:
> >> >> > - vgic_migrate_irq the irq back to vcpu0 when the kernel sets the irq 
> >> >> > as
> >> >> >   GICD_IROUTER_SPI_MODE_ANY
> >> >>
> >> >>    When irq is set to vcpu1 and later when GICD_IROUTER_SPI_MODE_ANY
> >> >> then I assume that vcpu1 is also valid for the moment if irq is pending.
> >> >> So no need to do any migration.
> >> >
> >> > That would be OK, except that vgicv3_get_target_vcpu is actually
> >> > returning vcpu0. We should try to match physical and virtual irq
> >> > delivery as much as possible. So if the physical irq is delivered to
> >> > pcpu1 (or whatever is the pcpu currently running vcpu1), then we should
> >> > try hard to deliver the corresponding virq to vcpu1.
> >> >
> >> > Calling vgic_migrate_irq changes the physical irq affinity to the pcpu
> >> > running the destination vcpu. So step 1 above moves physical irq
> >> > delivery to pcpu1 (assuming that pcpu1 is running vcpu1 for simplicity).
> >> > After the guest kernel sets the irq as GICD_IROUTER_SPI_MODE_ANY, even
> >> > though we could deliver the irq to any vcpu, we should actually delivery
> >> > the irq to the vcpu running on the pcpu that received the interrupt. In
> >> > my example it would still be vcpu1. Therefore we need to return vcpu1
> >> > from vgicv3_get_target_vcpu.
> >> >
> >> > Instead as it is now, we would cause an SGI to be sent from pcpu1 to
> >> > pcpu0 in order to inject the irq to vcpu0 (assuming that vcpu0 is
> >> > running on pcpu0 for simplicity).
> >> >
> >> >
> >> >> Also, as per GICv3 spec, when GICD_IROUTER_SPI_MODE_ANY is set which is
> >> >> previous not set ( 0 -> 1 ), the affinity value in IROUTER is 
> >> >> invalid/unknown.
> >> >> So later when vgicv3_get_target_vcpu() is called, it always returns 
> >> >> vcpu0.
> >> >
> >> > Could you please tell me which one is the relevant chapter of the GICv3
> >> > spec? I couldn't find the statement you mentioned. Maybe my version of
> >> > the spec is outdated.
> >>
> >> See 20.0 version section 5.3.4
> >>
> >> "When this bit is written from zero to one, the Affinity fields become 
> >> UNKNOWN."
> >
> > Yeah, my version is outdated :-/
> >
> > In any case I would still recommend always keeping a valid value in
> > irouter. Maybe we just want to revert to vcpu0, but still it should be a
> > valid configuration.
> >
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.