|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |