diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
index a9c15515bfd7..a1f9641a6425 100644
--- a/arch/blackfin/kernel/kgdb.c
+++ b/arch/blackfin/kernel/kgdb.c
@@ -203,6 +203,8 @@ struct hw_breakpoint {
 
 int kgdb_arch_init(void)
 {
+	debugger_step = 0;
+
 	kgdb_remove_all_hw_break();
 	return 0;
 }
@@ -368,6 +370,7 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
 	char *ptr;
 	int newPC;
 	int wp_status;
+	int i;
 
 	switch (remcom_in_buffer[0]) {
 	case 'c':
@@ -392,7 +395,18 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
 		/* set the trace bit if we're stepping */
 		if (remcom_in_buffer[0] == 's') {
 			linux_regs->syscfg |= 0x1;
-			debugger_step = 1;
+			debugger_step = linux_regs->ipend;
+			debugger_step >>= 6;
+			for (i = 10; i > 0; i--, debugger_step >>= 1)
+				if (debugger_step & 1)
+					break;
+			/* i indicate event priority of current stopped instruction
+			 * user space instruction is 0, IVG15 is 1, IVTMR is 10.
+			 * debugger_step > 0 means in single step mode
+			 */
+			debugger_step = i + 1;
+		} else {
+			debugger_step = 0;
 		}
 
 		wp_status = bfin_read_WPSTAT();
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 038f70e0be65..eceb484d90f9 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -158,23 +158,45 @@ ENTRY(_ex_single_step)
 	cc = r7 == r6;
 	if cc jump _bfin_return_from_exception;
 
+	/* Don't do single step in hardware exception handler */
+        p5.l = lo(IPEND);
+        p5.h = hi(IPEND);
+	r6 = [p5];
+	cc = bittst(r6, 5);
+	if cc jump _bfin_return_from_exception;
+
+#ifdef CONFIG_KGDB
+	/* skip single step if current interrupt priority is higher than
+	 * that of the first instruction, from which gdb starts single step */
+	r6 >>= 6;
+	r7 = 10;
+.Lfind_priority_start:
+	cc = bittst(r6, 0);
+	if cc jump .Lfind_priority_done;
+	r6 >>= 1;
+	r7 += -1;
+	cc = r7 == 0;
+	if cc jump .Lfind_priority_done;
+	jump.s .Lfind_priority_start;
+.Lfind_priority_done:
+	p4.l = _debugger_step;
+	p4.h = _debugger_step;
+	r6 = [p4];
+	cc = r6 == 0;
+	if cc jump .Ldo_single_step;
+	r6 += -1;
+	cc = r6 < r7;
+	if cc jump _bfin_return_from_exception;
+.Ldo_single_step:
+#endif
+
 	/* If we were in user mode, do the single step normally.  */
-	p5.l = lo(IPEND);
-	p5.h = hi(IPEND);
 	r6 = [p5];
 	r7 = 0xffe0 (z);
 	r7 = r7 & r6;
 	cc = r7 == 0;
-	if !cc jump 1f;
+	if cc jump 1f;
 
-	/* Single stepping only a single instruction, so clear the trace
-	 * bit here.  */
-	r7 = syscfg;
-	bitclr (r7, 0);
-	syscfg = R7;
-	jump _ex_trap_c;
-
-1:
 	/*
 	 * We were in an interrupt handler.  By convention, all of them save
 	 * SYSCFG with their first instruction, so by checking whether our
@@ -202,11 +224,15 @@ ENTRY(_ex_single_step)
 	cc = R7 == R6;
 	if !cc jump _bfin_return_from_exception;
 
+1:
+	/* Single stepping only a single instruction, so clear the trace
+	 * bit here.  */
 	r7 = syscfg;
 	bitclr (r7, 0);
 	syscfg = R7;
 
-	/* Fall through to _bfin_return_from_exception.  */
+	jump _ex_trap_c;
+
 ENDPROC(_ex_single_step)
 
 ENTRY(_bfin_return_from_exception)