From: Vijaya Kumar K <vijaya.ku...@caviumnetworks.com> Add support for emulating GITS_* registers
Signed-off-by: Vijaya Kumar K <vijaya.ku...@caviumnetworks.com> --- 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@lists.xen.org http://lists.xen.org/xen-devel