|
[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 |