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

[Xen-devel] [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs



From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>

With this patch add emulation of GICR registers for LPIs.
Also add LPI property table emulation.

Domain's LPI property table is unmapped during domain init
on LPIPROPBASE update and trapped on LPI property
table read and write

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
---
 xen/arch/arm/vgic-v3-its.c        |  156 +++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic-v3.c            |   64 ++++++++++++---
 xen/include/asm-arm/domain.h      |    1 +
 xen/include/asm-arm/gic-its.h     |    1 +
 xen/include/asm-arm/gic.h         |    2 +
 xen/include/asm-arm/gic_v3_defs.h |    2 +
 6 files changed, 214 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 7e1cc04..48c880a 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -996,6 +996,162 @@ err:
     return 0;
 }
 
+/* Search device structure and get corresponding plpi */
+int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid)
+{
+    struct domain *d = v->domain;
+    struct vits_device *dev;
+    struct its_lpi_chunk *chunk;
+    int i;
+
+    list_for_each_entry( dev, &d->arch.vits->vits_dev_list, entry )
+    {
+        list_for_each_entry( chunk, &dev->hwirq_list, entry )
+        {
+            for ( i = 0; i < IRQS_PER_CHUNK; i++ )
+            {
+                if ( test_bit(i, &chunk->lpi_map) && chunk->vid[i] == vid )
+                {
+                    *pid = chunk->pid[i];
+                     return 0;
+                }
+            }
+        }
+    }
+
+    return 1;
+}
+
+static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    uint8_t cfg;
+
+    spin_lock(&v->domain->arch.vits->lock);
+    offset = info->gpa -
+             (v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL);
+
+    if ( offset < SZ_64K )
+    {
+        DPRINTK("vITS: LPI Table read offset 0x%x\n", offset );
+        cfg = readb_relaxed(v->domain->arch.vits->lpi_prop_page + offset);
+        *r = cfg;
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    }
+    else
+        dprintk(XENLOG_ERR, "vITS: LPI Table read with wrong offset 0x%x\n",
+                offset);
+
+    spin_unlock(&v->domain->arch.vits->lock);
+
+    return 0;
+}
+
+static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+    uint32_t pid, vid;
+    uint8_t cfg;
+    bool_t enable;
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+
+    spin_lock(&v->domain->arch.vits->lock);
+    offset = info->gpa -
+             (v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL);
+
+    vid = offset + NR_GIC_LPI;
+    if ( offset < SZ_64K )
+    {
+        DPRINTK("vITS: LPI Table write offset 0x%x\n", offset );
+        if ( vgic_its_get_pid(v, vid, &pid) )
+        {
+            spin_unlock(&v->domain->arch.vits->lock);
+            dprintk(XENLOG_ERR, "vITS: pID not found for vid %d\n", vid);
+            return 0;
+        }
+
+        cfg = readb_relaxed(v->domain->arch.vits->lpi_prop_page + offset);
+        enable = (cfg & *r) & 0x1;
+
+        if ( !enable )
+             vgic_its_enable_lpis(v, pid);
+        else
+             vgic_its_disable_lpis(v, pid);
+
+        /* Update virtual prop page */
+        writeb_relaxed((*r & 0xff),
+                        v->domain->arch.vits->lpi_prop_page + offset);
+
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    }
+    else
+        dprintk(XENLOG_ERR, "vITS: LPI Table write with wrong offset 0x%x\n",
+                offset);
+
+    spin_unlock(&v->domain->arch.vits->lock);
+
+    return 0;
+}
+
+static const struct mmio_handler_ops vgic_gits_lpi_mmio_handler = {
+    .read_handler  = vgic_v3_gits_lpi_mmio_read,
+    .write_handler = vgic_v3_gits_lpi_mmio_write,
+};
+
+int vgic_its_unmap_lpi_prop(struct vcpu *v)
+{
+    paddr_t maddr;
+    uint32_t lpi_size;
+    int i;
+
+    spin_lock(&v->domain->arch.vits->lock);
+    maddr = v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL;
+    lpi_size = 1UL << ((v->domain->arch.vits->lpi_propbase & 0x1f) + 1);
+
+    DPRINTK("vITS: Unmap guest LPI conf table maddr 0x%lx lpi_size 0x%x\n",
+             maddr, lpi_size);
+
+    if ( lpi_size < SZ_64K )
+    {
+        spin_unlock(&v->domain->arch.vits->lock);
+        dprintk(XENLOG_ERR, "vITS: LPI Prop page < 64K\n");
+        return 0;
+    }
+
+    /* XXX: As per 4.8.9 each re-distributor shares a common LPI configuration 
table
+     * So one set of mmio handlers to manage configuration table is enough
+     */
+    for ( i = 0; i < lpi_size / PAGE_SIZE; i++ )
+        guest_physmap_remove_page(v->domain, paddr_to_pfn(maddr),
+                                gmfn_to_mfn(v->domain, paddr_to_pfn(maddr)), 
0);
+
+    /* Register mmio handlers for this region */
+    register_mmio_handler(v->domain, &vgic_gits_lpi_mmio_handler,
+                          maddr, lpi_size);
+
+    /* Allocate Virtual LPI Property table */
+    v->domain->arch.vits->lpi_prop_page =
+        alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0);
+    if ( !v->domain->arch.vits->lpi_prop_page )
+    {
+        spin_unlock(&v->domain->arch.vits->lock);
+        dprintk(XENLOG_ERR, "vITS: Failed to allocate LPI Prop page\n");
+        return 0;
+    }
+
+    memset(v->domain->arch.vits->lpi_prop_page, 0xa2, lpi_size);
+    spin_unlock(&v->domain->arch.vits->lock);
+
+    return 1;
+}
+
 static int __vgic_v3_its_ctrl_mmio_read(struct vcpu *v, mmio_info_t *info,
                                         uint32_t gits_reg)
 {
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index bece189..89e6195 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -32,6 +32,7 @@
 #include <asm/gic_v3_defs.h>
 #include <asm/gic.h>
 #include <asm/vgic.h>
+#include <asm/gic-its.h>
 
 /* GICD_PIDRn register values for ARM implementations */
 #define GICV3_GICD_PIDR0  0x92
@@ -94,19 +95,29 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, 
mmio_info_t *info,
     switch ( gicr_reg )
     {
     case GICR_CTLR:
-        /* We have not implemented LPI's, read zero */
-        goto read_as_zero;
+        /*
+         * Enable LPI's for ITS. Direct injection of LPI
+         * by writing to GICR_{SET,CLR}LPIR are not supported
+         */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        vgic_lock(v);
+        *r = v->domain->arch.vgic.gicr_ctlr;
+        vgic_unlock(v);
+        return 1;
     case GICR_IIDR:
         if ( dabt.size != DABT_WORD ) goto bad_width;
         *r = GICV3_GICR_IIDR_VAL;
         return 1;
     case GICR_TYPER:
-        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
-        /* TBD: Update processor id in [23:8] when ITS support is added */
+        if ( dabt.size != DABT_WORD && dabt.size != DABT_DOUBLE_WORD )
+            goto bad_width;
+        /* XXX: Update processor id in [23:8] if GITS_TYPER: PTA is not set */
         aff = (MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 3) << 56 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 48 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 40 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0) << 32);
