[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs
On Mon, 2 Mar 2015, vijay.kilari@xxxxxxxxx wrote: > 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); We need to properly support priorities too. > + 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); I guess we could reuse the original unmapped guest page instead of allocating a new one? > + 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 > + */ Is this actually a limitation that we can have? Is there a way to communicate to the guest OS that 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); If I am not mistaken, nothing updates the virtual LPI pending table with the status of inflight virtual LPIs. The pending table is not emulated at all. I think that at the very least you should add a comment saying that reading the pending status of LPIs via the pending table is not supported. > + 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |