aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/pgtable.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/pgtable.c')
-rw-r--r--arch/s390/mm/pgtable.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index de8cbc30dcd1..0a2e5e086749 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -48,12 +48,23 @@ void crst_table_free(struct mm_struct *mm, unsigned long *table)
48} 48}
49 49
50#ifdef CONFIG_64BIT 50#ifdef CONFIG_64BIT
51static void __crst_table_upgrade(void *arg)
52{
53 struct mm_struct *mm = arg;
54
55 if (current->active_mm == mm)
56 update_mm(mm, current);
57 __tlb_flush_local();
58}
59
51int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) 60int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
52{ 61{
53 unsigned long *table, *pgd; 62 unsigned long *table, *pgd;
54 unsigned long entry; 63 unsigned long entry;
64 int flush;
55 65
56 BUG_ON(limit > (1UL << 53)); 66 BUG_ON(limit > (1UL << 53));
67 flush = 0;
57repeat: 68repeat:
58 table = crst_table_alloc(mm); 69 table = crst_table_alloc(mm);
59 if (!table) 70 if (!table)
@@ -79,12 +90,15 @@ repeat:
79 mm->pgd = (pgd_t *) table; 90 mm->pgd = (pgd_t *) table;
80 mm->task_size = mm->context.asce_limit; 91 mm->task_size = mm->context.asce_limit;
81 table = NULL; 92 table = NULL;
93 flush = 1;
82 } 94 }
83 spin_unlock_bh(&mm->page_table_lock); 95 spin_unlock_bh(&mm->page_table_lock);
84 if (table) 96 if (table)
85 crst_table_free(mm, table); 97 crst_table_free(mm, table);
86 if (mm->context.asce_limit < limit) 98 if (mm->context.asce_limit < limit)
87 goto repeat; 99 goto repeat;
100 if (flush)
101 on_each_cpu(__crst_table_upgrade, mm, 0);
88 return 0; 102 return 0;
89} 103}
90 104
@@ -92,6 +106,8 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
92{ 106{
93 pgd_t *pgd; 107 pgd_t *pgd;
94 108
109 if (current->active_mm == mm)
110 __tlb_flush_mm(mm);
95 while (mm->context.asce_limit > limit) { 111 while (mm->context.asce_limit > limit) {
96 pgd = mm->pgd; 112 pgd = mm->pgd;
97 switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { 113 switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) {
@@ -114,6 +130,8 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
114 mm->task_size = mm->context.asce_limit; 130 mm->task_size = mm->context.asce_limit;
115 crst_table_free(mm, (unsigned long *) pgd); 131 crst_table_free(mm, (unsigned long *) pgd);
116 } 132 }
133 if (current->active_mm == mm)
134 update_mm(mm, current);
117} 135}
118#endif 136#endif
119 137
@@ -1087,10 +1105,9 @@ again:
1087 continue; 1105 continue;
1088 /* Allocate new page table with pgstes */ 1106 /* Allocate new page table with pgstes */
1089 new = page_table_alloc_pgste(mm, addr); 1107 new = page_table_alloc_pgste(mm, addr);
1090 if (!new) { 1108 if (!new)
1091 mm->context.has_pgste = 0; 1109 return -ENOMEM;
1092 continue; 1110
1093 }
1094 spin_lock(&mm->page_table_lock); 1111 spin_lock(&mm->page_table_lock);
1095 if (likely((unsigned long *) pmd_deref(*pmd) == table)) { 1112 if (likely((unsigned long *) pmd_deref(*pmd) == table)) {
1096 /* Nuke pmd entry pointing to the "short" page table */ 1113 /* Nuke pmd entry pointing to the "short" page table */
@@ -1128,13 +1145,15 @@ static unsigned long page_table_realloc_pud(struct mmu_gather *tlb,
1128 if (pud_none_or_clear_bad(pud)) 1145 if (pud_none_or_clear_bad(pud))
1129 continue; 1146 continue;
1130 next = page_table_realloc_pmd(tlb, mm, pud, addr, next); 1147 next = page_table_realloc_pmd(tlb, mm, pud, addr, next);
1148 if (unlikely(IS_ERR_VALUE(next)))
1149 return next;
1131 } while (pud++, addr = next, addr != end); 1150 } while (pud++, addr = next, addr != end);
1132 1151
1133 return addr; 1152 return addr;
1134} 1153}
1135 1154
1136static void page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm, 1155static unsigned long page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
1137 unsigned long addr, unsigned long end) 1156 unsigned long addr, unsigned long end)
1138{ 1157{
1139 unsigned long next; 1158 unsigned long next;
1140 pgd_t *pgd; 1159 pgd_t *pgd;
@@ -1145,7 +1164,11 @@ static void page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
1145 if (pgd_none_or_clear_bad(pgd)) 1164 if (pgd_none_or_clear_bad(pgd))
1146 continue; 1165 continue;
1147 next = page_table_realloc_pud(tlb, mm, pgd, addr, next); 1166 next = page_table_realloc_pud(tlb, mm, pgd, addr, next);
1167 if (unlikely(IS_ERR_VALUE(next)))
1168 return next;
1148 } while (pgd++, addr = next, addr != end); 1169 } while (pgd++, addr = next, addr != end);
1170
1171 return 0;
1149} 1172}
1150 1173
1151/* 1174/*
@@ -1157,10 +1180,6 @@ int s390_enable_sie(void)
1157 struct mm_struct *mm = tsk->mm; 1180 struct mm_struct *mm = tsk->mm;
1158 struct mmu_gather tlb; 1181 struct mmu_gather tlb;
1159 1182
1160 /* Do we have switched amode? If no, we cannot do sie */
1161 if (s390_user_mode == HOME_SPACE_MODE)
1162 return -EINVAL;
1163
1164 /* Do we have pgstes? if yes, we are done */ 1183 /* Do we have pgstes? if yes, we are done */
1165 if (mm_has_pgste(tsk->mm)) 1184 if (mm_has_pgste(tsk->mm))
1166 return 0; 1185 return 0;
@@ -1169,9 +1188,9 @@ int s390_enable_sie(void)
1169 /* split thp mappings and disable thp for future mappings */ 1188 /* split thp mappings and disable thp for future mappings */
1170 thp_split_mm(mm); 1189 thp_split_mm(mm);
1171 /* Reallocate the page tables with pgstes */ 1190 /* Reallocate the page tables with pgstes */
1172 mm->context.has_pgste = 1;
1173 tlb_gather_mmu(&tlb, mm, 0, TASK_SIZE); 1191 tlb_gather_mmu(&tlb, mm, 0, TASK_SIZE);
1174 page_table_realloc(&tlb, mm, 0, TASK_SIZE); 1192 if (!page_table_realloc(&tlb, mm, 0, TASK_SIZE))
1193 mm->context.has_pgste = 1;
1175 tlb_finish_mmu(&tlb, 0, TASK_SIZE); 1194 tlb_finish_mmu(&tlb, 0, TASK_SIZE);
1176 up_write(&mm->mmap_sem); 1195 up_write(&mm->mmap_sem);
1177 return mm->context.has_pgste ? 0 : -ENOMEM; 1196 return mm->context.has_pgste ? 0 : -ENOMEM;