These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / powerpc / mm / hugetlbpage.c
index 3385e3d..9833fee 100644 (file)
@@ -89,6 +89,25 @@ int pgd_huge(pgd_t pgd)
         */
        return ((pgd_val(pgd) & 0x3) != 0x0);
 }
+
+#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_DEBUG_VM)
+/*
+ * This enables us to catch the wrong page directory format
+ * Moved here so that we can use WARN() in the call.
+ */
+int hugepd_ok(hugepd_t hpd)
+{
+       bool is_hugepd;
+
+       /*
+        * We should not find this format in page directory, warn otherwise.
+        */
+       is_hugepd = (((hpd.pd & 0x3) == 0x0) && ((hpd.pd & HUGEPD_SHIFT_MASK) != 0));
+       WARN(is_hugepd, "Found wrong page directory format\n");
+       return 0;
+}
+#endif
+
 #else
 int pmd_huge(pmd_t pmd)
 {
@@ -109,7 +128,7 @@ int pgd_huge(pgd_t pgd)
 pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
 {
        /* Only called for hugetlbfs pages, hence can ignore THP */
-       return __find_linux_pte_or_hugepte(mm->pgd, addr, NULL);
+       return __find_linux_pte_or_hugepte(mm->pgd, addr, NULL, NULL);
 }
 
 static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp,
@@ -336,7 +355,7 @@ int alloc_bootmem_huge_page(struct hstate *hstate)
 unsigned long gpage_npages[MMU_PAGE_COUNT];
 
 static int __init do_gpage_early_setup(char *param, char *val,
-                                      const char *unused)
+                                      const char *unused, void *arg)
 {
        static phys_addr_t size;
        unsigned long npages;
@@ -385,7 +404,7 @@ void __init reserve_hugetlb_gpages(void)
 
        strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE);
        parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0,
-                       &do_gpage_early_setup);
+                       NULL, &do_gpage_early_setup);
 
        /*
         * Walk gpage list in reverse, allocating larger page sizes first.
@@ -439,11 +458,6 @@ int alloc_bootmem_huge_page(struct hstate *hstate)
 }
 #endif
 
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
-       return 0;
-}
-
 #ifdef CONFIG_PPC_FSL_BOOK3E
 #define HUGEPD_FREELIST_SIZE \
        ((PAGE_SIZE - sizeof(struct hugepd_freelist)) / sizeof(pte_t))
@@ -689,13 +703,14 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
 struct page *
 follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
 {
+       bool is_thp;
        pte_t *ptep, pte;
        unsigned shift;
        unsigned long mask, flags;
        struct page *page = ERR_PTR(-EINVAL);
 
        local_irq_save(flags);
-       ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
+       ptep = find_linux_pte_or_hugepte(mm->pgd, address, &is_thp, &shift);
        if (!ptep)
                goto no_page;
        pte = READ_ONCE(*ptep);
@@ -704,7 +719,7 @@ follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
         * Transparent hugepages are handled by generic code. We can skip them
         * here.
         */
-       if (!shift || pmd_trans_huge(__pmd(pte_val(pte))))
+       if (!shift || is_thp)
                goto no_page;
 
        if (!pte_present(pte)) {
@@ -813,14 +828,6 @@ static int __init add_huge_page_size(unsigned long long size)
        if ((mmu_psize = shift_to_mmu_psize(shift)) < 0)
                return -EINVAL;
 
-#ifdef CONFIG_SPU_FS_64K_LS
-       /* Disable support for 64K huge pages when 64K SPU local store
-        * support is enabled as the current implementation conflicts.
-        */
-       if (shift == PAGE_SHIFT_64K)
-               return -EINVAL;
-#endif /* CONFIG_SPU_FS_64K_LS */
-
        BUG_ON(mmu_psize_defs[mmu_psize].shift != shift);
 
        /* Return if huge page size has already been setup */
@@ -933,7 +940,7 @@ static int __init hugetlbpage_init(void)
        return 0;
 }
 #endif
-module_init(hugetlbpage_init);
+arch_initcall(hugetlbpage_init);
 
 void flush_dcache_icache_hugepage(struct page *page)
 {
@@ -969,7 +976,7 @@ void flush_dcache_icache_hugepage(struct page *page)
  */
 
 pte_t *__find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
-                                  unsigned *shift)
+                                  bool *is_thp, unsigned *shift)
 {
        pgd_t pgd, *pgdp;
        pud_t pud, *pudp;
@@ -981,6 +988,9 @@ pte_t *__find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
        if (shift)
                *shift = 0;
 
+       if (is_thp)
+               *is_thp = false;
+
        pgdp = pgdir + pgd_index(ea);
        pgd  = READ_ONCE(*pgdp);
        /*
@@ -1028,7 +1038,14 @@ pte_t *__find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
                        if (pmd_none(pmd))
                                return NULL;
 
-                       if (pmd_huge(pmd) || pmd_large(pmd)) {
+                       if (pmd_trans_huge(pmd)) {
+                               if (is_thp)
+                                       *is_thp = true;
+                               ret_pte = (pte_t *) pmdp;
+                               goto out;
+                       }
+
+                       if (pmd_huge(pmd)) {
                                ret_pte = (pte_t *) pmdp;
                                goto out;
                        } else if (is_hugepd(__hugepd(pmd_val(pmd))))