+        /* Set LPI support */
+        aff |= (GICR_TYPER_DISTRIBUTED_IMP | GICR_TYPER_PLPIS);
         *r = aff;
         return 1;
     case GICR_STATUSR:
@@ -122,10 +133,13 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, 
mmio_info_t *info,
         /* WO. Read as zero */
         goto read_as_zero_64;
     case GICR_PROPBASER:
-        /* LPI's not implemented */
-        goto read_as_zero_64;
+        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+        /* Remove shareability attribute we don't want dom to flush */
+        *r = v->domain->arch.vits->lpi_propbase;
+        return 1;
     case GICR_PENDBASER:
-        /* LPI's not implemented */
+        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+        *r = v->domain->arch.vits->lpi_pendbase[v->vcpu_id];
         goto read_as_zero_64;
     case GICR_INVLPIR:
         /* WO. Read as zero */
@@ -200,8 +214,15 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, 
mmio_info_t *info,
     switch ( gicr_reg )
     {
     case GICR_CTLR:
-        /* LPI's not implemented */
-        goto write_ignore;
+        /*
+         * Enable LPI's for ITS. Direct injection of LPI
+         * by writing to GICR_{SET,CLR}LPIR are not supported
+         */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        vgic_lock(v);
+        v->domain->arch.vgic.gicr_ctlr = (*r) & GICR_CTL_ENABLE;
+        vgic_unlock(v);
+        return 1;
     case GICR_IIDR:
         /* RO */
         goto write_ignore;
@@ -221,11 +242,29 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, 
mmio_info_t *info,
         /* LPI is not implemented */
         goto write_ignore_64;
     case GICR_PROPBASER:
+        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+        vgic_lock(v);
+        /* LPI configuration tables are shared across cpus. Should be same */
+        if ( (v->domain->arch.vits->lpi_propbase != 0) &&
+             ((v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL) !=  (*r 
& 0xfffffffff000UL)) )
+        {
+            dprintk(XENLOG_G_ERR,
+                "vGICv3: vITS: Wrong configuration of LPI_PROPBASER\n");
+            vgic_unlock(v);
+            return 0;
+        }
+        v->domain->arch.vits->lpi_propbase = *r;
+        vgic_unlock(v);
+        return vgic_its_unmap_lpi_prop(v);
         /* LPI is not implemented */
         goto write_ignore_64;
     case GICR_PENDBASER:
-        /* LPI is not implemented */
-        goto write_ignore_64;
+        /* Just hold pendbaser value for guest read */
+        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+        vgic_lock(v);
+        v->domain->arch.vits->lpi_pendbase[v->vcpu_id] = *r;
+        vgic_unlock(v);
+        return 1;
     case GICR_INVLPIR:
         /* LPI is not implemented */
         goto write_ignore_64;
@@ -682,7 +721,8 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, 
mmio_info_t *info)
         if ( dabt.size != DABT_WORD ) goto bad_width;
         /* No secure world support for guests. */
         *r = (((v->domain->max_vcpus << 5) & GICD_TYPE_CPUS ) |
-              ((v->domain->arch.vgic.nr_spis / 32) & GICD_TYPE_LINES));
+              ((v->domain->arch.vgic.nr_spis / 32) & GICD_TYPE_LINES) |
+              GICD_TYPE_LPIS | GICD_TYPE_ID_BITS);
         return 1;
     case GICD_STATUSR:
         /*
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index d02c200..b6d85b8 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -101,6 +101,7 @@ struct arch_domain
         paddr_t cbase; /* CPU base address */
 #ifdef CONFIG_ARM_64
         /* GIC V3 addressing */
