Skip to content

Commit

Permalink
sparc64: Guard against flushing openfirmware mappings.
Browse files Browse the repository at this point in the history
[ Upstream commit 4ca9a23 ]

Based almost entirely upon a patch by Christopher Alexander Tobias
Schulze.

In commit db64fe0 ("mm: rewrite vmap
layer") lazy VMAP tlb flushing was added to the vmalloc layer.  This
causes problems on sparc64.

Sparc64 has two VMAP mapped regions and they are not contiguous with
eachother.  First we have the malloc mapping area, then another
unrelated region, then the vmalloc region.

This "another unrelated region" is where the firmware is mapped.

If the lazy TLB flushing logic in the vmalloc code triggers after
we've had both a module unload and a vfree or similar, it will pass an
address range that goes from somewhere inside the malloc region to
somewhere inside the vmalloc region, and thus covering the
openfirmware area entirely.

The sparc64 kernel learns about openfirmware's dynamic mappings in
this region early in the boot, and then services TLB misses in this
area.  But openfirmware has some locked TLB entries which are not
mentioned in those dynamic mappings and we should thus not disturb
them.

These huge lazy TLB flush ranges causes those openfirmware locked TLB
entries to be removed, resulting in all kinds of problems including
hard hangs and crashes during reboot/reset.

Besides causing problems like this, such huge TLB flush ranges are
also incredibly inefficient.  A plea has been made with the author of
the VMAP lazy TLB flushing code, but for now we'll put a safety guard
into our flush_tlb_kernel_range() implementation.

Since the implementation has become non-trivial, stop defining it as a
macro and instead make it a function in a C source file.

Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
David S. Miller authored and Greg Kroah-Hartman committed Aug 14, 2014
1 parent 5b36a75 commit 38f4577
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
12 changes: 2 additions & 10 deletions arch/sparc/include/asm/tlbflush_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
{
}

void flush_tlb_kernel_range(unsigned long start, unsigned long end);

#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE

extern void flush_tlb_pending(void);
Expand All @@ -49,11 +51,6 @@ extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);

#ifndef CONFIG_SMP

#define flush_tlb_kernel_range(start,end) \
do { flush_tsb_kernel_range(start,end); \
__flush_tlb_kernel_range(start,end); \
} while (0)

static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
{
__flush_tlb_page(CTX_HWBITS(mm->context), vaddr);
Expand All @@ -64,11 +61,6 @@ static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vad
extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr);

#define flush_tlb_kernel_range(start, end) \
do { flush_tsb_kernel_range(start,end); \
smp_flush_tlb_kernel_range(start, end); \
} while (0)

#define global_flush_tlb_page(mm, vaddr) \
smp_flush_tlb_page(mm, vaddr)

Expand Down
23 changes: 23 additions & 0 deletions arch/sparc/mm/init_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -2768,3 +2768,26 @@ void hugetlb_setup(struct pt_regs *regs)
}
}
#endif

#ifdef CONFIG_SMP
#define do_flush_tlb_kernel_range smp_flush_tlb_kernel_range
#else
#define do_flush_tlb_kernel_range __flush_tlb_kernel_range
#endif

void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
if (start < HI_OBP_ADDRESS && end > LOW_OBP_ADDRESS) {
if (start < LOW_OBP_ADDRESS) {
flush_tsb_kernel_range(start, LOW_OBP_ADDRESS);
do_flush_tlb_kernel_range(start, LOW_OBP_ADDRESS);
}
if (end > HI_OBP_ADDRESS) {
flush_tsb_kernel_range(end, HI_OBP_ADDRESS);
do_flush_tlb_kernel_range(end, HI_OBP_ADDRESS);
}
} else {
flush_tsb_kernel_range(start, end);
do_flush_tlb_kernel_range(start, end);
}
}

0 comments on commit 38f4577

Please sign in to comment.