From: Oliver Upton <oupton@kernel.org>
To: Sascha Bischoff <sascha.bischoff@arm.com>
Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
kvm@vger.kernel.org, maz@kernel.org, oliver.upton@linux.dev,
joey.gouly@arm.com, suzuki.poulose@arm.com, yuzenghui@huawei.com,
peter.maydell@linaro.org, lpieralisi@kernel.org,
timothy.hayes@arm.com, fuad.tabba@linux.dev
Subject: Re: [PATCH v2 08/16] KVM: arm64: gic-v5: Add ITS translation cache maintenance
Date: Wed, 4 Nov 2026 16:26:19 -0800 [thread overview]
Message-ID: <auvNK3FK7TxwGu8g@kernel.org> (raw)
In-Reply-To: <20261102194454.4086911-9-sascha.bischoff@arm.com>
On Mon, Nov 02, 2026 at 07:44:46PM +0000, Sascha Bischoff wrote:
> Walking the guest DT and ITTs on every MSI or ITS event is unnecessary
> once a DeviceID/EventID pair has been resolved. Add an XArray indexed
> by the DeviceID/EventID pair to cache resolved translations as a
> disposable acceleration structure, avoiding repeated walks of guest
> memory.
>
> Cache entries hold references to the resolved struct vgic_irq objects
> stored in the VM-wide LPI xarray. Lookups use RCU to access entries in
> interrupt context without taking a raw spinlock, and take an IRQ
> reference before returning an entry to the caller. Cache eviction drops
> the reference held by the cache and defers freeing the entry until RCU
> readers have finished. This keeps the cache tied to the normal LPI
> object lifetime instead of storing raw LPI numbers.
>
> Invalidate cached translations when the table configuration or guest
> invalidation commands make them stale. Changes to DT_BASER or DT_CFGR
> drop the entire cache, while writes of unchanged values leave it intact.
> INV_EVENTR removes either one event or the events covered by an L1 ITT
> entry, and INV_DEVICER removes the translations covered by either an L2
> DT entry or an L1 DT entry.
>
> The cache is not part of any userspace ABI and is never authoritative:
> entries can always be rebuilt from guest memory on the next lookup.
>
> The vgic_irq objects for LPIs track valid translations rather than
> mirror interrupt state. Mirroring that state would require querying
> the GIC on every guest exit. Once direct injection is added, the
> objects also record whether an LPI is mapped into the host ITT.
>
> Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
> ---
> arch/arm64/kvm/vgic/vgic-its-v5.c | 219 ++++++++++++++++++++++++++++--
> include/kvm/arm_vgic.h | 3 +
> 2 files changed, 208 insertions(+), 14 deletions(-)
Looking at the diffstat alone, I wonder why we can't share the
translation cache implementation between GICv3 and GICv5 as they
accomplish the exact same thing.
> +struct its_cache_translation_entry {
> + struct rcu_head rcu;
> + struct vgic_irq *irq;
> +};
Err... So the vgic_irq struct is already RCU-protected in GICv3 at
least. When the refcount drops to 0 no other observer can take a
reference on the object and the memory itself is freed after a grace
period.
So now we're using RCU on a struct that only contains a pointer to
another object subject to RCU protection?
> +static void its_cache_erase_range(struct vgic_v5_its *its,
> + unsigned long first, unsigned long last)
> +{
> + struct its_cache_translation_entry *entry;
> + unsigned long key;
> +
> + xa_for_each_range(&its->translation_cache, key, entry, first, last)
> + its_cache_erase_translation(its, key);
> +}
> +
Optimizing invalidations can be added on as a follow-up patch. The GICv3
ITS gets away with invalidating the entire cache any time it needs to
make a change.
> +static int its_cache_add_translation(struct kvm *kvm, struct vgic_v5_its *its,
> + u32 device_id, u16 event_id,
> + struct vgic_irq *irq)
> +{
> + unsigned long key = its_cache_key(device_id, event_id);
> + struct its_cache_translation_entry *entry;
> + struct its_cache_translation_entry *old;
> +
> + entry = kzalloc_obj(*entry, GFP_KERNEL_ACCOUNT);
> + if (!entry)
> + return -ENOMEM;
> +
> + entry->irq = irq;
> +
> + old = xa_store(&its->translation_cache, key, entry,
> + GFP_KERNEL_ACCOUNT);
> + if (xa_is_err(old)) {
> + kfree(entry);
> + return xa_err(old);
> + }
> +
> + if (old)
> + its_cache_drop_translation(kvm, old);
> +
> + return 0;
> +}
> +
> +static void its_cache_clear_translations(struct vgic_v5_its *its)
> +{
> + struct its_cache_translation_entry *entry;
> + unsigned long key;
> +
> + xa_for_each(&its->translation_cache, key, entry)
> + its_cache_erase_translation(its, key);
> +}
> +
> +static int its_cache_look_up_translation(struct vgic_v5_its *its,
> + u32 device_id, u16 event_id,
> + struct vgic_irq **irq)
> +{
> + unsigned long key = its_cache_key(device_id, event_id);
> + struct its_cache_translation_entry *entry;
> + int ret = -ENXIO;
> +
> + rcu_read_lock();
> + entry = xa_load(&its->translation_cache, key);
> + if (entry && vgic_try_get_irq_ref(entry->irq)) {
> + *irq = entry->irq;
> + ret = 0;
> + }
> + rcu_read_unlock();
> +
> + return ret;
> +}
> +
> +static int its_cache_l2sz_bits(u8 l2sz)
> +{
> + if (l2sz > GICV5_ITS_DT_ITT_CFGR_L2SZ_64k)
> + return -EINVAL;
> +
> + /* L2SZ 0, 1, and 2 encode 4K, 16K, and 64K tables of 8-byte entries. */
> + return 9 + 2 * l2sz;
> +}
> +
> +static void its_cache_handle_inv_devicer(struct vgic_v5_its *its)
> +{
> + unsigned int bits = its->inv_devicer.event_id_bits;
> + int l2_bits;
> +
> + if (its->inv_devicer.l1 && its->dt_cfgr.structure) {
> + l2_bits = its_cache_l2sz_bits(its->dt_cfgr.l2sz);
> + if (l2_bits < 0)
> + return;
+1 to Wei-Lin's comment about the CONSTRAINED UNPREDICTABLE behavior.
I don't think ignoring the invalidation is a valid option.
> + if (its->inv_eventr.l1) {
> + /* An L1 ITTE covers the EventIDs in its L2 ITT. */
> + bits = its_cache_l2sz_bits(its->inv_eventr.itt_l2sz);
> + if (bits < 0)
> + return;
Same here.
Overall, we need a very good explanation for why there isn't any code
reuse. We've had plenty of bugs in this territory on GICv3 and adding
another cache implementation doesn't seem particularly desirable.
Thanks,
Oliver
next prev parent reply other threads:[~2026-11-05 0:26 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 19:44 [PATCH v2 00/16] KVM: arm64: Add GICv5 ITS support Sascha Bischoff
2026-11-02 19:44 ` [PATCH v2 01/16] KVM: arm64: vgic: Split out common LPI allocation Sascha Bischoff
2026-11-03 13:41 ` Fuad Tabba
2026-11-02 19:44 ` [PATCH v2 02/16] KVM: arm64: vgic: Pass opaque device pointer to ITS MMIO callbacks Sascha Bischoff
2026-11-03 13:42 ` Fuad Tabba
2026-11-02 19:44 ` [PATCH v2 03/16] KVM: arm64: gic-v5: Share CoreSight ID register emulation Sascha Bischoff
2026-11-03 13:43 ` Fuad Tabba
2026-11-03 20:37 ` Wei-Lin Chang
2026-11-02 19:44 ` [PATCH v2 04/16] irqchip/gic-v5: Add ITS MMIO register definitions Sascha Bischoff
2026-11-03 13:44 ` Fuad Tabba
2026-11-02 19:44 ` [PATCH v2 05/16] KVM: arm64: gic-v5: Add ITS device skeleton Sascha Bischoff
2026-11-02 20:08 ` sashiko-bot
2026-11-02 19:44 ` [PATCH v2 06/16] KVM: arm64: gic-v5: Add ITS MMIO state emulation Sascha Bischoff
2026-11-02 20:05 ` sashiko-bot
2026-11-03 13:48 ` Fuad Tabba
2026-11-04 2:27 ` Wei-Lin Chang
2026-11-04 23:24 ` Oliver Upton
2026-11-02 19:44 ` [PATCH v2 07/16] KVM: arm64: gic-v5: Add ITS guest table translation emulation Sascha Bischoff
2026-11-02 20:23 ` sashiko-bot
2026-11-04 4:40 ` Wei-Lin Chang
2026-11-05 0:02 ` Oliver Upton
2026-11-02 19:44 ` [PATCH v2 08/16] KVM: arm64: gic-v5: Add ITS translation cache maintenance Sascha Bischoff
2026-11-03 13:54 ` Fuad Tabba
2026-11-04 22:46 ` Wei-Lin Chang
2026-11-05 0:26 ` Oliver Upton [this message]
2026-11-02 19:44 ` [PATCH v2 09/16] KVM: arm64: gic-v5: Add ITS MSI injection Sascha Bischoff
2026-11-02 20:38 ` sashiko-bot
2026-11-03 13:56 ` Fuad Tabba
2026-11-02 19:44 ` [PATCH v2 10/16] KVM: arm64: gic-v5: Add ITS userspace register access Sascha Bischoff
2026-11-02 20:52 ` sashiko-bot
2026-11-03 14:22 ` Fuad Tabba
2026-11-02 19:44 ` [PATCH v2 11/16] irqchip/gic-v5: Enable direct injection in ITS Sascha Bischoff
2026-11-02 20:57 ` sashiko-bot
2026-11-03 14:47 ` Fuad Tabba
2026-11-02 19:44 ` [PATCH v2 12/16] KVM: arm64: vgic: Move direct MSI support helper to common MMIO code Sascha Bischoff
2026-11-02 19:44 ` [PATCH v2 13/16] KVM: arm64: gic-v5: Implement irq forwarding Sascha Bischoff
2026-11-02 21:17 ` sashiko-bot
2026-11-03 15:29 ` Fuad Tabba
2026-11-02 19:44 ` [PATCH v2 14/16] KVM: selftests: Add VGICv5 ITS attribute tests Sascha Bischoff
2026-11-02 19:44 ` [PATCH v2 15/16] KVM: selftests: Add VGICv5 ITS translation cache tests Sascha Bischoff
2026-11-02 21:07 ` sashiko-bot
2026-11-03 16:02 ` Fuad Tabba
2026-11-02 19:44 ` [PATCH v2 16/16] KVM: arm64: gic-v5: Document ITS userspace ABI Sascha Bischoff
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=auvNK3FK7TxwGu8g@kernel.org \
--to=oupton@kernel.org \
--cc=fuad.tabba@linux.dev \
--cc=joey.gouly@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=lpieralisi@kernel.org \
--cc=maz@kernel.org \
--cc=oliver.upton@linux.dev \
--cc=peter.maydell@linaro.org \
--cc=sascha.bischoff@arm.com \
--cc=suzuki.poulose@arm.com \
--cc=timothy.hayes@arm.com \
--cc=yuzenghui@huawei.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.