|
@@ -9,6 +9,7 @@
|
|
|
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/mm_types.h>
|
|
|
+#include <misc/cxl-base.h>
|
|
|
|
|
|
#include <asm/pgalloc.h>
|
|
|
#include <asm/tlb.h>
|
|
@@ -64,6 +65,35 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
|
|
trace_hugepage_set_pmd(addr, pmd_val(pmd));
|
|
|
return set_pte_at(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
|
|
|
}
|
|
|
+
|
|
|
+static void do_nothing(void *unused)
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+/*
|
|
|
+ * Serialize against find_current_mm_pte which does lock-less
|
|
|
+ * lookup in page tables with local interrupts disabled. For huge pages
|
|
|
+ * it casts pmd_t to pte_t. Since format of pte_t is different from
|
|
|
+ * pmd_t we want to prevent transit from pmd pointing to page table
|
|
|
+ * to pmd pointing to huge page (and back) while interrupts are disabled.
|
|
|
+ * We clear pmd to possibly replace it with page table pointer in
|
|
|
+ * different code paths. So make sure we wait for the parallel
|
|
|
+ * find_current_mm_pte to finish.
|
|
|
+ */
|
|
|
+void serialize_against_pte_lookup(struct mm_struct *mm)
|
|
|
+{
|
|
|
+ smp_mb();
|
|
|
+ /*
|
|
|
+ * Cxl fault handling requires us to do a lockless page table
|
|
|
+ * walk while inserting hash page table entry with mm tracked
|
|
|
+ * in cxl context. Hence we need to do a global flush.
|
|
|
+ */
|
|
|
+ if (cxl_ctx_in_use())
|
|
|
+ smp_call_function(do_nothing, NULL, 1);
|
|
|
+ else
|
|
|
+ smp_call_function_many(mm_cpumask(mm), do_nothing, NULL, 1);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* We use this to invalidate a pmdp entry before switching from a
|
|
|
* hugepte to regular pmd entry.
|
|
@@ -77,7 +107,7 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
|
|
|
* This ensures that generic code that rely on IRQ disabling
|
|
|
* to prevent a parallel THP split work as expected.
|
|
|
*/
|
|
|
- kick_all_cpus_sync();
|
|
|
+ serialize_against_pte_lookup(vma->vm_mm);
|
|
|
}
|
|
|
|
|
|
static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot)
|