]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
arm64/mm: Optimize TLB flush in unmap_hotplug_[pmd|pud]_range()
authorAnshuman Khandual <anshuman.khandual@arm.com>
Fri, 26 Jun 2026 01:28:45 +0000 (02:28 +0100)
committerWill Deacon <will@kernel.org>
Mon, 29 Jun 2026 11:18:10 +0000 (12:18 +0100)
Commit 48478b9f7913 ("arm64/mm: Enable batched TLB flush in
unmap_hotplug_range") inadvertently introduced redundant TLB
invalidation when clearing a block entry, resulting in unnecessary
broadcast invalidation on CPUs without support for range-based
invalidation.

Re-introduce the old behaviour, along with some expanded comments to
help people working in this area next time around.

Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Reported-by: Ben Hutchings <ben@decadent.org.uk>
Closes: https://lore.kernel.org/all/b0d5836032ce3135bfc473f6bff791306d086925.camel@decadent.org.uk/
Fixes: 48478b9f7913 ("arm64/mm: Enable batched TLB flush in unmap_hotplug_range()")
Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
[will: Reword comments and commit message]
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/mm/mmu.c

index f2be501468ce5a4a336921b743b4eb4472253096..a25d8beacc8310d0dd08dfa0d43633bf0eb1b3dd 100644 (file)
@@ -1515,7 +1515,13 @@ static void unmap_hotplug_pmd_range(pud_t *pudp, unsigned long addr,
                        if (free_mapped) {
                                /* CONT blocks are not supported in the vmemmap */
                                WARN_ON(pmd_cont(pmd));
-                               flush_tlb_kernel_range(addr, addr + PMD_SIZE);
+                               /*
+                                * Invalidating a block entry requires just
+                                * a single overlapping TLB invalidation,
+                                * so limit the range of the flush to a single
+                                * page.
+                                */
+                               flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
                                free_hotplug_page_range(pmd_page(pmd),
                                                        PMD_SIZE, altmap);
                        }
@@ -1545,7 +1551,8 @@ static void unmap_hotplug_pud_range(p4d_t *p4dp, unsigned long addr,
                if (pud_leaf(pud)) {
                        pud_clear(pudp);
                        if (free_mapped) {
-                               flush_tlb_kernel_range(addr, addr + PUD_SIZE);
+                               /* See comment in unmap_hotplug_pmd_range(). */
+                               flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
                                free_hotplug_page_range(pud_page(pud),
                                                        PUD_SIZE, altmap);
                        }