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