From mboxrd@z Thu Jan 1 00:00:00 1970 From: vijay.kilari@gmail.com Subject: [PATCH v4 11/17] xen/arm: ITS: Add GICR register emulation Date: Fri, 10 Jul 2015 13:12:46 +0530 Message-ID: <1436514172-3263-12-git-send-email-vijay.kilari@gmail.com> References: <1436514172-3263-1-git-send-email-vijay.kilari@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1436514172-3263-1-git-send-email-vijay.kilari@gmail.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: Ian.Campbell@citrix.com, julien.grall@citrix.com, stefano.stabellini@eu.citrix.com, stefano.stabellini@citrix.com, tim@xen.org, xen-devel@lists.xen.org Cc: Prasun.Kapoor@caviumnetworks.com, Vijaya Kumar K , manish.jaggi@caviumnetworks.com, vijay.kilari@gmail.com List-Id: xen-devel@lists.xenproject.org From: Vijaya Kumar K Emulate LPI related changes to GICR registers Signed-off-by: Vijaya Kumar K --- v4: - Added LPI configuration table emulation - Rename function inline with vits - Copied guest lpi configuration table to xen --- xen/arch/arm/gic-v3.c | 15 ++++ xen/arch/arm/gic.c | 10 +++ xen/arch/arm/vgic-v3-its.c | 165 +++++++++++++++++++++++++++++++++++++ xen/arch/arm/vgic-v3.c | 85 +++++++++++++++++-- xen/arch/arm/vgic.c | 4 + xen/include/asm-arm/domain.h | 1 + xen/include/asm-arm/gic-its.h | 11 +++ xen/include/asm-arm/gic.h | 9 ++ xen/include/asm-arm/gic_v3_defs.h | 3 + 9 files changed, 295 insertions(+), 8 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 904fe57..e6004d2 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -677,6 +677,11 @@ static int __init gicv3_populate_rdist(void) return -ENODEV; } +static int gicv3_dist_supports_lpis(void) +{ + return readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_LPIS_SUPPORTED; +} + static int __cpuinit gicv3_cpu_init(void) { int i; @@ -1293,10 +1298,20 @@ static int __init gicv3_init(void) gicv3.rdist_regions[0].size, gicv3.rdist_regions[0].map_base, gicv3_info.maintenance_irq); + reg = readl_relaxed(GICD + GICD_TYPER); + + gicv3.rdist_data.id_bits = ((reg >> 19) & 0x1f) + 1; + gicv3_info.nr_id_bits = gicv3.rdist_data.id_bits; + spin_lock_init(&gicv3.lock); spin_lock(&gicv3.lock); + if ( gicv3_dist_supports_lpis() ) + gicv3_info.lpi_supported = 1; + else + gicv3_info.lpi_supported = 0; + gicv3_dist_init(); res = gicv3_cpu_init(); gicv3_hyp_init(); diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 4f3801b..3ebadcf 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -73,6 +73,16 @@ unsigned int gic_number_lines(void) return gic_hw_ops->info->nr_lines; } +unsigned int gic_nr_id_bits(void) +{ + return gic_hw_ops->info->nr_id_bits; +} + +bool_t gic_lpi_supported(void) +{ + return gic_hw_ops->info->lpi_supported; +} + void gic_save_state(struct vcpu *v) { ASSERT(!local_irq_is_enabled()); diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c index abf60e2..bbcc7bb 100644 --- a/xen/arch/arm/vgic-v3-its.c +++ b/xen/arch/arm/vgic-v3-its.c @@ -49,6 +49,36 @@ static void dump_cmd(its_cmd_block *cmd) } #endif +static void vits_disable_lpi(struct vcpu *v, uint32_t vlpi) +{ + struct pending_irq *p; + + p = irq_to_pending(v, vlpi); + clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status); + gic_remove_from_queues(v, vlpi); +} + +static void vits_enable_lpi(struct vcpu *v, uint32_t vlpi, uint8_t priority) +{ + struct pending_irq *p; + unsigned long flags; + + /* Get plpi for the given vlpi */ + p = irq_to_pending(v, vlpi); + + set_bit(GIC_IRQ_GUEST_ENABLED, &p->status); + + spin_lock_irqsave(&v->arch.vgic.lock, flags); + + /*XXX: raise on right vcpu */ + if ( !list_empty(&p->inflight) && + !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) ) + gic_raise_guest_irq(v, irq_to_virq(p->desc), p->priority); + + spin_unlock_irqrestore(&v->arch.vgic.lock, flags); +} + +/* ITS device table helper functions */ static int vits_entry(struct domain *d, paddr_t entry, void *addr, uint32_t size, bool_t set) { @@ -595,6 +625,141 @@ err: return 0; } +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); + + offset = info->gpa - + (v->domain->arch.vits->propbase & BIT_48_12_MASK); + + if ( offset < v->domain->arch.vits->prop_size ) + { + DPRINTK("%pv: vITS: LPI Table read offset 0x%x\n", v, offset); + spin_lock(&v->domain->arch.vits->prop_lock); + *r = *((u8*)v->domain->arch.vits->prop_page + offset); + spin_unlock(&v->domain->arch.vits->prop_lock); + return 1; + } + else + dprintk(XENLOG_G_ERR, "%pv: vITS: LPI Table read with wrong offset 0x%x\n", + v, offset); + + return 0; +} + +static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info) +{ + uint32_t offset; + uint32_t vid; + uint8_t cfg, *p; + 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); + + offset = info->gpa - + (v->domain->arch.vits->propbase & BIT_48_12_MASK); + + vid = offset + NR_GIC_LPI; + if ( offset < v->domain->arch.vits->prop_size ) + { + DPRINTK("%pv: vITS: LPI Table write offset 0x%x\n", v, offset); + + spin_lock(&v->domain->arch.vits->prop_lock); + p = ((u8*)v->domain->arch.vits->prop_page + offset); + cfg = *p; + enable = (cfg & *r) & 0x1; + + if ( !enable ) + vits_enable_lpi(v, vid, (*r & LPI_PRIORITY_MASK)); + else + vits_disable_lpi(v, vid); + + /* Update virtual prop page */ + *p = (*r & 0xff); + spin_unlock(&v->domain->arch.vits->prop_lock); + return 1; + } + else + dprintk(XENLOG_G_ERR, "%pv: vITS: LPI Table invalid write @ 0x%x\n", + v, offset); + + 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 vits_unmap_lpi_prop(struct vcpu *v) +{ + paddr_t maddr, addr; + unsigned long mfn; + uint32_t lpi_size, id_bits; + int i; + + maddr = v->domain->arch.vits->propbase & BIT_48_12_MASK; + id_bits = ((v->domain->arch.vits->propbase & GICR_PROPBASER_IDBITS_MASK)+1); + + DPRINTK("%pv: vITS: Unmap guest LPI conf table maddr 0x%lx lpi_size 0x%x\n", + v, maddr, lpi_size); + + spin_lock(&v->domain->arch.vits->prop_lock); + if ( id_bits > gic_nr_id_bits() ) + id_bits = gic_nr_id_bits(); + + lpi_size = 1UL << id_bits; + + v->domain->arch.vits->prop_size = lpi_size; + /* Allocate Virtual LPI Property table */ + /* TODO: To re-use guest property table? */ + v->domain->arch.vits->prop_page = + alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0); + if ( !v->domain->arch.vits->prop_page ) + { + dprintk(XENLOG_G_ERR, "%pv: vITS: Fail to allocate LPI Prop page\n", v); + return 0; + } + + addr = maddr; + for ( i = 0; i < lpi_size / PAGE_SIZE; i++ ) + { + vits_entry(v->domain, addr, + (void *)(v->domain->arch.vits->prop_page + i * PAGE_SIZE), + PAGE_SIZE, 0); + addr += PAGE_SIZE; + } + + /* + * Each re-distributor shares a common LPI configuration table + * So one set of mmio handlers to manage configuration table is enough + */ + addr = maddr; + for ( i = 0; i < lpi_size / PAGE_SIZE; i++ ) + { + mfn = gmfn_to_mfn(v->domain, paddr_to_pfn(addr)); + if ( unlikely(!mfn_valid(mfn)) ) + { + dprintk(XENLOG_G_ERR, "%pv: vITS: Wrong propbaser address\n", v); + return 0; + } + guest_physmap_remove_page(v->domain, paddr_to_pfn(addr), mfn, 0); + addr += PAGE_SIZE; + } + + /* Register mmio handlers for this region */ + register_mmio_handler(v->domain, &vgic_gits_lpi_mmio_handler, + maddr, lpi_size); + + spin_unlock(&v->domain->arch.vits->prop_lock); + + return 1; +} + static inline void vits_spin_lock(struct vgic_its *vits) { spin_lock(&vits->lock); diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index 4af5a84..25b69a0 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -30,6 +30,7 @@ #include #include #include +#include #include /* GICD_PIDRn register values for ARM implementations */ @@ -93,7 +94,18 @@ 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 */ + /* + * Enable LPI's for ITS. Direct injection of LPI + * by writing to GICR_{SET,CLR}LPIR are not supported + */ + if ( gic_lpi_supported() ) + { + if ( dabt.size != DABT_WORD ) goto bad_width; + vgic_lock(v); + *r = v->domain->arch.vgic.gicr_ctlr; + vgic_unlock(v); + return 1; + } goto read_as_zero_32; case GICR_IIDR: if ( dabt.size != DABT_WORD ) goto bad_width; @@ -106,11 +118,16 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info, MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 48 | MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 40 | MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0) << 32); + if ( gic_lpi_supported() ) + { + /* Set LPI support */ + aff |= GICR_TYPER_PLPIS; + /* GITS_TYPER.PTA is 0. Provice vcpu number as ta */ + aff |= (v->vcpu_id << GICR_TYPER_PROCESSOR_SHIFT); + } *r = aff; - if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST ) *r |= GICR_TYPER_LAST; - return 1; case GICR_STATUSR: /* Not implemented */ @@ -125,10 +142,21 @@ 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 */ + if ( gic_lpi_supported() ) + { + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width; + /* Remove shareability attribute we don't want dom to flush */ + *r = v->domain->arch.vits->propbase; + return 1; + } goto read_as_zero_64; case GICR_PENDBASER: - /* LPI's not implemented */ + if ( gic_lpi_supported() ) + { + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width; + *r = v->domain->arch.vits->pendbase[v->vcpu_id]; + return 1; + } goto read_as_zero_64; case GICR_INVLPIR: /* WO. Read as zero */ @@ -203,7 +231,18 @@ 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 */ + if ( gic_lpi_supported() ) + { + /* + * 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_CTLR_ENABLE_LPIS; + vgic_unlock(v); + return 1; + } goto write_ignore_32; case GICR_IIDR: /* RO */ @@ -224,10 +263,32 @@ 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: - /* LPI is not implemented */ + if ( gic_lpi_supported() ) + { + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width; + vgic_lock(v); + /* LPI configuration tables are shared across cpus. Should be same */ + /* TODO: Manage change in property table */ + if ( v->domain->arch.vits->propbase != 0 ) + { + vgic_unlock(v); + return 1; + } + v->domain->arch.vits->propbase = *r; + vgic_unlock(v); + return vits_unmap_lpi_prop(v); + } goto write_ignore_64; case GICR_PENDBASER: - /* LPI is not implemented */ + if ( gic_lpi_supported() ) + { + /* Just hold pendbaser value for guest read */ + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width; + vgic_lock(v); + v->domain->arch.vits->pendbase[v->vcpu_id] = *r; + vgic_unlock(v); + return 1; + } goto write_ignore_64; case GICR_INVLPIR: /* LPI is not implemented */ @@ -694,6 +755,14 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info) *r = ((ncpus - 1) << GICD_TYPE_CPUS_SHIFT | DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32)); + if ( gic_lpi_supported() ) + { + irq_bits = gic_nr_id_bits(); + *r |= GICD_TYPE_LPIS; + } + else + irq_bits = get_count_order(vgic_num_irqs(v->domain)); + *r |= (irq_bits - 1) << GICD_TYPE_ID_BITS_SHIFT; return 1; diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 73a6f7e..a5f66f6 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -154,6 +154,10 @@ void domain_vgic_free(struct domain *d) xfree(d->arch.vgic.shared_irqs); xfree(d->arch.vgic.pending_irqs); xfree(d->arch.vgic.allocated_irqs); +#ifdef CONFIG_ARM_64 + free_xenheap_pages(d->arch.vits->prop_page, + get_order_from_bytes(d->arch.vits->prop_size)); +#endif } int vcpu_vgic_init(struct vcpu *v) diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 67e4695..49db7f0 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -102,6 +102,7 @@ struct arch_domain paddr_t dbase; /* Distributor base address */ paddr_t cbase; /* CPU base address */ #ifdef CONFIG_ARM_64 + int gicr_ctlr; /* GIC V3 addressing */ paddr_t dbase_size; /* Distributor base size */ /* List of contiguous occupied by the redistributors */ diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h index 9c004c2..a79b70f 100644 --- a/xen/include/asm-arm/gic-its.h +++ b/xen/include/asm-arm/gic-its.h @@ -55,6 +55,16 @@ struct vgic_its unsigned long gits_size; /* GICR ctrl register */ uint32_t ctrl; + /* LPI propbase */ + paddr_t propbase; + /* percpu pendbase */ + paddr_t pendbase[MAX_VIRT_CPUS]; + /* Virtual LPI property table */ + void *prop_page; + /* Virtual LPI property size */ + uint64_t prop_size; + /* spinlock to protect lpi property table */ + spinlock_t prop_lock; /* vITT device table ipa */ paddr_t dt_ipa; /* vITT device table size */ @@ -266,6 +276,7 @@ int vits_get_vdevice_entry(struct domain *d, uint32_t devid, struct vits_device *vits_find_device(struct rb_root *root, uint32_t devid); int vits_insert_device(struct rb_root *root, struct vits_device *dev); void vits_remove_device(struct rb_root *root, struct vits_device *dev); +int vits_unmap_lpi_prop(struct vcpu *v); #endif /* __ASM_ARM_GIC_ITS_H__ */ /* diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index fdd96c8..69bf1ff 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -100,6 +100,7 @@ #define GICD_TYPE_CPUS_SHIFT 5 #define GICD_TYPE_CPUS 0x0e0 #define GICD_TYPE_SEC 0x400 +#define GICD_TYPE_LPIS (0x1UL << 17) #define GICC_CTL_ENABLE 0x1 #define GICC_CTL_EOI (0x1 << 9) @@ -283,6 +284,10 @@ extern void gic_dump_info(struct vcpu *v); /* Number of interrupt lines */ extern unsigned int gic_number_lines(void); +/* Number of interrupt id bits supported */ +extern unsigned int gic_nr_id_bits(void); +/* LPI support info */ +bool_t gic_lpi_supported(void); void gicv3_eoi_irq(struct irq_desc *irqd); void gicv3_dir_irq(struct irq_desc *irqd); @@ -302,6 +307,10 @@ struct gic_info { unsigned int maintenance_irq; /* Pointer to the device tree node representing the interrupt controller */ const struct dt_device_node *node; + /* Number of IRQ ID bits supported */ + uint32_t nr_id_bits; + /* LPIs are support information */ + bool_t lpi_supported; }; struct gic_hw_operations { diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h index 84366df..368ebb3 100644 --- a/xen/include/asm-arm/gic_v3_defs.h +++ b/xen/include/asm-arm/gic_v3_defs.h @@ -127,6 +127,7 @@ #define GICR_TYPER_PLPIS (1U << 0) #define GICR_TYPER_VLPIS (1U << 1) #define GICR_TYPER_LAST (1U << 4) +#define GICR_TYPER_PROCESSOR_SHIFT (8) #define GICR_PENDBASER_InnerShareable (1U << 10) #define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10) @@ -170,6 +171,7 @@ #define ICH_SGI_TARGETLIST_MASK 0xffff #define LPI_PROP_GROUP1 (1 << 1) #define LPI_PROP_ENABLED (1 << 0) +#define LPI_PRIORITY_MASK (0xfc) /* * ITS registers, offsets from ITS_base @@ -272,6 +274,7 @@ struct rdist { struct rdist_prop { void *prop_page; + int id_bits; uint64_t flags; }; -- 1.7.9.5