xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Andre Przywara <andre.przywara@arm.com>
To: Stefano Stabellini <sstabellini@kernel.org>
Cc: xen-devel@lists.xenproject.org,
	Julien Grall <julien.grall@arm.com>,
	Shanker Donthineni <shankerd@codeaurora.org>,
	Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>,
	Vijay Kilari <vijay.kilari@gmail.com>
Subject: Re: [PATCH v9 20/28] ARM: GICv3: handle unmapped LPIs
Date: Tue, 23 May 2017 15:41:57 +0100	[thread overview]
Message-ID: <aed2b963-8fdb-a906-d649-3cdf2b346411@arm.com> (raw)
In-Reply-To: <alpine.DEB.2.10.1705191755520.18759@sstabellini-ThinkPad-X260>

Hi Stefano,

On 20/05/17 02:25, Stefano Stabellini wrote:
> On Thu, 11 May 2017, Andre Przywara wrote:
>> When LPIs get unmapped by a guest, they might still be in some LR of
>> some VCPU. Nevertheless we remove the corresponding pending_irq
>> (possibly freeing it), and detect this case (irq_to_pending() returns
>> NULL) when the LR gets cleaned up later.
>> However a *new* LPI may get mapped with the same number while the old
>> LPI is *still* in some LR. To avoid getting the wrong state, we mark
>> every newly mapped LPI as PRISTINE, which means: has never been in an
>> LR before. If we detect the LPI in an LR anyway, it must have been an
>> older one, which we can simply retire.
>> Before inserting such a PRISTINE LPI into an LR, we must make sure that
>> it's not already in another LR, as the architecture forbids two
>> interrupts with the same virtual IRQ number on one CPU.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  xen/arch/arm/gic.c         | 55 +++++++++++++++++++++++++++++++++++++++++-----
>>  xen/include/asm-arm/vgic.h |  6 +++++
>>  2 files changed, 56 insertions(+), 5 deletions(-)
>>
>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>> index fd3fa05..8bf0578 100644
>> --- a/xen/arch/arm/gic.c
>> +++ b/xen/arch/arm/gic.c
>> @@ -375,6 +375,8 @@ static inline void gic_set_lr(int lr, struct pending_irq *p,
>>  {
>>      ASSERT(!local_irq_is_enabled());
>>  
>> +    clear_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &p->status);
>> +
>>      gic_hw_ops->update_lr(lr, p, state);
>>  
>>      set_bit(GIC_IRQ_GUEST_VISIBLE, &p->status);
>> @@ -442,12 +444,41 @@ void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq)
>>  #endif
>>  }
>>  
>> +/*
>> + * Find an unused LR to insert an IRQ into. If this new interrupt is a
>> + * PRISTINE LPI, scan the other LRs to avoid inserting the same IRQ twice.
>> + */
>> +static int gic_find_unused_lr(struct vcpu *v, struct pending_irq *p, int lr)
>> +{
>> +    unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
>> +    unsigned long *lr_mask = (unsigned long *) &this_cpu(lr_mask);
>> +    struct gic_lr lr_val;
>> +
>> +    ASSERT(spin_is_locked(&v->arch.vgic.lock));
>> +
>> +    if ( test_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &p->status) )
> 
> Maybe we should add an "unlikely".
> 
> I can see how this would be OKish at runtime, but at boot time there
> might be a bunch of PRISTINE_LPIs,

What is your concern here, performance?
Let's put this into perspective:
- The PRISTINE bit gets set upon MAPTI, which Linux usually does *once*
when the driver gets loaded. It gets cleared after the first injection.
- If that happens, we scan all LRs. Most implementations have 4(!) of
them (ARM GIC implementations, for instance), also the algorithm only
scans *used* LRs, so normally just one or two.
- Reading the LR is a *local* system register *read*, not an MMIO
access, and not propagated to other cores. Yes, this may be "costly"
(compared to other instructions), but it's probably still cheaper than a
page table walk (TLB miss) or L2 cache miss.

So to summarize: this is rare, iterates over only a very small number of
registers and is not hugely expensive.
At this point in time I would refrain from any kind of performance
optimization, at least unless we have solved all the other issues and
have done some benchmarking/profiling (on different hardware platforms).

> but no MAPDs have been issued yet, right?

As Julien already mentioned, this gets set after a MAPTI, which requires
a MAPD before.

Cheers,
Andre.

