diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index 795173c..22c679c 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -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):
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 7989989..01764c9 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -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;
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 02c1d12..a23079a 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -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);
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 931a672..fe09fb8 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -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);
