154 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0 */
 | |
| #ifndef _ALPHA_TLBFLUSH_H
 | |
| #define _ALPHA_TLBFLUSH_H
 | |
| 
 | |
| #include <linux/mm.h>
 | |
| #include <linux/sched.h>
 | |
| #include <asm/compiler.h>
 | |
| #include <asm/pgalloc.h>
 | |
| 
 | |
| #ifndef __EXTERN_INLINE
 | |
| #define __EXTERN_INLINE extern inline
 | |
| #define __MMU_EXTERN_INLINE
 | |
| #endif
 | |
| 
 | |
| extern void __load_new_mm_context(struct mm_struct *);
 | |
| 
 | |
| 
 | |
| /* Use a few helper functions to hide the ugly broken ASN
 | |
|    numbers on early Alphas (ev4 and ev45).  */
 | |
| 
 | |
| __EXTERN_INLINE void
 | |
| ev4_flush_tlb_current(struct mm_struct *mm)
 | |
| {
 | |
| 	__load_new_mm_context(mm);
 | |
| 	tbiap();
 | |
| }
 | |
| 
 | |
| __EXTERN_INLINE void
 | |
| ev5_flush_tlb_current(struct mm_struct *mm)
 | |
| {
 | |
| 	__load_new_mm_context(mm);
 | |
| }
 | |
| 
 | |
| /* Flush just one page in the current TLB set.  We need to be very
 | |
|    careful about the icache here, there is no way to invalidate a
 | |
|    specific icache page.  */
 | |
| 
 | |
| __EXTERN_INLINE void
 | |
| ev4_flush_tlb_current_page(struct mm_struct * mm,
 | |
| 			   struct vm_area_struct *vma,
 | |
| 			   unsigned long addr)
 | |
| {
 | |
| 	int tbi_flag = 2;
 | |
| 	if (vma->vm_flags & VM_EXEC) {
 | |
| 		__load_new_mm_context(mm);
 | |
| 		tbi_flag = 3;
 | |
| 	}
 | |
| 	tbi(tbi_flag, addr);
 | |
| }
 | |
| 
 | |
| __EXTERN_INLINE void
 | |
| ev5_flush_tlb_current_page(struct mm_struct * mm,
 | |
| 			   struct vm_area_struct *vma,
 | |
| 			   unsigned long addr)
 | |
| {
 | |
| 	if (vma->vm_flags & VM_EXEC)
 | |
| 		__load_new_mm_context(mm);
 | |
| 	else
 | |
| 		tbi(2, addr);
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef CONFIG_ALPHA_GENERIC
 | |
| # define flush_tlb_current		alpha_mv.mv_flush_tlb_current
 | |
| # define flush_tlb_current_page		alpha_mv.mv_flush_tlb_current_page
 | |
| #else
 | |
| # ifdef CONFIG_ALPHA_EV4
 | |
| #  define flush_tlb_current		ev4_flush_tlb_current
 | |
| #  define flush_tlb_current_page	ev4_flush_tlb_current_page
 | |
| # else
 | |
| #  define flush_tlb_current		ev5_flush_tlb_current
 | |
| #  define flush_tlb_current_page	ev5_flush_tlb_current_page
 | |
| # endif
 | |
| #endif
 | |
| 
 | |
| #ifdef __MMU_EXTERN_INLINE
 | |
| #undef __EXTERN_INLINE
 | |
| #undef __MMU_EXTERN_INLINE
 | |
| #endif
 | |
| 
 | |
| /* Flush current user mapping.  */
 | |
| static inline void
 | |
| flush_tlb(void)
 | |
| {
 | |
| 	flush_tlb_current(current->active_mm);
 | |
| }
 | |
| 
 | |
| /* Flush someone else's user mapping.  */
 | |
| static inline void
 | |
| flush_tlb_other(struct mm_struct *mm)
 | |
| {
 | |
| 	unsigned long *mmc = &mm->context[smp_processor_id()];
 | |
| 	/* Check it's not zero first to avoid cacheline ping pong
 | |
| 	   when possible.  */
 | |
| 	if (*mmc) *mmc = 0;
 | |
| }
 | |
| 
 | |
| #ifndef CONFIG_SMP
 | |
| /* Flush everything (kernel mapping may also have changed
 | |
|    due to vmalloc/vfree).  */
 | |
| static inline void flush_tlb_all(void)
 | |
| {
 | |
| 	tbia();
 | |
| }
 | |
| 
 | |
| /* Flush a specified user mapping.  */
 | |
| static inline void
 | |
| flush_tlb_mm(struct mm_struct *mm)
 | |
| {
 | |
| 	if (mm == current->active_mm)
 | |
| 		flush_tlb_current(mm);
 | |
| 	else
 | |
| 		flush_tlb_other(mm);
 | |
| }
 | |
| 
 | |
| /* Page-granular tlb flush.  */
 | |
| static inline void
 | |
| flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 | |
| {
 | |
| 	struct mm_struct *mm = vma->vm_mm;
 | |
| 
 | |
| 	if (mm == current->active_mm)
 | |
| 		flush_tlb_current_page(mm, vma, addr);
 | |
| 	else
 | |
| 		flush_tlb_other(mm);
 | |
| }
 | |
| 
 | |
| /* Flush a specified range of user mapping.  On the Alpha we flush
 | |
|    the whole user tlb.  */
 | |
| static inline void
 | |
| flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 | |
| 		unsigned long end)
 | |
| {
 | |
| 	flush_tlb_mm(vma->vm_mm);
 | |
| }
 | |
| 
 | |
| #else /* CONFIG_SMP */
 | |
| 
 | |
| extern void flush_tlb_all(void);
 | |
| extern void flush_tlb_mm(struct mm_struct *);
 | |
| extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 | |
| extern void flush_tlb_range(struct vm_area_struct *, unsigned long,
 | |
| 			    unsigned long);
 | |
| 
 | |
| #endif /* CONFIG_SMP */
 | |
| 
 | |
| static inline void flush_tlb_kernel_range(unsigned long start,
 | |
| 					unsigned long end)
 | |
| {
 | |
| 	flush_tlb_all();
 | |
| }
 | |
| 
 | |
| #endif /* _ALPHA_TLBFLUSH_H */
 | 
