aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/pgalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/pgalloc.c')
-rw-r--r--arch/s390/mm/pgalloc.c85
1 files changed, 28 insertions, 57 deletions
diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c
index f6c3de26cda8..e8b5962ac12a 100644
--- a/arch/s390/mm/pgalloc.c
+++ b/arch/s390/mm/pgalloc.c
@@ -76,81 +76,52 @@ static void __crst_table_upgrade(void *arg)
76 __tlb_flush_local(); 76 __tlb_flush_local();
77} 77}
78 78
79int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) 79int crst_table_upgrade(struct mm_struct *mm)
80{ 80{
81 unsigned long *table, *pgd; 81 unsigned long *table, *pgd;
82 unsigned long entry;
83 int flush;
84 82
85 BUG_ON(limit > TASK_MAX_SIZE); 83 /* upgrade should only happen from 3 to 4 levels */
86 flush = 0; 84 BUG_ON(mm->context.asce_limit != (1UL << 42));
87repeat: 85
88 table = crst_table_alloc(mm); 86 table = crst_table_alloc(mm);
89 if (!table) 87 if (!table)
90 return -ENOMEM; 88 return -ENOMEM;
89
91 spin_lock_bh(&mm->page_table_lock); 90 spin_lock_bh(&mm->page_table_lock);
92 if (mm->context.asce_limit < limit) { 91 pgd = (unsigned long *) mm->pgd;
93 pgd = (unsigned long *) mm->pgd; 92 crst_table_init(table, _REGION2_ENTRY_EMPTY);
94 if (mm->context.asce_limit <= (1UL << 31)) { 93 pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd);
95 entry = _REGION3_ENTRY_EMPTY; 94 mm->pgd = (pgd_t *) table;
96 mm->context.asce_limit = 1UL << 42; 95 mm->context.asce_limit = 1UL << 53;
97 mm->context.asce_bits = _ASCE_TABLE_LENGTH | 96 mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
98 _ASCE_USER_BITS | 97 _ASCE_USER_BITS | _ASCE_TYPE_REGION2;
99 _ASCE_TYPE_REGION3; 98 mm->task_size = mm->context.asce_limit;
100 } else {
101 entry = _REGION2_ENTRY_EMPTY;
102 mm->context.asce_limit = 1UL << 53;
103 mm->context.asce_bits = _ASCE_TABLE_LENGTH |
104 _ASCE_USER_BITS |
105 _ASCE_TYPE_REGION2;
106 }
107 crst_table_init(table, entry);
108 pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd);
109 mm->pgd = (pgd_t *) table;
110 mm->task_size = mm->context.asce_limit;
111 table = NULL;
112 flush = 1;
113 }
114 spin_unlock_bh(&mm->page_table_lock); 99 spin_unlock_bh(&mm->page_table_lock);
115 if (table) 100
116 crst_table_free(mm, table); 101 on_each_cpu(__crst_table_upgrade, mm, 0);
117 if (mm->context.asce_limit < limit)
118 goto repeat;
119 if (flush)
120 on_each_cpu(__crst_table_upgrade, mm, 0);
121 return 0; 102 return 0;
122} 103}
123 104
124void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) 105void crst_table_downgrade(struct mm_struct *mm)
125{ 106{
126 pgd_t *pgd; 107 pgd_t *pgd;
127 108
109 /* downgrade should only happen from 3 to 2 levels (compat only) */
110 BUG_ON(mm->context.asce_limit != (1UL << 42));
111
128 if (current->active_mm == mm) { 112 if (current->active_mm == mm) {
129 clear_user_asce(); 113 clear_user_asce();
130 __tlb_flush_mm(mm); 114 __tlb_flush_mm(mm);
131 } 115 }
132 while (mm->context.asce_limit > limit) { 116
133 pgd = mm->pgd; 117 pgd = mm->pgd;
134 switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { 118 mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN);
135 case _REGION_ENTRY_TYPE_R2: 119 mm->context.asce_limit = 1UL << 31;
136 mm->context.asce_limit = 1UL << 42; 120 mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
137 mm->context.asce_bits = _ASCE_TABLE_LENGTH | 121 _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT;
138 _ASCE_USER_BITS | 122 mm->task_size = mm->context.asce_limit;
139 _ASCE_TYPE_REGION3; 123 crst_table_free(mm, (unsigned long *) pgd);
140 break; 124
141 case _REGION_ENTRY_TYPE_R3:
142 mm->context.asce_limit = 1UL << 31;
143 mm->context.asce_bits = _ASCE_TABLE_LENGTH |
144 _ASCE_USER_BITS |
145 _ASCE_TYPE_SEGMENT;
146 break;
147 default:
148 BUG();
149 }
150 mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN);
151 mm->task_size = mm->context.asce_limit;
152 crst_table_free(mm, (unsigned long *) pgd);
153 }
154 if (current->active_mm == mm) 125 if (current->active_mm == mm)
155 set_user_asce(mm); 126 set_user_asce(mm);
156} 127}