]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/mm/pageattr.c
Merge branch 'core/percpu' into percpu-cpumask-x86-for-linus-2
[linux-2.6-omap-h63xx.git] / arch / x86 / mm / pageattr.c
index 84ba74820ad6436479a6456ec8d8e3a9a3c5c591..9c4294986af779ed62ab088af0dae0f0048eb0c9 100644 (file)
@@ -482,6 +482,13 @@ static int split_large_page(pte_t *kpte, unsigned long address)
        pbase = (pte_t *)page_address(base);
        paravirt_alloc_pte(&init_mm, page_to_pfn(base));
        ref_prot = pte_pgprot(pte_clrhuge(*kpte));
+       /*
+        * If we ever want to utilize the PAT bit, we need to
+        * update this function to make sure it's converted from
+        * bit 12 to bit 7 when we cross from the 2MB level to
+        * the 4K level:
+        */
+       WARN_ON_ONCE(pgprot_val(ref_prot) & _PAGE_PAT_LARGE);
 
 #ifdef CONFIG_X86_64
        if (level == PG_LEVEL_1G) {
@@ -508,18 +515,24 @@ static int split_large_page(pte_t *kpte, unsigned long address)
 #endif
 
        /*
-        * Install the new, split up pagetable. Important details here:
+        * Install the new, split up pagetable.
         *
-        * On Intel the NX bit of all levels must be cleared to make a
-        * page executable. See section 4.13.2 of Intel 64 and IA-32
-        * Architectures Software Developer's Manual).
+        * We use the standard kernel pagetable protections for the new
+        * pagetable protections, the actual ptes set above control the
+        * primary protection behavior:
+        */
+       __set_pmd_pte(kpte, address, mk_pte(base, __pgprot(_KERNPG_TABLE)));
+
+       /*
+        * Intel Atom errata AAH41 workaround.
         *
-        * Mark the entry present. The current mapping might be
-        * set to not present, which we preserved above.
+        * The real fix should be in hw or in a microcode update, but
+        * we also probabilistically try to reduce the window of having
+        * a large TLB mixed with 4K TLBs while instruction fetches are
+        * going on.
         */
-       ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte)));
-       pgprot_val(ref_prot) |= _PAGE_PRESENT;
-       __set_pmd_pte(kpte, address, mk_pte(base, ref_prot));
+       __flush_tlb_all();
+
        base = NULL;
 
 out_unlock:
@@ -575,7 +588,6 @@ static int __change_page_attr(struct cpa_data *cpa, int primary)
                address = cpa->vaddr[cpa->curpage];
        else
                address = *cpa->vaddr;
-
 repeat:
        kpte = lookup_address(address, &level);
        if (!kpte)
@@ -812,6 +824,13 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 
        vm_unmap_aliases();
 
+       /*
+        * If we're called with lazy mmu updates enabled, the
+        * in-memory pte state may be stale.  Flush pending updates to
+        * bring them up to date.
+        */
+       arch_flush_lazy_mmu_mode();
+
        cpa.vaddr = addr;
        cpa.numpages = numpages;
        cpa.mask_set = mask_set;
@@ -854,6 +873,13 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
        } else
                cpa_flush_all(cache);
 
+       /*
+        * If we've been called with lazy mmu updates enabled, then
+        * make sure that everything gets flushed out before we
+        * return.
+        */
+       arch_flush_lazy_mmu_mode();
+
 out:
        return ret;
 }