From: Vijaya Kumar K
Emulate LPI related changes to GICR registers
Signed-off-by: Vijaya Kumar K
---
v6: - Moved LPI handling code to vgic-v3.c
- parse LPI property table on GICR_PROPBASER update
- use vgic_is_lpi_supported()
v5: - Handled all sizes access to LPI configuration table
- Rename vits_unmap_lpi_prop as vits_map_lpi_prop
v4: - Added LPI configuration table emulation
- Rename function inline with vits
- Copied guest lpi configuration table to xen
---
xen/arch/arm/vgic-v3-its.c|4 +
xen/arch/arm/vgic-v3.c| 354 -
xen/include/asm-arm/domain.h |3 +
xen/include/asm-arm/gic-its.h |9 +
xen/include/asm-arm/gic_v3_defs.h |4 +
5 files changed, 366 insertions(+), 8 deletions(-)
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index c384ecf..7c0375a 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -908,6 +909,7 @@ int vits_domain_init(struct domain *d)
vits = d->arch.vgic.vits;
spin_lock_init(>lock);
+spin_lock_init(>prop_lock);
vits->collections = xzalloc_array(struct its_collection,
vits_get_max_collections(d));
@@ -933,6 +935,8 @@ int vits_domain_init(struct domain *d)
void vits_domain_free(struct domain *d)
{
+ free_xenheap_pages(d->arch.vgic.vits->prop_page,
+ get_order_from_bytes(d->arch.vgic.vits->prop_size));
xfree(d->arch.vgic.vits->collections);
xfree(d->arch.vgic.vits);
}
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 4caac5e..dd7dc32 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -29,6 +29,8 @@
#include
#include
#include
+#include
+#include
#include
/* GICD_PIDRn register values for ARM implementations */
@@ -105,18 +107,287 @@ static struct vcpu *vgic_v3_get_target_vcpu(struct vcpu
*v, unsigned int irq)
return v_target;
}
+static void vits_disable_lpi(struct vcpu *v, uint32_t vlpi)
+{
+struct pending_irq *p;
+struct vcpu *v_target = v->domain->vcpu[0];
+
+p = irq_to_pending(v_target, vlpi);
+if ( test_bit(GIC_IRQ_GUEST_ENABLED, >status) )
+{
+clear_bit(GIC_IRQ_GUEST_ENABLED, >status);
+gic_remove_from_queues(v_target, vlpi);
+}
+}
+
+static void vits_enable_lpi(struct vcpu *v, uint32_t vlpi, uint8_t priority)
+{
+struct pending_irq *p;
+unsigned long flags;
+struct vcpu *v_target = v->domain->vcpu[0];
+
+/*
+ * We don't have vlpi to plpi mapping and hence we cannot
+ * have target on which corresponding vlpi is enabled.
+ * So for now we are always injecting vlpi on vcpu0.
+ * (See vgic_vcpu_inject_lpi() function) and so we get pending_irq
+ * structure on vcpu0.
+ * TODO: Get correct target vcpu
+ */
+p = irq_to_pending(v_target, vlpi);
+
+set_bit(GIC_IRQ_GUEST_ENABLED, >status);
+
+spin_lock_irqsave(_target->arch.vgic.lock, flags);
+
+if ( !list_empty(>inflight) &&
+ !test_bit(GIC_IRQ_GUEST_VISIBLE, >status) )
+gic_raise_guest_irq(v_target, vlpi, p->priority);
+
+spin_unlock_irqrestore(_target->arch.vgic.lock, flags);
+}
+
+static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+uint32_t offset;
+void *addr;
+uint64_t val;
+unsigned long flags;
+struct vgic_its *vits = v->domain->arch.vgic.vits;
+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 - (vits->propbase & GICR_PROPBASER_PA_MASK);
+if ( offset > vits->prop_size )
+{
+dprintk(XENLOG_G_ERR, "%pv: vITS: LPI property table out of range\n",
+current);
+return 1;
+}
+
+/* Neglect if not LPI. */
+if ( offset < FIRST_GIC_LPI )
+{
+*r = 0;
+return 1;
+}
+
+addr = (void *)((u8*)vits->prop_page + offset);
+spin_lock_irqsave(>prop_lock, flags);
+switch (dabt.size)
+{
+case DABT_DOUBLE_WORD:
+val = *((u64*)addr);
+*r = val;
+break;
+case DABT_WORD:
+val = *((u32*)addr);
+*r = (u32)val;
+break;
+case DABT_HALF_WORD:
+val = *((u16*)addr);
+*r = (u16)val;
+break;
+default:
+val = *((u8*)addr);
+*r = (u8)val;
+}
+spin_unlock_irqrestore(>prop_lock, flags);
+
+return 1;
+}
+
+static void vgic_v3_gits_update_lpis_state(struct vcpu *v, uint32_t vid,
+ uint32_t size)
+{
+struct vgic_its *vits = v->domain->arch.vgic.vits;
+uint32_t i;
+uint8_t cfg, *p;
+bool_t enable;
+
+p = ((u8*)vits->prop_page + vid);
+
+for ( i = 0 ; i < size;