MIPS: 64-bit: Fix system lockup.
authorGreg Ungerer <gerg@snapgear.com>
Wed, 20 May 2009 06:12:32 +0000 (16:12 +1000)
committerRalf Baechle <ralf@linux-mips.org>
Wed, 20 May 2009 17:53:14 +0000 (18:53 +0100)
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: Greg Ungerer <gerg@snapgear.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/mm/tlb-r3k.c
arch/mips/mm/tlb-r4k.c
arch/mips/mm/tlb-r8k.c

index f0cf46a..1c0048a 100644 (file)
@@ -82,8 +82,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        int cpu = smp_processor_id();
 
        if (cpu_context(cpu, mm) != 0) {
-               unsigned long flags;
-               int size;
+               unsigned long size, flags;
 
 #ifdef DEBUG_TLB
                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)
 {
-       unsigned long flags;
-       int size;
+       unsigned long size, flags;
 
 #ifdef DEBUG_TLB
        printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", start, end);
index 9619f66..892be42 100644 (file)
@@ -117,8 +117,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        int cpu = smp_processor_id();
 
        if (cpu_context(cpu, mm) != 0) {
-               unsigned long flags;
-               int size;
+               unsigned long size, flags;
 
                ENTER_CRITICAL(flags);
                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)
 {
-       unsigned long flags;
-       int size;
+       unsigned long size, flags;
 
        ENTER_CRITICAL(flags);
        size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
index 4f01a3b..4ec95cc 100644 (file)
@@ -111,8 +111,7 @@ out_restore:
 /* Usable for KV1 addresses only! */
 void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
-       unsigned long flags;
-       int size;
+       unsigned long size, flags;
 
        size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
        size = (size + 1) >> 1;