diff options
Diffstat (limited to 'include/asm-s390/tlb.h')
-rw-r--r-- | include/asm-s390/tlb.h | 49 |
1 files changed, 37 insertions, 12 deletions
diff --git a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h index 3c8177fa9e06..3d8a96d39d9d 100644 --- a/include/asm-s390/tlb.h +++ b/include/asm-s390/tlb.h | |||
@@ -38,7 +38,7 @@ struct mmu_gather { | |||
38 | struct mm_struct *mm; | 38 | struct mm_struct *mm; |
39 | unsigned int fullmm; | 39 | unsigned int fullmm; |
40 | unsigned int nr_ptes; | 40 | unsigned int nr_ptes; |
41 | unsigned int nr_pmds; | 41 | unsigned int nr_pxds; |
42 | void *array[TLB_NR_PTRS]; | 42 | void *array[TLB_NR_PTRS]; |
43 | }; | 43 | }; |
44 | 44 | ||
@@ -53,7 +53,7 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, | |||
53 | tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) || | 53 | tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) || |
54 | (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm); | 54 | (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm); |
55 | tlb->nr_ptes = 0; | 55 | tlb->nr_ptes = 0; |
56 | tlb->nr_pmds = TLB_NR_PTRS; | 56 | tlb->nr_pxds = TLB_NR_PTRS; |
57 | if (tlb->fullmm) | 57 | if (tlb->fullmm) |
58 | __tlb_flush_mm(mm); | 58 | __tlb_flush_mm(mm); |
59 | return tlb; | 59 | return tlb; |
@@ -62,12 +62,13 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, | |||
62 | static inline void tlb_flush_mmu(struct mmu_gather *tlb, | 62 | static inline void tlb_flush_mmu(struct mmu_gather *tlb, |
63 | unsigned long start, unsigned long end) | 63 | unsigned long start, unsigned long end) |
64 | { | 64 | { |
65 | if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pmds < TLB_NR_PTRS)) | 65 | if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS)) |
66 | __tlb_flush_mm(tlb->mm); | 66 | __tlb_flush_mm(tlb->mm); |
67 | while (tlb->nr_ptes > 0) | 67 | while (tlb->nr_ptes > 0) |
68 | pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]); | 68 | pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]); |
69 | while (tlb->nr_pmds < TLB_NR_PTRS) | 69 | while (tlb->nr_pxds < TLB_NR_PTRS) |
70 | pmd_free(tlb->mm, (pmd_t *) tlb->array[tlb->nr_pmds++]); | 70 | /* pgd_free frees the pointer as region or segment table */ |
71 | pgd_free(tlb->mm, tlb->array[tlb->nr_pxds++]); | ||
71 | } | 72 | } |
72 | 73 | ||
73 | static inline void tlb_finish_mmu(struct mmu_gather *tlb, | 74 | static inline void tlb_finish_mmu(struct mmu_gather *tlb, |
@@ -95,33 +96,57 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) | |||
95 | * pte_free_tlb frees a pte table and clears the CRSTE for the | 96 | * pte_free_tlb frees a pte table and clears the CRSTE for the |
96 | * page table from the tlb. | 97 | * page table from the tlb. |
97 | */ | 98 | */ |
98 | static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t page) | 99 | static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte) |
99 | { | 100 | { |
100 | if (!tlb->fullmm) { | 101 | if (!tlb->fullmm) { |
101 | tlb->array[tlb->nr_ptes++] = page; | 102 | tlb->array[tlb->nr_ptes++] = pte; |
102 | if (tlb->nr_ptes >= tlb->nr_pmds) | 103 | if (tlb->nr_ptes >= tlb->nr_pxds) |
103 | tlb_flush_mmu(tlb, 0, 0); | 104 | tlb_flush_mmu(tlb, 0, 0); |
104 | } else | 105 | } else |
105 | pte_free(tlb->mm, page); | 106 | pte_free(tlb->mm, pte); |
106 | } | 107 | } |
107 | 108 | ||
108 | /* | 109 | /* |
109 | * pmd_free_tlb frees a pmd table and clears the CRSTE for the | 110 | * pmd_free_tlb frees a pmd table and clears the CRSTE for the |
110 | * segment table entry from the tlb. | 111 | * segment table entry from the tlb. |
112 | * If the mm uses a two level page table the single pmd is freed | ||
113 | * as the pgd. pmd_free_tlb checks the asce_limit against 2GB | ||
114 | * to avoid the double free of the pmd in this case. | ||
111 | */ | 115 | */ |
112 | static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) | 116 | static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) |
113 | { | 117 | { |
114 | #ifdef __s390x__ | 118 | #ifdef __s390x__ |
119 | if (tlb->mm->context.asce_limit <= (1UL << 31)) | ||
120 | return; | ||
115 | if (!tlb->fullmm) { | 121 | if (!tlb->fullmm) { |
116 | tlb->array[--tlb->nr_pmds] = (struct page *) pmd; | 122 | tlb->array[--tlb->nr_pxds] = pmd; |
117 | if (tlb->nr_ptes >= tlb->nr_pmds) | 123 | if (tlb->nr_ptes >= tlb->nr_pxds) |
118 | tlb_flush_mmu(tlb, 0, 0); | 124 | tlb_flush_mmu(tlb, 0, 0); |
119 | } else | 125 | } else |
120 | pmd_free(tlb->mm, pmd); | 126 | pmd_free(tlb->mm, pmd); |
121 | #endif | 127 | #endif |
122 | } | 128 | } |
123 | 129 | ||
124 | #define pud_free_tlb(tlb, pud) do { } while (0) | 130 | /* |
131 | * pud_free_tlb frees a pud table and clears the CRSTE for the | ||
132 | * region third table entry from the tlb. | ||
133 | * If the mm uses a three level page table the single pud is freed | ||
134 | * as the pgd. pud_free_tlb checks the asce_limit against 4TB | ||
135 | * to avoid the double free of the pud in this case. | ||
136 | */ | ||
137 | static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud) | ||
138 | { | ||
139 | #ifdef __s390x__ | ||
140 | if (tlb->mm->context.asce_limit <= (1UL << 42)) | ||
141 | return; | ||
142 | if (!tlb->fullmm) { | ||
143 | tlb->array[--tlb->nr_pxds] = pud; | ||
144 | if (tlb->nr_ptes >= tlb->nr_pxds) | ||
145 | tlb_flush_mmu(tlb, 0, 0); | ||
146 | } else | ||
147 | pud_free(tlb->mm, pud); | ||
148 | #endif | ||
149 | } | ||
125 | 150 | ||
126 | #define tlb_start_vma(tlb, vma) do { } while (0) | 151 | #define tlb_start_vma(tlb, vma) do { } while (0) |
127 | #define tlb_end_vma(tlb, vma) do { } while (0) | 152 | #define tlb_end_vma(tlb, vma) do { } while (0) |