diff options
author | jhb <jhb@FreeBSD.org> | 2015-02-06 18:19:59 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2015-02-06 18:19:59 +0000 |
commit | 9dfc36d98560234b3c913fd291aa845cc98eb563 (patch) | |
tree | dde8f43f0382ce3e4d9bd95d56103d2a144f5960 /sys/x86 | |
parent | 6064614ca50b8b6311bd60d1f85c0dcba8ef8954 (diff) | |
download | FreeBSD-src-9dfc36d98560234b3c913fd291aa845cc98eb563.zip FreeBSD-src-9dfc36d98560234b3c913fd291aa845cc98eb563.tar.gz |
Revert the IPI startup sequence to match what is described in the
Intel Multiprocessor Specification v1.4. The Intel SDM claims that
the INIT IPIs here are invalid, but other systems follow the MP
spec instead.
While here, fix the IPI wait routine to accept a timeout in microseconds
instead of a raw spin count, and don't spin forever during AP startup.
Instead, panic if a STARTUP IPI is not delivered after 20 us.
PR: 196542
Differential Revision: https://reviews.freebsd.org/D1719
MFC after: 2 weeks
Diffstat (limited to 'sys/x86')
-rw-r--r-- | sys/x86/x86/local_apic.c | 28 |
1 files changed, 14 insertions, 14 deletions
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index e3228ce..080822b 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -1452,22 +1452,22 @@ SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_THIRD, apic_setup_io, NULL); static int native_lapic_ipi_wait(int delay) { - int x, incr; + int x; /* - * Wait delay loops for IPI to be sent. This is highly bogus - * since this is sensitive to CPU clock speed. If delay is + * Wait delay microseconds for IPI to be sent. If delay is * -1, we wait forever. */ if (delay == -1) { - incr = 0; - delay = 1; - } else - incr = 1; - for (x = 0; x < delay; x += incr) { + while ((lapic->icr_lo & APIC_DELSTAT_MASK) != APIC_DELSTAT_IDLE) + ia32_pause(); + return (1); + } + + for (x = 0; x < delay; x += 5) { if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE) return (1); - ia32_pause(); + DELAY(5); } return (0); } @@ -1501,9 +1501,9 @@ native_lapic_ipi_raw(register_t icrlo, u_int dest) intr_restore(saveintr); } -#define BEFORE_SPIN 1000000 +#define BEFORE_SPIN 50000 #ifdef DETECT_DEADLOCK -#define AFTER_SPIN 1000 +#define AFTER_SPIN 50 #endif static void @@ -1514,7 +1514,7 @@ native_lapic_ipi_vectored(u_int vector, int dest) KASSERT((vector & ~APIC_VECTOR_MASK) == 0, ("%s: invalid vector %d", __func__, vector)); - icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE; + icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE | APIC_LEVEL_ASSERT; /* * IPI_STOP_HARD is just a "fake" vector used to send a NMI. @@ -1522,9 +1522,9 @@ native_lapic_ipi_vectored(u_int vector, int dest) * the vector. */ if (vector == IPI_STOP_HARD) - icrlo |= APIC_DELMODE_NMI | APIC_LEVEL_ASSERT; + icrlo |= APIC_DELMODE_NMI; else - icrlo |= vector | APIC_DELMODE_FIXED | APIC_LEVEL_DEASSERT; + icrlo |= vector | APIC_DELMODE_FIXED; destfield = 0; switch (dest) { case APIC_IPI_DEST_SELF: |