@@ -224,20 +224,15 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ISENABLER, DABT_WORD);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank, flags);
- *r = vgic_reg32_extract(rank->ienable, info);
- vgic_unlock_rank(v, rank, flags);
+ irq = (gicd_reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero;
+ *r = vgic_reg32_extract(gather_irq_info_enabled(v, irq), info);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICENABLER, DABT_WORD);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank, flags);
- *r = vgic_reg32_extract(rank->ienable, info);
- vgic_unlock_rank(v, rank, flags);
+ irq = (gicd_reg - GICD_ISENABLER) * 8;
+ *r = vgic_reg32_extract(gather_irq_info_enabled(v, irq), info);
return 1;
/* Read the pending status of an IRQ via GICD is not supported */
@@ -430,24 +425,19 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ISENABLER, DABT_WORD);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank, flags);
- tr = rank->ienable;
- vgic_reg32_setbits(&rank->ienable, r, info);
- vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
- vgic_unlock_rank(v, rank, flags);
+ irq = (gicd_reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore;
+ tr = gather_irq_info_enabled(v, irq);
+ vgic_reg32_setbits(&tr, r, info);
+ vgic_enable_irqs(v, irq, tr);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICENABLER, DABT_WORD);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank, flags);
- tr = rank->ienable;
- vgic_reg32_clearbits(&rank->ienable, r, info);
- vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
- vgic_unlock_rank(v, rank, flags);
+ irq = (gicd_reg - GICD_ISENABLER) * 8;
+ tr = gather_irq_info_enabled(v, irq);
+ vgic_reg32_clearbits(&tr, r, info);
+ vgic_disable_irqs(v, irq, tr);
return 1;
case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
@@ -474,8 +474,6 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
register_t *r)
{
struct hsr_dabt dabt = info->dabt;
- struct vgic_irq_rank *rank;
- unsigned long flags;
unsigned int irq;
switch ( reg )
@@ -487,20 +485,16 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
- if ( rank == NULL ) goto read_as_zero;
- vgic_lock_rank(v, rank, flags);
- *r = vgic_reg32_extract(rank->ienable, info);
- vgic_unlock_rank(v, rank, flags);
+ irq = (reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero;
+ *r = vgic_reg32_extract(gather_irq_info_enabled(v, irq), info);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
- if ( rank == NULL ) goto read_as_zero;
- vgic_lock_rank(v, rank, flags);
- *r = vgic_reg32_extract(rank->ienable, info);
- vgic_unlock_rank(v, rank, flags);
+ irq = (reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero;
+ *r = vgic_reg32_extract(gather_irq_info_enabled(v, irq), info);
return 1;
/* Read the pending status of an IRQ via GICD/GICR is not supported */
@@ -550,9 +544,6 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
register_t r)
{
struct hsr_dabt dabt = info->dabt;
- struct vgic_irq_rank *rank;
- uint32_t tr;
- unsigned long flags;
unsigned int irq;
switch ( reg )
@@ -562,26 +553,32 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
goto write_ignore_32;
case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
+ {
+ uint32_t new_reg, tr;
+
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
- if ( rank == NULL ) goto write_ignore;
- vgic_lock_rank(v, rank, flags);
- tr = rank->ienable;
- vgic_reg32_setbits(&rank->ienable, r, info);
- vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
- vgic_unlock_rank(v, rank, flags);
+ irq = (reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore;
+ new_reg = gather_irq_info_enabled(v, irq);
+ tr = new_reg;
+ vgic_reg32_setbits(&new_reg, r, info);
+ vgic_enable_irqs(v, irq, new_reg & (~tr));
return 1;
+ }
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
+ {
+ uint32_t new_reg, tr;
+
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
- if ( rank == NULL ) goto write_ignore;
- vgic_lock_rank(v, rank, flags);
- tr = rank->ienable;
- vgic_reg32_clearbits(&rank->ienable, r, info);
- vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
- vgic_unlock_rank(v, rank, flags);
+ irq = (reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore;
+ new_reg = gather_irq_info_enabled(v, irq);
+ tr = new_reg;
+ vgic_reg32_clearbits(&new_reg, r, info);
+ vgic_disable_irqs(v, irq, (~new_reg) & tr);
return 1;
+ }
case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
if ( dabt.size != DABT_WORD ) goto bad_width;
@@ -235,6 +235,11 @@ static void set_priority(struct pending_irq *p, uint8_t prio)
p->new_priority = prio;
}
+unsigned int extract_enabled(struct pending_irq *p)
+{
+ return test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) ? 1 : 0;
+}
+
unsigned int extract_config(struct pending_irq *p)
{
return test_bit(GIC_IRQ_GUEST_EDGE, &p->status) ? 2 : 0;
@@ -280,6 +285,7 @@ void scatter_irq_info_##name(struct vcpu *v, unsigned int irq, \
/* grep fodder: gather_irq_info_priority, scatter_irq_info_priority below */
DEFINE_GATHER_IRQ_INFO(priority, extract_priority, 8)
DEFINE_SCATTER_IRQ_INFO(priority, set_priority, 8)
+DEFINE_GATHER_IRQ_INFO(enabled, extract_enabled, 1)
DEFINE_GATHER_IRQ_INFO(config, extract_config, 2)
DEFINE_SCATTER_IRQ_INFO(config, set_config, 2)
@@ -347,21 +353,19 @@ void arch_move_irqs(struct vcpu *v)
}
}
-void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
+void vgic_disable_irqs(struct vcpu *v, unsigned int irq, uint32_t r)
{
const unsigned long mask = r;
struct pending_irq *p;
- unsigned int irq;
unsigned long flags;
int i = 0;
struct vcpu *v_target;
while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
- irq = i + (32 * n);
- v_target = vgic_get_target_vcpu(v, irq);
- p = irq_to_pending(v_target, irq);
+ v_target = vgic_get_target_vcpu(v, irq + i);
+ p = irq_to_pending(v_target, irq + i);
clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
- gic_remove_from_queues(v_target, irq);
+ gic_remove_from_queues(v_target, irq + i);
if ( p->desc != NULL )
{
spin_lock_irqsave(&p->desc->lock, flags);
@@ -372,22 +376,21 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
}
}
-void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
+void vgic_enable_irqs(struct vcpu *v, unsigned int irq, uint32_t r)
{
const unsigned long mask = r;
struct pending_irq *p;
- unsigned int irq, int_type;
+ unsigned int int_type;
unsigned long flags;
int i = 0;
struct vcpu *v_target;
struct domain *d = v->domain;
while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
- irq = i + (32 * n);
- v_target = vgic_get_target_vcpu(v, irq);
+ v_target = vgic_get_target_vcpu(v, irq + i);
spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
- p = irq_to_pending(v_target, irq);
+ p = irq_to_pending(v_target, irq + i);
spin_lock(&p->lock);
set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
@@ -406,7 +409,7 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
* The irq cannot be a PPI, we only support delivery of SPIs
* to guests.
*/
- ASSERT(irq >= 32);
+ ASSERT(irq + i >= 32);
if ( irq_type_set_by_domain(d) )
gic_set_irq_type(p->desc, int_type);
p->desc->handler->enable(p->desc);
@@ -104,8 +104,6 @@ struct vgic_irq_rank {
uint8_t index;
- uint32_t ienable;
-
/*
* It's more convenient to store a target VCPU per vIRQ
* than the register ITARGETSR/IROUTER itself.
@@ -178,6 +176,7 @@ void scatter_irq_info_priority(struct vcpu *v, unsigned int irq,
uint32_t gather_irq_info_config(struct vcpu *v, unsigned int irq);
void scatter_irq_info_config(struct vcpu *v, unsigned int irq,
unsigned int value);
+uint32_t gather_irq_info_enabled(struct vcpu *v, unsigned int irq);
#define VGIC_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
@@ -311,8 +310,8 @@ extern struct pending_irq *spi_to_pending(struct domain *d, unsigned int irq);
extern struct vgic_irq_rank *vgic_rank_offset(struct vcpu *v, int b, int n, int s);
extern struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq);
extern bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr);
-extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n);
-extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n);
+extern void vgic_disable_irqs(struct vcpu *v, unsigned int irq, uint32_t r);
+extern void vgic_enable_irqs(struct vcpu *v, unsigned int irq, uint32_t r);
extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops);
int vgic_v2_init(struct domain *d, int *mmio_count);
int vgic_v3_init(struct domain *d, int *mmio_count);
Currently we store the enable bit of an interrupt in the rank structure. Remove it from there and let the MMIO emulation use the already existing GIC_IRQ_GUEST_ENABLED in the status bits of struct pending_irq. Signed-off-by: Andre Przywara <andre.przywara@arm.com> --- xen/arch/arm/vgic-v2.c | 38 ++++++++++++-------------------- xen/arch/arm/vgic-v3.c | 55 ++++++++++++++++++++++------------------------ xen/arch/arm/vgic.c | 27 +++++++++++++---------- xen/include/asm-arm/vgic.h | 7 +++--- 4 files changed, 58 insertions(+), 69 deletions(-)