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

[Xen-devel] [RFC PATCH 11/19] xen/arm: its: Add emulation of ITS control registers



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

Add support for emulating GITS_* registers

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
---
 xen/arch/arm/gic-v3-its.c     |    9 +
 xen/arch/arm/vgic-v3-its.c    |  369 ++++++++++++++++++++++++++++++++++++++++-
 xen/include/asm-arm/gic-its.h |    2 +
 3 files changed, 379 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 68bb7ba..5d9550f 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -68,6 +68,7 @@
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
 
 struct its_node *its;
+uint32_t pta_type;
 
 /*
  * Collection structure - just an ID, and a redistributor address to
@@ -139,6 +140,11 @@ struct its_cmd_desc {
 typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
                                 struct its_cmd_desc *);
 
+uint32_t its_get_pta_type(void)
+{
+    return pta_type;
+}
+
 static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
@@ -764,6 +770,9 @@ static int its_probe(struct dt_device_node *node)
     its->phys_size = its_size;
     its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
 
+    if ( (readq_relaxed(its->base + GITS_TYPER) & GITS_TYPER_PTA) )
+       pta_type = 1;
+
     its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ);
     if (!its->cmd_base) {
         err = -ENOMEM;
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 4babb2a..7e1cc04 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -965,7 +965,7 @@ static int vgic_its_read_virt_cmd(struct vcpu *v,
     return 0;
 }
 
-int vgic_its_process_cmd(struct vcpu *v)
+static int vgic_its_process_cmd(struct vcpu *v)
 {
     struct its_cmd_block virt_cmd;
     struct domain *d = v->domain;
@@ -996,6 +996,373 @@ err:
     return 0;
 }
 
+static int __vgic_v3_its_ctrl_mmio_read(struct vcpu *v, mmio_info_t *info,
+                                        uint32_t gits_reg)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    uint64_t val = 0;
+    uint32_t index;
+
+    switch ( gits_reg )
+    {
+    case GITS_CTLR:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        return 1;
+    case GITS_IIDR:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        return 1;
+    case GITS_TYPER:
+         /* GITS_TYPER support word read */
+        spin_lock(&v->domain->arch.vits->lock);
+        val = ((its_get_pta_type() << VITS_GITS_TYPER_PTA_SHIFT) |
+               VITS_GITS_TYPER_HCC   | VITS_GITS_DEV_BITS |
+               VITS_GITS_ID_BITS     | VITS_GITS_ITT_SIZE |
+               VITS_GITS_DISTRIBUTED | VITS_GITS_PLPIS);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = val;
+        else if ( dabt.size == DABT_WORD )
+            *r = (u32)(val >> 32);
+        else
+        {
+            spin_unlock(&v->domain->arch.vits->lock);
+            goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+
+    case GITS_TYPER + 4:
+        if (dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        val = ((its_get_pta_type() << VITS_GITS_TYPER_PTA_SHIFT) |
+               VITS_GITS_TYPER_HCC   | VITS_GITS_DEV_BITS |
+               VITS_GITS_ID_BITS     | VITS_GITS_ITT_SIZE |
+               VITS_GITS_DISTRIBUTED | VITS_GITS_PLPIS);
+        *r = (u32)val;
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case 0x0010 ... 0x007c:
+    case 0xc000 ... 0xffcc:
+        /* Implementation defined -- read ignored */
+        dprintk(XENLOG_G_DEBUG,
+                "vGITS: read unknown 0x000c - 0x007c r%d offset %#08x\n",
+                dabt.reg, gits_reg);
+        goto read_as_zero;
+    case GITS_CBASER:
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = v->domain->arch.vits->cmd_base && 0xc7ffffffffffffffUL;
+        else if ( dabt.size == DABT_WORD )
+            *r = (u32)v->domain->arch.vits->cmd_base;
+        else
+        {
+             spin_unlock(&v->domain->arch.vits->lock);
+             goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CBASER + 4:
+         /* CBASER support word read */
+        if (dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        *r = (u32)(v->domain->arch.vits->cmd_base >> 32);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CWRITER:
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = v->domain->arch.vits->cmd_write;
+        else if ( dabt.size == DABT_WORD )
+            *r = (u32)v->domain->arch.vits->cmd_write;
+        else
+        {
+             spin_unlock(&v->domain->arch.vits->lock);
+             goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CWRITER + 4:
+         /* CWRITER support word read */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        *r = (u32)(v->domain->arch.vits->cmd_write >> 32);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CREADR:
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = v->domain->arch.vits->cmd_read;
+        else if ( dabt.size == DABT_WORD )
+            *r = (u32)v->domain->arch.vits->cmd_read;
+        else
+        {
+             spin_unlock(&v->domain->arch.vits->lock);
+             goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CREADR + 4:
+         /* CREADR support word read */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        *r = (u32)(v->domain->arch.vits->cmd_read >> 32);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case 0x0098 ... 0x009c:
+    case 0x00a0 ... 0x00fc:
+    case 0x0140 ... 0xbffc:
+        /* Reserved -- read ignored */
+        dprintk(XENLOG_G_DEBUG,
+                "vGITS: read unknown 0x0098-9c or 0x00a0-fc r%d offset 
%#08x\n",
+                dabt.reg, gits_reg);
+        goto read_as_zero;
+    case GITS_BASER ... GITS_BASERN:
+        spin_lock(&v->domain->arch.vits->lock);
+        index = (gits_reg - GITS_BASER) / 8;
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = v->domain->arch.vits->baser[index];
+        else if ( dabt.size == DABT_WORD )
+        {
+            if ( (gits_reg % 8) == 0 )
+                *r = (u32)v->domain->arch.vits->baser[index];
+            else
+                *r = (u32)(v->domain->arch.vits->baser[index] >> 32);
+        }
+        else
+        {
+            spin_unlock(&v->domain->arch.vits->lock);
+            goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_PIDR0:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR0_VAL;
+        return 1;
+    case GITS_PIDR1:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR1_VAL;
+        return 1;
+    case GITS_PIDR2:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR2_VAL;
+        return 1;
+    case GITS_PIDR3:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR3_VAL;
+        return 1;
+    case GITS_PIDR4:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR4_VAL;
+        return 1;
+    case GITS_PIDR5 ... GITS_PIDR7:
+        goto read_as_zero;
+   default:
+        dprintk(XENLOG_G_ERR, "vGITS: unhandled read r%d offset %#08x\n",
+               dabt.reg, gits_reg);
+        return 0;
+    }
+
+bad_width:
+    dprintk(XENLOG_G_ERR, "vGITS: bad read width %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, gits_reg);
+    domain_crash_synchronous();
+    return 0;
+
+read_as_zero:
+    if ( dabt.size != DABT_WORD ) goto bad_width;
+    *r = 0;
+    return 1;
+}
+
+static int __vgic_v3_its_ctrl_mmio_write(struct vcpu *v, mmio_info_t *info,
+                                         uint32_t gits_reg)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    int ret, index;
+    uint64_t val;
+
+    switch ( gits_reg )
+    {
+    case GITS_CTLR:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        v->domain->arch.vits->ctrl = *r;
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_IIDR:
+        /* R0 -- write ignored */
+        goto write_ignore;
+    case GITS_TYPER:
+    case GITS_TYPER + 4:
+        /* R0 -- write ignored */
+        goto write_ignore;
+    case 0x0010 ... 0x007c:
+    case 0xc000 ... 0xffcc:
+        /* Implementation defined -- write ignored */
+        dprintk(XENLOG_G_DEBUG,
+                "vGITS: write to unknown 0x000c - 0x007c r%d offset %#08x\n",
+                dabt.reg, gits_reg);
+        goto write_ignore;
+    case GITS_CBASER:
+        if ( dabt.size == DABT_BYTE ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            v->domain->arch.vits->cmd_base = *r;
+        else
+        {
+            val = v->domain->arch.vits->cmd_base & 0xffffffff00000000UL;
+            val = (*r) | val;
+            v->domain->arch.vits->cmd_base =  val;
+        }
+        v->domain->arch.vits->cmd_qsize  =  SZ_4K * ((*r & 0xff) + 1);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CBASER + 4:
+         /* CBASER support word read */
+        if (dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        val = v->domain->arch.vits->cmd_base & 0xffffffffUL;
+        val = ((*r & 0xffffffffUL) << 32 ) | val;
+        v->domain->arch.vits->cmd_base =  val;
+        /* No Need to update cmd_qsize with higher word write */
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CWRITER:
+        if ( dabt.size == DABT_BYTE ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            v->domain->arch.vits->cmd_write = *r;
+        else
+        {
+            val = v->domain->arch.vits->cmd_write & 0xffffffff00000000UL;
+            val = (*r) | val;
+            v->domain->arch.vits->cmd_write =  val;
+        }
+        ret = vgic_its_process_cmd(v);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return ret;
+    case GITS_CWRITER + 4:
+        if (dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        val = v->domain->arch.vits->cmd_write & 0xffffffffUL;
+        val = ((*r & 0xffffffffUL) << 32) | val;
+        v->domain->arch.vits->cmd_write =  val;
+        ret = vgic_its_process_cmd(v);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return ret;
+    case GITS_CREADR:
+        /* R0 -- write ignored */
+        goto write_ignore;
+    case 0x0098 ... 0x009c:
+    case 0x00a0 ... 0x00fc:
+    case 0x0140 ... 0xbffc:
+        /* Reserved -- write ignored */
+        dprintk(XENLOG_G_DEBUG,
+                "vGITS: write to unknown 0x98-9c or 0xa0-fc r%d offset 
%#08x\n",
+                dabt.reg, gits_reg);
+        goto write_ignore;
+    case GITS_BASER ... GITS_BASERN:
+        /* Nothing to do with this values. Just store and emulate */
+        spin_lock(&v->domain->arch.vits->lock);
+        index = (gits_reg - GITS_BASER) / 8;
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            v->domain->arch.vits->baser[index] = *r;
+        else if ( dabt.size == DABT_WORD )
+        {
+            if ( (gits_reg % 8) == 0 )
+            {
+                val = v->domain->arch.vits->cmd_write & 0xffffffff00000000UL;
+                val = (*r) | val;
+                v->domain->arch.vits->baser[index] = val;
+            }
+            else
+            {
+                val = v->domain->arch.vits->baser[index] & 0xffffffffUL;
+                val = ((*r & 0xffffffffUL) << 32) | val;
+                v->domain->arch.vits->baser[index] = val;
+            }
+        }
+        else
+        {
+            goto bad_width;
+            spin_unlock(&v->domain->arch.vits->lock);
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_PIDR7 ... GITS_PIDR0:
+        /* R0 -- write ignored */
+        goto write_ignore;
+   default:
+        dprintk(XENLOG_G_ERR, "vGITS: unhandled write r%d offset %#08x\n",
+                dabt.reg, gits_reg);
+        return 0;
+    }
+
+bad_width:
+    dprintk(XENLOG_G_ERR, "vGITS: bad write width %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, gits_reg);
+    domain_crash_synchronous();
+    return 0;
+
+write_ignore:
+    if ( dabt.size != DABT_WORD ) goto bad_width;
+    *r = 0;
+    return 1;
+}
+
+static int vgic_v3_gits_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+
+    offset = info->gpa - v->domain->arch.vits->phys_base;
+
+    if ( offset < SZ_64K )
+        return __vgic_v3_its_ctrl_mmio_read(v, info, offset);
+    else
+        gdprintk(XENLOG_G_WARNING, "vGITS: unknown gpa read address \
+                  %"PRIpaddr"\n", info->gpa);
+
+    return 0;
+}
+
+static int vgic_v3_gits_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+
+    offset = info->gpa  - v->domain->arch.vits->phys_base;
+    if ( offset < SZ_64K )
+        return __vgic_v3_its_ctrl_mmio_write(v, info, offset);
+    else
+        gdprintk(XENLOG_G_WARNING, "vGIC-ITS: unknown gpa write address"
+                 " %"PRIpaddr"\n", info->gpa);
+
+    return 0;
+}
+
+static const struct mmio_handler_ops vgic_gits_mmio_handler = {
+    .read_handler  = vgic_v3_gits_mmio_read,
+    .write_handler = vgic_v3_gits_mmio_write,
+};
+
+int vgic_its_domain_init(struct domain *d)
+{
+    d->arch.vits = xzalloc(struct vgic_its);
+    if ( d->arch.vits == NULL )
+        return -ENOMEM;
+
+    INIT_LIST_HEAD(&d->arch.vits->vits_dev_list);
+    spin_lock_init(&d->arch.vits->lock);
+
+    register_mmio_handler(d, &vgic_gits_mmio_handler, d->arch.vits->phys_base,
+                          SZ_64K);
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 0b2f95e..bb9ac33 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -227,10 +227,12 @@ 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);
 uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid);
 
 int its_check_target(uint64_t vta);
 int its_get_target(uint8_t pcid, uint64_t *pta);
+uint32_t its_get_pta_type(void);
 int its_get_physical_cid(uint32_t *col_id, uint64_t ta);
 int gic_its_send_cmd(struct vcpu *v, struct its_cmd_block *phys_cmd);
 
-- 
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®.