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);
                 }