Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5e696e5 authored by Greg Ungerer's avatar Greg Ungerer Committed by Ralf Baechle
Browse files

MIPS: 64-bit: Fix system lockup.



The address range size calculation inside local_flush_tlb_kernel_range()
is being truncated by a too small size variable holder on 64-bit systems.
The truncated size can result in an erroneous tlbsize check that means we
sit spinning inside a loop trying to flush a hige number of TLB entries.
This is for all intents and purposes a system hang. Fix by using an
appropriately sized valiable to hold the size.

[Ralf: Greg's original patch submission identified the issue and fixed one
instance in tlb-r4k.c but there there were several more.  For consistency
I also modified tlb-r3k.c even though that file is only used on 32-bit.]

Signed-off-by: default avatarGreg Ungerer <gerg@snapgear.com>
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 195d1a96
Loading
Loading
Loading
Loading
+2 −4
Original line number Original line Diff line number Diff line
@@ -82,8 +82,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
	int cpu = smp_processor_id();
	int cpu = smp_processor_id();


	if (cpu_context(cpu, mm) != 0) {
	if (cpu_context(cpu, mm) != 0) {
		unsigned long flags;
		unsigned long size, flags;
		int size;


#ifdef DEBUG_TLB
#ifdef DEBUG_TLB
		printk("[tlbrange<%lu,0x%08lx,0x%08lx>]",
		printk("[tlbrange<%lu,0x%08lx,0x%08lx>]",
@@ -121,8 +120,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,


void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
{
	unsigned long flags;
	unsigned long size, flags;
	int size;


#ifdef DEBUG_TLB
#ifdef DEBUG_TLB
	printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", start, end);
	printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", start, end);
+2 −4
Original line number Original line Diff line number Diff line
@@ -117,8 +117,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
	int cpu = smp_processor_id();
	int cpu = smp_processor_id();


	if (cpu_context(cpu, mm) != 0) {
	if (cpu_context(cpu, mm) != 0) {
		unsigned long flags;
		unsigned long size, flags;
		int size;


		ENTER_CRITICAL(flags);
		ENTER_CRITICAL(flags);
		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
@@ -160,8 +159,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,


void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
{
	unsigned long flags;
	unsigned long size, flags;
	int size;


	ENTER_CRITICAL(flags);
	ENTER_CRITICAL(flags);
	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+1 −2
Original line number Original line Diff line number Diff line
@@ -111,8 +111,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
/* Usable for KV1 addresses only! */
/* Usable for KV1 addresses only! */
void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
{
	unsigned long flags;
	unsigned long size, flags;
	int size;


	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
	size = (size + 1) >> 1;
	size = (size + 1) >> 1;