Print this page
11584 ::xcall would be useful
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
@@ -23,10 +23,11 @@
* Use is subject to license terms.
*/
/*
* Copyright (c) 2010, Intel Corporation.
* All rights reserved.
+ * Copyright 2018 Joyent, Inc.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/t_lock.h>
@@ -77,59 +78,43 @@
* The reason for this asynchronous approach is to allow for fast global
* TLB shootdowns. If all CPUs, say N, tried to do a global TLB invalidation
* on a different Virtual Address at the same time. The old code required
* N squared IPIs. With this method, depending on timing, it could happen
* with just N IPIs.
- */
-
-/*
- * The default is to not enable collecting counts of IPI information, since
- * the updating of shared cachelines could cause excess bus traffic.
- */
-uint_t xc_collect_enable = 0;
-uint64_t xc_total_cnt = 0; /* total #IPIs sent for cross calls */
-uint64_t xc_multi_cnt = 0; /* # times we piggy backed on another IPI */
-
-/*
- * Values for message states. Here are the normal transitions. A transition
- * of "->" happens in the slave cpu and "=>" happens in the master cpu as
- * the messages are passed back and forth.
*
+ * Here are the normal transitions for XC_MSG_* values in ->xc_command. A
+ * transition of "->" happens in the slave cpu and "=>" happens in the master
+ * cpu as the messages are passed back and forth.
+ *
* FREE => ASYNC -> DONE => FREE
* FREE => CALL -> DONE => FREE
* FREE => SYNC -> WAITING => RELEASED -> DONE => FREE
*
- * The interesing one above is ASYNC. You might ask, why not go directly
- * to FREE, instead of DONE. If it did that, it might be possible to exhaust
+ * The interesting one above is ASYNC. You might ask, why not go directly
+ * to FREE, instead of DONE? If it did that, it might be possible to exhaust
* the master's xc_free list if a master can generate ASYNC messages faster
* then the slave can process them. That could be handled with more complicated
* handling. However since nothing important uses ASYNC, I've not bothered.
*/
-#define XC_MSG_FREE (0) /* msg in xc_free queue */
-#define XC_MSG_ASYNC (1) /* msg in slave xc_msgbox */
-#define XC_MSG_CALL (2) /* msg in slave xc_msgbox */
-#define XC_MSG_SYNC (3) /* msg in slave xc_msgbox */
-#define XC_MSG_WAITING (4) /* msg in master xc_msgbox or xc_waiters */
-#define XC_MSG_RELEASED (5) /* msg in slave xc_msgbox */
-#define XC_MSG_DONE (6) /* msg in master xc_msgbox */
/*
+ * The default is to not enable collecting counts of IPI information, since
+ * the updating of shared cachelines could cause excess bus traffic.
+ */
+uint_t xc_collect_enable = 0;
+uint64_t xc_total_cnt = 0; /* total #IPIs sent for cross calls */
+uint64_t xc_multi_cnt = 0; /* # times we piggy backed on another IPI */
+
+/*
* We allow for one high priority message at a time to happen in the system.
* This is used for panic, kmdb, etc., so no locking is done.
*/
static volatile cpuset_t xc_priority_set_store;
static volatile ulong_t *xc_priority_set = CPUSET2BV(xc_priority_set_store);
static xc_data_t xc_priority_data;
/*
- * Wrappers to avoid C compiler warnings due to volatile. The atomic bit
- * operations don't accept volatile bit vectors - which is a bit silly.
- */
-#define XC_BT_SET(vector, b) BT_ATOMIC_SET((ulong_t *)(vector), (b))
-#define XC_BT_CLEAR(vector, b) BT_ATOMIC_CLEAR((ulong_t *)(vector), (b))
-
-/*
* Decrement a CPU's work count
*/
static void
xc_decrement(struct machcpu *mcpu)
{
@@ -191,10 +176,24 @@
old_head->xc_next = NULL;
return (old_head);
}
/*
+ * Extract the next message from the CPU's queue, and place the message in
+ * .xc_curmsg. The latter is solely to make debugging (and ::xcall) more
+ * useful.
+ */
+static xc_msg_t *
+xc_get(void)
+{
+ struct machcpu *mcpup = &CPU->cpu_m;
+ xc_msg_t *msg = xc_extract(&mcpup->xc_msgbox);
+ mcpup->xc_curmsg = msg;
+ return (msg);
+}
+
+/*
* Initialize the machcpu fields used for cross calls
*/
static uint_t xc_initialized = 0;
void
@@ -326,22 +325,21 @@
rc = DDI_INTR_CLAIMED;
/*
* We may have to wait for a message to arrive.
*/
- for (msg = NULL; msg == NULL;
- msg = xc_extract(&mcpup->xc_msgbox)) {
+ for (msg = NULL; msg == NULL; msg = xc_get()) {
/*
* Alway check for and handle a priority message.
*/
if (BT_TEST(xc_priority_set, CPU->cpu_id)) {
func = xc_priority_data.xc_func;
a1 = xc_priority_data.xc_a1;
a2 = xc_priority_data.xc_a2;
a3 = xc_priority_data.xc_a3;
- XC_BT_CLEAR(xc_priority_set, CPU->cpu_id);
+ BT_ATOMIC_CLEAR(xc_priority_set, CPU->cpu_id);
xc_decrement(mcpup);
func(a1, a2, a3);
if (mcpup->xc_work_cnt == 0)
return (rc);
}
@@ -441,10 +439,12 @@
default:
panic("bad message 0x%p in msgbox", (void *)msg);
break;
}
+
+ CPU->cpu_m.xc_curmsg = NULL;
}
return (rc);
}
/*
@@ -579,11 +579,11 @@
* problem. We'll just erase the previous request - which was
* most likely a kmdb_enter that has already expired - and plow
* ahead.
*/
if (BT_TEST(xc_priority_set, c)) {
- XC_BT_CLEAR(xc_priority_set, c);
+ BT_ATOMIC_CLEAR(xc_priority_set, c);
if (cpup->cpu_m.xc_work_cnt > 0)
xc_decrement(&cpup->cpu_m);
}
}
@@ -605,11 +605,11 @@
cpup = cpu[c];
if (cpup == NULL || !(cpup->cpu_flags & CPU_READY) ||
cpup == CPU)
continue;
(void) xc_increment(&cpup->cpu_m);
- XC_BT_SET(xc_priority_set, c);
+ BT_ATOMIC_SET(xc_priority_set, c);
send_dirint(c, XC_HI_PIL);
for (i = 0; i < 10; ++i) {
(void) atomic_cas_ptr(&cpup->cpu_m.xc_msgbox,
cpup->cpu_m.xc_msgbox, cpup->cpu_m.xc_msgbox);
}