diff mbox series

[XEN,v2,09/25] arm: new VGIC: vgic_init: implement map_resources

Message ID c89e43a412d1805dc988d1b8145695f85da3e112.1699618395.git.mykyta_poturai@epam.com (mailing list archive)
State New, archived
Headers show
Series arm: Add GICv3 support to the New VGIC | expand

Commit Message

Mykyta Poturai Nov. 10, 2023, 12:56 p.m. UTC
map_resources is the last initialization step needed before the first
VCPU is run. At that stage the code stores the MMIO base addresses used.
Also it registers the respective register frames with the MMIO framework.

This is based on Linux commit b0442ee227e826af by Eric Auger

Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
---
 xen/arch/arm/vgic/vgic-init.c |  2 +-
 xen/arch/arm/vgic/vgic-v3.c   | 85 +++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.c      | 13 +-----
 xen/arch/arm/vgic/vgic.h      |  5 +++
 4 files changed, 93 insertions(+), 12 deletions(-)
diff mbox series

Patch

diff --git a/xen/arch/arm/vgic/vgic-init.c b/xen/arch/arm/vgic/vgic-init.c
index c3b34be192..ca13cf385c 100644
--- a/xen/arch/arm/vgic/vgic-init.c
+++ b/xen/arch/arm/vgic/vgic-init.c
@@ -178,7 +178,7 @@  int domain_vgic_init(struct domain *d, unsigned int nr_spis)
     if ( dist->version == GIC_V2 )
         ret = vgic_v2_map_resources(d);
     else
-        ret = -ENXIO;
+        ret = vgic_v3_map_resources(d);
 
     if ( ret )
         return ret;
diff --git a/xen/arch/arm/vgic/vgic-v3.c b/xen/arch/arm/vgic/vgic-v3.c
index b018ee6040..470bb63147 100644
--- a/xen/arch/arm/vgic/vgic-v3.c
+++ b/xen/arch/arm/vgic/vgic-v3.c
@@ -14,11 +14,33 @@ 
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 #include <asm/new_vgic.h>
+#include <asm/gic_v3_defs.h>
 #include <asm/gic.h>
 #include <xen/sched.h>
 
 #include "vgic.h"
 
+static struct {
+    bool enabled;
+    /* Distributor interface address */
+    paddr_t dbase;
+    /* Re-distributor regions */
+    unsigned int nr_rdist_regions;
+    const struct rdist_region *regions;
+    unsigned int intid_bits; /* Number of interrupt ID bits */
+} vgic_v3_hw_data;
+
+void vgic_v3_setup_hw(paddr_t dbase, unsigned int nr_rdist_regions,
+                      const struct rdist_region *regions,
+                      unsigned int intid_bits)
+{
+    vgic_v3_hw_data.enabled          = true;
+    vgic_v3_hw_data.dbase            = dbase;
+    vgic_v3_hw_data.nr_rdist_regions = nr_rdist_regions;
+    vgic_v3_hw_data.regions          = regions;
+    vgic_v3_hw_data.intid_bits       = intid_bits;
+}
+
 /*
  * transfer the content of the LRs back into the corresponding ap_list:
  * - active bit is transferred as is
@@ -204,3 +226,66 @@  void vgic_v3_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr)
 
     gic_hw_ops->write_lr(lr, &lr_val);
 }
+
+unsigned int vgic_v3_max_rdist_count(const struct domain *d)
+{
+    /*
+     * Normally there is only one GICv3 redistributor region.
+     * The GICv3 DT binding provisions for multiple regions, since there are
+     * platforms out there which need those (multi-socket systems).
+     * For domain using the host memory layout, we have to live with the MMIO
+     * layout the hardware provides, so we have to copy the multiple regions
+     * - as the first region may not provide enough space to hold all
+     * redistributors we need.
+     * All the other domains will get a constructed memory map, so we can go
+     * with the architected single redistributor region.
+     */
+    return domain_use_host_layout(d) ? vgic_v3_hw_data.nr_rdist_regions
+                                     : GUEST_GICV3_RDIST_REGIONS;
+}
+
+int vgic_v3_map_resources(struct domain *d)
+{
+    int rdist_count, i, ret;
+
+    /* Allocate memory for Re-distributor regions */
+    rdist_count = vgic_v3_max_rdist_count(d);
+
+    /*
+     * For domain using the host memory layout, it gets the hardware
+     * address.
+     * Other domains get the virtual platform layout.
+     */
+    if ( domain_use_host_layout(d) )
+    {
+        d->arch.vgic.dbase = vgic_v3_hw_data.dbase;
+
+        for ( i = 0; i < vgic_v3_hw_data.nr_rdist_regions; i++ )
+        {
+            vgic_v3_set_redist_base(d, i, vgic_v3_hw_data.regions[i].base,
+                                    vgic_v3_hw_data.regions[i].size /
+                                        GICV3_GICR_SIZE);
+        }
+    }
+    else
+    {
+        d->arch.vgic.dbase = GUEST_GICV3_GICD_BASE;
+
+        /* A single Re-distributor region is mapped for the guest. */
+        BUILD_BUG_ON(GUEST_GICV3_RDIST_REGIONS != 1);
+
+        /* The first redistributor should contain enough space for all CPUs */
+        BUILD_BUG_ON((GUEST_GICV3_GICR0_SIZE / GICV3_GICR_SIZE) <
+                     MAX_VIRT_CPUS);
+        vgic_v3_set_redist_base(d, 0, GUEST_GICV3_GICR0_BASE,
+                                GUEST_GICV3_GICR0_SIZE / GICV3_GICR_SIZE);
+    }
+
+    /* Register mmio handle for the Distributor */
+    ret =
+        vgic_register_dist_iodev(d, gaddr_to_gfn(d->arch.vgic.dbase), VGIC_V3);
+
+    d->arch.vgic.ready = true;
+
+    return 0;
+}
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 946877bbac..2f9644dc18 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -968,23 +968,14 @@  unsigned int vgic_max_vcpus(unsigned int domctl_vgic_version)
     {
     case XEN_DOMCTL_CONFIG_GIC_V2:
         return VGIC_V2_MAX_CPUS;
+    case XEN_DOMCTL_CONFIG_GIC_V3:
+        return VGIC_V3_MAX_CPUS;
 
     default:
         return 0;
     }
 }
 
-#ifdef CONFIG_GICV3
-/* Dummy implementation to allow building without actual vGICv3 support. */
-void vgic_v3_setup_hw(paddr_t dbase,
-                      unsigned int nr_rdist_regions,
-                      const struct rdist_region *regions,
-                      unsigned int intid_bits)
-{
-    panic("New VGIC implementation does not yet support GICv3\n");
-}
-#endif
-
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index 0e0cf7b213..7dbadf7501 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -74,6 +74,7 @@  int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
 #ifdef CONFIG_GICV3
 void vgic_v3_fold_lr_state(struct vcpu *vcpu);
 void vgic_v3_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
+int vgic_v3_map_resources(struct domain *d);
 bool vgic_v3_emulate_reg(struct cpu_user_regs *regs, union hsr hsr);
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
 int vgic_v3_set_redist_base(struct domain *d, u32 index, u64 addr, u32 count);
@@ -85,6 +86,10 @@  static inline void vgic_v3_fold_lr_state(struct vcpu *vcpu)
 static inline void vgic_v3_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr)
 {
 }
+static inline int vgic_v3_map_resources(struct domain *d)
+{
+    return 0;
+}
 static inline unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
 {
     return 0;