arch/powerpc/mm/nohash/mmu_context.c

Source file repositories/reference/linux-study-clean/arch/powerpc/mm/nohash/mmu_context.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/mm/nohash/mmu_context.c
Extension
.c
Size
10930 bytes
Lines
405
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (mm->context.active) {
			id++;
			if (id > LAST_CONTEXT)
				id = FIRST_CONTEXT;
			continue;
		}

		/* Mark this mm has having no context anymore */
		mm->context.id = MMU_NO_CONTEXT;

		/* Mark it stale on all CPUs that used this mm. For threaded
		 * implementations, we set it on all threads on each core
		 * represented in the mask. A future implementation will use
		 * a core map instead but this will do for now.
		 */
		for_each_cpu(cpu, mm_cpumask(mm)) {
			for (i = cpu_first_thread_sibling(cpu);
			     i <= cpu_last_thread_sibling(cpu); i++) {
				if (stale_map[i])
					__set_bit(id, stale_map[i]);
			}
			cpu = i - 1;
		}
		return id;
	}

	/* This will happen if you have more CPUs than available contexts,
	 * all we can do here is wait a bit and try again
	 */
	raw_spin_unlock(&context_lock);
	cpu_relax();
	raw_spin_lock(&context_lock);

	/* This will cause the caller to try again */
	return MMU_NO_CONTEXT;
}

static unsigned int steal_all_contexts(void)
{
	struct mm_struct *mm;
	int cpu = smp_processor_id();
	unsigned int id;

	for (id = FIRST_CONTEXT; id <= LAST_CONTEXT; id++) {
		/* Pick up the victim mm */
		mm = context_mm[id];

		/* Mark this mm as having no context anymore */
		mm->context.id = MMU_NO_CONTEXT;
		if (id != FIRST_CONTEXT) {
			context_mm[id] = NULL;
			__clear_bit(id, context_map);
		}
		if (IS_ENABLED(CONFIG_SMP))
			__clear_bit(id, stale_map[cpu]);
	}

	/* Flush the TLB for all contexts (not to be used on SMP) */
	_tlbil_all();

	nr_free_contexts = LAST_CONTEXT - FIRST_CONTEXT;

	return FIRST_CONTEXT;
}

/* Note that this will also be called on SMP if all other CPUs are
 * offlined, which means that it may be called for cpu != 0. For
 * this to work, we somewhat assume that CPUs that are onlined
 * come up with a fully clean TLB (or are cleaned when offlined)
 */
static unsigned int steal_context_up(unsigned int id)
{
	struct mm_struct *mm;
	int cpu = smp_processor_id();

	/* Pick up the victim mm */
	mm = context_mm[id];

	/* Flush the TLB for that context */
	local_flush_tlb_mm(mm);

	/* Mark this mm has having no context anymore */
	mm->context.id = MMU_NO_CONTEXT;

	/* XXX This clear should ultimately be part of local_flush_tlb_mm */
	if (IS_ENABLED(CONFIG_SMP))
		__clear_bit(id, stale_map[cpu]);

	return id;
}

Annotation

Implementation Notes