|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] arm/acpi: Fix the deadlock in function vgic_lock_rank()
Commit 9d77b3c01d1261c (Configure SPI interrupt type and route to
Dom0 dynamically) causing dead loop inside the spinlock function.
Note that spinlocks in XEN are not recursive. Re-acquiring a spinlock
that has already held by calling CPU leads to deadlock. This happens
whenever dom0 does writes to GICD regs ISENABLER/ICENABLER.
The following call trace explains the problem.
DOM0 writes GICD_ISENABLER/GICD_ICENABLER
vgic_v3_distr_common_mmio_write()
vgic_lock_rank() --> acquiring first time
vgic_enable_irqs()
route_irq_to_guest()
gic_route_irq_to_guest()
vgic_get_target_vcpu()
vgic_lock_rank() --> attemping acquired lock
The simple fix release spinlock before calling vgic_enable_irqs()
and vgic_disable_irqs().
Signed-off-by: Shanker Donthineni <shankerd@xxxxxxxxxxxxxx>
---
xen/arch/arm/vgic-v2.c | 10 +++++++---
xen/arch/arm/vgic-v3.c | 10 +++++++---
xen/arch/arm/vgic.c | 4 ++--
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index 9adb4a9..44cd834 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -415,7 +415,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
mmio_info_t *info,
struct hsr_dabt dabt = info->dabt;
struct vgic_irq_rank *rank;
int gicd_reg = (int)(info->gpa - v->domain->arch.vgic.dbase);
- uint32_t tr;
+ uint32_t tr, index;
unsigned long flags;
perfc_incr(vgicd_writes);
@@ -457,8 +457,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
mmio_info_t *info,
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);
+ index = rank->index;
+ tr = rank->ienable & (~tr);
vgic_unlock_rank(v, rank, flags);
+ vgic_enable_irqs(v, tr, index);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
@@ -468,8 +470,10 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
mmio_info_t *info,
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);
+ index = rank->index;
+ tr = (~rank->ienable) & tr;
vgic_unlock_rank(v, rank, flags);
+ vgic_disable_irqs(v, tr, index);
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 b37a7c0..e04e180 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -568,7 +568,7 @@ static int __vgic_v3_distr_common_mmio_write(const char
*name, struct vcpu *v,
{
struct hsr_dabt dabt = info->dabt;
struct vgic_irq_rank *rank;
- uint32_t tr;
+ uint32_t tr, index;
unsigned long flags;
switch ( reg )
@@ -584,8 +584,10 @@ static int __vgic_v3_distr_common_mmio_write(const char
*name, struct vcpu *v,
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);
+ index = rank->index;
+ tr = rank->ienable & (~tr);
vgic_unlock_rank(v, rank, flags);
+ vgic_enable_irqs(v, tr, index);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
@@ -595,8 +597,10 @@ static int __vgic_v3_distr_common_mmio_write(const char
*name, struct vcpu *v,
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);
+ index = rank->index;
+ tr = (~rank->ienable) & tr;
vgic_unlock_rank(v, rank, flags);
+ vgic_disable_irqs(v, tr, index);
return 1;
case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index aa420bb..82758d2 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -322,7 +322,7 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
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);
p = irq_to_pending(v_target, irq);
clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
gic_remove_from_queues(v_target, irq);
@@ -377,7 +377,7 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
gprintk(XENLOG_ERR, "Unable to route IRQ %u to domain %u\n",
irq, d->domain_id);
}
- v_target = __vgic_get_target_vcpu(v, irq);
+ v_target = vgic_get_target_vcpu(v, irq);
p = irq_to_pending(v_target, irq);
set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
--
Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |