[S390] Add four level page tables for CONFIG_64BIT=y.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
diff --git a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h
index ecac75e..9b2ddb7 100644
--- a/include/asm-s390/tlb.h
+++ b/include/asm-s390/tlb.h
@@ -38,7 +38,7 @@
 	struct mm_struct *mm;
 	unsigned int fullmm;
 	unsigned int nr_ptes;
-	unsigned int nr_pmds;
+	unsigned int nr_pxds;
 	void *array[TLB_NR_PTRS];
 };
 
@@ -53,7 +53,7 @@
 	tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) ||
 		(atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm);
 	tlb->nr_ptes = 0;
-	tlb->nr_pmds = TLB_NR_PTRS;
+	tlb->nr_pxds = TLB_NR_PTRS;
 	if (tlb->fullmm)
 		__tlb_flush_mm(mm);
 	return tlb;
@@ -62,12 +62,13 @@
 static inline void tlb_flush_mmu(struct mmu_gather *tlb,
 				 unsigned long start, unsigned long end)
 {
-	if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pmds < TLB_NR_PTRS))
+	if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS))
 		__tlb_flush_mm(tlb->mm);
 	while (tlb->nr_ptes > 0)
 		pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]);
-	while (tlb->nr_pmds < TLB_NR_PTRS)
-		pmd_free(tlb->mm, (pmd_t *) tlb->array[tlb->nr_pmds++]);
+	while (tlb->nr_pxds < TLB_NR_PTRS)
+		/* pgd_free frees the pointer as region or segment table */
+		pgd_free(tlb->mm, tlb->array[tlb->nr_pxds++]);
 }
 
 static inline void tlb_finish_mmu(struct mmu_gather *tlb,
@@ -99,7 +100,7 @@
 {
 	if (!tlb->fullmm) {
 		tlb->array[tlb->nr_ptes++] = pte;
-		if (tlb->nr_ptes >= tlb->nr_pmds)
+		if (tlb->nr_ptes >= tlb->nr_pxds)
 			tlb_flush_mmu(tlb, 0, 0);
 	} else
 		pte_free(tlb->mm, pte);
@@ -113,15 +114,29 @@
 {
 #ifdef __s390x__
 	if (!tlb->fullmm) {
-		tlb->array[--tlb->nr_pmds] = (struct page *) pmd;
-		if (tlb->nr_ptes >= tlb->nr_pmds)
+		tlb->array[--tlb->nr_pxds] = pmd;
+		if (tlb->nr_ptes >= tlb->nr_pxds)
 			tlb_flush_mmu(tlb, 0, 0);
 	} else
 		pmd_free(tlb->mm, pmd);
 #endif
 }
 
-#define pud_free_tlb(tlb, pud)			do { } while (0)
+/*
+ * pud_free_tlb frees a pud table and clears the CRSTE for the
+ * region third table entry from the tlb.
+ */
+static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
+{
+#ifdef __s390x__
+	if (!tlb->fullmm) {
+		tlb->array[--tlb->nr_pxds] = pud;
+		if (tlb->nr_ptes >= tlb->nr_pxds)
+			tlb_flush_mmu(tlb, 0, 0);
+	} else
+		pud_free(tlb->mm, pud);
+#endif
+}
 
 #define tlb_start_vma(tlb, vma)			do { } while (0)
 #define tlb_end_vma(tlb, vma)			do { } while (0)