Merge tag 'locks-v4.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton...
[sfrench/cifs-2.6.git] / arch / powerpc / include / asm / mmu_context.h
index 79d570cbf3325c0e2c67f648badf6edd3dbcd730..b2f89b621b159148c6d836e3c9c3d47a89aafe47 100644 (file)
@@ -143,24 +143,33 @@ static inline void mm_context_remove_copro(struct mm_struct *mm)
 {
        int c;
 
-       c = atomic_dec_if_positive(&mm->context.copros);
-
-       /* Detect imbalance between add and remove */
-       WARN_ON(c < 0);
-
        /*
-        * Need to broadcast a global flush of the full mm before
-        * decrementing active_cpus count, as the next TLBI may be
-        * local and the nMMU and/or PSL need to be cleaned up.
-        * Should be rare enough so that it's acceptable.
+        * When removing the last copro, we need to broadcast a global
+        * flush of the full mm, as the next TLBI may be local and the
+        * nMMU and/or PSL need to be cleaned up.
+        *
+        * Both the 'copros' and 'active_cpus' counts are looked at in
+        * flush_all_mm() to determine the scope (local/global) of the
+        * TLBIs, so we need to flush first before decrementing
+        * 'copros'. If this API is used by several callers for the
+        * same context, it can lead to over-flushing. It's hopefully
+        * not common enough to be a problem.
         *
         * Skip on hash, as we don't know how to do the proper flush
         * for the time being. Invalidations will remain global if
-        * used on hash.
+        * used on hash. Note that we can't drop 'copros' either, as
+        * it could make some invalidations local with no flush
+        * in-between.
         */
-       if (c == 0 && radix_enabled()) {
+       if (radix_enabled()) {
                flush_all_mm(mm);
-               dec_mm_active_cpus(mm);
+
+               c = atomic_dec_if_positive(&mm->context.copros);
+               /* Detect imbalance between add and remove */
+               WARN_ON(c < 0);
+
+               if (c == 0)
+                       dec_mm_active_cpus(mm);
        }
 }
 #else