aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Egge <tegge@FreeBSD.org>1998-03-03 19:54:49 +0000
committerTor Egge <tegge@FreeBSD.org>1998-03-03 19:54:49 +0000
commitff2757128488e8363b0124098a1bec4f0049eae2 (patch)
treef865d01463e28744394e657ae3672d3d95bb0175
parent221e0c595b9163ca22f0cc22e511e62e2c16d39f (diff)
downloadsrc-ff2757128488e8363b0124098a1bec4f0049eae2.tar.gz
src-ff2757128488e8363b0124098a1bec4f0049eae2.zip
When sending an IPI to a specific target, disable interrupts inside the
critical region in order to avoid sending the IPI to the wrong target.
Notes
Notes: svn path=/head/; revision=34018
-rw-r--r--sys/i386/i386/mpapic.c78
1 files changed, 70 insertions, 8 deletions
diff --git a/sys/i386/i386/mpapic.c b/sys/i386/i386/mpapic.c
index ef733d348567..24f5072b4342 100644
--- a/sys/i386/i386/mpapic.c
+++ b/sys/i386/i386/mpapic.c
@@ -22,7 +22,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: mpapic.c,v 1.26 1997/08/21 05:08:25 fsmp Exp $
+ * $Id: mpapic.c,v 1.27 1997/12/08 18:36:02 fsmp Exp $
*/
#include "opt_smp.h"
@@ -488,6 +488,73 @@ apic_ipi(int dest_type, int vector, int delivery_mode)
return 0;
}
+static int
+apic_ipi_singledest(int cpu, int vector, int delivery_mode)
+{
+ u_long icr_lo;
+ u_long icr_hi;
+ u_long eflags;
+
+#if defined(DETECT_DEADLOCK)
+#define MAX_SPIN1 10000000
+#define MAX_SPIN2 1000
+ int x;
+
+ /* "lazy delivery", ie we only barf if they stack up on us... */
+ for (x = MAX_SPIN1; x; --x) {
+ if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
+ break;
+ }
+ if (x == 0)
+ panic("apic_ipi was stuck");
+#endif /* DETECT_DEADLOCK */
+
+ eflags = read_eflags();
+ __asm __volatile("cli" : : : "memory");
+ icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
+ icr_hi |= (CPU_TO_ID(cpu) << 24);
+ lapic.icr_hi = icr_hi;
+
+ /* build IRC_LOW */
+ icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
+ | APIC_DEST_DESTFLD | delivery_mode | vector;
+
+ /* write APIC ICR */
+ lapic.icr_lo = icr_lo;
+ write_eflags(eflags);
+
+ /* wait for pending status end */
+#if defined(DETECT_DEADLOCK)
+ for (x = MAX_SPIN2; x; --x) {
+ if ((lapic.icr_lo & APIC_DELSTAT_MASK) == 0)
+ break;
+ }
+#ifdef needsattention
+/*
+ * XXX FIXME:
+ * The above loop waits for the message to actually be delivered.
+ * It breaks out after an arbitrary timout on the theory that it eventually
+ * will be delivered and we will catch a real failure on the next entry to
+ * this function, which would panic().
+ * We could skip this wait entirely, EXCEPT it probably protects us from
+ * other "less robust" routines that assume the message was delivered and
+ * acted upon when this function returns. TLB shootdowns are one such
+ * "less robust" function.
+ */
+ if (x == 0)
+ printf("apic_ipi might be stuck\n");
+#endif
+#undef MAX_SPIN2
+#undef MAX_SPIN1
+#else
+ while (lapic.icr_lo & APIC_DELSTAT_MASK)
+ /* spin */ ;
+#endif /* DETECT_DEADLOCK */
+
+ /** XXX FIXME: return result */
+ return 0;
+}
+
/*
* Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
@@ -501,21 +568,16 @@ selected_apic_ipi(u_int target, int vector, int delivery_mode)
{
int x;
int status;
- u_long icr_hi;
if (target & ~0x7fff)
return -1; /* only 15 targets allowed */
for (status = 0, x = 0; x <= 14; ++x)
if (target & (1 << x)) {
- /* write the destination field for the target AP */
- icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
- icr_hi |= (CPU_TO_ID(x) << 24);
- lapic.icr_hi = icr_hi;
/* send the IPI */
- if (apic_ipi(APIC_DEST_DESTFLD, vector,
- delivery_mode) == -1)
+ if (apic_ipi_singledest(x, vector,
+ delivery_mode) == -1)
status |= (1 << x);
}
return status;