summaryrefslogtreecommitdiffstats
path: root/sys/amd64/amd64/mp_machdep.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2015-02-06 18:19:59 +0000
committerjhb <jhb@FreeBSD.org>2015-02-06 18:19:59 +0000
commit9dfc36d98560234b3c913fd291aa845cc98eb563 (patch)
treedde8f43f0382ce3e4d9bd95d56103d2a144f5960 /sys/amd64/amd64/mp_machdep.c
parent6064614ca50b8b6311bd60d1f85c0dcba8ef8954 (diff)
downloadFreeBSD-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/amd64/amd64/mp_machdep.c')
-rw-r--r--sys/amd64/amd64/mp_machdep.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 3184f13..91b5c9f 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -1065,14 +1065,27 @@ ipi_startup(int apic_id, int vector)
{
/*
+ * This attempts to follow the algorithm described in the
+ * Intel Multiprocessor Specification v1.4 in section B.4.
+ * For each IPI, we allow the local APIC ~20us to deliver the
+ * IPI. If that times out, we panic.
+ */
+
+ /*
* first we do an INIT IPI: this INIT IPI might be run, resetting
* and running the target CPU. OR this INIT IPI might be latched (P5
* bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be
* ignored.
*/
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
- lapic_ipi_wait(-1);
+ lapic_ipi_wait(20);
+
+ /* Explicitly deassert the INIT IPI. */
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
+ APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT,
+ apic_id);
+
DELAY(10000); /* wait ~10mS */
/*
@@ -1084,9 +1097,11 @@ ipi_startup(int apic_id, int vector)
* will run.
*/
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
vector, apic_id);
- lapic_ipi_wait(-1);
+ if (!lapic_ipi_wait(20))
+ panic("Failed to deliver first STARTUP IPI to APIC %d",
+ apic_id);
DELAY(200); /* wait ~200uS */
/*
@@ -1096,9 +1111,12 @@ ipi_startup(int apic_id, int vector)
* recognized after hardware RESET or INIT IPI.
*/
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
vector, apic_id);
- lapic_ipi_wait(-1);
+ if (!lapic_ipi_wait(20))
+ panic("Failed to deliver second STARTUP IPI to APIC %d",
+ apic_id);
+
DELAY(200); /* wait ~200uS */
}
OpenPOWER on IntegriCloud