[PARISC] Add PREEMPT support
authorKyle McMartin <kyle@parisc-linux.org>
Sat, 25 Mar 2006 04:24:21 +0000 (21:24 -0700)
committerKyle McMartin <kyle@hera.kernel.org>
Thu, 30 Mar 2006 17:48:54 +0000 (17:48 +0000)
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
arch/parisc/Kconfig
arch/parisc/kernel/entry.S
include/asm-parisc/thread_info.h

index 6b3c50964ca9e79bfd2ba2fcb8f1a30968f91278..2fdf21989dc20a88d0d288bdf190dd3837bf8aaf 100644 (file)
@@ -177,14 +177,10 @@ config ARCH_DISCONTIGMEM_DEFAULT
        def_bool y
        depends on ARCH_DISCONTIGMEM_ENABLE
 
+source "kernel/Kconfig.preempt"
 source "kernel/Kconfig.hz"
 source "mm/Kconfig"
 
-config PREEMPT
-       bool
-#      bool "Preemptible Kernel"
-       default n
-
 config COMPAT
        def_bool y
        depends on 64BIT
index 6d17c0a3431b63d293db6e30e0e7e5c6051d8595..7c95d7663c299980913a4c56ff144e226dac74fc 100644 (file)
@@ -1014,14 +1014,21 @@ intr_restore:
        nop
        nop
 
+#ifndef CONFIG_PREEMPT
+# define intr_do_preempt       intr_restore
+#endif /* !CONFIG_PREEMPT */
+
        .import schedule,code
 intr_do_resched:
-       /* Only do reschedule if we are returning to user space */
+       /* Only call schedule on return to userspace. If we're returning
+        * to kernel space, we may schedule if CONFIG_PREEMPT, otherwise
+        * we jump back to intr_restore.
+        */
        LDREG   PT_IASQ0(%r16), %r20
-       CMPIB= 0,%r20,intr_restore /* backward */
+       CMPIB=  0, %r20, intr_do_preempt
        nop
        LDREG   PT_IASQ1(%r16), %r20
-       CMPIB= 0,%r20,intr_restore /* backward */
+       CMPIB=  0, %r20, intr_do_preempt
        nop
 
 #ifdef CONFIG_64BIT
@@ -1037,6 +1044,32 @@ intr_do_resched:
 #endif
        ldo     R%intr_check_sig(%r2), %r2
 
+       /* preempt the current task on returning to kernel
+        * mode from an interrupt, iff need_resched is set,
+        * and preempt_count is 0. otherwise, we continue on
+        * our merry way back to the current running task.
+        */
+#ifdef CONFIG_PREEMPT
+       .import preempt_schedule_irq,code
+intr_do_preempt:
+       rsm     PSW_SM_I, %r0           /* disable interrupts */
+
+       /* current_thread_info()->preempt_count */
+       mfctl   %cr30, %r1
+       LDREG   TI_PRE_COUNT(%r1), %r19
+       CMPIB<> 0, %r19, intr_restore   /* if preempt_count > 0 */
+       nop                             /* prev insn branched backwards */
+
+       /* check if we interrupted a critical path */
+       LDREG   PT_PSW(%r16), %r20
+       bb,<,n  %r20, 31 - PSW_SM_I, intr_restore
+       nop
+
+       BL      preempt_schedule_irq, %r2
+       nop
+
+       b       intr_restore            /* ssm PSW_SM_I done by intr_restore */
+#endif /* CONFIG_PREEMPT */
 
        .import do_signal,code
 intr_do_signal:
index ac32f140b83aa1135259d63d615eb4baf4eafdac..f2f83b04cd8b8fad0c1bc5c19fa3b839d5cc1704 100644 (file)
@@ -49,7 +49,8 @@ struct thread_info {
 
 #endif /* !__ASSEMBLY */
 
-#define PREEMPT_ACTIVE          0x10000000
+#define PREEMPT_ACTIVE_BIT     28
+#define PREEMPT_ACTIVE         (1 << PREEMPT_ACTIVE_BIT)
 
 /*
  * thread information flags