These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / x86 / mm / pgtable.c
index 0b97d2c..fb0a9dd 100644 (file)
@@ -563,16 +563,31 @@ void native_set_fixmap(enum fixed_addresses idx, phys_addr_t phys,
 }
 
 #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
+/**
+ * pud_set_huge - setup kernel PUD mapping
+ *
+ * MTRRs can override PAT memory types with 4KiB granularity. Therefore, this
+ * function sets up a huge page only if any of the following conditions are met:
+ *
+ * - MTRRs are disabled, or
+ *
+ * - MTRRs are enabled and the range is completely covered by a single MTRR, or
+ *
+ * - MTRRs are enabled and the corresponding MTRR memory type is WB, which
+ *   has no effect on the requested PAT memory type.
+ *
+ * Callers should try to decrease page size (1GB -> 2MB -> 4K) if the bigger
+ * page mapping attempt fails.
+ *
+ * Returns 1 on success and 0 on failure.
+ */
 int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
 {
-       u8 mtrr;
+       u8 mtrr, uniform;
 
-       /*
-        * Do not use a huge page when the range is covered by non-WB type
-        * of MTRRs.
-        */
-       mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE);
-       if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != 0xFF))
+       mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE, &uniform);
+       if ((mtrr != MTRR_TYPE_INVALID) && (!uniform) &&
+           (mtrr != MTRR_TYPE_WRBACK))
                return 0;
 
        prot = pgprot_4k_2_large(prot);
@@ -584,17 +599,24 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
        return 1;
 }
 
+/**
+ * pmd_set_huge - setup kernel PMD mapping
+ *
+ * See text over pud_set_huge() above.
+ *
+ * Returns 1 on success and 0 on failure.
+ */
 int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot)
 {
-       u8 mtrr;
+       u8 mtrr, uniform;
 
-       /*
-        * Do not use a huge page when the range is covered by non-WB type
-        * of MTRRs.
-        */
-       mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE);
-       if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != 0xFF))
+       mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE, &uniform);
+       if ((mtrr != MTRR_TYPE_INVALID) && (!uniform) &&
+           (mtrr != MTRR_TYPE_WRBACK)) {
+               pr_warn_once("%s: Cannot satisfy [mem %#010llx-%#010llx] with a huge-page mapping due to MTRR override.\n",
+                            __func__, addr, addr + PMD_SIZE);
                return 0;
+       }
 
        prot = pgprot_4k_2_large(prot);
 
@@ -605,6 +627,11 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot)
        return 1;
 }
 
+/**
+ * pud_clear_huge - clear kernel PUD mapping when it is set
+ *
+ * Returns 1 on success and 0 on failure (no PUD map is found).
+ */
 int pud_clear_huge(pud_t *pud)
 {
        if (pud_large(*pud)) {
@@ -615,6 +642,11 @@ int pud_clear_huge(pud_t *pud)
        return 0;
 }
 
+/**
+ * pmd_clear_huge - clear kernel PMD mapping when it is set
+ *
+ * Returns 1 on success and 0 on failure (no PMD map is found).
+ */
 int pmd_clear_huge(pmd_t *pmd)
 {
        if (pmd_large(*pmd)) {