18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * This file contains the routines for handling the MMU on those
48c2ecf20Sopenharmony_ci * PowerPC implementations where the MMU substantially follows the
58c2ecf20Sopenharmony_ci * architecture specification.  This includes the 6xx, 7xx, 7xxx,
68c2ecf20Sopenharmony_ci * and 8260 implementations but excludes the 8xx and 4xx.
78c2ecf20Sopenharmony_ci *  -- paulus
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  Derived from arch/ppc/mm/init.c:
108c2ecf20Sopenharmony_ci *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
138c2ecf20Sopenharmony_ci *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
148c2ecf20Sopenharmony_ci *    Copyright (C) 1996 Paul Mackerras
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *  Derived from "arch/i386/mm/init.c"
178c2ecf20Sopenharmony_ci *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/mm.h>
218c2ecf20Sopenharmony_ci#include <linux/init.h>
228c2ecf20Sopenharmony_ci#include <linux/export.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <asm/mmu_context.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
288c2ecf20Sopenharmony_ci * (virtual segment identifiers) for each context.  Although the
298c2ecf20Sopenharmony_ci * hardware supports 24-bit VSIDs, and thus >1 million contexts,
308c2ecf20Sopenharmony_ci * we only use 32,768 of them.  That is ample, since there can be
318c2ecf20Sopenharmony_ci * at most around 30,000 tasks in the system anyway, and it means
328c2ecf20Sopenharmony_ci * that we can use a bitmap to indicate which contexts are in use.
338c2ecf20Sopenharmony_ci * Using a bitmap means that we entirely avoid all of the problems
348c2ecf20Sopenharmony_ci * that we used to have when the context number overflowed,
358c2ecf20Sopenharmony_ci * particularly on SMP systems.
368c2ecf20Sopenharmony_ci *  -- paulus.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ci#define NO_CONTEXT      	((unsigned long) -1)
398c2ecf20Sopenharmony_ci#define LAST_CONTEXT    	32767
408c2ecf20Sopenharmony_ci#define FIRST_CONTEXT    	1
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/*
438c2ecf20Sopenharmony_ci * This function defines the mapping from contexts to VSIDs (virtual
448c2ecf20Sopenharmony_ci * segment IDs).  We use a skew on both the context and the high 4 bits
458c2ecf20Sopenharmony_ci * of the 32-bit virtual address (the "effective segment ID") in order
468c2ecf20Sopenharmony_ci * to spread out the entries in the MMU hash table.  Note, if this
478c2ecf20Sopenharmony_ci * function is changed then arch/ppc/mm/hashtable.S will have to be
488c2ecf20Sopenharmony_ci * changed to correspond.
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci *
518c2ecf20Sopenharmony_ci * CTX_TO_VSID(ctx, va)	(((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
528c2ecf20Sopenharmony_ci *				 & 0xffffff)
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic unsigned long next_mmu_context;
568c2ecf20Sopenharmony_cistatic unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ciunsigned long __init_new_context(void)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	unsigned long ctx = next_mmu_context;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	while (test_and_set_bit(ctx, context_map)) {
638c2ecf20Sopenharmony_ci		ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
648c2ecf20Sopenharmony_ci		if (ctx > LAST_CONTEXT)
658c2ecf20Sopenharmony_ci			ctx = 0;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci	next_mmu_context = (ctx + 1) & LAST_CONTEXT;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	return ctx;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__init_new_context);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * Set up the context for a new address space.
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_ciint init_new_context(struct task_struct *t, struct mm_struct *mm)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	mm->context.id = __init_new_context();
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return 0;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/*
848c2ecf20Sopenharmony_ci * Free a context ID. Make sure to call this with preempt disabled!
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_civoid __destroy_context(unsigned long ctx)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	clear_bit(ctx, context_map);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__destroy_context);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/*
938c2ecf20Sopenharmony_ci * We're finished using the context for an address space.
948c2ecf20Sopenharmony_ci */
958c2ecf20Sopenharmony_civoid destroy_context(struct mm_struct *mm)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	preempt_disable();
988c2ecf20Sopenharmony_ci	if (mm->context.id != NO_CONTEXT) {
998c2ecf20Sopenharmony_ci		__destroy_context(mm->context.id);
1008c2ecf20Sopenharmony_ci		mm->context.id = NO_CONTEXT;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci	preempt_enable();
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/*
1068c2ecf20Sopenharmony_ci * Initialize the context management stuff.
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_civoid __init mmu_context_init(void)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	/* Reserve context 0 for kernel use */
1118c2ecf20Sopenharmony_ci	context_map[0] = (1 << FIRST_CONTEXT) - 1;
1128c2ecf20Sopenharmony_ci	next_mmu_context = FIRST_CONTEXT;
1138c2ecf20Sopenharmony_ci}
114