|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 11/17] xen/arm: ITS: Add GICR register emulation
From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
Emulate LPI related changes to GICR registers
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
---
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 <asm/mmio.h>
#include <asm/gic_v3_defs.h>
#include <asm/gic.h>
+#include <asm/gic-its.h>
#include <asm/vgic.h>
/* 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
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |