diff -r 53fed814fa5f xen/include/asm-x86/hvm/vioapic.h --- a/xen/include/asm-x86/hvm/vioapic.h Mon May 15 11:14:20 2006 -0400 +++ b/xen/include/asm-x86/hvm/vioapic.h Tue May 16 11:27:52 2006 -0400 @@ -104,6 +104,7 @@ typedef struct hvm_vioapic { RedirStatus redirtbl[IOAPIC_NUM_PINS]; struct vlapic *lapic_info[MAX_LAPIC_NUM]; struct domain *domain; + spinlock_t lock; } hvm_vioapic_t; hvm_vioapic_t *hvm_vioapic_init(struct domain *d); diff -r 53fed814fa5f xen/arch/x86/hvm/vioapic.c --- a/xen/arch/x86/hvm/vioapic.c Mon May 15 11:14:20 2006 -0400 +++ b/xen/arch/x86/hvm/vioapic.c Tue May 16 11:27:52 2006 -0400 @@ -65,6 +65,7 @@ int ioapic_load(QEMUFile* f, void* opaqu } #endif +/* Caller must hold vioapic lock */ static unsigned long hvm_vioapic_read_indirect(struct hvm_vioapic *s, unsigned long addr, unsigned long length) @@ -72,6 +73,8 @@ static unsigned long hvm_vioapic_read_in unsigned long result = 0; ASSERT(s); + + BUG_ON(!spin_is_locked(&s->lock)); switch (s->ioregsel) { case IOAPIC_REG_VERSION: @@ -121,6 +124,7 @@ static unsigned long hvm_vioapic_read(st { struct hvm_vioapic *s = &(v->domain->arch.hvm_domain.vioapic); uint32_t result = 0; + unsigned long flags; HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "hvm_vioapic_read addr %lx\n", addr); @@ -134,7 +138,9 @@ static unsigned long hvm_vioapic_read(st break; case IOAPIC_REG_WINDOW: + spin_lock_irqsave(&s->lock, flags); result = hvm_vioapic_read_indirect(s, addr, length); + spin_unlock_irqrestore(&s->lock, flags); break; default: @@ -152,11 +158,14 @@ static void hvm_vioapic_update_imr(struc clear_bit(index, &s->imr); } +/* Caller must hold vioapic lock */ static void hvm_vioapic_write_indirect(struct hvm_vioapic *s, unsigned long addr, unsigned long length, unsigned long val) { + BUG_ON(!spin_is_locked(&s->lock)); + switch (s->ioregsel) { case IOAPIC_REG_VERSION: printk("hvm_vioapic_write_indirect: version register read only\n"); @@ -210,6 +219,7 @@ static void hvm_vioapic_write(struct vcp unsigned long val) { hvm_vioapic_t *s = &(v->domain->arch.hvm_domain.vioapic); + unsigned long flags; ASSERT(s); @@ -221,7 +231,9 @@ static void hvm_vioapic_write(struct vcp break; case IOAPIC_REG_WINDOW: + spin_lock_irqsave(&s->lock, flags); hvm_vioapic_write_indirect(s, addr, length, val); + spin_unlock_irqrestore(&s->lock, flags); break; #ifdef __ia64__ @@ -277,6 +289,7 @@ static void ioapic_update_config(hvm_vio s->base_address = address; } +/* Caller must hold vioapic lock */ static int ioapic_inj_irq(hvm_vioapic_t *s, struct vlapic * target, uint8_t vector, @@ -286,6 +299,8 @@ static int ioapic_inj_irq(hvm_vioapic_t int result = 0; ASSERT(s && target); + + BUG_ON(!spin_is_locked(&s->lock)); HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_inj_irq " "irq %d trig %d delive mode %d\n", @@ -308,11 +323,14 @@ static int ioapic_inj_irq(hvm_vioapic_t } #ifndef __ia64__ +/* Caller must hold vioapic lock */ static int ioapic_match_logical_addr(hvm_vioapic_t *s, int number, uint8_t dest) { int result = 0; ASSERT(s && s->lapic_info[number]); + + BUG_ON(!spin_is_locked(&s->lock)); HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_match_logical_addr " "number %i dest %x\n", @@ -342,6 +360,7 @@ extern int ioapic_match_logical_addr(hvm extern int ioapic_match_logical_addr(hvm_vioapic_t *s, int number, uint8_t dest); #endif +/* Caller must hold vioapic lock */ static uint32_t ioapic_get_delivery_bitmask(hvm_vioapic_t *s, uint16_t dest, uint8_t dest_mode, @@ -350,6 +369,8 @@ static uint32_t ioapic_get_delivery_bitm { uint32_t mask = 0; int i; + + BUG_ON(!spin_is_locked(&s->lock)); HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_get_delivery_bitmask " "dest %d dest_mode %d " @@ -383,6 +404,7 @@ static uint32_t ioapic_get_delivery_bitm return mask; } +/* Caller must hold vioapic lock */ static void ioapic_deliver(hvm_vioapic_t *s, int irqno) { uint16_t dest = s->redirtbl[irqno].RedirForm.dest_id; @@ -391,6 +413,8 @@ static void ioapic_deliver(hvm_vioapic_t uint8_t vector = s->redirtbl[irqno].RedirForm.vector; uint8_t trig_mode = s->redirtbl[irqno].RedirForm.trigmod; uint32_t deliver_bitmask; + + BUG_ON(!spin_is_locked(&s->lock)); HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "IOAPIC deliver: " "dest %x dest_mode %x delivery_mode %x vector %x trig_mode %x\n", @@ -448,20 +472,26 @@ static void ioapic_deliver(hvm_vioapic_t } } +/* Caller must hold vioapic lock */ static int ioapic_get_highest_irq(hvm_vioapic_t *s) { uint32_t irqs; ASSERT(s); + + BUG_ON(!spin_is_locked(&s->lock)); irqs = s->irr & ~s->isr & ~s->imr; return __fls(irqs); } +/* Caller must hold vioapic lock */ static void service_ioapic(hvm_vioapic_t *s) { int irqno; + + BUG_ON(!spin_is_locked(&s->lock)); while ((irqno = ioapic_get_highest_irq(s)) != -1) { @@ -483,28 +513,35 @@ void hvm_vioapic_do_irqs(struct domain * void hvm_vioapic_do_irqs(struct domain *d, uint16_t irqs) { hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic); + unsigned long flags; if (!hvm_apic_support(d)) return; + spin_lock_irqsave(&s->lock, flags); s->irr |= irqs & ~s->imr; service_ioapic(s); + spin_unlock_irqrestore(&s->lock, flags); } void hvm_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs) { hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic); + unsigned long flags; if (!hvm_apic_support(d)) return; + spin_lock_irqsave(&s->lock, flags); s->irr &= ~irqs; service_ioapic(s); + spin_unlock_irqrestore(&s->lock, flags); } void hvm_vioapic_set_irq(struct domain *d, int irq, int level) { hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic); + unsigned long flags; if (!hvm_apic_support(d)) return ; @@ -534,6 +571,7 @@ void hvm_vioapic_set_irq(struct domain * s->redirtbl[irq].RedirForm.mask, s->redirtbl[irq].RedirForm.dest_id); + spin_lock_irqsave(&s->lock, flags); if (irq >= 0 && irq < IOAPIC_NUM_PINS) { uint32_t bit = 1 << irq; if (s->redirtbl[irq].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER) { @@ -549,6 +587,7 @@ void hvm_vioapic_set_irq(struct domain * } service_ioapic(s); + spin_unlock_irqrestore(&s->lock, flags); } /* XXX If level interrupt, use vector->irq table for performance */ @@ -611,6 +650,8 @@ hvm_vioapic_t * hvm_vioapic_init(struct s->domain = d; + spin_lock_init(&s->lock); + for (i = 0; i < MAX_LAPIC_NUM; i++) s->lapic_info[i] = NULL;