kernel - Deal with lost IPIs (VM related) (2)
[dragonfly.git] / sys / platform / pc64 / x86_64 / pmap_inval.c
1 /*
2  * Copyright (c) 2003-2011 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 /*
36  * pmap invalidation support code.  Certain hardware requirements must
37  * be dealt with when manipulating page table entries and page directory
38  * entries within a pmap.  In particular, we cannot safely manipulate
39  * page tables which are in active use by another cpu (even if it is
40  * running in userland) for two reasons: First, TLB writebacks will
41  * race against our own modifications and tests.  Second, even if we
42  * were to use bus-locked instruction we can still screw up the 
43  * target cpu's instruction pipeline due to Intel cpu errata.
44  */
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/proc.h>
50 #include <sys/vmmeter.h>
51 #include <sys/thread2.h>
52 #include <sys/sysctl.h>
53
54 #include <vm/vm.h>
55 #include <vm/pmap.h>
56 #include <vm/vm_object.h>
57
58 #include <machine/cputypes.h>
59 #include <machine/md_var.h>
60 #include <machine/specialreg.h>
61 #include <machine/smp.h>
62 #include <machine/globaldata.h>
63 #include <machine/pmap.h>
64 #include <machine/pmap_inval.h>
65 #include <machine/clock.h>
66
67 #if 1   /* DEBUGGING */
68 #define LOOPRECOVER                     /* enable watchdog */
69 #endif
70
71 /*
72  * Watchdog recovery interval = 1.0 / (1 << radix), or 1/16 second
73  * for the initial watchdog.  If the initial watchdog fails, further
74  * instances occur at 1/2 second intervals.
75  *
76  * The watchdog value is generous for two reasons.  First, because the
77  * situaation is not supposed to happen at all (but does), and second,
78  * because VMs could be very slow at handling IPIs.
79  */
80 #define LOOPRECOVER_RADIX1      4       /* initial recovery */
81 #define LOOPRECOVER_RADIX2      1       /* repeated recoveries */
82
83 #define MAX_INVAL_PAGES         128
84
85 struct pmap_inval_info {
86         vm_offset_t     va;
87         pt_entry_t      *ptep;
88         pt_entry_t      opte;
89         pt_entry_t      npte;
90         enum { INVDONE, INVSTORE, INVCMPSET } mode;
91         int             success;
92         int             npgs;
93         cpumask_t       done;
94         cpumask_t       mask;
95 #ifdef LOOPRECOVER
96         cpumask_t       sigmask;
97         int             failed;
98         int64_t         tsc_target;
99 #endif
100 } __cachealign;
101
102 typedef struct pmap_inval_info pmap_inval_info_t;
103
104 static pmap_inval_info_t        invinfo[MAXCPU];
105 extern cpumask_t                smp_invmask;
106 #ifdef LOOPRECOVER
107 #ifdef LOOPMASK_IN
108 extern cpumask_t                smp_in_mask;
109 #endif
110 extern cpumask_t                smp_smurf_mask;
111 #endif
112 static long pmap_inval_bulk_count;
113 static int pmap_inval_watchdog_print;   /* must always default off */
114
115 SYSCTL_LONG(_machdep, OID_AUTO, pmap_inval_bulk_count, CTLFLAG_RW,
116             &pmap_inval_bulk_count, 0, "");
117 SYSCTL_INT(_machdep, OID_AUTO, pmap_inval_watchdog_print, CTLFLAG_RW,
118             &pmap_inval_watchdog_print, 0, "");
119
120 static void
121 pmap_inval_init(pmap_t pmap)
122 {
123         cpulock_t olock;
124         cpulock_t nlock;
125
126         crit_enter_id("inval");
127
128         if (pmap != &kernel_pmap) {
129                 for (;;) {
130                         olock = pmap->pm_active_lock;
131                         cpu_ccfence();
132                         nlock = olock | CPULOCK_EXCL;
133                         if (olock != nlock &&
134                             atomic_cmpset_int(&pmap->pm_active_lock,
135                                               olock, nlock)) {
136                                 break;
137                         }
138                         lwkt_process_ipiq();
139                         cpu_pause();
140                 }
141                 atomic_add_acq_long(&pmap->pm_invgen, 1);
142         }
143 }
144
145 static void
146 pmap_inval_done(pmap_t pmap)
147 {
148         if (pmap != &kernel_pmap) {
149                 atomic_clear_int(&pmap->pm_active_lock, CPULOCK_EXCL);
150                 atomic_add_acq_long(&pmap->pm_invgen, 1);
151         }
152         crit_exit_id("inval");
153 }
154
155 #ifdef LOOPRECOVER
156
157 /*
158  * Debugging and lost IPI recovery code.
159  */
160 static
161 __inline
162 int
163 loopwdog(struct pmap_inval_info *info)
164 {
165         int64_t tsc;
166
167         tsc = rdtsc();
168         if (info->tsc_target - tsc < 0 && tsc_frequency) {
169                 info->tsc_target = tsc + (tsc_frequency >> LOOPRECOVER_RADIX2);
170                 return 1;
171         }
172         return 0;
173 }
174
175 static
176 void
177 loopdebug(const char *msg, pmap_inval_info_t *info)
178 {
179         int p;
180         int cpu = mycpu->gd_cpuid;
181
182         /*
183          * Don't kprintf() anything if the pmap inval watchdog gets hit.
184          * DRM can cause an occassional watchdog hit (at least with a 1/16
185          * second watchdog), and attempting to kprintf to the KVM frame buffer
186          * from Xinvltlb, which ignores critical sections, can implode the
187          * system.
188          */
189         if (pmap_inval_watchdog_print == 0)
190                 return;
191
192         cpu_lfence();
193 #ifdef LOOPRECOVER
194         atomic_add_long(&smp_smurf_mask.ary[0], 0);
195 #endif
196         kprintf("ipilost-%s! %d mode=%d m=%08jx d=%08jx "
197 #ifdef LOOPRECOVER
198                 "s=%08jx "
199 #endif
200 #ifdef LOOPMASK_IN
201                 "in=%08jx "
202 #endif
203 #ifdef LOOPRECOVER
204                 "smurf=%08jx\n"
205 #endif
206                 , msg, cpu, info->mode,
207                 info->mask.ary[0],
208                 info->done.ary[0]
209 #ifdef LOOPRECOVER
210                 , info->sigmask.ary[0]
211 #endif
212 #ifdef LOOPMASK_IN
213                 , smp_in_mask.ary[0]
214 #endif
215 #ifdef LOOPRECOVER
216                 , smp_smurf_mask.ary[0]
217 #endif
218                 );
219         kprintf("mdglob ");
220         for (p = 0; p < ncpus; ++p)
221                 kprintf(" %d", CPU_prvspace[p]->mdglobaldata.gd_xinvaltlb);
222         kprintf("\n");
223 }
224
225 #endif
226
227 #ifdef CHECKSIG
228
229 #define CHECKSIGMASK(info)      _checksigmask(info, __FILE__, __LINE__)
230
231 static
232 void
233 _checksigmask(pmap_inval_info_t *info, const char *file, int line)
234 {
235         cpumask_t tmp;
236
237         tmp = info->mask;
238         CPUMASK_ANDMASK(tmp, info->sigmask);
239         if (CPUMASK_CMPMASKNEQ(tmp, info->mask)) {
240                 kprintf("\"%s\" line %d: bad sig/mask %08jx %08jx\n",
241                         file, line, info->sigmask.ary[0], info->mask.ary[0]);
242         }
243 }
244
245 #else
246
247 #define CHECKSIGMASK(info)
248
249 #endif
250
251 /*
252  * Invalidate the specified va across all cpus associated with the pmap.
253  * If va == (vm_offset_t)-1, we invltlb() instead of invlpg().  The operation
254  * will be done fully synchronously with storing npte into *ptep and returning
255  * opte.
256  *
257  * If ptep is NULL the operation will execute semi-synchronously.
258  * ptep must be NULL if npgs > 1
259  */
260 pt_entry_t
261 pmap_inval_smp(pmap_t pmap, vm_offset_t va, int npgs,
262                pt_entry_t *ptep, pt_entry_t npte)
263 {
264         globaldata_t gd = mycpu;
265         pmap_inval_info_t *info;
266         pt_entry_t opte = 0;
267         int cpu = gd->gd_cpuid;
268         cpumask_t tmpmask;
269         unsigned long rflags;
270
271         /*
272          * Initialize invalidation for pmap and enter critical section.
273          */
274         if (pmap == NULL)
275                 pmap = &kernel_pmap;
276         pmap_inval_init(pmap);
277
278         /*
279          * Shortcut single-cpu case if possible.
280          */
281         if (CPUMASK_CMPMASKEQ(pmap->pm_active, gd->gd_cpumask)) {
282                 /*
283                  * Convert to invltlb if there are too many pages to
284                  * invlpg on.
285                  */
286                 if (npgs > MAX_INVAL_PAGES) {
287                         npgs = 0;
288                         va = (vm_offset_t)-1;
289                 }
290
291                 /*
292                  * Invalidate the specified pages, handle invltlb if requested.
293                  */
294                 while (npgs) {
295                         --npgs;
296                         if (ptep) {
297                                 opte = atomic_swap_long(ptep, npte);
298                                 ++ptep;
299                         }
300                         if (va == (vm_offset_t)-1)
301                                 break;
302                         cpu_invlpg((void *)va);
303                         va += PAGE_SIZE;
304                 }
305                 if (va == (vm_offset_t)-1)
306                         cpu_invltlb();
307                 pmap_inval_done(pmap);
308
309                 return opte;
310         }
311
312         /*
313          * We need a critical section to prevent getting preempted while
314          * we setup our command.  A preemption might execute its own
315          * pmap_inval*() command and create confusion below.
316          *
317          * tsc_target is our watchdog timeout that will attempt to recover
318          * from a lost IPI.  Set to 1/16 second for now.
319          */
320         info = &invinfo[cpu];
321         info->tsc_target = rdtsc() + (tsc_frequency >> LOOPRECOVER_RADIX1);
322
323         /*
324          * We must wait for other cpus which may still be finishing up a
325          * prior operation that we requested.
326          *
327          * We do not have to disable interrupts here.  An Xinvltlb can occur
328          * at any time (even within a critical section), but it will not
329          * act on our command until we set our done bits.
330          */
331         while (CPUMASK_TESTNZERO(info->done)) {
332 #ifdef LOOPRECOVER
333                 if (loopwdog(info)) {
334                         info->failed = 1;
335                         loopdebug("A", info);
336                         /* XXX recover from possible bug */
337                         CPUMASK_ASSZERO(info->done);
338                 }
339 #endif
340                 cpu_pause();
341         }
342         KKASSERT(info->mode == INVDONE);
343
344         /*
345          * Must set our cpu in the invalidation scan mask before
346          * any possibility of [partial] execution (remember, XINVLTLB
347          * can interrupt a critical section).
348          */
349         ATOMIC_CPUMASK_ORBIT(smp_invmask, cpu);
350
351         info->va = va;
352         info->npgs = npgs;
353         info->ptep = ptep;
354         info->npte = npte;
355         info->opte = 0;
356 #ifdef LOOPRECOVER
357         info->failed = 0;
358 #endif
359         info->mode = INVSTORE;
360
361         tmpmask = pmap->pm_active;      /* volatile (bits may be cleared) */
362         cpu_ccfence();
363         CPUMASK_ANDMASK(tmpmask, smp_active_mask);
364
365         /*
366          * If ptep is NULL the operation can be semi-synchronous, which means
367          * we can improve performance by flagging and removing idle cpus
368          * (see the idleinvlclr function in mp_machdep.c).
369          *
370          * Typically kernel page table operation is semi-synchronous.
371          */
372         if (ptep == NULL)
373                 smp_smurf_idleinvlclr(&tmpmask);
374         CPUMASK_ORBIT(tmpmask, cpu);
375         info->mask = tmpmask;
376
377         /*
378          * Command may start executing the moment 'done' is initialized,
379          * disable current cpu interrupt to prevent 'done' field from
380          * changing (other cpus can't clear done bits until the originating
381          * cpu clears its mask bit, but other cpus CAN start clearing their
382          * mask bits).
383          */
384 #ifdef LOOPRECOVER
385         info->sigmask = tmpmask;
386         CHECKSIGMASK(info);
387 #endif
388         cpu_sfence();
389         rflags = read_rflags();
390         cpu_disable_intr();
391
392         ATOMIC_CPUMASK_COPY(info->done, tmpmask);
393         /* execution can begin here due to races */
394
395         /*
396          * Pass our copy of the done bits (so they don't change out from
397          * under us) to generate the Xinvltlb interrupt on the targets.
398          */
399         smp_invlpg(&tmpmask);
400         opte = info->opte;
401         KKASSERT(info->mode == INVDONE);
402
403         /*
404          * Target cpus will be in their loop exiting concurrently with our
405          * cleanup.  They will not lose the bitmask they obtained before so
406          * we can safely clear this bit.
407          */
408         ATOMIC_CPUMASK_NANDBIT(smp_invmask, cpu);
409         write_rflags(rflags);
410         pmap_inval_done(pmap);
411
412         return opte;
413 }
414
415 /*
416  * API function - invalidate the pte at (va) and replace *ptep with npte
417  * atomically only if *ptep equals opte, across the pmap's active cpus.
418  *
419  * Returns 1 on success, 0 on failure (caller typically retries).
420  */
421 int
422 pmap_inval_smp_cmpset(pmap_t pmap, vm_offset_t va, pt_entry_t *ptep,
423                       pt_entry_t opte, pt_entry_t npte)
424 {
425         globaldata_t gd = mycpu;
426         pmap_inval_info_t *info;
427         int success;
428         int cpu = gd->gd_cpuid;
429         cpumask_t tmpmask;
430         unsigned long rflags;
431
432         /*
433          * Initialize invalidation for pmap and enter critical section.
434          */
435         if (pmap == NULL)
436                 pmap = &kernel_pmap;
437         pmap_inval_init(pmap);
438
439         /*
440          * Shortcut single-cpu case if possible.
441          */
442         if (CPUMASK_CMPMASKEQ(pmap->pm_active, gd->gd_cpumask)) {
443                 if (atomic_cmpset_long(ptep, opte, npte)) {
444                         if (va == (vm_offset_t)-1)
445                                 cpu_invltlb();
446                         else
447                                 cpu_invlpg((void *)va);
448                         pmap_inval_done(pmap);
449                         return 1;
450                 } else {
451                         pmap_inval_done(pmap);
452                         return 0;
453                 }
454         }
455
456         /*
457          * We need a critical section to prevent getting preempted while
458          * we setup our command.  A preemption might execute its own
459          * pmap_inval*() command and create confusion below.
460          */
461         info = &invinfo[cpu];
462
463         /*
464          * We must wait for other cpus which may still be finishing
465          * up a prior operation.
466          */
467         while (CPUMASK_TESTNZERO(info->done)) {
468 #ifdef LOOPRECOVER
469                 if (loopwdog(info)) {
470                         info->failed = 1;
471                         loopdebug("B", info);
472                         /* XXX recover from possible bug */
473                         CPUMASK_ASSZERO(info->done);
474                 }
475 #endif
476                 cpu_pause();
477         }
478         KKASSERT(info->mode == INVDONE);
479
480         /*
481          * Must set our cpu in the invalidation scan mask before
482          * any possibility of [partial] execution (remember, XINVLTLB
483          * can interrupt a critical section).
484          */
485         ATOMIC_CPUMASK_ORBIT(smp_invmask, cpu);
486
487         info->va = va;
488         info->npgs = 1;                 /* unused */
489         info->ptep = ptep;
490         info->npte = npte;
491         info->opte = opte;
492 #ifdef LOOPRECOVER
493         info->failed = 0;
494 #endif
495         info->mode = INVCMPSET;
496         info->success = 0;
497
498         tmpmask = pmap->pm_active;      /* volatile */
499         cpu_ccfence();
500         CPUMASK_ANDMASK(tmpmask, smp_active_mask);
501         CPUMASK_ORBIT(tmpmask, cpu);
502         info->mask = tmpmask;
503
504         /*
505          * Command may start executing the moment 'done' is initialized,
506          * disable current cpu interrupt to prevent 'done' field from
507          * changing (other cpus can't clear done bits until the originating
508          * cpu clears its mask bit).
509          */
510 #ifdef LOOPRECOVER
511         info->sigmask = tmpmask;
512         CHECKSIGMASK(info);
513 #endif
514         cpu_sfence();
515         rflags = read_rflags();
516         cpu_disable_intr();
517
518         ATOMIC_CPUMASK_COPY(info->done, tmpmask);
519
520         /*
521          * Pass our copy of the done bits (so they don't change out from
522          * under us) to generate the Xinvltlb interrupt on the targets.
523          */
524         smp_invlpg(&tmpmask);
525         success = info->success;
526         KKASSERT(info->mode == INVDONE);
527
528         ATOMIC_CPUMASK_NANDBIT(smp_invmask, cpu);
529         write_rflags(rflags);
530         pmap_inval_done(pmap);
531
532         return success;
533 }
534
535 void
536 pmap_inval_bulk_init(pmap_inval_bulk_t *bulk, struct pmap *pmap)
537 {
538         bulk->pmap = pmap;
539         bulk->va_beg = 0;
540         bulk->va_end = 0;
541         bulk->count = 0;
542 }
543
544 pt_entry_t
545 pmap_inval_bulk(pmap_inval_bulk_t *bulk, vm_offset_t va,
546                 pt_entry_t *ptep, pt_entry_t npte)
547 {
548         pt_entry_t pte;
549
550         /*
551          * Degenerate case, localized or we don't care (e.g. because we
552          * are jacking the entire page table) or the pmap is not in-use
553          * by anyone.  No invalidations are done on any cpu.
554          */
555         if (bulk == NULL) {
556                 pte = atomic_swap_long(ptep, npte);
557                 return pte;
558         }
559
560         /*
561          * If it isn't the kernel pmap we execute the operation synchronously
562          * on all cpus belonging to the pmap, which avoids concurrency bugs in
563          * the hw related to changing pte's out from under threads.
564          *
565          * Eventually I would like to implement streaming pmap invalidation
566          * for user pmaps to reduce mmap/munmap overheads for heavily-loaded
567          * threaded programs.
568          */
569         if (bulk->pmap != &kernel_pmap) {
570                 pte = pmap_inval_smp(bulk->pmap, va, 1, ptep, npte);
571                 return pte;
572         }
573
574         /*
575          * This is the kernel_pmap.  All unmap operations presume that there
576          * are no other cpus accessing the addresses in question.  Implement
577          * the bulking algorithm.  collect the required information and
578          * synchronize once at the end.
579          */
580         pte = atomic_swap_long(ptep, npte);
581         if (va == (vm_offset_t)-1) {
582                 bulk->va_beg = va;
583         } else if (bulk->va_beg == bulk->va_end) {
584                 bulk->va_beg = va;
585                 bulk->va_end = va + PAGE_SIZE;
586         } else if (va == bulk->va_end) {
587                 bulk->va_end = va + PAGE_SIZE;
588         } else {
589                 bulk->va_beg = (vm_offset_t)-1;
590                 bulk->va_end = 0;
591 #if 0
592                 pmap_inval_bulk_flush(bulk);
593                 bulk->count = 1;
594                 if (va == (vm_offset_t)-1) {
595                         bulk->va_beg = va;
596                         bulk->va_end = 0;
597                 } else {
598                         bulk->va_beg = va;
599                         bulk->va_end = va + PAGE_SIZE;
600                 }
601 #endif
602         }
603         ++bulk->count;
604
605         return pte;
606 }
607
608 void
609 pmap_inval_bulk_flush(pmap_inval_bulk_t *bulk)
610 {
611         if (bulk == NULL)
612                 return;
613         if (bulk->count > 0)
614                 pmap_inval_bulk_count += (bulk->count - 1);
615         if (bulk->va_beg != bulk->va_end) {
616                 if (bulk->va_beg == (vm_offset_t)-1) {
617                         pmap_inval_smp(bulk->pmap, bulk->va_beg, 1, NULL, 0);
618                 } else {
619                         long n;
620
621                         n = (bulk->va_end - bulk->va_beg) >> PAGE_SHIFT;
622                         pmap_inval_smp(bulk->pmap, bulk->va_beg, n, NULL, 0);
623                 }
624         }
625         bulk->va_beg = 0;
626         bulk->va_end = 0;
627         bulk->count = 0;
628 }
629
630 /*
631  * Called with a critical section held and interrupts enabled.
632  */
633 int
634 pmap_inval_intr(cpumask_t *cpumaskp, int toolong)
635 {
636         globaldata_t gd = mycpu;
637         pmap_inval_info_t *info;
638         int loopme = 0;
639         int cpu;
640         cpumask_t cpumask;
641
642         /*
643          * Check all cpus for invalidations we may need to service.
644          */
645         cpu_ccfence();
646         cpu = gd->gd_cpuid;
647         cpumask = *cpumaskp;
648
649         while (CPUMASK_TESTNZERO(cpumask)) {
650                 int n = BSFCPUMASK(cpumask);
651
652 #ifdef LOOPRECOVER
653                 KKASSERT(n >= 0 && n < MAXCPU);
654 #endif
655
656                 CPUMASK_NANDBIT(cpumask, n);
657                 info = &invinfo[n];
658
659                 /*
660                  * Due to interrupts/races we can catch a new operation
661                  * in an older interrupt.  A fence is needed once we detect
662                  * the (not) done bit.
663                  */
664                 if (!CPUMASK_TESTBIT(info->done, cpu))
665                         continue;
666                 cpu_lfence();
667 #ifdef LOOPRECOVER
668                 if (toolong) {
669                         kprintf("pminvl %d->%d %08jx %08jx mode=%d\n",
670                                 cpu, n, info->done.ary[0], info->mask.ary[0],
671                                 info->mode);
672                 }
673 #endif
674
675                 /*
676                  * info->mask and info->done always contain the originating
677                  * cpu until the originator is done.  Targets may still be
678                  * present in info->done after the originator is done (they
679                  * will be finishing up their loops).
680                  *
681                  * Clear info->mask bits on other cpus to indicate that they
682                  * have quiesced (entered the loop).  Once the other mask bits
683                  * are clear we can execute the operation on the original,
684                  * then clear the mask and done bits on the originator.  The
685                  * targets will then finish up their side and clear their
686                  * done bits.
687                  *
688                  * The command is considered 100% done when all done bits have
689                  * been cleared.
690                  */
691                 if (n != cpu) {
692                         /*
693                          * Command state machine for 'other' cpus.
694                          */
695                         if (CPUMASK_TESTBIT(info->mask, cpu)) {
696                                 /*
697                                  * Other cpu indicate to originator that they
698                                  * are quiesced.
699                                  */
700                                 ATOMIC_CPUMASK_NANDBIT(info->mask, cpu);
701                                 loopme = 1;
702                         } else if (info->ptep &&
703                                    CPUMASK_TESTBIT(info->mask, n)) {
704                                 /*
705                                  * Other cpu must wait for the originator (n)
706                                  * to complete its command if ptep is not NULL.
707                                  */
708                                 loopme = 1;
709                         } else {
710                                 /*
711                                  * Other cpu detects that the originator has
712                                  * completed its command, or there was no
713                                  * command.
714                                  *
715                                  * Now that the page table entry has changed,
716                                  * we can follow up with our own invalidation.
717                                  */
718                                 vm_offset_t va = info->va;
719                                 int npgs;
720
721                                 if (va == (vm_offset_t)-1 ||
722                                     info->npgs > MAX_INVAL_PAGES) {
723                                         cpu_invltlb();
724                                 } else {
725                                         for (npgs = info->npgs; npgs; --npgs) {
726                                                 cpu_invlpg((void *)va);
727                                                 va += PAGE_SIZE;
728                                         }
729                                 }
730                                 ATOMIC_CPUMASK_NANDBIT(info->done, cpu);
731                                 /* info invalid now */
732                                 /* loopme left alone */
733                         }
734                 } else if (CPUMASK_TESTBIT(info->mask, cpu)) {
735                         /*
736                          * Originator is waiting for other cpus
737                          */
738                         if (CPUMASK_CMPMASKNEQ(info->mask, gd->gd_cpumask)) {
739                                 /*
740                                  * Originator waits for other cpus to enter
741                                  * their loop (aka quiesce).
742                                  *
743                                  * If this bugs out the IPI may have been lost,
744                                  * try to reissue by resetting our own
745                                  * reentrancy bit and clearing the smurf mask
746                                  * for the cpus that did not respond, then
747                                  * reissuing the IPI.
748                                  */
749                                 loopme = 1;
750 #ifdef LOOPRECOVER
751                                 if (loopwdog(info)) {
752                                         info->failed = 1;
753                                         loopdebug("C", info);
754                                         /* XXX recover from possible bug */
755                                         mdcpu->gd_xinvaltlb = 0;
756                                         ATOMIC_CPUMASK_NANDMASK(smp_smurf_mask,
757                                                                 info->mask);
758                                         cpu_disable_intr();
759                                         smp_invlpg(&smp_active_mask);
760
761                                         /*
762                                          * Force outer-loop retest of Xinvltlb
763                                          * requests (see mp_machdep.c).
764                                          */
765                                         mdcpu->gd_xinvaltlb = 2;
766                                         cpu_enable_intr();
767                                 }
768 #endif
769                         } else {
770                                 /*
771                                  * Originator executes operation and clears
772                                  * mask to allow other cpus to finish.
773                                  */
774                                 KKASSERT(info->mode != INVDONE);
775                                 if (info->mode == INVSTORE) {
776                                         if (info->ptep)
777                                                 info->opte = atomic_swap_long(info->ptep, info->npte);
778                                         CHECKSIGMASK(info);
779                                         ATOMIC_CPUMASK_NANDBIT(info->mask, cpu);
780                                         CHECKSIGMASK(info);
781                                 } else {
782                                         if (atomic_cmpset_long(info->ptep,
783                                                               info->opte, info->npte)) {
784                                                 info->success = 1;
785                                         } else {
786                                                 info->success = 0;
787                                         }
788                                         CHECKSIGMASK(info);
789                                         ATOMIC_CPUMASK_NANDBIT(info->mask, cpu);
790                                         CHECKSIGMASK(info);
791                                 }
792                                 loopme = 1;
793                         }
794                 } else {
795                         /*
796                          * Originator does not have to wait for the other
797                          * cpus to finish.  It clears its done bit.  A new
798                          * command will not be initiated by the originator
799                          * until the other cpus have cleared their done bits
800                          * (asynchronously).
801                          */
802                         vm_offset_t va = info->va;
803                         int npgs;
804
805                         if (va == (vm_offset_t)-1 ||
806                             info->npgs > MAX_INVAL_PAGES) {
807                                 cpu_invltlb();
808                         } else {
809                                 for (npgs = info->npgs; npgs; --npgs) {
810                                         cpu_invlpg((void *)va);
811                                         va += PAGE_SIZE;
812                                 }
813                         }
814
815                         /* leave loopme alone */
816                         /* other cpus may still be finishing up */
817                         /* can't race originator since that's us */
818                         info->mode = INVDONE;
819                         ATOMIC_CPUMASK_NANDBIT(info->done, cpu);
820                 }
821         }
822         return loopme;
823 }