diff options
Diffstat (limited to 'arch/s390/include/asm/tlb.h')
| -rw-r--r-- | arch/s390/include/asm/tlb.h | 106 | 
1 files changed, 49 insertions, 57 deletions
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h index f1f644f2240..a25f09fbaf3 100644 --- a/arch/s390/include/asm/tlb.h +++ b/arch/s390/include/asm/tlb.h @@ -22,71 +22,77 @@   */  #include <linux/mm.h> +#include <linux/pagemap.h>  #include <linux/swap.h>  #include <asm/processor.h>  #include <asm/pgalloc.h> -#include <asm/smp.h>  #include <asm/tlbflush.h> -#ifndef CONFIG_SMP -#define TLB_NR_PTRS	1 -#else -#define TLB_NR_PTRS	508 -#endif -  struct mmu_gather {  	struct mm_struct *mm; +	struct mmu_table_batch *batch;  	unsigned int fullmm; -	unsigned int nr_ptes; -	unsigned int nr_pxds; -	void *array[TLB_NR_PTRS]; +	unsigned long start, end;  }; -DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); +struct mmu_table_batch { +	struct rcu_head		rcu; +	unsigned int		nr; +	void			*tables[0]; +}; -static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, -						unsigned int full_mm_flush) -{ -	struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); +#define MAX_TABLE_BATCH		\ +	((PAGE_SIZE - sizeof(struct mmu_table_batch)) / sizeof(void *)) + +extern void tlb_table_flush(struct mmu_gather *tlb); +extern void tlb_remove_table(struct mmu_gather *tlb, void *table); +static inline void tlb_gather_mmu(struct mmu_gather *tlb, +				  struct mm_struct *mm, +				  unsigned long start, +				  unsigned long end) +{  	tlb->mm = mm; -	tlb->fullmm = full_mm_flush; -	tlb->nr_ptes = 0; -	tlb->nr_pxds = TLB_NR_PTRS; -	if (tlb->fullmm) -		__tlb_flush_mm(mm); -	return tlb; +	tlb->start = start; +	tlb->end = end; +	tlb->fullmm = !(start | (end+1)); +	tlb->batch = NULL;  } -static inline void tlb_flush_mmu(struct mmu_gather *tlb, -				 unsigned long start, unsigned long end) +static inline void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)  { -	if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS)) -		__tlb_flush_mm(tlb->mm); -	while (tlb->nr_ptes > 0) -		page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]); -	while (tlb->nr_pxds < TLB_NR_PTRS) -		crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]); +	__tlb_flush_mm_lazy(tlb->mm);  } -static inline void tlb_finish_mmu(struct mmu_gather *tlb, -				  unsigned long start, unsigned long end) +static inline void tlb_flush_mmu_free(struct mmu_gather *tlb)  { -	tlb_flush_mmu(tlb, start, end); +	tlb_table_flush(tlb); +} -	rcu_table_freelist_finish(); -	/* keep the page table cache within bounds */ -	check_pgt_cache(); +static inline void tlb_flush_mmu(struct mmu_gather *tlb) +{ +	tlb_flush_mmu_tlbonly(tlb); +	tlb_flush_mmu_free(tlb); +} -	put_cpu_var(mmu_gathers); +static inline void tlb_finish_mmu(struct mmu_gather *tlb, +				  unsigned long start, unsigned long end) +{ +	tlb_flush_mmu(tlb);  }  /*   * Release the page cache reference for a pte removed by - * tlb_ptep_clear_flush. In both flush modes the tlb fo a page cache page + * tlb_ptep_clear_flush. In both flush modes the tlb for a page cache page   * has already been freed, so just do free_page_and_swap_cache.   */ +static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) +{ +	free_page_and_swap_cache(page); +	return 1; /* avoid calling tlb_flush_mmu */ +} +  static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)  {  	free_page_and_swap_cache(page); @@ -99,12 +105,7 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)  static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,  				unsigned long address)  { -	if (!tlb->fullmm) { -		tlb->array[tlb->nr_ptes++] = pte; -		if (tlb->nr_ptes >= tlb->nr_pxds) -			tlb_flush_mmu(tlb, 0, 0); -	} else -		page_table_free(tlb->mm, (unsigned long *) pte); +	page_table_free_rcu(tlb, (unsigned long *) pte);  }  /* @@ -117,15 +118,10 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,  static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,  				unsigned long address)  { -#ifdef __s390x__ +#ifdef CONFIG_64BIT  	if (tlb->mm->context.asce_limit <= (1UL << 31))  		return; -	if (!tlb->fullmm) { -		tlb->array[--tlb->nr_pxds] = pmd; -		if (tlb->nr_ptes >= tlb->nr_pxds) -			tlb_flush_mmu(tlb, 0, 0); -	} else -		crst_table_free(tlb->mm, (unsigned long *) pmd); +	tlb_remove_table(tlb, pmd);  #endif  } @@ -139,21 +135,17 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,  static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,  				unsigned long address)  { -#ifdef __s390x__ +#ifdef CONFIG_64BIT  	if (tlb->mm->context.asce_limit <= (1UL << 42))  		return; -	if (!tlb->fullmm) { -		tlb->array[--tlb->nr_pxds] = pud; -		if (tlb->nr_ptes >= tlb->nr_pxds) -			tlb_flush_mmu(tlb, 0, 0); -	} else -		crst_table_free(tlb->mm, (unsigned long *) pud); +	tlb_remove_table(tlb, pud);  #endif  }  #define tlb_start_vma(tlb, vma)			do { } while (0)  #define tlb_end_vma(tlb, vma)			do { } while (0)  #define tlb_remove_tlb_entry(tlb, ptep, addr)	do { } while (0) +#define tlb_remove_pmd_tlb_entry(tlb, pmdp, addr)	do { } while (0)  #define tlb_migrate_finish(mm)			do { } while (0)  #endif /* _S390_TLB_H */  | 
