Blackfin: initial preempt support while returning from interrupt
authorBarry Song <barry.song@analog.com>
Thu, 12 Aug 2010 07:56:40 +0000 (07:56 +0000)
committerMike Frysinger <vapier@gentoo.org>
Fri, 22 Oct 2010 07:48:55 +0000 (03:48 -0400)
Signed-off-by: Barry Song <barry.song@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/interrupt.S

index af1bffa21dc14dccdefca16268da5c737024dfa8..16ea779c3a6f87c928b3d93d9836438b16b72e3d 100644 (file)
@@ -889,6 +889,66 @@ ENTRY(_ret_from_exception)
        rts;
 ENDPROC(_ret_from_exception)
 
+#if defined(CONFIG_PREEMPT)
+
+ENTRY(_up_to_irq14)
+#if ANOMALY_05000281 || ANOMALY_05000461
+       r0.l = lo(SAFE_USER_INSTRUCTION);
+       r0.h = hi(SAFE_USER_INSTRUCTION);
+       reti = r0;
+#endif
+
+#ifdef CONFIG_DEBUG_HWERR
+       /* enable irq14 & hwerr interrupt, until we transition to _evt_evt14 */
+       r0 = (EVT_IVG14 | EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#else
+       /* Only enable irq14 interrupt, until we transition to _evt_evt14 */
+       r0 = (EVT_IVG14 | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#endif
+       sti r0;
+
+       p0.l = lo(EVT14);
+       p0.h = hi(EVT14);
+       p1.l = _evt_up_evt14;
+       p1.h = _evt_up_evt14;
+       [p0] = p1;
+       csync;
+
+       raise 14;
+1:
+       jump 1b;
+ENDPROC(_up_to_irq14)
+
+ENTRY(_evt_up_evt14)
+#ifdef CONFIG_DEBUG_HWERR
+       r0 = (EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+       sti r0;
+#else
+       cli r0;
+#endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+       [--sp] = rets;
+       sp += -12;
+       call _trace_hardirqs_off;
+       sp += 12;
+       rets = [sp++];
+#endif
+       [--sp] = RETI;
+       SP += 4;
+
+       /* restore normal evt14 */
+       p0.l = lo(EVT14);
+       p0.h = hi(EVT14);
+       p1.l = _evt_evt14;
+       p1.h = _evt_evt14;
+       [p0] = p1;
+       csync;
+
+       rts;
+ENDPROC(_evt_up_evt14)
+
+#endif
+
 #ifdef CONFIG_IPIPE
 
 _resume_kernel_from_int:
@@ -902,8 +962,54 @@ _resume_kernel_from_int:
        ( r7:4, p5:3 ) = [sp++];
        rets = [sp++];
        rts
+#elif defined(CONFIG_PREEMPT)
+
+_resume_kernel_from_int:
+       /* check preempt_count */
+       r7 = sp;
+       r4.l = lo(ALIGN_PAGE_MASK);
+       r4.h = hi(ALIGN_PAGE_MASK);
+       r7 = r7 & r4;
+       p5 = r7;
+       r7 = [p5 + TI_PREEMPT];
+       cc = r7 == 0x0;
+       if !cc jump .Lreturn_to_kernel;
+.Lneed_schedule:
+       r7 = [p5 + TI_FLAGS];
+       r4.l = lo(_TIF_WORK_MASK);
+       r4.h = hi(_TIF_WORK_MASK);
+       r7 =  r7 & r4;
+       cc = BITTST(r7, TIF_NEED_RESCHED);
+       if !cc jump .Lreturn_to_kernel;
+       /*
+        * let schedule done at level 15, otherwise sheduled process will run
+        * at high level and block low level interrupt
+        */
+       r6 = reti;  /* save reti */
+       r5.l = .Lkernel_schedule;
+       r5.h = .Lkernel_schedule;
+       reti = r5;
+       rti;
+.Lkernel_schedule:
+       [--sp] = rets;
+       sp += -12;
+       pseudo_long_call _preempt_schedule_irq, p4;
+       sp += 12;
+       rets = [sp++];
+
+       [--sp] = rets;
+       sp += -12;
+       /* up to irq14 so that reti after restore_all can return to irq15(kernel) */
+       pseudo_long_call _up_to_irq14, p4;
+       sp += 12;
+       rets = [sp++];
+
+       reti = r6; /* restore reti so that origin process can return to interrupted point */
+
+       jump .Lneed_schedule;
 #else
-#define _resume_kernel_from_int         2f
+
+#define _resume_kernel_from_int        .Lreturn_to_kernel
 #endif
 
 ENTRY(_return_from_int)
@@ -913,7 +1019,7 @@ ENTRY(_return_from_int)
        p2.h = hi(ILAT);
        r0 = [p2];
        cc = bittst (r0, EVT_IVG15_P);
-       if cc jump 2f;
+       if cc jump .Lreturn_to_kernel;
 
        /* if not return to user mode, get out */
        p2.l = lo(IPEND);
@@ -945,7 +1051,7 @@ ENTRY(_return_from_int)
        STI r0;
        raise 15;       /* raise evt15 to do signal or reschedule */
        rti;
-2:
+.Lreturn_to_kernel:
        rts;
 ENDPROC(_return_from_int)
 
index cee62cf4acd429d07b4d84991c6e088f795a1eb4..2df37db3b49b60dbe9df7e768b0fb31cf5946c69 100644 (file)
@@ -116,7 +116,24 @@ __common_int_entry:
        cc = r0 == 0;
        if cc jump .Lcommon_restore_context;
 #else /* CONFIG_IPIPE */
+
+#ifdef CONFIG_PREEMPT
+       r7 = sp;
+       r4.l = lo(ALIGN_PAGE_MASK);
+       r4.h = hi(ALIGN_PAGE_MASK);
+       r7 = r7 & r4;
+       p5 = r7;
+       r7 = [p5 + TI_PREEMPT]; /* get preempt count */
+       r7 += 1;                /* increment it */
+       [p5 + TI_PREEMPT] = r7;
+#endif
        pseudo_long_call _do_irq, p2;
+
+#ifdef CONFIG_PREEMPT
+       r7 += -1;
+       [p5 + TI_PREEMPT] = r7; /* restore preempt count */
+#endif
+
        SP += 12;
 #endif /* CONFIG_IPIPE */
        pseudo_long_call _return_from_int, p2;