Merge branch 'ida-4.19' of git://git.infradead.org/users/willy/linux-dax
[linux-2.6-microblaze.git] / arch / powerpc / mm / mmu_context_book3s64.c
index 39e9ef0..dbd8f76 100644 (file)
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 
-static DEFINE_SPINLOCK(mmu_context_lock);
 static DEFINE_IDA(mmu_context_ida);
 
 static int alloc_context_id(int min_id, int max_id)
 {
-       int index, err;
-
-again:
-       if (!ida_pre_get(&mmu_context_ida, GFP_KERNEL))
-               return -ENOMEM;
-
-       spin_lock(&mmu_context_lock);
-       err = ida_get_new_above(&mmu_context_ida, min_id, &index);
-       spin_unlock(&mmu_context_lock);
-
-       if (err == -EAGAIN)
-               goto again;
-       else if (err)
-               return err;
-
-       if (index > max_id) {
-               spin_lock(&mmu_context_lock);
-               ida_remove(&mmu_context_ida, index);
-               spin_unlock(&mmu_context_lock);
-               return -ENOMEM;
-       }
-
-       return index;
+       return ida_alloc_range(&mmu_context_ida, min_id, max_id, GFP_KERNEL);
 }
 
 void hash__reserve_context_id(int id)
 {
-       int rc, result = 0;
-
-       do {
-               if (!ida_pre_get(&mmu_context_ida, GFP_KERNEL))
-                       break;
-
-               spin_lock(&mmu_context_lock);
-               rc = ida_get_new_above(&mmu_context_ida, id, &result);
-               spin_unlock(&mmu_context_lock);
-       } while (rc == -EAGAIN);
+       int result = ida_alloc_range(&mmu_context_ida, id, id, GFP_KERNEL);
 
        WARN(result != id, "mmu: Failed to reserve context id %d (rc %d)\n", id, result);
 }
@@ -172,9 +140,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 
 void __destroy_context(int context_id)
 {
-       spin_lock(&mmu_context_lock);
-       ida_remove(&mmu_context_ida, context_id);
-       spin_unlock(&mmu_context_lock);
+       ida_free(&mmu_context_ida, context_id);
 }
 EXPORT_SYMBOL_GPL(__destroy_context);
 
@@ -182,13 +148,11 @@ static void destroy_contexts(mm_context_t *ctx)
 {
        int index, context_id;
 
-       spin_lock(&mmu_context_lock);
        for (index = 0; index < ARRAY_SIZE(ctx->extended_id); index++) {
                context_id = ctx->extended_id[index];
                if (context_id)
-                       ida_remove(&mmu_context_ida, context_id);
+                       ida_free(&mmu_context_ida, context_id);
        }
-       spin_unlock(&mmu_context_lock);
 }
 
 static void pte_frag_destroy(void *pte_frag)
@@ -200,9 +164,9 @@ static void pte_frag_destroy(void *pte_frag)
        /* drop all the pending references */
        count = ((unsigned long)pte_frag & ~PAGE_MASK) >> PTE_FRAG_SIZE_SHIFT;
        /* We allow PTE_FRAG_NR fragments from a PTE page */
-       if (page_ref_sub_and_test(page, PTE_FRAG_NR - count)) {
+       if (atomic_sub_and_test(PTE_FRAG_NR - count, &page->pt_frag_refcount)) {
                pgtable_page_dtor(page);
-               free_unref_page(page);
+               __free_page(page);
        }
 }
 
@@ -215,13 +179,13 @@ static void pmd_frag_destroy(void *pmd_frag)
        /* drop all the pending references */
        count = ((unsigned long)pmd_frag & ~PAGE_MASK) >> PMD_FRAG_SIZE_SHIFT;
        /* We allow PTE_FRAG_NR fragments from a PTE page */
-       if (page_ref_sub_and_test(page, PMD_FRAG_NR - count)) {
+       if (atomic_sub_and_test(PMD_FRAG_NR - count, &page->pt_frag_refcount)) {
                pgtable_pmd_page_dtor(page);
-               free_unref_page(page);
+               __free_page(page);
        }
 }
 
-static void destroy_pagetable_page(struct mm_struct *mm)
+static void destroy_pagetable_cache(struct mm_struct *mm)
 {
        void *frag;
 
@@ -244,13 +208,14 @@ void destroy_context(struct mm_struct *mm)
                WARN_ON(process_tb[mm->context.id].prtb0 != 0);
        else
                subpage_prot_free(mm);
-       destroy_pagetable_page(mm);
        destroy_contexts(&mm->context);
        mm->context.id = MMU_NO_CONTEXT;
 }
 
 void arch_exit_mmap(struct mm_struct *mm)
 {
+       destroy_pagetable_cache(mm);
+
        if (radix_enabled()) {
                /*
                 * Radix doesn't have a valid bit in the process table