summary refs log tree commit diff
path: root/arch/blackfin
diff options
context:
space:
mode:
authorRobin Getz <robin.getz@analog.com>2007-10-29 17:20:41 +0800
committerBryan Wu <bryan.wu@analog.com>2007-10-29 17:20:41 +0800
commit885be03b069131d242506f0f717d38659b2bdb6c (patch)
tree52c1858645ee28b9d0bc7166744da3eef5bc6f1f /arch/blackfin
parent64307f7db3690140a16c6748e65068f8a279877c (diff)
downloadlinux-885be03b069131d242506f0f717d38659b2bdb6c.tar.gz
Blackfin arch: fix bug: kernel prints out error message twice
This fixes two things:
 - stop calling write_lock_irq/write_unlock_irq which can turn modify
   irq levels
 - don't calling mmput when handing exceptions - since this might_sleep,
   which does a rti, and leaves us in kernel space (irq15, rather
   than irq5).

Signed-off-by: Robin Getz <robin.getz@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>

Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/kernel/traps.c30
1 files changed, 18 insertions, 12 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index afd044e78af6..ce86659f9b65 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -54,12 +54,13 @@ void __init trap_init(void)
 int kstack_depth_to_print = 48;
 
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
-static int printk_address(unsigned long address)
+static void printk_address(unsigned long address)
 {
 	struct vm_list_struct *vml;
 	struct task_struct *p;
 	struct mm_struct *mm;
-	unsigned long offset;
+	unsigned long flags, offset;
+	unsigned int in_exception = bfin_read_IPEND() & 0x10;
 
 #ifdef CONFIG_KALLSYMS
 	unsigned long symsize;
@@ -75,9 +76,10 @@ static int printk_address(unsigned long address)
 		/* yeah! kernel space! */
 		if (!modname)
 			modname = delim = "";
-		return printk("<0x%p> { %s%s%s%s + 0x%lx }",
+		printk("<0x%p> { %s%s%s%s + 0x%lx }",
 		              (void *)address, delim, modname, delim, symname,
 		              (unsigned long)offset);
+		return;
 
 	}
 #endif
@@ -86,9 +88,9 @@ static int printk_address(unsigned long address)
 	 * mappings of all our processes and see if we can't be a whee
 	 * bit more specific
 	 */
-	write_lock_irq(&tasklist_lock);
+	write_lock_irqsave(&tasklist_lock, flags);
 	for_each_process(p) {
-		mm = get_task_mm(p);
+		mm = (in_exception ? p->mm : get_task_mm(p));
 		if (!mm)
 			continue;
 
@@ -117,20 +119,24 @@ static int printk_address(unsigned long address)
 				else
 					offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
 
-				write_unlock_irq(&tasklist_lock);
-				mmput(mm);
-				return printk("<0x%p> [ %s + 0x%lx ]",
-				              (void *)address, name, offset);
+				printk("<0x%p> [ %s + 0x%lx ]",
+					(void *)address, name, offset);
+				if (!in_exception)
+					mmput(mm);
+				goto done;
 			}
 
 			vml = vml->next;
 		}
-		mmput(mm);
+		if (!in_exception)
+			mmput(mm);
 	}
-	write_unlock_irq(&tasklist_lock);
 
 	/* we were unable to find this address anywhere */
-	return printk("[<0x%p>]", (void *)address);
+	printk("[<0x%p>]", (void *)address);
+
+done:
+	write_unlock_irqrestore(&tasklist_lock, flags);
 }
 #endif