s390/pgtable: make pmd and pud helper functions available
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Tue, 10 May 2016 08:34:47 +0000 (10:34 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 13 Jun 2016 13:58:15 +0000 (15:58 +0200)
Make pmd_wrprotect() and pmd_mkwrite() available independently from
CONFIG_TRANSPARENT_HUGEPAGE and CONFIG_HUGETLB_PAGE so these can be
used on the kernel mapping.

Also introduce a couple of pud helper functions, namely pud_pfn(),
pud_wrprotect(), pud_mkwrite(), pud_mkdirty() and pud_mkclean()
which only work on the kernel mapping.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/pgtable.h

index 68942f4c8668a1a39075ff427b0a5502ab891ba0..882d6f4aad252859c74514974967836e92ccc3c9 100644 (file)
@@ -270,6 +270,9 @@ static inline int is_module_addr(void *addr)
 #define _REGION3_ENTRY         (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH)
 #define _REGION3_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID)
 
+#define _REGION3_ENTRY_ORIGIN_LARGE ~0x7fffffffUL /* large page address             */
+#define _REGION3_ENTRY_ORIGIN  ~0x7ffUL/* region third table origin         */
+
 #define _REGION3_ENTRY_DIRTY   0x2000  /* SW region dirty bit */
 #define _REGION3_ENTRY_YOUNG   0x1000  /* SW region young bit */
 #define _REGION3_ENTRY_LARGE   0x0400  /* RTTE-format control, large page  */
@@ -525,6 +528,16 @@ static inline int pud_large(pud_t pud)
        return !!(pud_val(pud) & _REGION3_ENTRY_LARGE);
 }
 
+static inline unsigned long pud_pfn(pud_t pud)
+{
+       unsigned long origin_mask;
+
+       origin_mask = _REGION3_ENTRY_ORIGIN;
+       if (pud_large(pud))
+               origin_mask = _REGION3_ENTRY_ORIGIN_LARGE;
+       return (pud_val(pud) & origin_mask) >> PAGE_SHIFT;
+}
+
 static inline int pud_bad(pud_t pud)
 {
        /*
@@ -1020,20 +1033,6 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
 #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_unmap(pte) do { } while (0)
 
-#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLB_PAGE)
-static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot)
-{
-       /*
-        * pgprot is PAGE_NONE, PAGE_READ, or PAGE_WRITE (see __Pxxx / __Sxxx)
-        * Convert to segment table entry format.
-        */
-       if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE))
-               return pgprot_val(SEGMENT_NONE);
-       if (pgprot_val(pgprot) == pgprot_val(PAGE_READ))
-               return pgprot_val(SEGMENT_READ);
-       return pgprot_val(SEGMENT_WRITE);
-}
-
 static inline pmd_t pmd_wrprotect(pmd_t pmd)
 {
        pmd_val(pmd) &= ~_SEGMENT_ENTRY_WRITE;
@@ -1070,6 +1069,56 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)
        return pmd;
 }
 
+static inline pud_t pud_wrprotect(pud_t pud)
+{
+       pud_val(pud) &= ~_REGION3_ENTRY_WRITE;
+       pud_val(pud) |= _REGION_ENTRY_PROTECT;
+       return pud;
+}
+
+static inline pud_t pud_mkwrite(pud_t pud)
+{
+       pud_val(pud) |= _REGION3_ENTRY_WRITE;
+       if (pud_large(pud) && !(pud_val(pud) & _REGION3_ENTRY_DIRTY))
+               return pud;
+       pud_val(pud) &= ~_REGION_ENTRY_PROTECT;
+       return pud;
+}
+
+static inline pud_t pud_mkclean(pud_t pud)
+{
+       if (pud_large(pud)) {
+               pud_val(pud) &= ~_REGION3_ENTRY_DIRTY;
+               pud_val(pud) |= _REGION_ENTRY_PROTECT;
+       }
+       return pud;
+}
+
+static inline pud_t pud_mkdirty(pud_t pud)
+{
+       if (pud_large(pud)) {
+               pud_val(pud) |= _REGION3_ENTRY_DIRTY |
+                               _REGION3_ENTRY_SOFT_DIRTY;
+               if (pud_val(pud) & _REGION3_ENTRY_WRITE)
+                       pud_val(pud) &= ~_REGION_ENTRY_PROTECT;
+       }
+       return pud;
+}
+
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLB_PAGE)
+static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot)
+{
+       /*
+        * pgprot is PAGE_NONE, PAGE_READ, or PAGE_WRITE (see __Pxxx / __Sxxx)
+        * Convert to segment table entry format.
+        */
+       if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE))
+               return pgprot_val(SEGMENT_NONE);
+       if (pgprot_val(pgprot) == pgprot_val(PAGE_READ))
+               return pgprot_val(SEGMENT_READ);
+       return pgprot_val(SEGMENT_WRITE);
+}
+
 static inline pmd_t pmd_mkyoung(pmd_t pmd)
 {
        if (pmd_large(pmd)) {