| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 1999 Niibe Yutaka | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  |  * Copyright (C) 2003 - 2007 Paul Mundt | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * ASID handling idea taken from MIPS implementation. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #ifndef __ASM_SH_MMU_CONTEXT_H
 | 
					
						
							|  |  |  | #define __ASM_SH_MMU_CONTEXT_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  | #ifdef __KERNEL__
 | 
					
						
							| 
									
										
										
										
											2008-07-29 08:09:44 +09:00
										 |  |  | #include <cpu/mmu_context.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <asm/tlbflush.h>
 | 
					
						
							|  |  |  | #include <asm/uaccess.h>
 | 
					
						
							|  |  |  | #include <asm/io.h>
 | 
					
						
							| 
									
										
										
										
											2007-05-02 19:27:14 +02:00
										 |  |  | #include <asm-generic/mm_hooks.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The MMU "context" consists of two things: | 
					
						
							|  |  |  |  *    (a) TLB cache version (or round, cycle whatever expression you like) | 
					
						
							|  |  |  |  *    (b) ASID (Address Space IDentifier) | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2009-03-17 17:49:49 +09:00
										 |  |  | #ifdef CONFIG_CPU_HAS_PTEAEX
 | 
					
						
							|  |  |  | #define MMU_CONTEXT_ASID_MASK		0x0000ffff
 | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #define MMU_CONTEXT_ASID_MASK		0x000000ff
 | 
					
						
							| 
									
										
										
										
											2009-03-17 17:49:49 +09:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-17 17:49:49 +09:00
										 |  |  | #define MMU_CONTEXT_VERSION_MASK	(~0UL & ~MMU_CONTEXT_ASID_MASK)
 | 
					
						
							|  |  |  | #define MMU_CONTEXT_FIRST_VERSION	(MMU_CONTEXT_ASID_MASK + 1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Impossible ASID value, to differentiate from NO_CONTEXT. */ | 
					
						
							|  |  |  | #define MMU_NO_ASID			MMU_CONTEXT_FIRST_VERSION
 | 
					
						
							|  |  |  | #define NO_CONTEXT			0UL
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | #define asid_cache(cpu)		(cpu_data[cpu].asid_cache)
 | 
					
						
							| 
									
										
										
										
											2008-07-28 18:39:25 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_MMU
 | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  | #define cpu_context(cpu, mm)	((mm)->context.id[cpu])
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define cpu_asid(cpu, mm)	\
 | 
					
						
							|  |  |  | 	(cpu_context((cpu), (mm)) & MMU_CONTEXT_ASID_MASK) | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Virtual Page Number mask | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define MMU_VPN_MASK	0xfffff000
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  | #if defined(CONFIG_SUPERH32)
 | 
					
						
							| 
									
										
										
										
											2012-10-02 18:01:25 +01:00
										 |  |  | #include <asm/mmu_context_32.h>
 | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2012-10-02 18:01:25 +01:00
										 |  |  | #include <asm/mmu_context_64.h>
 | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Get MMU context if needed. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | static inline void get_mmu_context(struct mm_struct *mm, unsigned int cpu) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	unsigned long asid = asid_cache(cpu); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Check if we have old version of context. */ | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	if (((cpu_context(cpu, mm) ^ asid) & MMU_CONTEXT_VERSION_MASK) == 0) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		/* It's up to date, do nothing */ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* It's old, we need to get new context with new version. */ | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	if (!(++asid & MMU_CONTEXT_ASID_MASK)) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * We exhaust ASID of this version. | 
					
						
							|  |  |  | 		 * Flush all TLB and start new cycle. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2009-08-20 17:24:40 +09:00
										 |  |  | 		local_flush_tlb_all(); | 
					
						
							| 
									
										
										
										
											2006-11-21 13:53:44 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  | #ifdef CONFIG_SUPERH64
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * The SH-5 cache uses the ASIDs, requiring both the I and D | 
					
						
							|  |  |  | 		 * cache to be flushed when the ASID is exhausted. Weak. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		flush_cache_all(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Fix version; Note that we avoid version #0 | 
					
						
							|  |  |  | 		 * to distingush NO_CONTEXT. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 		if (!asid) | 
					
						
							|  |  |  | 			asid = MMU_CONTEXT_FIRST_VERSION; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cpu_context(cpu, mm) = asid_cache(cpu) = asid; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Initialize the context related info for a new mm_struct | 
					
						
							|  |  |  |  * instance. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-11-21 13:53:44 +09:00
										 |  |  | static inline int init_new_context(struct task_struct *tsk, | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 				   struct mm_struct *mm) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < num_online_cpus(); i++) | 
					
						
							|  |  |  | 		cpu_context(i, mm) = NO_CONTEXT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * After we have set current->mm to a new value, this activates | 
					
						
							|  |  |  |  * the context for the new mm so we see the new mappings. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | static inline void activate_context(struct mm_struct *mm, unsigned int cpu) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	get_mmu_context(mm, cpu); | 
					
						
							|  |  |  | 	set_asid(cpu_asid(cpu, mm)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-21 13:53:44 +09:00
										 |  |  | static inline void switch_mm(struct mm_struct *prev, | 
					
						
							|  |  |  | 			     struct mm_struct *next, | 
					
						
							|  |  |  | 			     struct task_struct *tsk) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	unsigned int cpu = smp_processor_id(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-21 13:53:44 +09:00
										 |  |  | 	if (likely(prev != next)) { | 
					
						
							| 
									
										
										
										
											2009-06-12 22:33:14 +09:30
										 |  |  | 		cpumask_set_cpu(cpu, mm_cpumask(next)); | 
					
						
							| 
									
										
										
										
											2006-11-21 13:53:44 +09:00
										 |  |  | 		set_TTB(next->pgd); | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 		activate_context(next, cpu); | 
					
						
							|  |  |  | 	} else | 
					
						
							| 
									
										
										
										
											2009-06-12 22:33:14 +09:30
										 |  |  | 		if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 			activate_context(next, cpu); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-06-14 23:23:41 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define activate_mm(prev, next)		switch_mm((prev),(next),NULL)
 | 
					
						
							|  |  |  | #define deactivate_mm(tsk,mm)		do { } while (0)
 | 
					
						
							|  |  |  | #define enter_lazy_tlb(mm,tsk)		do { } while (0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2009-06-14 23:23:41 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #define set_asid(asid)			do { } while (0)
 | 
					
						
							|  |  |  | #define get_asid()			(0)
 | 
					
						
							| 
									
										
										
										
											2008-12-10 18:17:19 +09:00
										 |  |  | #define cpu_asid(cpu, mm)		({ (void)cpu; NO_CONTEXT; })
 | 
					
						
							| 
									
										
										
										
											2008-04-25 12:58:40 +09:00
										 |  |  | #define switch_and_save_asid(asid)	(0)
 | 
					
						
							| 
									
										
										
										
											2007-03-28 16:38:13 +09:00
										 |  |  | #define set_TTB(pgd)			do { } while (0)
 | 
					
						
							|  |  |  | #define get_TTB()			(0)
 | 
					
						
							| 
									
										
										
										
											2007-11-09 16:37:18 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-14 23:23:41 +09:00
										 |  |  | #include <asm-generic/mmu_context.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* CONFIG_MMU */
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4)
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * If this processor has an MMU, we need methods to turn it off/on .. | 
					
						
							|  |  |  |  * paging_init() will also have to be updated for the processor in | 
					
						
							|  |  |  |  * question. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline void enable_mmu(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	unsigned int cpu = smp_processor_id(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	/* Enable MMU */ | 
					
						
							| 
									
										
										
										
											2010-01-26 12:58:40 +09:00
										 |  |  | 	__raw_writel(MMU_CONTROL_INIT, MMUCR); | 
					
						
							| 
									
										
										
										
											2006-09-27 14:57:44 +09:00
										 |  |  | 	ctrl_barrier(); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	if (asid_cache(cpu) == NO_CONTEXT) | 
					
						
							|  |  |  | 		asid_cache(cpu) = MMU_CONTEXT_FIRST_VERSION; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-25 09:51:47 +09:00
										 |  |  | 	set_asid(asid_cache(cpu) & MMU_CONTEXT_ASID_MASK); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void disable_mmu(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long cr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-26 12:58:40 +09:00
										 |  |  | 	cr = __raw_readl(MMUCR); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	cr &= ~MMU_CONTROL_INIT; | 
					
						
							| 
									
										
										
										
											2010-01-26 12:58:40 +09:00
										 |  |  | 	__raw_writel(cr, MMUCR); | 
					
						
							| 
									
										
										
										
											2006-09-27 14:57:44 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ctrl_barrier(); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * MMU control handlers for processors lacking memory | 
					
						
							|  |  |  |  * management hardware. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-03-28 16:38:13 +09:00
										 |  |  | #define enable_mmu()	do { } while (0)
 | 
					
						
							|  |  |  | #define disable_mmu()	do { } while (0)
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* __KERNEL__ */
 | 
					
						
							|  |  |  | #endif /* __ASM_SH_MMU_CONTEXT_H */
 |