arch/riscv/mm/context.c

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

File Facts

System
Linux kernel
Corpus path
arch/riscv/mm/context.c
Extension
.c
Size
9819 bytes
Lines
339
Domain
Architecture Layer
Bucket
arch/riscv
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 (per_cpu(reserved_context, cpu) == cntx) {
			hit = true;
			per_cpu(reserved_context, cpu) = newcntx;
		}
	}

	return hit;
}

static void __flush_context(void)
{
	int i;
	unsigned long cntx;

	/* Must be called with context_lock held */
	lockdep_assert_held(&context_lock);

	/* Update the list of reserved ASIDs and the ASID bitmap. */
	bitmap_zero(context_asid_map, num_asids);

	/* Mark already active ASIDs as used */
	for_each_possible_cpu(i) {
		cntx = atomic_long_xchg_relaxed(&per_cpu(active_context, i), 0);
		/*
		 * If this CPU has already been through a rollover, but
		 * hasn't run another task in the meantime, we must preserve
		 * its reserved CONTEXT, as this is the only trace we have of
		 * the process it is still running.
		 */
		if (cntx == 0)
			cntx = per_cpu(reserved_context, i);

		__set_bit(cntx2asid(cntx), context_asid_map);
		per_cpu(reserved_context, i) = cntx;
	}

	/* Mark ASID #0 as used because it is used at boot-time */
	__set_bit(0, context_asid_map);

	/* Queue a TLB invalidation for each CPU on next context-switch */
	cpumask_setall(&context_tlb_flush_pending);
}

static unsigned long __new_context(struct mm_struct *mm)
{
	static u32 cur_idx = 1;
	unsigned long cntx = atomic_long_read(&mm->context.id);
	unsigned long asid, ver = atomic_long_read(&current_version);

	/* Must be called with context_lock held */
	lockdep_assert_held(&context_lock);

	if (cntx != 0) {
		unsigned long newcntx = ver | cntx2asid(cntx);

		/*
		 * If our current CONTEXT was active during a rollover, we
		 * can continue to use it and this was just a false alarm.
		 */
		if (check_update_reserved_context(cntx, newcntx))
			return newcntx;

		/*
		 * We had a valid CONTEXT in a previous life, so try to
		 * re-use it if possible.
		 */
		if (!__test_and_set_bit(cntx2asid(cntx), context_asid_map))
			return newcntx;
	}

	/*
	 * Allocate a free ASID. If we can't find one then increment
	 * current_version and flush all ASIDs.
	 */
	asid = find_next_zero_bit(context_asid_map, num_asids, cur_idx);
	if (asid != num_asids)
		goto set_asid;

	/* We're out of ASIDs, so increment current_version */
	ver = atomic_long_add_return_relaxed(BIT(SATP_ASID_BITS), &current_version);

	/* Flush everything  */
	__flush_context();

	/* We have more ASIDs than CPUs, so this will always succeed */
	asid = find_next_zero_bit(context_asid_map, num_asids, 1);

set_asid:
	__set_bit(asid, context_asid_map);
	cur_idx = asid;

Annotation

Implementation Notes