kernel - Deal with lost IPIs (VM related)
[dragonfly.git] / sys / platform / pc64 / x86_64 / pmap_inval.c
blob520f6c476a2538d8003a06dc9466d89f4282d5a4
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:
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.
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.
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.
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>
54 #include <vm/vm.h>
55 #include <vm/pmap.h>
56 #include <vm/vm_object.h>
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>
67 #if 1 /* DEBUGGING */
68 #define LOOPRECOVER /* enable watchdog */
69 #endif
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.
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.
80 #define LOOPRECOVER_RADIX1 4 /* initial recovery */
81 #define LOOPRECOVER_RADIX2 1 /* repeated recoveries */
83 #define MAX_INVAL_PAGES 128
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;
102 typedef struct pmap_inval_info pmap_inval_info_t;
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;
114 SYSCTL_LONG(_machdep, OID_AUTO, pmap_inval_bulk_count, CTLFLAG_RW,
115 &pmap_inval_bulk_count, 0, "");
117 static void
118 pmap_inval_init(pmap_t pmap)
120 cpulock_t olock;
121 cpulock_t nlock;
123 crit_enter_id("inval");
125 if (pmap != &kernel_pmap) {
126 for (;;) {
127 olock = pmap->pm_active_lock;
128 cpu_ccfence();
129 nlock = olock | CPULOCK_EXCL;
130 if (olock != nlock &&
131 atomic_cmpset_int(&pmap->pm_active_lock,
132 olock, nlock)) {
133 break;
135 lwkt_process_ipiq();
136 cpu_pause();
138 atomic_add_acq_long(&pmap->pm_invgen, 1);
142 static void
143 pmap_inval_done(pmap_t pmap)
145 if (pmap != &kernel_pmap) {
146 atomic_clear_int(&pmap->pm_active_lock, CPULOCK_EXCL);
147 atomic_add_acq_long(&pmap->pm_invgen, 1);
149 crit_exit_id("inval");
152 #ifdef LOOPRECOVER
155 * Debugging and lost IPI recovery code.
157 static
158 __inline
160 loopwdog(struct pmap_inval_info *info)
162 int64_t tsc;
164 tsc = rdtsc();
165 if (info->tsc_target - tsc < 0 && tsc_frequency) {
166 info->tsc_target = tsc + (tsc_frequency >> LOOPRECOVER_RADIX2);
167 return 1;
169 return 0;
172 static
173 void
174 loopdebug(const char *msg, pmap_inval_info_t *info)
176 int p;
177 int cpu = mycpu->gd_cpuid;
179 cpu_lfence();
180 #ifdef LOOPRECOVER
181 atomic_add_long(&smp_smurf_mask.ary[0], 0);
182 #endif
183 kprintf("ipilost-%s! %d mode=%d m=%08jx d=%08jx "
184 #ifdef LOOPRECOVER
185 "s=%08jx "
186 #endif
187 #ifdef LOOPMASK_IN
188 "in=%08jx "
189 #endif
190 #ifdef LOOPRECOVER
191 "smurf=%08jx\n"
192 #endif
193 , msg, cpu, info->mode,
194 info->mask.ary[0],
195 info->done.ary[0]
196 #ifdef LOOPRECOVER
197 , info->sigmask.ary[0]
198 #endif
199 #ifdef LOOPMASK_IN
200 , smp_in_mask.ary[0]
201 #endif
202 #ifdef LOOPRECOVER
203 , smp_smurf_mask.ary[0]
204 #endif
206 kprintf("mdglob ");
207 for (p = 0; p < ncpus; ++p)
208 kprintf(" %d", CPU_prvspace[p]->mdglobaldata.gd_xinvaltlb);
209 kprintf("\n");
212 #endif
214 #ifdef CHECKSIG
216 #define CHECKSIGMASK(info) _checksigmask(info, __FILE__, __LINE__)
218 static
219 void
220 _checksigmask(pmap_inval_info_t *info, const char *file, int line)
222 cpumask_t tmp;
224 tmp = info->mask;
225 CPUMASK_ANDMASK(tmp, info->sigmask);
226 if (CPUMASK_CMPMASKNEQ(tmp, info->mask)) {
227 kprintf("\"%s\" line %d: bad sig/mask %08jx %08jx\n",
228 file, line, info->sigmask.ary[0], info->mask.ary[0]);
232 #else
234 #define CHECKSIGMASK(info)
236 #endif
239 * Invalidate the specified va across all cpus associated with the pmap.
240 * If va == (vm_offset_t)-1, we invltlb() instead of invlpg(). The operation
241 * will be done fully synchronously with storing npte into *ptep and returning
242 * opte.
244 * If ptep is NULL the operation will execute semi-synchronously.
245 * ptep must be NULL if npgs > 1
247 pt_entry_t
248 pmap_inval_smp(pmap_t pmap, vm_offset_t va, int npgs,
249 pt_entry_t *ptep, pt_entry_t npte)
251 globaldata_t gd = mycpu;
252 pmap_inval_info_t *info;
253 pt_entry_t opte = 0;
254 int cpu = gd->gd_cpuid;
255 cpumask_t tmpmask;
256 unsigned long rflags;
259 * Initialize invalidation for pmap and enter critical section.
261 if (pmap == NULL)
262 pmap = &kernel_pmap;
263 pmap_inval_init(pmap);
266 * Shortcut single-cpu case if possible.
268 if (CPUMASK_CMPMASKEQ(pmap->pm_active, gd->gd_cpumask)) {
270 * Convert to invltlb if there are too many pages to
271 * invlpg on.
273 if (npgs > MAX_INVAL_PAGES) {
274 npgs = 0;
275 va = (vm_offset_t)-1;
279 * Invalidate the specified pages, handle invltlb if requested.
281 while (npgs) {
282 --npgs;
283 if (ptep) {
284 opte = atomic_swap_long(ptep, npte);
285 ++ptep;
287 if (va == (vm_offset_t)-1)
288 break;
289 cpu_invlpg((void *)va);
290 va += PAGE_SIZE;
292 if (va == (vm_offset_t)-1)
293 cpu_invltlb();
294 pmap_inval_done(pmap);
296 return opte;
300 * We need a critical section to prevent getting preempted while
301 * we setup our command. A preemption might execute its own
302 * pmap_inval*() command and create confusion below.
304 * tsc_target is our watchdog timeout that will attempt to recover
305 * from a lost IPI. Set to 1/16 second for now.
307 info = &invinfo[cpu];
308 info->tsc_target = rdtsc() + (tsc_frequency >> LOOPRECOVER_RADIX1);
311 * We must wait for other cpus which may still be finishing up a
312 * prior operation that we requested.
314 * We do not have to disable interrupts here. An Xinvltlb can occur
315 * at any time (even within a critical section), but it will not
316 * act on our command until we set our done bits.
318 while (CPUMASK_TESTNZERO(info->done)) {
319 #ifdef LOOPRECOVER
320 if (loopwdog(info)) {
321 info->failed = 1;
322 loopdebug("A", info);
323 /* XXX recover from possible bug */
324 CPUMASK_ASSZERO(info->done);
326 #endif
327 cpu_pause();
329 KKASSERT(info->mode == INVDONE);
332 * Must set our cpu in the invalidation scan mask before
333 * any possibility of [partial] execution (remember, XINVLTLB
334 * can interrupt a critical section).
336 ATOMIC_CPUMASK_ORBIT(smp_invmask, cpu);
338 info->va = va;
339 info->npgs = npgs;
340 info->ptep = ptep;
341 info->npte = npte;
342 info->opte = 0;
343 #ifdef LOOPRECOVER
344 info->failed = 0;
345 #endif
346 info->mode = INVSTORE;
348 tmpmask = pmap->pm_active; /* volatile (bits may be cleared) */
349 cpu_ccfence();
350 CPUMASK_ANDMASK(tmpmask, smp_active_mask);
353 * If ptep is NULL the operation can be semi-synchronous, which means
354 * we can improve performance by flagging and removing idle cpus
355 * (see the idleinvlclr function in mp_machdep.c).
357 * Typically kernel page table operation is semi-synchronous.
359 if (ptep == NULL)
360 smp_smurf_idleinvlclr(&tmpmask);
361 CPUMASK_ORBIT(tmpmask, cpu);
362 info->mask = tmpmask;
365 * Command may start executing the moment 'done' is initialized,
366 * disable current cpu interrupt to prevent 'done' field from
367 * changing (other cpus can't clear done bits until the originating
368 * cpu clears its mask bit, but other cpus CAN start clearing their
369 * mask bits).
371 #ifdef LOOPRECOVER
372 info->sigmask = tmpmask;
373 CHECKSIGMASK(info);
374 #endif
375 cpu_sfence();
376 rflags = read_rflags();
377 cpu_disable_intr();
379 ATOMIC_CPUMASK_COPY(info->done, tmpmask);
380 /* execution can begin here due to races */
383 * Pass our copy of the done bits (so they don't change out from
384 * under us) to generate the Xinvltlb interrupt on the targets.
386 smp_invlpg(&tmpmask);
387 opte = info->opte;
388 KKASSERT(info->mode == INVDONE);
391 * Target cpus will be in their loop exiting concurrently with our
392 * cleanup. They will not lose the bitmask they obtained before so
393 * we can safely clear this bit.
395 ATOMIC_CPUMASK_NANDBIT(smp_invmask, cpu);
396 write_rflags(rflags);
397 pmap_inval_done(pmap);
399 return opte;
403 * API function - invalidate the pte at (va) and replace *ptep with npte
404 * atomically only if *ptep equals opte, across the pmap's active cpus.
406 * Returns 1 on success, 0 on failure (caller typically retries).
409 pmap_inval_smp_cmpset(pmap_t pmap, vm_offset_t va, pt_entry_t *ptep,
410 pt_entry_t opte, pt_entry_t npte)
412 globaldata_t gd = mycpu;
413 pmap_inval_info_t *info;
414 int success;
415 int cpu = gd->gd_cpuid;
416 cpumask_t tmpmask;
417 unsigned long rflags;
420 * Initialize invalidation for pmap and enter critical section.
422 if (pmap == NULL)
423 pmap = &kernel_pmap;
424 pmap_inval_init(pmap);
427 * Shortcut single-cpu case if possible.
429 if (CPUMASK_CMPMASKEQ(pmap->pm_active, gd->gd_cpumask)) {
430 if (atomic_cmpset_long(ptep, opte, npte)) {
431 if (va == (vm_offset_t)-1)
432 cpu_invltlb();
433 else
434 cpu_invlpg((void *)va);
435 pmap_inval_done(pmap);
436 return 1;
437 } else {
438 pmap_inval_done(pmap);
439 return 0;
444 * We need a critical section to prevent getting preempted while
445 * we setup our command. A preemption might execute its own
446 * pmap_inval*() command and create confusion below.
448 info = &invinfo[cpu];
451 * We must wait for other cpus which may still be finishing
452 * up a prior operation.
454 while (CPUMASK_TESTNZERO(info->done)) {
455 #ifdef LOOPRECOVER
456 if (loopwdog(info)) {
457 info->failed = 1;
458 loopdebug("B", info);
459 /* XXX recover from possible bug */
460 CPUMASK_ASSZERO(info->done);
462 #endif
463 cpu_pause();
465 KKASSERT(info->mode == INVDONE);
468 * Must set our cpu in the invalidation scan mask before
469 * any possibility of [partial] execution (remember, XINVLTLB
470 * can interrupt a critical section).
472 ATOMIC_CPUMASK_ORBIT(smp_invmask, cpu);
474 info->va = va;
475 info->npgs = 1; /* unused */
476 info->ptep = ptep;
477 info->npte = npte;
478 info->opte = opte;
479 #ifdef LOOPRECOVER
480 info->failed = 0;
481 #endif
482 info->mode = INVCMPSET;
483 info->success = 0;
485 tmpmask = pmap->pm_active; /* volatile */
486 cpu_ccfence();
487 CPUMASK_ANDMASK(tmpmask, smp_active_mask);
488 CPUMASK_ORBIT(tmpmask, cpu);
489 info->mask = tmpmask;
492 * Command may start executing the moment 'done' is initialized,
493 * disable current cpu interrupt to prevent 'done' field from
494 * changing (other cpus can't clear done bits until the originating
495 * cpu clears its mask bit).
497 #ifdef LOOPRECOVER
498 info->sigmask = tmpmask;
499 CHECKSIGMASK(info);
500 #endif
501 cpu_sfence();
502 rflags = read_rflags();
503 cpu_disable_intr();
505 ATOMIC_CPUMASK_COPY(info->done, tmpmask);
508 * Pass our copy of the done bits (so they don't change out from
509 * under us) to generate the Xinvltlb interrupt on the targets.
511 smp_invlpg(&tmpmask);
512 success = info->success;
513 KKASSERT(info->mode == INVDONE);
515 ATOMIC_CPUMASK_NANDBIT(smp_invmask, cpu);
516 write_rflags(rflags);
517 pmap_inval_done(pmap);
519 return success;
522 void
523 pmap_inval_bulk_init(pmap_inval_bulk_t *bulk, struct pmap *pmap)
525 bulk->pmap = pmap;
526 bulk->va_beg = 0;
527 bulk->va_end = 0;
528 bulk->count = 0;
531 pt_entry_t
532 pmap_inval_bulk(pmap_inval_bulk_t *bulk, vm_offset_t va,
533 pt_entry_t *ptep, pt_entry_t npte)
535 pt_entry_t pte;
538 * Degenerate case, localized or we don't care (e.g. because we
539 * are jacking the entire page table) or the pmap is not in-use
540 * by anyone. No invalidations are done on any cpu.
542 if (bulk == NULL) {
543 pte = atomic_swap_long(ptep, npte);
544 return pte;
548 * If it isn't the kernel pmap we execute the operation synchronously
549 * on all cpus belonging to the pmap, which avoids concurrency bugs in
550 * the hw related to changing pte's out from under threads.
552 * Eventually I would like to implement streaming pmap invalidation
553 * for user pmaps to reduce mmap/munmap overheads for heavily-loaded
554 * threaded programs.
556 if (bulk->pmap != &kernel_pmap) {
557 pte = pmap_inval_smp(bulk->pmap, va, 1, ptep, npte);
558 return pte;
562 * This is the kernel_pmap. All unmap operations presume that there
563 * are no other cpus accessing the addresses in question. Implement
564 * the bulking algorithm. collect the required information and
565 * synchronize once at the end.
567 pte = atomic_swap_long(ptep, npte);
568 if (va == (vm_offset_t)-1) {
569 bulk->va_beg = va;
570 } else if (bulk->va_beg == bulk->va_end) {
571 bulk->va_beg = va;
572 bulk->va_end = va + PAGE_SIZE;
573 } else if (va == bulk->va_end) {
574 bulk->va_end = va + PAGE_SIZE;
575 } else {
576 bulk->va_beg = (vm_offset_t)-1;
577 bulk->va_end = 0;
578 #if 0
579 pmap_inval_bulk_flush(bulk);
580 bulk->count = 1;
581 if (va == (vm_offset_t)-1) {
582 bulk->va_beg = va;
583 bulk->va_end = 0;
584 } else {
585 bulk->va_beg = va;
586 bulk->va_end = va + PAGE_SIZE;
588 #endif
590 ++bulk->count;
592 return pte;
595 void
596 pmap_inval_bulk_flush(pmap_inval_bulk_t *bulk)
598 if (bulk == NULL)
599 return;
600 if (bulk->count > 0)
601 pmap_inval_bulk_count += (bulk->count - 1);
602 if (bulk->va_beg != bulk->va_end) {
603 if (bulk->va_beg == (vm_offset_t)-1) {
604 pmap_inval_smp(bulk->pmap, bulk->va_beg, 1, NULL, 0);
605 } else {
606 long n;
608 n = (bulk->va_end - bulk->va_beg) >> PAGE_SHIFT;
609 pmap_inval_smp(bulk->pmap, bulk->va_beg, n, NULL, 0);
612 bulk->va_beg = 0;
613 bulk->va_end = 0;
614 bulk->count = 0;
618 * Called with a critical section held and interrupts enabled.
621 pmap_inval_intr(cpumask_t *cpumaskp, int toolong)
623 globaldata_t gd = mycpu;
624 pmap_inval_info_t *info;
625 int loopme = 0;
626 int cpu;
627 cpumask_t cpumask;
630 * Check all cpus for invalidations we may need to service.
632 cpu_ccfence();
633 cpu = gd->gd_cpuid;
634 cpumask = *cpumaskp;
636 while (CPUMASK_TESTNZERO(cpumask)) {
637 int n = BSFCPUMASK(cpumask);
639 #ifdef LOOPRECOVER
640 KKASSERT(n >= 0 && n < MAXCPU);
641 #endif
643 CPUMASK_NANDBIT(cpumask, n);
644 info = &invinfo[n];
647 * Due to interrupts/races we can catch a new operation
648 * in an older interrupt. A fence is needed once we detect
649 * the (not) done bit.
651 if (!CPUMASK_TESTBIT(info->done, cpu))
652 continue;
653 cpu_lfence();
654 #ifdef LOOPRECOVER
655 if (toolong) {
656 kprintf("pminvl %d->%d %08jx %08jx mode=%d\n",
657 cpu, n, info->done.ary[0], info->mask.ary[0],
658 info->mode);
660 #endif
663 * info->mask and info->done always contain the originating
664 * cpu until the originator is done. Targets may still be
665 * present in info->done after the originator is done (they
666 * will be finishing up their loops).
668 * Clear info->mask bits on other cpus to indicate that they
669 * have quiesced (entered the loop). Once the other mask bits
670 * are clear we can execute the operation on the original,
671 * then clear the mask and done bits on the originator. The
672 * targets will then finish up their side and clear their
673 * done bits.
675 * The command is considered 100% done when all done bits have
676 * been cleared.
678 if (n != cpu) {
680 * Command state machine for 'other' cpus.
682 if (CPUMASK_TESTBIT(info->mask, cpu)) {
684 * Other cpu indicate to originator that they
685 * are quiesced.
687 ATOMIC_CPUMASK_NANDBIT(info->mask, cpu);
688 loopme = 1;
689 } else if (info->ptep &&
690 CPUMASK_TESTBIT(info->mask, n)) {
692 * Other cpu must wait for the originator (n)
693 * to complete its command if ptep is not NULL.
695 loopme = 1;
696 } else {
698 * Other cpu detects that the originator has
699 * completed its command, or there was no
700 * command.
702 * Now that the page table entry has changed,
703 * we can follow up with our own invalidation.
705 vm_offset_t va = info->va;
706 int npgs;
708 if (va == (vm_offset_t)-1 ||
709 info->npgs > MAX_INVAL_PAGES) {
710 cpu_invltlb();
711 } else {
712 for (npgs = info->npgs; npgs; --npgs) {
713 cpu_invlpg((void *)va);
714 va += PAGE_SIZE;
717 ATOMIC_CPUMASK_NANDBIT(info->done, cpu);
718 /* info invalid now */
719 /* loopme left alone */
721 } else if (CPUMASK_TESTBIT(info->mask, cpu)) {
723 * Originator is waiting for other cpus
725 if (CPUMASK_CMPMASKNEQ(info->mask, gd->gd_cpumask)) {
727 * Originator waits for other cpus to enter
728 * their loop (aka quiesce).
730 * If this bugs out the IPI may have been lost,
731 * try to reissue by resetting our own
732 * reentrancy bit and clearing the smurf mask
733 * for the cpus that did not respond, then
734 * reissuing the IPI.
736 loopme = 1;
737 #ifdef LOOPRECOVER
738 if (loopwdog(info)) {
739 info->failed = 1;
740 loopdebug("C", info);
741 /* XXX recover from possible bug */
742 mdcpu->gd_xinvaltlb = 0;
743 ATOMIC_CPUMASK_NANDMASK(smp_smurf_mask,
744 info->mask);
745 cpu_disable_intr();
746 smp_invlpg(&smp_active_mask);
747 cpu_enable_intr();
749 #endif
750 } else {
752 * Originator executes operation and clears
753 * mask to allow other cpus to finish.
755 KKASSERT(info->mode != INVDONE);
756 if (info->mode == INVSTORE) {
757 if (info->ptep)
758 info->opte = atomic_swap_long(info->ptep, info->npte);
759 CHECKSIGMASK(info);
760 ATOMIC_CPUMASK_NANDBIT(info->mask, cpu);
761 CHECKSIGMASK(info);
762 } else {
763 if (atomic_cmpset_long(info->ptep,
764 info->opte, info->npte)) {
765 info->success = 1;
766 } else {
767 info->success = 0;
769 CHECKSIGMASK(info);
770 ATOMIC_CPUMASK_NANDBIT(info->mask, cpu);
771 CHECKSIGMASK(info);
773 loopme = 1;
775 } else {
777 * Originator does not have to wait for the other
778 * cpus to finish. It clears its done bit. A new
779 * command will not be initiated by the originator
780 * until the other cpus have cleared their done bits
781 * (asynchronously).
783 vm_offset_t va = info->va;
784 int npgs;
786 if (va == (vm_offset_t)-1 ||
787 info->npgs > MAX_INVAL_PAGES) {
788 cpu_invltlb();
789 } else {
790 for (npgs = info->npgs; npgs; --npgs) {
791 cpu_invlpg((void *)va);
792 va += PAGE_SIZE;
796 /* leave loopme alone */
797 /* other cpus may still be finishing up */
798 /* can't race originator since that's us */
799 info->mode = INVDONE;
800 ATOMIC_CPUMASK_NANDBIT(info->done, cpu);
803 return loopme;