// SPDX-License-Identifier: GPL-2.0-or-later1/*2* OpenRISC tlb.c3*4* Linux architectural port borrowing liberally from similar works of5* others. All original copyrights apply as per the original source6* declaration.7*8* Modifications for the OpenRISC architecture:9* Copyright (C) 2003 Matjaz Breskvar <[email protected]>10* Copyright (C) 2010-2011 Julius Baxter <[email protected]>11* Copyright (C) 2010-2011 Jonas Bonn <[email protected]>12*/1314#include <linux/sched.h>15#include <linux/kernel.h>16#include <linux/errno.h>17#include <linux/string.h>18#include <linux/types.h>19#include <linux/ptrace.h>20#include <linux/mman.h>21#include <linux/mm.h>22#include <linux/init.h>2324#include <asm/tlbflush.h>25#include <asm/mmu_context.h>26#include <asm/spr_defs.h>2728#define NO_CONTEXT -12930#define NUM_DTLB_SETS (1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> \31SPR_DMMUCFGR_NTS_OFF))32#define NUM_ITLB_SETS (1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> \33SPR_IMMUCFGR_NTS_OFF))34#define DTLB_OFFSET(addr) (((addr) >> PAGE_SHIFT) & (NUM_DTLB_SETS-1))35#define ITLB_OFFSET(addr) (((addr) >> PAGE_SHIFT) & (NUM_ITLB_SETS-1))36/*37* Invalidate all TLB entries.38*39* This comes down to setting the 'valid' bit for all xTLBMR registers to 0.40* Easiest way to accomplish this is to just zero out the xTLBMR register41* completely.42*43*/4445void local_flush_tlb_all(void)46{47int i;48unsigned long num_tlb_sets;4950/* Determine number of sets for IMMU. */51/* FIXME: Assumption is I & D nsets equal. */52num_tlb_sets = NUM_ITLB_SETS;5354for (i = 0; i < num_tlb_sets; i++) {55mtspr_off(SPR_DTLBMR_BASE(0), i, 0);56mtspr_off(SPR_ITLBMR_BASE(0), i, 0);57}58}5960#define have_dtlbeir (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_TEIRI)61#define have_itlbeir (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_TEIRI)6263/*64* Invalidate a single page. This is what the xTLBEIR register is for.65*66* There's no point in checking the vma for PAGE_EXEC to determine whether it's67* the data or instruction TLB that should be flushed... that would take more68* than the few instructions that the following compiles down to!69*70* The case where we don't have the xTLBEIR register really only works for71* MMU's with a single way and is hard-coded that way.72*/7374#define flush_dtlb_page_eir(addr) mtspr(SPR_DTLBEIR, addr)75#define flush_dtlb_page_no_eir(addr) \76mtspr_off(SPR_DTLBMR_BASE(0), DTLB_OFFSET(addr), 0);7778#define flush_itlb_page_eir(addr) mtspr(SPR_ITLBEIR, addr)79#define flush_itlb_page_no_eir(addr) \80mtspr_off(SPR_ITLBMR_BASE(0), ITLB_OFFSET(addr), 0);8182void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)83{84if (have_dtlbeir)85flush_dtlb_page_eir(addr);86else87flush_dtlb_page_no_eir(addr);8889if (have_itlbeir)90flush_itlb_page_eir(addr);91else92flush_itlb_page_no_eir(addr);93}9495void local_flush_tlb_range(struct vm_area_struct *vma,96unsigned long start, unsigned long end)97{98int addr;99bool dtlbeir;100bool itlbeir;101102dtlbeir = have_dtlbeir;103itlbeir = have_itlbeir;104105for (addr = start; addr < end; addr += PAGE_SIZE) {106if (dtlbeir)107flush_dtlb_page_eir(addr);108else109flush_dtlb_page_no_eir(addr);110111if (itlbeir)112flush_itlb_page_eir(addr);113else114flush_itlb_page_no_eir(addr);115}116}117118/*119* Invalidate the selected mm context only.120*121* FIXME: Due to some bug here, we're flushing everything for now.122* This should be changed to loop over over mm and call flush_tlb_range.123*/124125void local_flush_tlb_mm(struct mm_struct *mm)126{127128/* Was seeing bugs with the mm struct passed to us. Scrapped most of129this function. */130/* Several architectures do this */131local_flush_tlb_all();132}133134/* called in schedule() just before actually doing the switch_to */135136void switch_mm(struct mm_struct *prev, struct mm_struct *next,137struct task_struct *next_tsk)138{139unsigned int cpu;140141if (unlikely(prev == next))142return;143144cpu = smp_processor_id();145146cpumask_clear_cpu(cpu, mm_cpumask(prev));147cpumask_set_cpu(cpu, mm_cpumask(next));148149/* remember the pgd for the fault handlers150* this is similar to the pgd register in some other CPU's.151* we need our own copy of it because current and active_mm152* might be invalid at points where we still need to derefer153* the pgd.154*/155current_pgd[cpu] = next->pgd;156157/* We don't have context support implemented, so flush all158* entries belonging to previous map159*/160local_flush_tlb_mm(prev);161}162163/*164* Initialize the context related info for a new mm_struct165* instance.166*/167168int init_new_context(struct task_struct *tsk, struct mm_struct *mm)169{170mm->context = NO_CONTEXT;171return 0;172}173174/* called by __exit_mm to destroy the used MMU context if any before175* destroying the mm itself. this is only called when the last user of the mm176* drops it.177*/178179void destroy_context(struct mm_struct *mm)180{181flush_tlb_mm(mm);182183}184185186