svn commit: r209506 - in stable/8/sys: amd64/amd64 i386/i386
John Baldwin
jhb at FreeBSD.org
Thu Jun 24 13:17:46 UTC 2010
Author: jhb
Date: Thu Jun 24 13:17:45 2010
New Revision: 209506
URL: http://svn.freebsd.org/changeset/base/209506
Log:
MFC 208915,208991:
- Use a bit more care when moving I/O APIC interrupts between CPUs. Mask
the interrupt followed by a brief delay if it is not currently masked
before moving the interrupt.
- Move the icu_lock out of ioapic_program_intpin() and into callers. This
closes a race where ioapic_program_intpin() could use a stale value of
the masked state to compute the masked bit in the register.
Modified:
stable/8/sys/amd64/amd64/io_apic.c
stable/8/sys/i386/i386/io_apic.c
Directory Properties:
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
stable/8/sys/dev/xen/xenpci/ (props changed)
Modified: stable/8/sys/amd64/amd64/io_apic.c
==============================================================================
--- stable/8/sys/amd64/amd64/io_apic.c Thu Jun 24 13:11:12 2010 (r209505)
+++ stable/8/sys/amd64/amd64/io_apic.c Thu Jun 24 13:17:45 2010 (r209506)
@@ -261,16 +261,15 @@ ioapic_program_intpin(struct ioapic_ints
* If a pin is completely invalid or if it is valid but hasn't
* been enabled yet, just ensure that the pin is masked.
*/
+ mtx_assert(&icu_lock, MA_OWNED);
if (intpin->io_irq == IRQ_DISABLED || (intpin->io_irq < NUM_IO_INTS &&
intpin->io_vector == 0)) {
- mtx_lock_spin(&icu_lock);
low = ioapic_read(io->io_addr,
IOAPIC_REDTBL_LO(intpin->io_intpin));
if ((low & IOART_INTMASK) == IOART_INTMCLR)
ioapic_write(io->io_addr,
IOAPIC_REDTBL_LO(intpin->io_intpin),
low | IOART_INTMSET);
- mtx_unlock_spin(&icu_lock);
return;
}
@@ -312,14 +311,12 @@ ioapic_program_intpin(struct ioapic_ints
}
/* Write the values to the APIC. */
- mtx_lock_spin(&icu_lock);
intpin->io_lowreg = low;
ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
value &= ~IOART_DEST;
value |= high;
ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
- mtx_unlock_spin(&icu_lock);
}
static int
@@ -352,6 +349,19 @@ ioapic_assign_cpu(struct intsrc *isrc, u
if (new_vector == 0)
return (ENOSPC);
+ /*
+ * Mask the old intpin if it is enabled while it is migrated.
+ *
+ * At least some level-triggered interrupts seem to need the
+ * extra DELAY() to avoid being stuck in a non-EOI'd state.
+ */
+ mtx_lock_spin(&icu_lock);
+ if (!intpin->io_masked && !intpin->io_edgetrigger) {
+ ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
+ intpin->io_lowreg | IOART_INTMSET);
+ DELAY(100);
+ }
+
intpin->io_cpu = apic_id;
intpin->io_vector = new_vector;
if (isrc->is_handlers > 0)
@@ -364,6 +374,8 @@ ioapic_assign_cpu(struct intsrc *isrc, u
intpin->io_vector);
}
ioapic_program_intpin(intpin);
+ mtx_unlock_spin(&icu_lock);
+
/*
* Free the old vector after the new one is established. This is done
* to prevent races where we could miss an interrupt.
@@ -399,9 +411,11 @@ ioapic_disable_intr(struct intsrc *isrc)
/* Mask this interrupt pin and free its APIC vector. */
vector = intpin->io_vector;
apic_disable_vector(intpin->io_cpu, vector);
+ mtx_lock_spin(&icu_lock);
intpin->io_masked = 1;
intpin->io_vector = 0;
ioapic_program_intpin(intpin);
+ mtx_unlock_spin(&icu_lock);
apic_free_vector(intpin->io_cpu, vector, intpin->io_irq);
}
}
@@ -443,6 +457,7 @@ ioapic_config_intr(struct intsrc *isrc,
* XXX: Should we write to the ELCR if the trigger mode changes for
* an EISA IRQ or an ISA IRQ with the ELCR present?
*/
+ mtx_lock_spin(&icu_lock);
if (intpin->io_bus == APIC_BUS_EISA)
pol = INTR_POLARITY_HIGH;
changed = 0;
@@ -464,6 +479,7 @@ ioapic_config_intr(struct intsrc *isrc,
}
if (changed)
ioapic_program_intpin(intpin);
+ mtx_unlock_spin(&icu_lock);
return (0);
}
@@ -473,8 +489,10 @@ ioapic_resume(struct pic *pic)
struct ioapic *io = (struct ioapic *)pic;
int i;
+ mtx_lock_spin(&icu_lock);
for (i = 0; i < io->io_numintr; i++)
ioapic_program_intpin(&io->io_pins[i]);
+ mtx_unlock_spin(&icu_lock);
}
/*
Modified: stable/8/sys/i386/i386/io_apic.c
==============================================================================
--- stable/8/sys/i386/i386/io_apic.c Thu Jun 24 13:11:12 2010 (r209505)
+++ stable/8/sys/i386/i386/io_apic.c Thu Jun 24 13:17:45 2010 (r209506)
@@ -261,16 +261,15 @@ ioapic_program_intpin(struct ioapic_ints
* If a pin is completely invalid or if it is valid but hasn't
* been enabled yet, just ensure that the pin is masked.
*/
+ mtx_assert(&icu_lock, MA_OWNED);
if (intpin->io_irq == IRQ_DISABLED || (intpin->io_irq < NUM_IO_INTS &&
intpin->io_vector == 0)) {
- mtx_lock_spin(&icu_lock);
low = ioapic_read(io->io_addr,
IOAPIC_REDTBL_LO(intpin->io_intpin));
if ((low & IOART_INTMASK) == IOART_INTMCLR)
ioapic_write(io->io_addr,
IOAPIC_REDTBL_LO(intpin->io_intpin),
low | IOART_INTMSET);
- mtx_unlock_spin(&icu_lock);
return;
}
@@ -312,14 +311,12 @@ ioapic_program_intpin(struct ioapic_ints
}
/* Write the values to the APIC. */
- mtx_lock_spin(&icu_lock);
intpin->io_lowreg = low;
ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
value &= ~IOART_DEST;
value |= high;
ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
- mtx_unlock_spin(&icu_lock);
}
static int
@@ -352,6 +349,19 @@ ioapic_assign_cpu(struct intsrc *isrc, u
if (new_vector == 0)
return (ENOSPC);
+ /*
+ * Mask the old intpin if it is enabled while it is migrated.
+ *
+ * At least some level-triggered interrupts seem to need the
+ * extra DELAY() to avoid being stuck in a non-EOI'd state.
+ */
+ mtx_lock_spin(&icu_lock);
+ if (!intpin->io_masked && !intpin->io_edgetrigger) {
+ ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
+ intpin->io_lowreg | IOART_INTMSET);
+ DELAY(100);
+ }
+
intpin->io_cpu = apic_id;
intpin->io_vector = new_vector;
if (isrc->is_handlers > 0)
@@ -364,6 +374,8 @@ ioapic_assign_cpu(struct intsrc *isrc, u
intpin->io_vector);
}
ioapic_program_intpin(intpin);
+ mtx_unlock_spin(&icu_lock);
+
/*
* Free the old vector after the new one is established. This is done
* to prevent races where we could miss an interrupt.
@@ -399,9 +411,11 @@ ioapic_disable_intr(struct intsrc *isrc)
/* Mask this interrupt pin and free its APIC vector. */
vector = intpin->io_vector;
apic_disable_vector(intpin->io_cpu, vector);
+ mtx_lock_spin(&icu_lock);
intpin->io_masked = 1;
intpin->io_vector = 0;
ioapic_program_intpin(intpin);
+ mtx_unlock_spin(&icu_lock);
apic_free_vector(intpin->io_cpu, vector, intpin->io_irq);
}
}
@@ -443,6 +457,7 @@ ioapic_config_intr(struct intsrc *isrc,
* XXX: Should we write to the ELCR if the trigger mode changes for
* an EISA IRQ or an ISA IRQ with the ELCR present?
*/
+ mtx_lock_spin(&icu_lock);
if (intpin->io_bus == APIC_BUS_EISA)
pol = INTR_POLARITY_HIGH;
changed = 0;
@@ -464,6 +479,7 @@ ioapic_config_intr(struct intsrc *isrc,
}
if (changed)
ioapic_program_intpin(intpin);
+ mtx_unlock_spin(&icu_lock);
return (0);
}
@@ -473,8 +489,10 @@ ioapic_resume(struct pic *pic)
struct ioapic *io = (struct ioapic *)pic;
int i;
+ mtx_lock_spin(&icu_lock);
for (i = 0; i < io->io_numintr; i++)
ioapic_program_intpin(&io->io_pins[i]);
+ mtx_unlock_spin(&icu_lock);
}
/*
More information about the svn-src-stable
mailing list