diff options
Diffstat (limited to 'include/asm-generic/tlb.h')
| -rw-r--r-- | include/asm-generic/tlb.h | 86 | 
1 files changed, 74 insertions, 12 deletions
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index b3353e21f3b3..6be86c1c5c58 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h @@ -20,6 +20,8 @@  #include <asm/pgalloc.h>  #include <asm/tlbflush.h> +#ifdef CONFIG_MMU +  #ifdef CONFIG_HAVE_RCU_TABLE_FREE  /*   * Semi RCU freeing of the page directories. @@ -97,12 +99,30 @@ struct mmu_gather {  #endif  	unsigned long		start;  	unsigned long		end; -	/* we are in the middle of an operation to clear -	 * a full mm and can make some optimizations */ -	unsigned int		fullmm : 1, -	/* we have performed an operation which -	 * requires a complete flush of the tlb */ -				need_flush_all : 1; +	/* +	 * we are in the middle of an operation to clear +	 * a full mm and can make some optimizations +	 */ +	unsigned int		fullmm : 1; + +	/* +	 * we have performed an operation which +	 * requires a complete flush of the tlb +	 */ +	unsigned int		need_flush_all : 1; + +	/* +	 * we have removed page directories +	 */ +	unsigned int		freed_tables : 1; + +	/* +	 * at which levels have we cleared entries? +	 */ +	unsigned int		cleared_ptes : 1; +	unsigned int		cleared_pmds : 1; +	unsigned int		cleared_puds : 1; +	unsigned int		cleared_p4ds : 1;  	struct mmu_gather_batch *active;  	struct mmu_gather_batch	local; @@ -118,6 +138,7 @@ void arch_tlb_gather_mmu(struct mmu_gather *tlb,  void tlb_flush_mmu(struct mmu_gather *tlb);  void arch_tlb_finish_mmu(struct mmu_gather *tlb,  			 unsigned long start, unsigned long end, bool force); +void tlb_flush_mmu_free(struct mmu_gather *tlb);  extern bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page,  				   int page_size); @@ -137,6 +158,11 @@ static inline void __tlb_reset_range(struct mmu_gather *tlb)  		tlb->start = TASK_SIZE;  		tlb->end = 0;  	} +	tlb->freed_tables = 0; +	tlb->cleared_ptes = 0; +	tlb->cleared_pmds = 0; +	tlb->cleared_puds = 0; +	tlb->cleared_p4ds = 0;  }  static inline void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb) @@ -186,6 +212,25 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,  }  #endif +static inline unsigned long tlb_get_unmap_shift(struct mmu_gather *tlb) +{ +	if (tlb->cleared_ptes) +		return PAGE_SHIFT; +	if (tlb->cleared_pmds) +		return PMD_SHIFT; +	if (tlb->cleared_puds) +		return PUD_SHIFT; +	if (tlb->cleared_p4ds) +		return P4D_SHIFT; + +	return PAGE_SHIFT; +} + +static inline unsigned long tlb_get_unmap_size(struct mmu_gather *tlb) +{ +	return 1UL << tlb_get_unmap_shift(tlb); +} +  /*   * In the case of tlb vma handling, we can optimise these away in the   * case where we're doing a full MM flush.  When we're doing a munmap, @@ -219,13 +264,19 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,  #define tlb_remove_tlb_entry(tlb, ptep, address)		\  	do {							\  		__tlb_adjust_range(tlb, address, PAGE_SIZE);	\ +		tlb->cleared_ptes = 1;				\  		__tlb_remove_tlb_entry(tlb, ptep, address);	\  	} while (0) -#define tlb_remove_huge_tlb_entry(h, tlb, ptep, address)	     \ -	do {							     \ -		__tlb_adjust_range(tlb, address, huge_page_size(h)); \ -		__tlb_remove_tlb_entry(tlb, ptep, address);	     \ +#define tlb_remove_huge_tlb_entry(h, tlb, ptep, address)	\ +	do {							\ +		unsigned long _sz = huge_page_size(h);		\ +		__tlb_adjust_range(tlb, address, _sz);		\ +		if (_sz == PMD_SIZE)				\ +			tlb->cleared_pmds = 1;			\ +		else if (_sz == PUD_SIZE)			\ +			tlb->cleared_puds = 1;			\ +		__tlb_remove_tlb_entry(tlb, ptep, address);	\  	} while (0)  /** @@ -239,6 +290,7 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,  #define tlb_remove_pmd_tlb_entry(tlb, pmdp, address)			\  	do {								\  		__tlb_adjust_range(tlb, address, HPAGE_PMD_SIZE);	\ +		tlb->cleared_pmds = 1;					\  		__tlb_remove_pmd_tlb_entry(tlb, pmdp, address);		\  	} while (0) @@ -253,6 +305,7 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,  #define tlb_remove_pud_tlb_entry(tlb, pudp, address)			\  	do {								\  		__tlb_adjust_range(tlb, address, HPAGE_PUD_SIZE);	\ +		tlb->cleared_puds = 1;					\  		__tlb_remove_pud_tlb_entry(tlb, pudp, address);		\  	} while (0) @@ -278,6 +331,8 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,  #define pte_free_tlb(tlb, ptep, address)			\  	do {							\  		__tlb_adjust_range(tlb, address, PAGE_SIZE);	\ +		tlb->freed_tables = 1;				\ +		tlb->cleared_pmds = 1;				\  		__pte_free_tlb(tlb, ptep, address);		\  	} while (0)  #endif @@ -285,7 +340,9 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,  #ifndef pmd_free_tlb  #define pmd_free_tlb(tlb, pmdp, address)			\  	do {							\ -		__tlb_adjust_range(tlb, address, PAGE_SIZE);		\ +		__tlb_adjust_range(tlb, address, PAGE_SIZE);	\ +		tlb->freed_tables = 1;				\ +		tlb->cleared_puds = 1;				\  		__pmd_free_tlb(tlb, pmdp, address);		\  	} while (0)  #endif @@ -295,6 +352,8 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,  #define pud_free_tlb(tlb, pudp, address)			\  	do {							\  		__tlb_adjust_range(tlb, address, PAGE_SIZE);	\ +		tlb->freed_tables = 1;				\ +		tlb->cleared_p4ds = 1;				\  		__pud_free_tlb(tlb, pudp, address);		\  	} while (0)  #endif @@ -304,12 +363,15 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,  #ifndef p4d_free_tlb  #define p4d_free_tlb(tlb, pudp, address)			\  	do {							\ -		__tlb_adjust_range(tlb, address, PAGE_SIZE);		\ +		__tlb_adjust_range(tlb, address, PAGE_SIZE);	\ +		tlb->freed_tables = 1;				\  		__p4d_free_tlb(tlb, pudp, address);		\  	} while (0)  #endif  #endif +#endif /* CONFIG_MMU */ +  #define tlb_migrate_finish(mm) do {} while (0)  #endif /* _ASM_GENERIC__TLB_H */  | 
