Path: blob/master/arch/xtensa/include/asm/mmu_context.h
26451 views
/*1* Switch an MMU context.2*3* This file is subject to the terms and conditions of the GNU General Public4* License. See the file "COPYING" in the main directory of this archive5* for more details.6*7* Copyright (C) 2001 - 2013 Tensilica Inc.8*/910#ifndef _XTENSA_MMU_CONTEXT_H11#define _XTENSA_MMU_CONTEXT_H1213#ifndef CONFIG_MMU14#include <asm/nommu_context.h>15#else1617#include <linux/stringify.h>18#include <linux/sched.h>19#include <linux/mm_types.h>20#include <linux/pgtable.h>2122#include <asm/vectors.h>2324#include <asm/cacheflush.h>25#include <asm/tlbflush.h>26#include <asm-generic/mm_hooks.h>27#include <asm-generic/percpu.h>2829#if (XCHAL_HAVE_TLBS != 1)30# error "Linux must have an MMU!"31#endif3233DECLARE_PER_CPU(unsigned long, asid_cache);34#define cpu_asid_cache(cpu) per_cpu(asid_cache, cpu)3536/*37* NO_CONTEXT is the invalid ASID value that we don't ever assign to38* any user or kernel context. We use the reserved values in the39* ASID_INSERT macro below.40*41* 0 invalid42* 1 kernel43* 2 reserved44* 3 reserved45* 4...255 available46*/4748#define NO_CONTEXT 049#define ASID_USER_FIRST 450#define ASID_MASK ((1 << XCHAL_MMU_ASID_BITS) - 1)51#define ASID_INSERT(x) (0x03020001 | (((x) & ASID_MASK) << 8))5253void init_mmu(void);54void init_kio(void);5556static inline void set_rasid_register (unsigned long val)57{58__asm__ __volatile__ (" wsr %0, rasid\n\t"59" isync\n" : : "a" (val));60}6162static inline unsigned long get_rasid_register (void)63{64unsigned long tmp;65__asm__ __volatile__ (" rsr %0, rasid\n\t" : "=a" (tmp));66return tmp;67}6869static inline void get_new_mmu_context(struct mm_struct *mm, unsigned int cpu)70{71unsigned long asid = cpu_asid_cache(cpu);72if ((++asid & ASID_MASK) == 0) {73/*74* Start new asid cycle; continue counting with next75* incarnation bits; skipping over 0, 1, 2, 3.76*/77local_flush_tlb_all();78asid += ASID_USER_FIRST;79}80cpu_asid_cache(cpu) = asid;81mm->context.asid[cpu] = asid;82mm->context.cpu = cpu;83}8485static inline void get_mmu_context(struct mm_struct *mm, unsigned int cpu)86{87/*88* Check if our ASID is of an older version and thus invalid.89*/9091if (mm) {92unsigned long asid = mm->context.asid[cpu];9394if (asid == NO_CONTEXT ||95((asid ^ cpu_asid_cache(cpu)) & ~ASID_MASK))96get_new_mmu_context(mm, cpu);97}98}99100static inline void activate_context(struct mm_struct *mm, unsigned int cpu)101{102get_mmu_context(mm, cpu);103set_rasid_register(ASID_INSERT(mm->context.asid[cpu]));104invalidate_page_directory();105}106107/*108* Initialize the context related info for a new mm_struct109* instance. Valid cpu values are 0..(NR_CPUS-1), so initializing110* to -1 says the process has never run on any core.111*/112113#define init_new_context init_new_context114static inline int init_new_context(struct task_struct *tsk,115struct mm_struct *mm)116{117int cpu;118for_each_possible_cpu(cpu) {119mm->context.asid[cpu] = NO_CONTEXT;120}121mm->context.cpu = -1;122return 0;123}124125static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,126struct task_struct *tsk)127{128unsigned int cpu = smp_processor_id();129int migrated = next->context.cpu != cpu;130/* Flush the icache if we migrated to a new core. */131if (migrated) {132__invalidate_icache_all();133next->context.cpu = cpu;134}135if (migrated || prev != next)136activate_context(next, cpu);137}138139/*140* Destroy context related info for an mm_struct that is about141* to be put to rest.142*/143#define destroy_context destroy_context144static inline void destroy_context(struct mm_struct *mm)145{146invalidate_page_directory();147}148149150#include <asm-generic/mmu_context.h>151152#endif /* CONFIG_MMU */153#endif /* _XTENSA_MMU_CONTEXT_H */154155156