powerpc: add barrier after writing kernel PTE
authorScott Wood <scottwood@freescale.com>
Sat, 12 Oct 2013 00:22:37 +0000 (19:22 -0500)
committerScott Wood <scottwood@freescale.com>
Thu, 9 Jan 2014 23:52:19 +0000 (17:52 -0600)
There is no barrier between something like ioremap() writing to
a PTE, and returning the value to a caller that may then store the
pointer in a place that is visible to other CPUs.  Such callers
generally don't perform barriers of their own.

Even if callers of ioremap() and similar things did use barriers,
the most logical choise would be smp_wmb(), which is not
architecturally sufficient when BookE hardware tablewalk is used.  A
full sync is specified by the architecture.

For userspace mappings, OTOH, we generally already have an lwsync due
to locking, and if we occasionally take a spurious fault due to not
having a full sync with hardware tablewalk, it will not be fatal
because we will retry rather than oops.

Signed-off-by: Scott Wood <scottwood@freescale.com>
arch/powerpc/mm/pgtable_32.c
arch/powerpc/mm/pgtable_64.c

index 5b9601715289c450a23e41b7ffc62d428496b8c9..343a87fa78b5eb3ea403c7a4dcf18ef5da7e2b63 100644 (file)
@@ -299,6 +299,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
                set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
                                                     __pgprot(flags)));
        }
+       smp_wmb();
        return err;
 }
 
index 02e8681fb8655a724b6e75746301d8a0cbb6befb..755138218e04be6e21f144e01a1ed5ac0da7ea2a 100644 (file)
@@ -153,6 +153,18 @@ int map_kernel_page(unsigned long ea, unsigned long pa, int flags)
                }
 #endif /* !CONFIG_PPC_MMU_NOHASH */
        }
+
+#ifdef CONFIG_PPC_BOOK3E_64
+       /*
+        * With hardware tablewalk, a sync is needed to ensure that
+        * subsequent accesses see the PTE we just wrote.  Unlike userspace
+        * mappings, we can't tolerate spurious faults, so make sure
+        * the new PTE will be seen the first time.
+        */
+       mb();
+#else
+       smp_wmb();
+#endif
        return 0;
 }