aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/include/asm/pgtable.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/include/asm/pgtable.h')
-rw-r--r--arch/s390/include/asm/pgtable.h105
1 files changed, 72 insertions, 33 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 66101f6c6d81..50a75d96f939 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -229,6 +229,7 @@ extern unsigned long MODULES_END;
229#define _PAGE_READ 0x010 /* SW pte read bit */ 229#define _PAGE_READ 0x010 /* SW pte read bit */
230#define _PAGE_WRITE 0x020 /* SW pte write bit */ 230#define _PAGE_WRITE 0x020 /* SW pte write bit */
231#define _PAGE_SPECIAL 0x040 /* SW associated with special page */ 231#define _PAGE_SPECIAL 0x040 /* SW associated with special page */
232#define _PAGE_UNUSED 0x080 /* SW bit for pgste usage state */
232#define __HAVE_ARCH_PTE_SPECIAL 233#define __HAVE_ARCH_PTE_SPECIAL
233 234
234/* Set of bits not changed in pte_modify */ 235/* Set of bits not changed in pte_modify */
@@ -394,6 +395,12 @@ extern unsigned long MODULES_END;
394 395
395#endif /* CONFIG_64BIT */ 396#endif /* CONFIG_64BIT */
396 397
398/* Guest Page State used for virtualization */
399#define _PGSTE_GPS_ZERO 0x0000000080000000UL
400#define _PGSTE_GPS_USAGE_MASK 0x0000000003000000UL
401#define _PGSTE_GPS_USAGE_STABLE 0x0000000000000000UL
402#define _PGSTE_GPS_USAGE_UNUSED 0x0000000001000000UL
403
397/* 404/*
398 * A user page table pointer has the space-switch-event bit, the 405 * A user page table pointer has the space-switch-event bit, the
399 * private-space-control bit and the storage-alteration-event-control 406 * private-space-control bit and the storage-alteration-event-control
@@ -617,6 +624,14 @@ static inline int pte_none(pte_t pte)
617 return pte_val(pte) == _PAGE_INVALID; 624 return pte_val(pte) == _PAGE_INVALID;
618} 625}
619 626
627static inline int pte_swap(pte_t pte)
628{
629 /* Bit pattern: (pte & 0x603) == 0x402 */
630 return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT |
631 _PAGE_TYPE | _PAGE_PRESENT))
632 == (_PAGE_INVALID | _PAGE_TYPE);
633}
634
620static inline int pte_file(pte_t pte) 635static inline int pte_file(pte_t pte)
621{ 636{
622 /* Bit pattern: (pte & 0x601) == 0x600 */ 637 /* Bit pattern: (pte & 0x601) == 0x600 */
@@ -823,20 +838,20 @@ unsigned long gmap_translate(unsigned long address, struct gmap *);
823unsigned long __gmap_fault(unsigned long address, struct gmap *); 838unsigned long __gmap_fault(unsigned long address, struct gmap *);
824unsigned long gmap_fault(unsigned long address, struct gmap *); 839unsigned long gmap_fault(unsigned long address, struct gmap *);
825void gmap_discard(unsigned long from, unsigned long to, struct gmap *); 840void gmap_discard(unsigned long from, unsigned long to, struct gmap *);
841void __gmap_zap(unsigned long address, struct gmap *);
826 842
827void gmap_register_ipte_notifier(struct gmap_notifier *); 843void gmap_register_ipte_notifier(struct gmap_notifier *);
828void gmap_unregister_ipte_notifier(struct gmap_notifier *); 844void gmap_unregister_ipte_notifier(struct gmap_notifier *);
829int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len); 845int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len);
830void gmap_do_ipte_notify(struct mm_struct *, unsigned long addr, pte_t *); 846void gmap_do_ipte_notify(struct mm_struct *, pte_t *);
831 847
832static inline pgste_t pgste_ipte_notify(struct mm_struct *mm, 848static inline pgste_t pgste_ipte_notify(struct mm_struct *mm,
833 unsigned long addr,
834 pte_t *ptep, pgste_t pgste) 849 pte_t *ptep, pgste_t pgste)
835{ 850{
836#ifdef CONFIG_PGSTE 851#ifdef CONFIG_PGSTE
837 if (pgste_val(pgste) & PGSTE_IN_BIT) { 852 if (pgste_val(pgste) & PGSTE_IN_BIT) {
838 pgste_val(pgste) &= ~PGSTE_IN_BIT; 853 pgste_val(pgste) &= ~PGSTE_IN_BIT;
839 gmap_do_ipte_notify(mm, addr, ptep); 854 gmap_do_ipte_notify(mm, ptep);
840 } 855 }
841#endif 856#endif
842 return pgste; 857 return pgste;
@@ -854,6 +869,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
854 869
855 if (mm_has_pgste(mm)) { 870 if (mm_has_pgste(mm)) {
856 pgste = pgste_get_lock(ptep); 871 pgste = pgste_get_lock(ptep);
872 pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
857 pgste_set_key(ptep, pgste, entry); 873 pgste_set_key(ptep, pgste, entry);
858 pgste_set_pte(ptep, entry); 874 pgste_set_pte(ptep, entry);
859 pgste_set_unlock(ptep, pgste); 875 pgste_set_unlock(ptep, pgste);
@@ -883,6 +899,12 @@ static inline int pte_young(pte_t pte)
883 return (pte_val(pte) & _PAGE_YOUNG) != 0; 899 return (pte_val(pte) & _PAGE_YOUNG) != 0;
884} 900}
885 901
902#define __HAVE_ARCH_PTE_UNUSED
903static inline int pte_unused(pte_t pte)
904{
905 return pte_val(pte) & _PAGE_UNUSED;
906}
907
886/* 908/*
887 * pgd/pmd/pte modification functions 909 * pgd/pmd/pte modification functions
888 */ 910 */
@@ -1036,30 +1058,41 @@ static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
1036 1058
1037static inline void __ptep_ipte(unsigned long address, pte_t *ptep) 1059static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
1038{ 1060{
1039 if (!(pte_val(*ptep) & _PAGE_INVALID)) { 1061 unsigned long pto = (unsigned long) ptep;
1062
1040#ifndef CONFIG_64BIT 1063#ifndef CONFIG_64BIT
1041 /* pto must point to the start of the segment table */ 1064 /* pto in ESA mode must point to the start of the segment table */
1042 pte_t *pto = (pte_t *) (((unsigned long) ptep) & 0x7ffffc00); 1065 pto &= 0x7ffffc00;
1043#else
1044 /* ipte in zarch mode can do the math */
1045 pte_t *pto = ptep;
1046#endif 1066#endif
1047 asm volatile( 1067 /* Invalidation + global TLB flush for the pte */
1048 " ipte %2,%3" 1068 asm volatile(
1049 : "=m" (*ptep) : "m" (*ptep), 1069 " ipte %2,%3"
1050 "a" (pto), "a" (address)); 1070 : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address));
1051 } 1071}
1072
1073static inline void ptep_flush_direct(struct mm_struct *mm,
1074 unsigned long address, pte_t *ptep)
1075{
1076 if (pte_val(*ptep) & _PAGE_INVALID)
1077 return;
1078 __ptep_ipte(address, ptep);
1052} 1079}
1053 1080
1054static inline void ptep_flush_lazy(struct mm_struct *mm, 1081static inline void ptep_flush_lazy(struct mm_struct *mm,
1055 unsigned long address, pte_t *ptep) 1082 unsigned long address, pte_t *ptep)
1056{ 1083{
1057 int active = (mm == current->active_mm) ? 1 : 0; 1084 int active, count;
1058 1085
1059 if (atomic_read(&mm->context.attach_count) > active) 1086 if (pte_val(*ptep) & _PAGE_INVALID)
1060 __ptep_ipte(address, ptep); 1087 return;
1061 else 1088 active = (mm == current->active_mm) ? 1 : 0;
1089 count = atomic_add_return(0x10000, &mm->context.attach_count);
1090 if ((count & 0xffff) <= active) {
1091 pte_val(*ptep) |= _PAGE_INVALID;
1062 mm->context.flush_mm = 1; 1092 mm->context.flush_mm = 1;
1093 } else
1094 __ptep_ipte(address, ptep);
1095 atomic_sub(0x10000, &mm->context.attach_count);
1063} 1096}
1064 1097
1065#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG 1098#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
@@ -1072,11 +1105,11 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
1072 1105
1073 if (mm_has_pgste(vma->vm_mm)) { 1106 if (mm_has_pgste(vma->vm_mm)) {
1074 pgste = pgste_get_lock(ptep); 1107 pgste = pgste_get_lock(ptep);
1075 pgste = pgste_ipte_notify(vma->vm_mm, addr, ptep, pgste); 1108 pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
1076 } 1109 }
1077 1110
1078 pte = *ptep; 1111 pte = *ptep;
1079 __ptep_ipte(addr, ptep); 1112 ptep_flush_direct(vma->vm_mm, addr, ptep);
1080 young = pte_young(pte); 1113 young = pte_young(pte);
1081 pte = pte_mkold(pte); 1114 pte = pte_mkold(pte);
1082 1115
@@ -1118,7 +1151,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
1118 1151
1119 if (mm_has_pgste(mm)) { 1152 if (mm_has_pgste(mm)) {
1120 pgste = pgste_get_lock(ptep); 1153 pgste = pgste_get_lock(ptep);
1121 pgste = pgste_ipte_notify(mm, address, ptep, pgste); 1154 pgste = pgste_ipte_notify(mm, ptep, pgste);
1122 } 1155 }
1123 1156
1124 pte = *ptep; 1157 pte = *ptep;
@@ -1142,12 +1175,11 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
1142 1175
1143 if (mm_has_pgste(mm)) { 1176 if (mm_has_pgste(mm)) {
1144 pgste = pgste_get_lock(ptep); 1177 pgste = pgste_get_lock(ptep);
1145 pgste_ipte_notify(mm, address, ptep, pgste); 1178 pgste_ipte_notify(mm, ptep, pgste);
1146 } 1179 }
1147 1180
1148 pte = *ptep; 1181 pte = *ptep;
1149 ptep_flush_lazy(mm, address, ptep); 1182 ptep_flush_lazy(mm, address, ptep);
1150 pte_val(*ptep) |= _PAGE_INVALID;
1151 1183
1152 if (mm_has_pgste(mm)) { 1184 if (mm_has_pgste(mm)) {
1153 pgste = pgste_update_all(&pte, pgste); 1185 pgste = pgste_update_all(&pte, pgste);
@@ -1180,14 +1212,17 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
1180 1212
1181 if (mm_has_pgste(vma->vm_mm)) { 1213 if (mm_has_pgste(vma->vm_mm)) {
1182 pgste = pgste_get_lock(ptep); 1214 pgste = pgste_get_lock(ptep);
1183 pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste); 1215 pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
1184 } 1216 }
1185 1217
1186 pte = *ptep; 1218 pte = *ptep;
1187 __ptep_ipte(address, ptep); 1219 ptep_flush_direct(vma->vm_mm, address, ptep);
1188 pte_val(*ptep) = _PAGE_INVALID; 1220 pte_val(*ptep) = _PAGE_INVALID;
1189 1221
1190 if (mm_has_pgste(vma->vm_mm)) { 1222 if (mm_has_pgste(vma->vm_mm)) {
1223 if ((pgste_val(pgste) & _PGSTE_GPS_USAGE_MASK) ==
1224 _PGSTE_GPS_USAGE_UNUSED)
1225 pte_val(pte) |= _PAGE_UNUSED;
1191 pgste = pgste_update_all(&pte, pgste); 1226 pgste = pgste_update_all(&pte, pgste);
1192 pgste_set_unlock(ptep, pgste); 1227 pgste_set_unlock(ptep, pgste);
1193 } 1228 }
@@ -1211,7 +1246,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
1211 1246
1212 if (!full && mm_has_pgste(mm)) { 1247 if (!full && mm_has_pgste(mm)) {
1213 pgste = pgste_get_lock(ptep); 1248 pgste = pgste_get_lock(ptep);
1214 pgste = pgste_ipte_notify(mm, address, ptep, pgste); 1249 pgste = pgste_ipte_notify(mm, ptep, pgste);
1215 } 1250 }
1216 1251
1217 pte = *ptep; 1252 pte = *ptep;
@@ -1236,7 +1271,7 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
1236 if (pte_write(pte)) { 1271 if (pte_write(pte)) {
1237 if (mm_has_pgste(mm)) { 1272 if (mm_has_pgste(mm)) {
1238 pgste = pgste_get_lock(ptep); 1273 pgste = pgste_get_lock(ptep);
1239 pgste = pgste_ipte_notify(mm, address, ptep, pgste); 1274 pgste = pgste_ipte_notify(mm, ptep, pgste);
1240 } 1275 }
1241 1276
1242 ptep_flush_lazy(mm, address, ptep); 1277 ptep_flush_lazy(mm, address, ptep);
@@ -1262,10 +1297,10 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
1262 return 0; 1297 return 0;
1263 if (mm_has_pgste(vma->vm_mm)) { 1298 if (mm_has_pgste(vma->vm_mm)) {
1264 pgste = pgste_get_lock(ptep); 1299 pgste = pgste_get_lock(ptep);
1265 pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste); 1300 pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
1266 } 1301 }
1267 1302
1268 __ptep_ipte(address, ptep); 1303 ptep_flush_direct(vma->vm_mm, address, ptep);
1269 1304
1270 if (mm_has_pgste(vma->vm_mm)) { 1305 if (mm_has_pgste(vma->vm_mm)) {
1271 pgste_set_pte(ptep, entry); 1306 pgste_set_pte(ptep, entry);
@@ -1449,12 +1484,16 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
1449static inline void pmdp_flush_lazy(struct mm_struct *mm, 1484static inline void pmdp_flush_lazy(struct mm_struct *mm,
1450 unsigned long address, pmd_t *pmdp) 1485 unsigned long address, pmd_t *pmdp)
1451{ 1486{
1452 int active = (mm == current->active_mm) ? 1 : 0; 1487 int active, count;
1453 1488
1454 if ((atomic_read(&mm->context.attach_count) & 0xffff) > active) 1489 active = (mm == current->active_mm) ? 1 : 0;
1455 __pmd_idte(address, pmdp); 1490 count = atomic_add_return(0x10000, &mm->context.attach_count);
1456 else 1491 if ((count & 0xffff) <= active) {
1492 pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID;
1457 mm->context.flush_mm = 1; 1493 mm->context.flush_mm = 1;
1494 } else
1495 __pmd_idte(address, pmdp);
1496 atomic_sub(0x10000, &mm->context.attach_count);
1458} 1497}
1459 1498
1460#ifdef CONFIG_TRANSPARENT_HUGEPAGE 1499#ifdef CONFIG_TRANSPARENT_HUGEPAGE