{
        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