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

[XEN PATCH v2 19/25] arm: new VGIC: its: Add LPI translation cache definition


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Mykyta Poturai <Mykyta_Poturai@xxxxxxxx>
  • Date: Fri, 10 Nov 2023 12:56:22 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=laODZ4Gs+y5E4svUvsfAqE5Iuee5D06nD4w3sS8JL40=; b=XglTUcfubP67CF3FVgVD//4DcSaDO5sIZ2vcV89JAWCR5gV8bWX9Pr+q4LkhQMt6V2fy1CaoZ4GOtSEcVbOGzOPPDTaplVSacty3sLcboTR1ywLPfhiDs3Qm5MhHQiPLYZolhdie1EJWE+NyDYLzd9uDo8CNmnGxq2reKcBKmmD3ZD8tJR0WY/2G3XwVdyve9Y4NVzFlFwWfbeIt99W1AOoCaKZ3cDWq43Qc7oFg/RnZLtLD62p61sbKwo71W5DzJMECRK/H1h64FrBl+m4GklrrTUthItvtiS/H3HXUAwxPoYS1DzhPWxWq+GofzZJMeuGfG/LrhQ3E89bwAjPx3Q==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=JqZ15/rfG7fUg7DWQvFcGgAW4ZsygIPMMMMH2NnpQ2QbD9HTg8fSrvTTdXe7jmM+uIQrsZbhrAld4MiDbYfBOLhXKvvITC+X2Za6WHC7pny/cYdb3sh5qqqnS1rSLS0cJf4sYzIjjuVtNYPn0AwpGRE2lbdjg4HySewK7S4qRqmkfKAJ1ihVBbeZa0qx5S7A6jnO3L2F/qULaZm5Vs6gHrabRlrvJvbB4v+P7/lMKdtnF0mTvk2u9ma4M61hwpK6bjSIARan0/8d/qDVkbI/ldB+V6s9AMe6QmPxHs53m30MojvQsDb2v2rzwfPjYUPxjMUMwzECWH7mjtoTRaxOkw==
  • Cc: Mykyta Poturai <Mykyta_Poturai@xxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>
  • Delivery-date: Fri, 10 Nov 2023 12:56:46 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHaE9VOswsQu2Pw50ypJgIWmh5TYw==
  • Thread-topic: [XEN PATCH v2 19/25] arm: new VGIC: its: Add LPI translation cache definition

Add the basic data structure that expresses an MSI to LPI
translation as well as the allocation/release hooks.

Implement cache invalidation, lookup and storage.

The size of the cache is arbitrarily defined as 16*nr_vcpus.

This is based on Linux commits 24cab82c34aa6f, 7d825fd6eaa7467,
89489ee9ced8 and 86a7dae884f38 by Marc Zyngier

Signed-off-by: Mykyta Poturai <mykyta_poturai@xxxxxxxx>
---
 xen/arch/arm/include/asm/new_vgic.h |   3 +
 xen/arch/arm/vgic/vgic-its.c        | 195 ++++++++++++++++++++++++++++
 2 files changed, 198 insertions(+)

diff --git a/xen/arch/arm/include/asm/new_vgic.h 
b/xen/arch/arm/include/asm/new_vgic.h
index d0fd15e154..b038fb7861 100644
--- a/xen/arch/arm/include/asm/new_vgic.h
+++ b/xen/arch/arm/include/asm/new_vgic.h
@@ -212,6 +212,9 @@ struct vgic_dist {
     spinlock_t          lpi_list_lock;
     struct list_head    lpi_list_head;
     unsigned int        lpi_list_count;
+
+    /* LPI translation cache */
+    struct list_head   lpi_translation_cache;
 };
 
 struct vgic_cpu {
diff --git a/xen/arch/arm/vgic/vgic-its.c b/xen/arch/arm/vgic/vgic-its.c
index 6c726dde3a..48dfa09115 100644
--- a/xen/arch/arm/vgic/vgic-its.c
+++ b/xen/arch/arm/vgic/vgic-its.c
@@ -44,6 +44,14 @@ struct its_ite {
     u32 event_id;
 };
 
+struct vgic_translation_cache_entry {
+    struct list_head entry;
+    paddr_t db;
+    u32 devid;
+    u32 eventid;
+    struct vgic_irq *irq;
+};
+
 /*
  * Find and returns a device in the device table for an ITS.
  * Must be called with the its_devices_lock mutex held.
@@ -152,6 +160,144 @@ int vgic_copy_lpi_list(struct domain *d, struct vcpu 
*vcpu, u32 **intid_ptr)
     return i;
 }
 
+void __vgic_put_lpi_locked(struct domain *d, struct vgic_irq *irq)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+
+    if ( !atomic_dec_and_test(&irq->refcount) )
+    {
+        return;
+    };
+
+    list_del(&irq->lpi_list);
+    dist->lpi_list_count--;
+
+    xfree(irq);
+}
+
+static struct vgic_irq *__vgic_its_check_cache(struct vgic_dist *dist,
+                                               paddr_t db, u32 devid,
+                                               u32 eventid)
+{
+    struct vgic_translation_cache_entry *cte, *fcte;
+
+    list_for_each_entry(cte, &dist->lpi_translation_cache, entry)
+    {
+        /*
+         * If we hit a NULL entry, there is nothing after this
+         * point.
+         */
+        if ( !cte->irq )
+            break;
+
+        if ( cte->db != db || cte->devid != devid || cte->eventid != eventid )
+            continue;
+
+        /*
+         * Move this entry to the head, as it is the most
+         * recently used.
+         */
+        fcte = list_first_entry(&dist->lpi_translation_cache,
+                                struct vgic_translation_cache_entry, entry);
+
+        if ( fcte->irq != cte->irq )
+            list_move(&cte->entry, &dist->lpi_translation_cache);
+
+        return cte->irq;
+    }
+
+    return NULL;
+}
+
+static struct vgic_irq *vgic_its_check_cache(struct domain *d, paddr_t db,
+                                            u32 devid, u32 eventid)
+{
+       struct vgic_dist *dist = &d->arch.vgic;
+       struct vgic_irq *irq;
+
+       spin_lock(&dist->lpi_list_lock);
+       irq = __vgic_its_check_cache(dist, db, devid, eventid);
+       spin_unlock(&dist->lpi_list_lock);
+
+       return irq;
+}
+
+static void vgic_its_cache_translation(struct domain *d, struct vgic_its *its,
+                                       u32 devid, u32 eventid,
+                                       struct vgic_irq *irq)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+    struct vgic_translation_cache_entry *cte;
+    unsigned long flags;
+    paddr_t db;
+
+    /* Do not cache a directly injected interrupt */
+    if ( irq->hw )
+        return;
+
+    spin_lock_irqsave(&dist->lpi_list_lock, flags);
+
+    if ( unlikely(list_empty(&dist->lpi_translation_cache)) )
+        goto out;
+
+    /*
+     * We could have raced with another CPU caching the same
+     * translation behind our back, so let's check it is not in
+     * already
+     */
+    db = its->vgic_its_base + GITS_TRANSLATER;
+    if ( __vgic_its_check_cache(dist, db, devid, eventid) )
+        goto out;
+
+    /* Always reuse the last entry (LRU policy) */
+    cte = list_last_entry(&dist->lpi_translation_cache, typeof(*cte), entry);
+
+    /*
+     * Caching the translation implies having an extra reference
+     * to the interrupt, so drop the potential reference on what
+     * was in the cache, and increment it on the new interrupt.
+     */
+    if ( cte->irq )
+        __vgic_put_lpi_locked(d, cte->irq);
+
+    vgic_get_irq_kref(irq);
+
+    cte->db      = db;
+    cte->devid   = devid;
+    cte->eventid = eventid;
+    cte->irq     = irq;
+
+    /* Move the new translation to the head of the list */
+    list_move(&cte->entry, &dist->lpi_translation_cache);
+
+out:
+    spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
+}
+
+void vgic_its_invalidate_cache(struct domain *d)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+    struct vgic_translation_cache_entry *cte;
+    unsigned long flags;
+
+    spin_lock_irqsave(&dist->lpi_list_lock, flags);
+
+    list_for_each_entry(cte, &dist->lpi_translation_cache, entry)
+    {
+        /*
+         * If we hit a NULL entry, there is nothing after this
+         * point.
+         */
+        if ( !cte->irq )
+            break;
+
+        __vgic_put_lpi_locked(d, cte->irq);
+        cte->irq = NULL;
+    }
+
+    spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
+}
+
 /* Requires the its_lock to be held. */
 static void its_free_ite(struct domain *d, struct its_ite *ite)
 {
@@ -184,6 +330,8 @@ void vgic_its_free_device(struct vgic_its_device *device)
     list_for_each_entry_safe(ite, temp, &device->itt_head, ite_list)
         its_free_ite(d, ite);
 
+    vgic_its_invalidate_cache(d);
+
     list_del(&device->dev_list);
     xfree(device);
 }
@@ -351,6 +499,8 @@ static void vgic_mmio_write_its_ctlr(struct domain *d, 
struct vgic_its *its,
         goto out;
 
     its->enabled = !!(val & GITS_CTLR_ENABLE);
+    if ( !its->enabled )
+        vgic_its_invalidate_cache(d);
 
     /*
      * Try to process any pending commands. This function bails out early
@@ -742,6 +892,48 @@ out:
     return ret;
 }
 
+/* Default is 16 cached LPIs per vcpu */
+#define LPI_DEFAULT_PCPU_CACHE_SIZE 16
+
+void vgic_lpi_translation_cache_init(struct domain *d)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+    unsigned int sz;
+    int i;
+
+    if ( !list_empty(&dist->lpi_translation_cache) )
+        return;
+
+    sz = d->max_vcpus * LPI_DEFAULT_PCPU_CACHE_SIZE;
+
+    for ( i = 0; i < sz; i++ )
+    {
+        struct vgic_translation_cache_entry *cte;
+
+        /* An allocation failure is not fatal */
+        cte = xzalloc(struct vgic_translation_cache_entry);
+        if ( WARN_ON(!cte) )
+            break;
+
+        INIT_LIST_HEAD(&cte->entry);
+        list_add(&cte->entry, &dist->lpi_translation_cache);
+    }
+}
+
+void vgic_lpi_translation_cache_destroy(struct domain *d)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+    struct vgic_translation_cache_entry *cte, *tmp;
+
+    vgic_its_invalidate_cache(d);
+
+    list_for_each_entry_safe(cte, tmp, &dist->lpi_translation_cache, entry)
+    {
+        list_del(&cte->entry);
+        xfree(cte);
+    }
+}
+
 #define INITIAL_BASER_VALUE                                                    
\
     (GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb) |                         
\
      GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, SameAsInner) |                  
\
@@ -763,6 +955,8 @@ static int vgic_its_create(struct domain *d, u64 addr)
 
     d->arch.vgic.its = its;
 
+    vgic_lpi_translation_cache_init(d);
+
     spin_lock_init(&its->its_lock);
     spin_lock_init(&its->cmd_lock);
 
@@ -829,6 +1023,7 @@ void vgic_v3_its_free_domain(struct domain *d)
 
     vgic_its_free_device_list(d, its);
     vgic_its_free_collection_list(d, its);
+    vgic_lpi_translation_cache_destroy(d);
 
     spin_unlock(&d->arch.vgic.its_devices_lock);
     spin_unlock(&its->its_lock);
-- 
2.34.1



 


Rackspace

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