powerpc/nohash: Move 8xx version of pte_update() into pte-8xx.h
[sfrench/cifs-2.6.git] / arch / powerpc / include / asm / nohash / 32 / pte-8xx.h
index e6fe1d5731f2c5bb1813c34959c46c740ec6428a..52395a5ecd7075731dfb8500410ea90ad36b41db 100644 (file)
@@ -187,6 +187,63 @@ static inline unsigned long pte_leaf_size(pte_t pte)
 
 #define pte_leaf_size pte_leaf_size
 
+/*
+ * On the 8xx, the page tables are a bit special. For 16k pages, we have
+ * 4 identical entries. For 512k pages, we have 128 entries as if it was
+ * 4k pages, but they are flagged as 512k pages for the hardware.
+ * For other page sizes, we have a single entry in the table.
+ */
+static pmd_t *pmd_off(struct mm_struct *mm, unsigned long addr);
+static int hugepd_ok(hugepd_t hpd);
+
+static inline int number_of_cells_per_pte(pmd_t *pmd, pte_basic_t val, int huge)
+{
+       if (!huge)
+               return PAGE_SIZE / SZ_4K;
+       else if (hugepd_ok(*((hugepd_t *)pmd)))
+               return 1;
+       else if (IS_ENABLED(CONFIG_PPC_4K_PAGES) && !(val & _PAGE_HUGE))
+               return SZ_16K / SZ_4K;
+       else
+               return SZ_512K / SZ_4K;
+}
+
+static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
+                                    unsigned long clr, unsigned long set, int huge)
+{
+       pte_basic_t *entry = (pte_basic_t *)p;
+       pte_basic_t old = pte_val(*p);
+       pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
+       int num, i;
+       pmd_t *pmd = pmd_off(mm, addr);
+
+       num = number_of_cells_per_pte(pmd, new, huge);
+
+       for (i = 0; i < num; i += PAGE_SIZE / SZ_4K, new += PAGE_SIZE) {
+               *entry++ = new;
+               if (IS_ENABLED(CONFIG_PPC_16K_PAGES) && num != 1) {
+                       *entry++ = new;
+                       *entry++ = new;
+                       *entry++ = new;
+               }
+       }
+
+       return old;
+}
+
+#define pte_update pte_update
+
+#ifdef CONFIG_PPC_16K_PAGES
+#define ptep_get ptep_get
+static inline pte_t ptep_get(pte_t *ptep)
+{
+       pte_basic_t val = READ_ONCE(ptep->pte);
+       pte_t pte = {val, val, val, val};
+
+       return pte;
+}
+#endif /* CONFIG_PPC_16K_PAGES */
+
 #endif
 
 #endif /* __KERNEL__ */