From: Tetsu Yamamoto <tyamamot@redhat.com> Date: Thu, 16 Oct 2008 11:44:24 -0400 Subject: [xen] ia64: make viosapic SMP-safe by adding lock/unlock Message-id: 48F76158.1010802@redhat.com O-Subject: [RHEL5.3 PATCH] xen-ia64: Make viosapic SMP-safe adding lock/unlock similar to x86 vioapic Bugzilla: 466552 RH-Acked-by: Bill Burns <bburns@redhat.com> RH-Acked-by: Rik van Riel <riel@redhat.com> BZ466552 https://bugzilla.redhat.com/show_bug.cgi?id=466552 [Description] Windows guest on ia64/xen hangs during network performance test. The cause is that viosapic is not SMP-safe. This is fixed by the patch in the upstream. - [IA64] Make viosapic SMP-safe adding lock/unlock similar to x86 vioapic http://xenbits.xensource.com/xen-unstable.hg?rev/764d33505b98 [Upstream Status] The patch was applied in the upstream a year ago. [brew ID] http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1517140 [Test Status] I tested this patch with kernel-119 on ia64 box running network performance test (ttcp) on a Windows guest for more than 48 hours. The guest did not hang. Please review and ACK. Regards, Tetsu Yamamoto # HG changeset patch # User Alex Williamson <alex.williamson@hp.com> # Date 1190905706 21600 # Node ID 764d33505b98f43c1c265a07a2b2ae3c252a5388 # Parent b658296982eeee313f36460a4f575f0a4dde0116 [IA64] Make viosapic SMP-safe adding lock/unlock similar to x86 vioapic Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> diff --git a/arch/ia64/vmx/viosapic.c b/arch/ia64/vmx/viosapic.c index f951aa0..fe16600 100644 --- a/arch/ia64/vmx/viosapic.c +++ b/arch/ia64/vmx/viosapic.c @@ -23,6 +23,10 @@ * * Yunhong Jiang <yunhong.jiang@intel.com> * Ported to xen by using virtual IRQ line. + * + * Copyright (C) 2007 VA Linux Systems Japan K.K. + * Isaku Yamahata <yamahata at valinux co jp> + * SMP support */ #include <xen/config.h> @@ -44,6 +48,7 @@ static void viosapic_deliver(struct viosapic *viosapic, int irq) uint8_t vector = viosapic->redirtbl[irq].vector; struct vcpu *v; + ASSERT(spin_is_locked(&viosapic->lock)); switch ( delivery_mode ) { case SAPIC_FIXED: @@ -90,6 +95,7 @@ static int get_redir_num(struct viosapic *viosapic, int vector) { int i; + ASSERT(spin_is_locked(&viosapic->lock)); for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ ) if ( viosapic->redirtbl[i].vector == vector ) return i; @@ -118,20 +124,24 @@ static void viosapic_update_EOI(struct viosapic *viosapic, int vector) { int redir_num; + spin_lock(&viosapic->lock); if ( (redir_num = get_redir_num(viosapic, vector)) == -1 ) { + spin_unlock(&viosapic->lock); gdprintk(XENLOG_WARNING, "Can't find redir item for %d EOI\n", vector); return; } if ( !test_and_clear_bit(redir_num, &viosapic->isr) ) { + spin_unlock(&viosapic->lock); if ( viosapic->redirtbl[redir_num].trig_mode == SAPIC_LEVEL ) gdprintk(XENLOG_WARNING, "redir %d not set for %d EOI\n", redir_num, vector); return; } service_iosapic(viosapic); + spin_unlock(&viosapic->lock); } @@ -150,18 +160,21 @@ static unsigned long viosapic_read_indirect(struct viosapic *viosapic, default: { - uint32_t redir_index = (viosapic->ioregsel - 0x10) >> 1; + /* ioregsel might be written at the same time. copy it before use. */ + uint32_t ioregsel = viosapic->ioregsel; + uint32_t redir_index; uint64_t redir_content; + redir_index = (ioregsel - 0x10) >> 1; if ( redir_index >= VIOSAPIC_NUM_PINS ) { gdprintk(XENLOG_WARNING, "viosapic_read_indirect:undefined " - "ioregsel %x\n", viosapic->ioregsel); + "ioregsel %x\n", ioregsel); break; } redir_content = viosapic->redirtbl[redir_index].bits; - result = (viosapic->ioregsel & 0x1) ? + result = (ioregsel & 0x1) ? (redir_content >> 32) & 0xffffffff : redir_content & 0xffffffff; break; @@ -213,9 +226,12 @@ static void viosapic_write_indirect(struct viosapic *viosapic, default: { - uint32_t redir_index = (viosapic->ioregsel - 0x10) >> 1; + /* ioregsel might be written at the same time. copy it before use. */ + uint32_t ioregsel = viosapic->ioregsel; + uint32_t redir_index; uint64_t redir_content; + redir_index = (ioregsel - 0x10) >> 1; if ( redir_index >= VIOSAPIC_NUM_PINS ) { gdprintk(XENLOG_WARNING, "viosapic_write_indirect " @@ -223,9 +239,10 @@ static void viosapic_write_indirect(struct viosapic *viosapic, break; } + spin_lock(&viosapic->lock); redir_content = viosapic->redirtbl[redir_index].bits; - if ( viosapic->ioregsel & 0x1 ) + if ( ioregsel & 0x1 ) { redir_content = (((uint64_t)val & 0xffffffff) << 32) | (redir_content & 0xffffffff); @@ -236,6 +253,7 @@ static void viosapic_write_indirect(struct viosapic *viosapic, (val & 0xffffffff); } viosapic->redirtbl[redir_index].bits = redir_content; + spin_unlock(&viosapic->lock); break; } } /* switch */ diff --git a/arch/ia64/vmx/vlsapic.c b/arch/ia64/vmx/vlsapic.c index 70ef86f..077f75a 100644 --- a/arch/ia64/vmx/vlsapic.c +++ b/arch/ia64/vmx/vlsapic.c @@ -771,6 +771,8 @@ static void vlsapic_write_xtp(struct vcpu *v, uint8_t val) struct viosapic * viosapic; struct vcpu *lvcpu, *vcpu; viosapic = vcpu_viosapic(v); + + spin_lock(&viosapic->lock); lvcpu = viosapic->lowest_vcpu; VLSAPIC_XTP(v) = val; @@ -783,6 +785,7 @@ static void vlsapic_write_xtp(struct vcpu *v, uint8_t val) lvcpu = NULL; viosapic->lowest_vcpu = lvcpu; + spin_unlock(&viosapic->lock); } void vlsapic_write(struct vcpu *v,