arch/mips/mm/context.c

Source file repositories/reference/linux-study-clean/arch/mips/mm/context.c

File Facts

System
Linux kernel
Corpus path
arch/mips/mm/context.c
Extension
.c
Size
7832 bytes
Lines
291
Domain
Architecture Layer
Bucket
arch/mips
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration 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 (per_cpu(reserved_mmids, cpu) == mmid) {
			hit = true;
			per_cpu(reserved_mmids, cpu) = newmmid;
		}
	}

	return hit;
}

static u64 get_new_mmid(struct mm_struct *mm)
{
	static u32 cur_idx = MMID_KERNEL_WIRED + 1;
	u64 mmid, version, mmid_mask;

	mmid = cpu_context(0, mm);
	version = atomic64_read(&mmid_version);
	mmid_mask = cpu_asid_mask(&boot_cpu_data);

	if (!asid_versions_eq(0, mmid, 0)) {
		u64 newmmid = version | (mmid & mmid_mask);

		/*
		 * If our current MMID was active during a rollover, we
		 * can continue to use it and this was just a false alarm.
		 */
		if (check_update_reserved_mmid(mmid, newmmid)) {
			mmid = newmmid;
			goto set_context;
		}

		/*
		 * We had a valid MMID in a previous life, so try to re-use
		 * it if possible.
		 */
		if (!__test_and_set_bit(mmid & mmid_mask, mmid_map)) {
			mmid = newmmid;
			goto set_context;
		}
	}

	/* Allocate a free MMID */
	mmid = find_next_zero_bit(mmid_map, num_mmids, cur_idx);
	if (mmid != num_mmids)
		goto reserve_mmid;

	/* We're out of MMIDs, so increment the global version */
	version = atomic64_add_return_relaxed(asid_first_version(0),
					      &mmid_version);

	/* Note currently active MMIDs & mark TLBs as requiring flushes */
	flush_context();

	/* We have more MMIDs than CPUs, so this will always succeed */
	mmid = find_first_zero_bit(mmid_map, num_mmids);

reserve_mmid:
	__set_bit(mmid, mmid_map);
	cur_idx = mmid;
	mmid |= version;
set_context:
	set_cpu_context(0, mm, mmid);
	return mmid;
}

void check_switch_mmu_context(struct mm_struct *mm)
{
	unsigned int cpu = smp_processor_id();
	u64 ctx, old_active_mmid;
	unsigned long flags;

	if (!cpu_has_mmid) {
		check_mmu_context(mm);
		write_c0_entryhi(cpu_asid(cpu, mm));
		goto setup_pgd;
	}

	/*
	 * MMID switch fast-path, to avoid acquiring cpu_mmid_lock when it's
	 * unnecessary.
	 *
	 * The memory ordering here is subtle. If our active_mmids is non-zero
	 * and the MMID matches the current version, then we update the CPU's
	 * asid_cache with a relaxed cmpxchg. Racing with a concurrent rollover
	 * means that either:
	 *
	 * - We get a zero back from the cmpxchg and end up waiting on
	 *   cpu_mmid_lock in check_mmu_context(). Taking the lock synchronises
	 *   with the rollover and so we are forced to see the updated
	 *   generation.
	 *

Annotation

Implementation Notes