kernels/linux-2.4.0/arch/sparc64/kernel/smp.c
/* We know that the window frames of the user have been flushed
 * to the stack before we get here because all callers of us
 * are flush_tlb_*() routines, and these run after flush_cache_*()
 * which performs the flushw.
 *
 * XXX I diked out the fancy flush avoidance code for the
 * XXX swapping cases for now until the new MM code stabilizes. -DaveM
 *
 * The SMP TLB coherency scheme we use works as follows:
 *
 * 1) mm->cpu_vm_mask is a bit mask of which cpus an address
 *    space has (potentially) executed on, this is the heuristic
 *    we use to avoid doing cross calls.
 *
 * 2) TLB context numbers are shared globally across all processors
 *    in the system, this allows us to play several games to avoid
 *    cross calls.
 *
 *    One invariant is that when a cpu switches to a process, and
 *    that processes tsk->active_mm->cpu_vm_mask does not have the
 *    current cpu's bit set, that tlb context is flushed locally.
 *
 *    If the address space is non-shared (ie. mm->count == 1) we avoid
 *    cross calls when we want to flush the currently running process's
 *    tlb state.  This is done by clearing all cpu bits except the current
 *    processor's in current->active_mm->cpu_vm_mask and performing the
 *    flush locally only.  This will force any subsequent cpus which run
 *    this task to flush the context from the local tlb if the process
 *    migrates to another cpu (again).
 *
 * 3) For shared address spaces (threads) and swapping we bite the
 *    bullet for most cases and perform the cross call.
 *
 *    The performance gain from "optimizing" away the cross call for threads is
 *    questionable (in theory the big win for threads is the massive sharing of
 *    address space state across processors).
 *
 *    For the swapping case the locking is difficult to get right, we'd have to
 *    enforce strict ordered access to mm->cpu_vm_mask via a spinlock for example.
 *    Then again one could argue that when you are swapping, the cost of a cross
 *    call won't even show up on the performance radar.  But in any case we do get
 *    rid of the cross-call when the task has a dead context or the task has only
 *    ever run on the local cpu.
 */
We know that the window frames of the user have been flushed
to the stack before we get here because all callers of us
are flush_tlb_*() routines, and these run after flush_cache_*()
which performs the flushw.

XXX I diked out the fancy flush avoidance code for the
XXX swapping cases for now until the new MM code stabilizes.

The SMP TLB coherency scheme we use works as follows.

1) mm->cpu_vm_mask is a bit mask of which cpus an address
space has (potentially) executed on, this is the heuristic
we use to avoid doing cross calls.

2) TLB context numbers are shared globally across all processors
in the system, this allows us to play several games to avoid
cross calls.

One invariant is that when a cpu switches to a process, and
that processes tsk->active_mm->cpu_vm_mask does not have the
current cpu's bit set, that tlb context is flushed locally.

If the address space is non-shared  we avoid
cross calls when we want to flush the currently running process's
tlb state.  This is done by clearing all cpu bits except the current
processor's in current->active_mm->cpu_vm_mask and performing the
flush locally only.  This will force any subsequent cpus which run
this task to flush the context from the local tlb if the process
migrates to another cpu (again).

3) For shared address spaces (threads) and swapping we bite the
bullet for most cases and perform the cross call.

The performance gain from "optimizing" away the cross call for threads is
questionable (in theory the big win for threads is the massive sharing of
address space state across processors).

For the swapping case the locking is difficult to get right, we'd have to
enforce strict ordered access to mm->cpu_vm_mask via a spinlock for example.
Then again one could argue that when you are swapping, the cost of a cross
call won't even show up on the performance radar.  But in any case we do get
rid of the cross-call when the task has a dead context or the task has only
ever run on the local cpu.
We know that the window frames of the user have been flushed to the stack before we get here because all callers of us are flush_tlb_ * () routines and these run after flush_cache_ * () which performs the flushw . XXX I diked out the fancy flush avoidance code for the XXX swapping cases for now until the new MM code stabilizes . The SMP TLB coherency scheme we use works as follows . 1 ) mm - > cpu_vm_mask is a bit mask of which cpus an address space has ( potentially ) executed on this is the heuristic we use to avoid doing cross calls . 2 ) TLB context numbers are shared globally across all processors in the system this allows us to play several games to avoid cross calls . One invariant is that when a cpu switches to a process and that processes tsk - > active_mm - > cpu_vm_mask does not have the current cpu ' s bit set that tlb context is flushed locally . If the address space is non - shared we avoid cross calls when we want to flush the currently running process ' s tlb state . This is done by clearing all cpu bits except the current processor ' s in current - > active_mm - > cpu_vm_mask and performing the flush locally only . This will force any subsequent cpus which run this task to flush the context from the local tlb if the process migrates to another cpu ( again ) . 3 ) For shared address spaces ( threads ) and swapping we bite the bullet for most cases and perform the cross call . The performance gain from " optimizing " away the cross call for threads is questionable ( in theory the big win for threads is the massive sharing of address space state across processors ) . For the swapping case the locking is difficult to get right we ' d have to enforce strict ordered access to mm - > cpu_vm_mask via a spinlock for example . Then again one could argue that when you are swapping the cost of a cross call won ' t even show up on the performance radar . But in any case we do get rid of the cross - call when the task has a dead context or the task has only ever run on the local cpu .
void smp_flush_tlb_mm(struct mm_struct *mm)
{
	if (CTX_VALID(mm->context)) {
		u32 ctx = CTX_HWBITS(mm->context);
		int cpu = smp_processor_id();
		if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
			mm->cpu_vm_mask = (1UL << cpu);
			goto local_flush_and_out;
		}
		smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
	local_flush_and_out:
		__flush_tlb_mm(ctx, SECONDARY_CONTEXT);
	}
}
void smp_flush_tlb_mm ( struct mm_struct * mm ) { if ( CTX_VALID ( mm -> context ) ) { u32 ctx = CTX_HWBITS ( mm -> context ) ; int cpu = smp_processor_id ( ) ; if ( mm == current -> active_mm && atomic_read ( & mm -> mm_users ) == 1 ) { mm -> cpu_vm_mask = ( 1UL << cpu ) ; goto local_flush_and_out ; } smp_cross_call ( & xcall_flush_tlb_mm , ctx , 0 , 0 ) ; local_flush_and_out : __flush_tlb_mm ( ctx , SECONDARY_CONTEXT ) ; } }
We know that the window frames of the user have been flushed
 to the stack before we get here because all callers of us
 are flush_tlb_*() routines, and these run after flush_cache_*()
 which performs the flushw.
We know that the window frames of the user have been flushed to the stack before we get here because all callers of us are flush_tlb_ * () routines and these run after flush_cache_ * () which performs the flushw .
/* See smp_flush_tlb_page for info about this. */