[S390] Virtual memmap for s390.
[pandora-kernel.git] / include / asm-s390 / pgtable.h
index ecdff13..ae61aca 100644 (file)
@@ -107,16 +107,27 @@ extern char empty_zero_page[PAGE_SIZE];
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
+extern unsigned long vmalloc_end;
 #define VMALLOC_OFFSET  (8*1024*1024)
 #define VMALLOC_START   (((unsigned long) high_memory + VMALLOC_OFFSET) \
                         & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_END    vmalloc_end
+
+/*
+ * We need some free virtual space to be able to do vmalloc.
+ * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc
+ * area. On a machine with 2GB memory we make sure that we
+ * have at least 128MB free space for vmalloc. On a machine
+ * with 4TB we make sure we have at least 128GB.
+ */
 #ifndef __s390x__
-# define VMALLOC_END     (0x7fffffffL)
+#define VMALLOC_MIN_SIZE       0x8000000UL
+#define VMALLOC_END_INIT       0x80000000UL
 #else /* __s390x__ */
-# define VMALLOC_END     (0x40000000000L)
+#define VMALLOC_MIN_SIZE       0x2000000000UL
+#define VMALLOC_END_INIT       0x40000000000UL
 #endif /* __s390x__ */
 
-
 /*
  * A 31 bit pagetable entry of S390 has following format:
  *  |   PFRA          |    |  OS  |
@@ -200,18 +211,45 @@ extern char empty_zero_page[PAGE_SIZE];
  */
 
 /* Hardware bits in the page table entry */
-#define _PAGE_RO        0x200          /* HW read-only                     */
-#define _PAGE_INVALID   0x400          /* HW invalid                       */
+#define _PAGE_RO       0x200           /* HW read-only bit  */
+#define _PAGE_INVALID  0x400           /* HW invalid bit    */
+#define _PAGE_SWT      0x001           /* SW pte type bit t */
+#define _PAGE_SWX      0x002           /* SW pte type bit x */
 
-/* Mask and six different types of pages. */
-#define _PAGE_TYPE_MASK                0x601
+/* Six different types of pages. */
 #define _PAGE_TYPE_EMPTY       0x400
 #define _PAGE_TYPE_NONE                0x401
-#define _PAGE_TYPE_SWAP                0x600
-#define _PAGE_TYPE_FILE                0x601
+#define _PAGE_TYPE_SWAP                0x403
+#define _PAGE_TYPE_FILE                0x601   /* bit 0x002 is used for offset !! */
 #define _PAGE_TYPE_RO          0x200
 #define _PAGE_TYPE_RW          0x000
 
+/*
+ * PTE type bits are rather complicated. handle_pte_fault uses pte_present,
+ * pte_none and pte_file to find out the pte type WITHOUT holding the page
+ * table lock. ptep_clear_flush on the other hand uses ptep_clear_flush to
+ * invalidate a given pte. ipte sets the hw invalid bit and clears all tlbs
+ * for the page. The page table entry is set to _PAGE_TYPE_EMPTY afterwards.
+ * This change is done while holding the lock, but the intermediate step
+ * of a previously valid pte with the hw invalid bit set can be observed by
+ * handle_pte_fault. That makes it necessary that all valid pte types with
+ * the hw invalid bit set must be distinguishable from the four pte types
+ * empty, none, swap and file.
+ *
+ *                     irxt  ipte  irxt
+ * _PAGE_TYPE_EMPTY    1000   ->   1000
+ * _PAGE_TYPE_NONE     1001   ->   1001
+ * _PAGE_TYPE_SWAP     1011   ->   1011
+ * _PAGE_TYPE_FILE     11?1   ->   11?1
+ * _PAGE_TYPE_RO       0100   ->   1100
+ * _PAGE_TYPE_RW       0000   ->   1000
+ *
+ * pte_none is true for bits combinations 1000, 1100
+ * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
+ * pte_file is true for bits combinations 1101, 1111
+ * swap pte is 1011 and 0001, 0011, 0101, 0111, 1010 and 1110 are invalid.
+ */
+
 #ifndef __s390x__
 
 /* Bits in the segment table entry */
@@ -365,18 +403,21 @@ static inline int pmd_bad(pmd_t pmd)
 
 static inline int pte_none(pte_t pte)
 {
-       return (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_EMPTY;
+       return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT);
 }
 
 static inline int pte_present(pte_t pte)
 {
-       return !(pte_val(pte) & _PAGE_INVALID) ||
-               (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_NONE;
+       unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT | _PAGE_SWX;
+       return (pte_val(pte) & mask) == _PAGE_TYPE_NONE ||
+               (!(pte_val(pte) & _PAGE_INVALID) &&
+                !(pte_val(pte) & _PAGE_SWT));
 }
 
 static inline int pte_file(pte_t pte)
 {
-       return (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_FILE;
+       unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT;
+       return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
 }
 
 #define pte_same(a,b)  (pte_val(a) == pte_val(b))
@@ -599,7 +640,7 @@ ptep_establish(struct vm_area_struct *vma,
  */
 static inline int page_test_and_clear_dirty(struct page *page)
 {
-       unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT);
+       unsigned long physpage = page_to_phys(page);
        int skey = page_get_storage_key(physpage);
 
        if (skey & _PAGE_CHANGED)
@@ -612,13 +653,13 @@ static inline int page_test_and_clear_dirty(struct page *page)
  */
 static inline int page_test_and_clear_young(struct page *page)
 {
-       unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT);
+       unsigned long physpage = page_to_phys(page);
        int ccode;
 
-       asm volatile (
-               "rrbe 0,%1\n"
-               "ipm  %0\n"
-               "srl  %0,28\n"
+       asm volatile(
+               "       rrbe    0,%1\n"
+               "       ipm     %0\n"
+               "       srl     %0,28\n"
                : "=d" (ccode) : "a" (physpage) : "cc" );
        return ccode & 2;
 }
@@ -636,7 +677,7 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 
 static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
 {
-       unsigned long physpage = __pa((page - mem_map) << PAGE_SHIFT);
+       unsigned long physpage = page_to_phys(page);
 
        return mk_pte_phys(physpage, pgprot);
 }
@@ -664,11 +705,11 @@ static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot)
 
 #define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK)
 
-#define pmd_page(pmd) (mem_map+(pmd_val(pmd) >> PAGE_SHIFT))
+#define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)
 
 #define pgd_page_vaddr(pgd) (pgd_val(pgd) & PAGE_MASK)
 
-#define pgd_page(pgd) (mem_map+(pgd_val(pgd) >> PAGE_SHIFT))
+#define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT)
 
 /* to find an entry in a page-table-directory */
 #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
@@ -776,11 +817,17 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 
 #define kern_addr_valid(addr)   (1)
 
+extern int add_shared_memory(unsigned long start, unsigned long size);
+extern int remove_shared_memory(unsigned long start, unsigned long size);
+
 /*
  * No page table caches to initialise
  */
 #define pgtable_cache_init()   do { } while (0)
 
+#define __HAVE_ARCH_MEMMAP_INIT
+extern void memmap_init(unsigned long, int, unsigned long, unsigned long);
+
 #define __HAVE_ARCH_PTEP_ESTABLISH
 #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG