@@ -18,6 +18,7 @@
#include <xen/lib.h>
#include <xen/sched.h>
#include <asm/new_vgic.h>
+#include <asm/gic_v3_its.h>
#include "vgic.h"
@@ -173,8 +174,14 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
}
INIT_LIST_HEAD(&dist->lpi_list_head);
+ INIT_LIST_HEAD(&dist->lpi_translation_cache);
+ dist->lpi_list_count=0;
spin_lock_init(&dist->lpi_list_lock);
+ ret = vgic_v3_its_init_domain(d);
+ if ( ret )
+ return ret;
+
if ( dist->version == GIC_V2 )
ret = vgic_v2_map_resources(d);
else
@@ -168,7 +168,7 @@ static int update_lpi_config(struct domain *d, struct vgic_irq *irq,
return 0;
}
-static int vgic_v3_lpi_sync_pending_status(struct domain *d, struct vgic_irq *irq)
+int vgic_v3_lpi_sync_pending_status(struct domain *d, struct vgic_irq *irq)
{
struct vcpu *vcpu;
int byte_offset, bit_nr;
@@ -29,7 +29,7 @@ bool vgic_has_its(struct domain *d)
if ( dist->version != GIC_V3 )
return false;
- return false;
+ return dist->has_its;
}
static struct vcpu *mpidr_to_vcpu(struct domain *d, unsigned long mpidr)
@@ -211,6 +211,29 @@ bool vgic_v3_emulate_reg(struct cpu_user_regs *regs, union hsr hsr)
}
}
+void vgic_flush_pending_lpis(struct vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+ struct vgic_irq *irq, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
+
+ list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list)
+ {
+ if ( irq->intid >= VGIC_MIN_LPI )
+ {
+ spin_lock(&irq->irq_lock);
+ list_del(&irq->ap_list);
+ irq->vcpu = NULL;
+ spin_unlock(&irq->irq_lock);
+ vgic_put_irq(vcpu->domain, irq);
+ }
+ }
+
+ spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
+}
+
/*
* The Revision field in the IIDR have the following meanings:
*
@@ -234,7 +257,15 @@ static unsigned long vgic_mmio_read_v3_misc(struct vcpu *vcpu, paddr_t addr,
case GICD_TYPER:
value = vgic->nr_spis + VGIC_NR_PRIVATE_IRQS;
value = (value >> 5) - 1;
- value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+ if ( vgic_has_its(vcpu->domain) )
+ {
+ value |= (INTERRUPT_ID_BITS_ITS - 1) << 19;
+ value |= GICD_TYPE_LPIS;
+ }
+ else
+ {
+ value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+ }
break;
case GICD_TYPER2:
break;
@@ -365,6 +396,9 @@ static unsigned long vgic_mmio_read_v3r_typer(struct vcpu *vcpu, paddr_t addr,
value = (u64)(mpidr & GENMASK(23, 0)) << 32;
value |= ((target_vcpu_id & 0xffff) << 8);
+ if ( vgic_has_its(vcpu->domain) )
+ value |= GICR_TYPER_PLPIS;
+
if ( vgic_mmio_vcpu_rdist_is_last(vcpu) )
value |= GICR_TYPER_LAST;
@@ -422,12 +456,18 @@ static void vgic_mmio_write_v3r_ctlr(struct vcpu *vcpu, paddr_t addr,
GICR_CTLR_RWP);
if ( ctlr != GICR_CTLR_ENABLE_LPIS )
return;
+
+ vgic_flush_pending_lpis(vcpu);
+ vgic_its_invalidate_cache(vcpu->domain);
+ atomic_set(&vgic_cpu->ctlr, 0);
}
else
{
ctlr = atomic_cmpxchg(&vgic_cpu->ctlr, 0, GICR_CTLR_ENABLE_LPIS);
if ( ctlr != 0 )
return;
+
+ vgic_enable_lpis(vcpu);
}
}
@@ -156,6 +156,7 @@ uint64_t update_64bit_reg(u64 reg, unsigned int offset, unsigned int len,
#ifdef CONFIG_HAS_ITS
int vgic_its_inv_lpi(struct domain *d, struct vgic_irq *irq);
int vgic_its_invall(struct vcpu *vcpu);
+void vgic_its_invalidate_cache(struct domain *d);
#else
static inline int vgic_its_inv_lpi(struct domain *d, struct vgic_irq *irq)
{
@@ -166,6 +167,10 @@ static inline int vgic_its_invall(struct vcpu *vcpu)
{
return 0;
}
+
+static inline void vgic_its_invalidate_cache(struct domain *d)
+{
+}
#endif
#endif
Now that all ITS emulation functionality is in place, we advertise the ITS device to the guest. Based on Linux commit 0e4e82f154e38 by Andre Przywara Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com> --- xen/arch/arm/vgic/vgic-init.c | 7 +++++ xen/arch/arm/vgic/vgic-its.c | 2 +- xen/arch/arm/vgic/vgic-mmio-v3.c | 44 ++++++++++++++++++++++++++++++-- xen/arch/arm/vgic/vgic-mmio.h | 5 ++++ 4 files changed, 55 insertions(+), 3 deletions(-)