+        int gicr_ctlr;
         paddr_t dbase_size; /* Distributor base size */
         paddr_t rbase[MAX_RDIST_COUNT];      /* Re-Distributor base address */
         paddr_t rbase_size[MAX_RDIST_COUNT]; /* Re-Distributor size */
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index bb9ac33..5329e9d 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -228,6 +228,7 @@ static inline void its_fixup_cmd(struct its_cmd_block *cmd)
 void vgic_its_enable_lpis(struct vcpu *v, uint32_t lpi);
 int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid);
 int vgic_its_domain_init(struct domain *d);
+int vgic_its_unmap_lpi_prop(struct vcpu *v);
 uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid);
 
 int its_check_target(uint64_t vta);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 1b4b7d1..681d75c 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -96,6 +96,8 @@
 #define GICD_TYPE_LINES 0x01f
 #define GICD_TYPE_CPUS  0x0e0
 #define GICD_TYPE_SEC   0x400
+#define GICD_TYPE_LPIS           (0x1UL << 17)
+#define GICD_TYPE_ID_BITS        (0x13UL << 19)
 
 #define GICC_CTL_ENABLE 0x1
 #define GICC_CTL_EOI    (0x1 << 9)
diff --git a/xen/include/asm-arm/gic_v3_defs.h 
b/xen/include/asm-arm/gic_v3_defs.h
index 83d75cf..b81f83f 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -127,9 +127,11 @@
 #define GICR_PROPBASER_RaWaWb          (7U << 7)
 #define GICR_PROPBASER_IDBITS_MASK     (0x1f)
 
+#define GICR_CTL_ENABLE              (1U << 0)
 #define GICR_TYPER_PLPIS             (1U << 0)
 #define GICR_TYPER_VLPIS             (1U << 1)
 #define GICR_TYPER_LAST              (1U << 4)
+#define GICR_TYPER_DISTRIBUTED_IMP   (1U << 3)
 
 #define DEFAULT_PMR_VALUE            0xff
 
-- 
1.7.9.5


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