> I have a suggestion, I'll leave it to you and Julien if you want to do
> this now, or maybe consider it as a TODO item. I am OK either way (I
> don't want to delay the ITS any longer).
> 
> I am thinking we should do this scanning only after at least one MAPD
> has been issued for a given cpu at least once. I would resurrect the
> idea of a DISCARD flag, but not on the pending_irq, that I believe it's
> difficult to handle, but a single global DISCARD flag per struct vcpu.
> 
> On MAPD, we set DISCARD for the target vcpu of the LPI we are dropping.
> Next time we want to inject a PRISTINE_IRQ on that cpu interface, we
> scan all LRs for interrupts with a NULL pending_irq. We remove those
> from LRs, then we remove the DISCARD flag.
> 
> Do you think it would work?
> 
> 
>> +    {
>> +        int used_lr = 0;
>> +
>> +        while ( (used_lr = find_next_bit(lr_mask, nr_lrs, used_lr)) < nr_lrs )
>> +        {
>> +            gic_hw_ops->read_lr(used_lr, &lr_val);
>> +            if ( lr_val.virq == p->irq )
>> +                return used_lr;
>> +        }
>> +    }
>> +
>> +    lr = find_next_zero_bit(lr_mask, nr_lrs, lr);
>> +
>> +    return lr;
>> +}
>> +
>>  void gic_raise_guest_irq(struct vcpu *v, unsigned int virtual_irq,
>>          unsigned int priority)
>>  {
>> -    int i;
>> -    unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
>>      struct pending_irq *p = irq_to_pending(v, virtual_irq);
>> +    unsigned int nr_lrs = gic_hw_ops->info->nr_lrs;
>> +    int i = nr_lrs;
>>  
>>      ASSERT(spin_is_locked(&v->arch.vgic.lock));
>>  
>> @@ -457,7 +488,8 @@ void gic_raise_guest_irq(struct vcpu *v, unsigned int virtual_irq,
>>  
>>      if ( v == current && list_empty(&v->arch.vgic.lr_pending) )
>>      {
>> -        i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
>> +        i = gic_find_unused_lr(v, p, 0);
>> +
>>          if (i < nr_lrs) {
>>              set_bit(i, &this_cpu(lr_mask));
>>              gic_set_lr(i, p, GICH_LR_PENDING);
>> @@ -509,7 +541,17 @@ static void gic_update_one_lr(struct vcpu *v, int i)
>>      }
>>      else if ( lr_val.state & GICH_LR_PENDING )
>>      {
>> -        int q __attribute__ ((unused)) = test_and_clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status);
>> +        int q __attribute__ ((unused));
>> +
>> +        if ( test_and_clear_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &p->status) )
>> +        {
>> +            gic_hw_ops->clear_lr(i);
>> +            clear_bit(i, &this_cpu(lr_mask));
>> +
>> +            return;
>> +        }
>> +
>> +        q = test_and_clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status);
>>  #ifdef GIC_DEBUG
>>          if ( q )
>>              gdprintk(XENLOG_DEBUG, "trying to inject irq=%d into d%dv%d, when it is already pending in LR%d\n",
>> @@ -521,6 +563,9 @@ static void gic_update_one_lr(struct vcpu *v, int i)
>>          gic_hw_ops->clear_lr(i);
>>          clear_bit(i, &this_cpu(lr_mask));
>>  
>> +        if ( test_and_clear_bit(GIC_IRQ_GUEST_PRISTINE_LPI, &p->status) )
>> +            return;
>>          if ( p->desc != NULL )
>>              clear_bit(_IRQ_INPROGRESS, &p->desc->status);
>>          clear_bit(GIC_IRQ_GUEST_VISIBLE, &p->status);
>> @@ -591,7 +636,7 @@ static void gic_restore_pending_irqs(struct vcpu *v)
>>      inflight_r = &v->arch.vgic.inflight_irqs;
>>      list_for_each_entry_safe ( p, t, &v->arch.vgic.lr_pending, lr_queue )
>>      {
>> -        lr = find_next_zero_bit(&this_cpu(lr_mask), nr_lrs, lr);
>> +        lr = gic_find_unused_lr(v, p, lr);
>>          if ( lr >= nr_lrs )
>>          {
>>              /* No more free LRs: find a lower priority irq to evict */
>> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
>> index 02732db..3fc4ceb 100644
>> --- a/xen/include/asm-arm/vgic.h
>> +++ b/xen/include/asm-arm/vgic.h
>> @@ -60,12 +60,18 @@ struct pending_irq
>>       * vcpu while it is still inflight and on an GICH_LR register on the
>>       * old vcpu.
>>       *
>> +     * GIC_IRQ_GUEST_PRISTINE_LPI: the IRQ is a newly mapped LPI, which
>> +     * has never been in an LR before. This means that any trace of an
>> +     * LPI with the same number in an LR must be from an older LPI, which
>> +     * has been unmapped before.
>> +     *
>>       */
>>  #define GIC_IRQ_GUEST_QUEUED   0
>>  #define GIC_IRQ_GUEST_ACTIVE   1
>>  #define GIC_IRQ_GUEST_VISIBLE  2
>>  #define GIC_IRQ_GUEST_ENABLED  3
>>  #define GIC_IRQ_GUEST_MIGRATING   4
>> +#define GIC_IRQ_GUEST_PRISTINE_LPI  5
>>      unsigned long status;
>>      struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */
>>      unsigned int irq;
>> -- 
>> 2.9.0
>>
>>
>> _______________________________________________
>> Xen-devel mailing list
>> Xen-devel@lists.xen.org
>> https://lists.xen.org/xen-devel
>>

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

  parent reply	other threads:[~2017-05-23 14:42 UTC|newest]

Thread overview: 108+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-11 17:53 [PATCH v9 00/28] arm64: Dom0 ITS emulation Andre Przywara
2017-05-11 17:53 ` [PATCH v9 01/28] ARM: GICv3: setup number of LPI bits for a GICv3 guest Andre Przywara
2017-05-11 18:34   ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 02/28] ARM: VGIC: move irq_to_pending() calls under the VGIC VCPU lock Andre Przywara
2017-05-20  0:34   ` Stefano Stabellini
2017-05-11 17:53 ` [PATCH v9 03/28] ARM: GIC: Add checks for NULL pointer pending_irq's Andre Przywara
2017-05-12 14:19   ` Julien Grall
2017-05-22 16:49     ` Andre Przywara
2017-05-22 17:15       ` Julien Grall
2017-05-25 16:14         ` Andre Przywara
2017-05-20  1:25   ` Stefano Stabellini
2017-05-11 17:53 ` [PATCH v9 04/28] ARM: GICv3: introduce separate pending_irq structs for LPIs Andre Przywara
2017-05-12 14:22   ` Julien Grall
2017-05-22 21:52   ` Stefano Stabellini
2017-05-11 17:53 ` [PATCH v9 05/28] ARM: GICv3: forward pending LPIs to guests Andre Przywara
2017-05-12 14:55   ` Julien Grall
2017-05-22 22:03   ` Stefano Stabellini
2017-05-25 16:42     ` Andre Przywara
2017-05-11 17:53 ` [PATCH v9 06/28] ARM: GICv3: enable ITS and LPIs on the host Andre Przywara
2017-05-11 17:53 ` [PATCH v9 07/28] ARM: vGICv3: handle virtual LPI pending and property tables Andre Przywara
2017-05-12 15:23   ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 08/28] ARM: introduce vgic_access_guest_memory() Andre Przywara
2017-05-12 15:30   ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 09/28] ARM: vGICv3: re-use vgic_reg64_check_access Andre Przywara
2017-05-11 17:53 ` [PATCH v9 10/28] ARM: GIC: export and extend vgic_init_pending_irq() Andre Przywara
2017-05-16 12:26   ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 11/28] ARM: VGIC: add vcpu_id to struct pending_irq Andre Przywara
2017-05-16 12:31   ` Julien Grall
2017-05-22 22:15     ` Stefano Stabellini
2017-05-23  9:49       ` Andre Przywara
2017-05-11 17:53 ` [PATCH v9 12/28] ARM: vGIC: advertise LPI support Andre Przywara
2017-05-16 13:03   ` Julien Grall
2017-05-22 22:19     ` Stefano Stabellini
2017-05-23 10:49       ` Julien Grall
2017-05-23 17:47         ` Stefano Stabellini
2017-05-24 10:10           ` Julien Grall
2017-05-25 18:02           ` Andre Przywara
2017-05-25 18:49             ` Stefano Stabellini
2017-05-25 20:07               ` Julien Grall
2017-05-25 21:05                 ` Stefano Stabellini
2017-05-26 10:19                   ` Julien Grall
2017-05-26 17:12                     ` Andre Przywara
2017-05-23 17:23     ` Andre Przywara
2017-05-11 17:53 ` [PATCH v9 13/28] ARM: vITS: add command handling stub and MMIO emulation Andre Przywara
2017-05-16 15:24   ` Julien Grall
2017-05-17 16:16   ` Julien Grall
2017-05-22 22:32   ` Stefano Stabellini
2017-05-23 10:54     ` Julien Grall
2017-05-23 17:43       ` Stefano Stabellini
2017-05-11 17:53 ` [PATCH v9 14/28] ARM: vITS: introduce translation table walks Andre Przywara
2017-05-16 15:57   ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 15/28] ARM: vITS: provide access to struct pending_irq Andre Przywara
2017-05-17 15:35   ` Julien Grall
2017-05-22 16:50     ` Andre Przywara
2017-05-22 17:19       ` Julien Grall
2017-05-26  9:10         ` Andre Przywara
2017-05-26 10:00           ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 16/28] ARM: vITS: handle INT command Andre Przywara
2017-05-17 16:17   ` Julien Grall
2017-05-23 17:24     ` Andre Przywara
2017-05-11 17:53 ` [PATCH v9 17/28] ARM: vITS: handle MAPC command Andre Przywara
2017-05-17 17:22   ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 18/28] ARM: vITS: handle CLEAR command Andre Przywara
2017-05-17 17:45   ` Julien Grall
2017-05-23 17:24     ` Andre Przywara
2017-05-24  9:04       ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 19/28] ARM: vITS: handle MAPD command Andre Przywara
2017-05-17 18:07   ` Julien Grall
2017-05-24  9:10     ` Andre Przywara
2017-05-24  9:56       ` Julien Grall
2017-05-24 13:09         ` Andre Przywara
2017-05-25 18:55           ` Stefano Stabellini
2017-05-25 20:17             ` Julien Grall
2017-05-25 20:44               ` Stefano Stabellini
2017-05-26  8:16                 ` Andre Przywara
2017-05-11 17:53 ` [PATCH v9 20/28] ARM: GICv3: handle unmapped LPIs Andre Przywara
2017-05-17 18:37   ` Julien Grall
2017-05-20  1:25   ` Stefano Stabellini
2017-05-22 23:48     ` Stefano Stabellini
2017-05-23 11:10       ` Julien Grall
2017-05-23 18:23         ` Stefano Stabellini
2017-05-24  9:47           ` Julien Grall
2017-05-24 17:49             ` Stefano Stabellini
2017-05-23 14:41     ` Andre Przywara [this message]
2017-05-11 17:53 ` [PATCH v9 21/28] ARM: vITS: handle MAPTI command Andre Przywara
2017-05-18 14:04   ` Julien Grall
2017-05-22 23:39   ` Stefano Stabellini
2017-05-23 10:01     ` Andre Przywara
2017-05-23 17:44       ` Stefano Stabellini
2017-05-11 17:53 ` [PATCH v9 22/28] ARM: vITS: handle MOVI command Andre Przywara
2017-05-18 14:17   ` Julien Grall
2017-05-23  0:28   ` Stefano Stabellini
2017-05-11 17:53 ` [PATCH v9 23/28] ARM: vITS: handle DISCARD command Andre Przywara
2017-05-18 14:23   ` Julien Grall
2017-05-22 16:50     ` Andre Przywara
2017-05-22 17:20       ` Julien Grall
2017-05-23  9:40         ` Andre Przywara
2017-05-11 17:53 ` [PATCH v9 24/28] ARM: vITS: handle INV command Andre Przywara
2017-05-23  0:01   ` Stefano Stabellini
2017-05-11 17:53 ` [PATCH v9 25/28] ARM: vITS: handle INVALL command Andre Przywara
2017-06-02 17:24   ` Julien Grall
2017-06-02 17:25     ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 26/28] ARM: vITS: increase mmio_count for each ITS Andre Przywara
2017-05-18 14:34   ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 27/28] ARM: vITS: create and initialize virtual ITSes for Dom0 Andre Przywara
2017-05-18 14:41   ` Julien Grall
2017-05-11 17:53 ` [PATCH v9 28/28] ARM: vITS: create ITS subnodes for Dom0 DT Andre Przywara
2017-05-11 18:31 ` [PATCH v9 00/28] arm64: Dom0 ITS emulation Julien Grall

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aed2b963-8fdb-a906-d649-3cdf2b346411@arm.com \
    --to=andre.przywara@arm.com \
    --cc=Vijaya.Kumar@caviumnetworks.com \
    --cc=julien.grall@arm.com \
    --cc=shankerd@codeaurora.org \
    --cc=sstabellini@kernel.org \
    --cc=vijay.kilari@gmail.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).