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

Re: [Xen-devel] [PATCH RFC] xen: arm: context switch vtimer PPI state.



On Mon, 2015-03-02 at 18:42 +0000, Stefano Stabellini wrote:
> On Tue, 10 Feb 2015, Ian Campbell wrote:
> > Stefano,
> > 
> > do you have any comments on the viability of the general approach here
> > before I go off and start addressing the review comments?
> 
> I think that the general approach is OK
> 
> 
> > Cheers,
> > Ian.
> > 
> > On Mon, 2015-01-26 at 15:55 +0000, Ian Campbell wrote:
> > > ... instead of artificially masking the timer interrupt in the timer
> > > state and relying on the guest to unmask (which it isn't required to
> > > do per the h/w spec, although Linux does)
> > > 
> > > To do this introduce the concept of routing a PPI to the currently
> > > running VCPU. For such interrupts irq_get_domain returns NULL.
> > > 
> > > Then we make use of the GICD I[SC]ACTIVER registers to save and
> > > restore the active state of the interrupt, which prevents the nested
> > > invocations which the current masking works around.
> > > 
> > > For edge triggered interrupts we also need to context switch the
> > > pending bit via I[SC]PENDR. Note that for level triggered interrupts
> > > SPENDR sets a latch which is only cleared by ICPENDR (and not by h/w
> > > state changes), therefore we do not want to context switch the pending
> > > state for level PPIs -- instead we rely on the context switch of the
> > > peripheral to restore the correct level.
> > > 
> > > RFC Only:
> > >  - Not implemented for GIC v3 yet.
> > >  - Lightly tested with hackbench on systems with level and edge
> > >    triggered vtimer PPI.
> > >  - Is irq_get_domain == NULL to indicate route-to-current-vcpu the
> > >    best idea? Any alternatives?
> > > 
> > > Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
> > > ---
> > >  xen/arch/arm/gic-v2.c        |   84 
> > > ++++++++++++++++++++++++++++++++++++++++++
> > >  xen/arch/arm/gic.c           |   32 +++++++++++++---
> > >  xen/arch/arm/irq.c           |   48 ++++++++++++++++++++++--
> > >  xen/arch/arm/time.c          |   26 +------------
> > >  xen/arch/arm/vtimer.c        |   24 ++++++++++--
> > >  xen/include/asm-arm/domain.h |   11 ++++++
> > >  xen/include/asm-arm/gic.h    |   14 +++++++
> > >  xen/include/asm-arm/irq.h    |    1 +
> > >  8 files changed, 204 insertions(+), 36 deletions(-)
> > > 
> > > diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
> > > index 31fb81a..9074aca 100644
> > > --- a/xen/arch/arm/gic-v2.c
> > > +++ b/xen/arch/arm/gic-v2.c
> > > @@ -156,6 +156,45 @@ static void gicv2_save_state(struct vcpu *v)
> > >      writel_gich(0, GICH_HCR);
> > >  }
> > >  
> > > +static void gicv2_save_and_mask_hwppi(struct vcpu *v, const unsigned 
> > > virq,
> 
> Shouldn't the argument be a physical irq? Maybe irq_desc?

I think it needs to be a virq in the namespace of the given v, since it
may not be 1:1 and we would want to look it up to get the correct p.
> 
> 
> > > +                                      struct hwppi_state *s)
> > > +{
> > > +    struct pending_irq *p = irq_to_pending(v, virq);

which we do here. I think such lookups are normally done within the
(v)gic  code rather than the callers, aren't they?

> > >  int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
> > > diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
> > > index ebdf19a..93c38ff 100644
> > > --- a/xen/arch/arm/irq.c
> > > +++ b/xen/arch/arm/irq.c
> > > @@ -202,6 +202,19 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int 
> > > irq, int is_fiq)
> > >          goto out;
> > >      }
> > >  
> > > +    if ( irq == current->arch.virt_timer.irq )
> > > +    {
> > > +        ASSERT(!irq_get_domain(desc));
> > > +
> > > +        desc->handler->end(desc);
> > > +
> > > +        set_bit(_IRQ_INPROGRESS, &desc->status);
> > > +        desc->arch.eoi_cpu = smp_processor_id();
> > > +
> > > +        vgic_vcpu_inject_irq(current, irq);
> > > +        goto out_no_end;
> > > +    }
> 
> I don't think we should special case virt_timer.irq here. I would try to
> reuse the normal _IRQ_GUEST path or make this if generic for any PPIs
> routed to guests.

Yes, I think I thought I had done that after making this quick hack the
first time around but obviously I must have forgotten!

> > > diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c
> > > index 848e2c6..d1f21a1 100644
> > > --- a/xen/arch/arm/vtimer.c
> > > +++ b/xen/arch/arm/vtimer.c
> > > @@ -47,9 +47,14 @@ static void phys_timer_expired(void *data)
> > >  static void virt_timer_expired(void *data)
> > >  {
> > >      struct vtimer *t = data;
> > > -    t->ctl |= CNTx_CTL_MASK;
> > > -    vgic_vcpu_inject_irq(t->v, t->irq);
> > > -    perfc_incr(vtimer_virt_inject);
> > > +    t->ctl |= CNTx_CTL_PENDING;
> > > +    if ( !(t->ctl & CNTx_CTL_MASK) )
> > > +    {
> > > +        /* An edge triggered interrupt should now be pending. */
> > > +        t->ppi_state.pending = true;
> > > +        vcpu_unblock(t->v);
> 
> I was going to say that this is trouble because
> local_events_need_delivery wouldn't recognize that we actually have an
> event pending. But it doesn't matter because local_events_need_delivery
> only works with the current vcpu and if this code trigger then the vcpu
> that needs to receive the event cannot be current. So I think that is OK
> but for clarity it might be better to add a check or a comment in
> local_events_need_delivery_nomask anyway.

i.e. a BUG_ON(t->v == current) + a comment to the affect that the timer
must never expire for the current vcpu?

> > > diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> > > index 90ab9c3..dd50e2c 100644
> > > --- a/xen/include/asm-arm/domain.h
> > > +++ b/xen/include/asm-arm/domain.h
> > > @@ -34,12 +34,23 @@ enum domain_type {
> > >  extern int dom0_11_mapping;
> > >  #define is_domain_direct_mapped(d) ((d) == hardware_domain && 
> > > dom0_11_mapping)
> > >  
> > > +struct hwppi_state {
> > > +    /* h/w state */
> > > +    unsigned long enabled:1;
> > > +    unsigned long pending:1;
> > > +    unsigned long active:1;
> > > +
> > > +    /* Xen s/w state */
> > > +    unsigned long inprogress:1;
> > > +};
> 
> Using a uint32_t bitmask would be more in line the rest of the code
> style, but it is just a matter of taste.

You mean "uint32_t inprogress:1" for each? Or
#define ENAVBLED 1
#define PENDING 2
etc
and test_set_bit stuff?

Ian.


_______________________________________________
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®.