Print this page
5042 stop using deprecated atomic functions

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/i86pc/os/x_call.c
          +++ new/usr/src/uts/i86pc/os/x_call.c
↓ open down ↓ 43 lines elided ↑ open up ↑
  44   44  #include <sys/mutex_impl.h>
  45   45  #include <sys/stack.h>
  46   46  #include <sys/promif.h>
  47   47  #include <sys/x86_archext.h>
  48   48  
  49   49  /*
  50   50   * Implementation for cross-processor calls via interprocessor interrupts
  51   51   *
  52   52   * This implementation uses a message passing architecture to allow multiple
  53   53   * concurrent cross calls to be in flight at any given time. We use the cmpxchg
  54      - * instruction, aka casptr(), to implement simple efficient work queues for
  55      - * message passing between CPUs with almost no need for regular locking.
  56      - * See xc_extract() and xc_insert() below.
       54 + * instruction, aka atomic_cas_ptr(), to implement simple efficient work
       55 + * queues for message passing between CPUs with almost no need for regular
       56 + * locking.  See xc_extract() and xc_insert() below.
  57   57   *
  58   58   * The general idea is that initiating a cross call means putting a message
  59   59   * on a target(s) CPU's work queue. Any synchronization is handled by passing
  60   60   * the message back and forth between initiator and target(s).
  61   61   *
  62   62   * Every CPU has xc_work_cnt, which indicates it has messages to process.
  63   63   * This value is incremented as message traffic is initiated and decremented
  64   64   * with every message that finishes all processing.
  65   65   *
  66   66   * The code needs no mfence or other membar_*() calls. The uses of
  67      - * casptr(), cas32() and atomic_dec_32() for the message passing are
  68      - * implemented with LOCK prefix instructions which are equivalent to mfence.
       67 + * atomic_cas_ptr(), atomic_cas_32() and atomic_dec_32() for the message
       68 + * passing are implemented with LOCK prefix instructions which are
       69 + * equivalent to mfence.
  69   70   *
  70   71   * One interesting aspect of this implmentation is that it allows 2 or more
  71   72   * CPUs to initiate cross calls to intersecting sets of CPUs at the same time.
  72   73   * The cross call processing by the CPUs will happen in any order with only
  73   74   * a guarantee, for xc_call() and xc_sync(), that an initiator won't return
  74   75   * from cross calls before all slaves have invoked the function.
  75   76   *
  76   77   * The reason for this asynchronous approach is to allow for fast global
  77   78   * TLB shootdowns. If all CPUs, say N, tried to do a global TLB invalidation
  78   79   * on a different Virtual Address at the same time. The old code required
↓ open down ↓ 58 lines elided ↑ open up ↑
 137  138  
 138  139  /*
 139  140   * Increment a CPU's work count and return the old value
 140  141   */
 141  142  static int
 142  143  xc_increment(struct machcpu *mcpu)
 143  144  {
 144  145          int old;
 145  146          do {
 146  147                  old = mcpu->xc_work_cnt;
 147      -        } while (cas32((uint32_t *)&mcpu->xc_work_cnt, old, old + 1) != old);
      148 +        } while (atomic_cas_32(&mcpu->xc_work_cnt, old, old + 1) != old);
 148  149          return (old);
 149  150  }
 150  151  
 151  152  /*
 152  153   * Put a message into a queue. The insertion is atomic no matter
 153  154   * how many different inserts/extracts to the same queue happen.
 154  155   */
 155  156  static void
 156  157  xc_insert(void *queue, xc_msg_t *msg)
 157  158  {
↓ open down ↓ 3 lines elided ↑ open up ↑
 161  162           * FREE messages should only ever be getting inserted into
 162  163           * the xc_master CPUs xc_free queue.
 163  164           */
 164  165          ASSERT(msg->xc_command != XC_MSG_FREE ||
 165  166              cpu[msg->xc_master] == NULL || /* possible only during init */
 166  167              queue == &cpu[msg->xc_master]->cpu_m.xc_free);
 167  168  
 168  169          do {
 169  170                  old_head = (xc_msg_t *)*(volatile xc_msg_t **)queue;
 170  171                  msg->xc_next = old_head;
 171      -        } while (casptr(queue, old_head, msg) != old_head);
      172 +        } while (atomic_cas_ptr(queue, old_head, msg) != old_head);
 172  173  }
 173  174  
 174  175  /*
 175  176   * Extract a message from a queue. The extraction is atomic only
 176  177   * when just one thread does extractions from the queue.
 177  178   * If the queue is empty, NULL is returned.
 178  179   */
 179  180  static xc_msg_t *
 180  181  xc_extract(xc_msg_t **queue)
 181  182  {
 182  183          xc_msg_t *old_head;
 183  184  
 184  185          do {
 185  186                  old_head = (xc_msg_t *)*(volatile xc_msg_t **)queue;
 186  187                  if (old_head == NULL)
 187  188                          return (old_head);
 188      -        } while (casptr(queue, old_head, old_head->xc_next) != old_head);
      189 +        } while (atomic_cas_ptr(queue, old_head, old_head->xc_next) !=
      190 +            old_head);
 189  191          old_head->xc_next = NULL;
 190  192          return (old_head);
 191  193  }
 192  194  
 193  195  /*
 194  196   * Initialize the machcpu fields used for cross calls
 195  197   */
 196  198  static uint_t xc_initialized = 0;
 197  199  
 198  200  void
↓ open down ↓ 402 lines elided ↑ open up ↑
 601  603                  if (!BT_TEST(set, c))
 602  604                          continue;
 603  605                  cpup = cpu[c];
 604  606                  if (cpup == NULL || !(cpup->cpu_flags & CPU_READY) ||
 605  607                      cpup == CPU)
 606  608                          continue;
 607  609                  (void) xc_increment(&cpup->cpu_m);
 608  610                  XC_BT_SET(xc_priority_set, c);
 609  611                  send_dirint(c, XC_HI_PIL);
 610  612                  for (i = 0; i < 10; ++i) {
 611      -                        (void) casptr(&cpup->cpu_m.xc_msgbox,
      613 +                        (void) atomic_cas_ptr(&cpup->cpu_m.xc_msgbox,
 612  614                              cpup->cpu_m.xc_msgbox, cpup->cpu_m.xc_msgbox);
 613  615                  }
 614  616          }
 615  617  }
 616  618  
 617  619  /*
 618  620   * Do cross call to all other CPUs with absolutely no waiting or handshaking.
 619  621   * This should only be used for extraordinary operations, like panic(), which
 620  622   * need to work, in some fashion, in a not completely functional system.
 621  623   * All other uses that want minimal waiting should use xc_call_nowait().
↓ open down ↓ 85 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX