Skip to contentSkip to conversation

First crack at preemption support for IA64

Linux-ia64 Peter Chubb 1 participant 1 message Nov 15, 2002

lore
Share & tools
lore
#0 lore raw

Hi folks,
Here's my first go at preemption support for IA64. I've tested it
on the simulator and I2000 UP. It's very rough around the edges (especially in entry.S), but someone may have some useful comments for me... so it's being released here.

So far, it appears that response to mouse movememnts ont eh console, etc., is *more* jerky with the preempt turned on than without.

Expect a warning from the IDE code when you boot, too. You'll get the same thing on IA32 with CONFIG_PREEMPT.

The stuff in entry.S is hard to follow. The pseudocode works like this:

ia64_leave_kernel(bool pKern, bool pUser, machine_context_t ctx)

{
	local_irq_disable();
	while (pUser && current->threadinfo->flags & (RESCHED | NOTIFY) ||
	      pKern && preempt_count = 0 &&
		    current->threadinfo->flags & RESCHED) {
		  if (pKern)
			preempt_count() = PREEMPT_ACTIVE;
		   if (current->threadinfo->flags & RESCHED)
		        schedule();
	           else
		        notify_resume();
		   local_irq_disable()
		   if (pKern)
		      preempt_count() = 0;
        }
	set_context(ctx);
}

but the set_context is effectively done in parallel with all of the other stuff.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.815 -> 1.816
# arch/ia64/kernel/entry.S 1.21 -> 1.22
# include/asm-ia64/hardirq.h 1.10 -> 1.11
# arch/ia64/Config.help 1.10 -> 1.11
# arch/ia64/kernel/efivars.c 1.8 -> 1.9
# arch/ia64/hp/sim/simserial.c 1.9 -> 1.10
# include/asm-ia64/thread_info.h 1.5 -> 1.6
# arch/ia64/config.in 1.36 -> 1.37
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/11/15 [email protected] 1.816
# Preliminary preemption support.
# --------------------------------------------
#

arch/ia64/Config.help +10 -0
diff -Nru a/arch/ia64/Config.help b/arch/ia64/Config.help
@@ -567,3 +567,13 @@
 
   Select "16MB" for a small granule size.
   Select "64MB" for a large granule size.  This is the current default.
+
+CONFIG_PREEMPT
+  This option reduces the latency of the kernel when reacting to
+  real-time or interactive events by allowing a low priority process to
+  be preempted even if it is in kernel mode executing a system call.
+  This allows applications to run more reliably even when the system is
+  under load.
+
+  Say Y here if you are building a kernel for a desktop, embedded
+  or real-time system.  Say N if you are unsure.
arch/ia64/config.in +1 -0
diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in
@@ -117,6 +117,7 @@
 fi
 
 bool 'SMP support' CONFIG_SMP
+bool 'Preemptible Kernel' CONFIG_PREEMPT
 bool 'Support running of Linux/x86 binaries' CONFIG_IA32_SUPPORT
 bool 'Performance monitor support' CONFIG_PERFMON
 tristate '/proc/pal support' CONFIG_IA64_PALINFO
arch/ia64/hp/sim/simserial.c +29 -21

157 lines not on this page · raw message

arch/ia64/kernel/efivars.c +6 -2
diff -Nru a/arch/ia64/kernel/efivars.c b/arch/ia64/kernel/efivars.c
@@ -66,6 +66,7 @@
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/efi.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -342,6 +343,9 @@
 
 
 
+/*
+ * Called with BKL held
+ */
 static int __init
 efivars_init(void)
 {
@@ -351,10 +355,11 @@
 	efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);
 	unsigned long variable_name_size = 1024;
 
-	spin_lock(&efivars_lock);
 
 	printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION);
 
+        BUG_ON(!kernel_locked());
+
         /* Since efi.c happens before procfs is available,
            we create the directory here if it doesn't
            already exist.  There's probably a better way
@@ -398,7 +403,6 @@
 	} while (status != EFI_NOT_FOUND);
 
 	kfree(variable_name);
-	spin_unlock(&efivars_lock);
 	return 0;
 }
 
arch/ia64/kernel/entry.S +18 -4
diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
@@ -570,10 +570,16 @@
 GLOBAL_ENTRY(ia64_leave_kernel)
 	PT_REGS_UNWIND_INFO(0)
 	// work.need_resched etc. mustn't get changed by this CPU before it returns to userspace:
+.work_recheck:
 (pUser)	cmp.eq.unc p6,p0=r0,r0			// p6 <- pUser
-(pUser)	rsm psr.i
+	rsm psr.i				// disable interrupts
 	;;
-(pUser)	adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
+	adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
+(pKern) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
+	;;
+(pKern) ld4  r21=[r20]			// preempt_count ->r21
+	;;
+(pKern)	cmp.eq	p6,p0=r21,r0
 	;;
 .work_processed:
 (p6)	ld4 r18=[r17]				// load current_thread_info()->flags
@@ -802,6 +808,11 @@
 .work_pending:
 	tbit.z p6,p0=r18,TIF_NEED_RESCHED		// current_thread_info()->need_resched=0?
 (p6)	br.cond.sptk.few .notify
+(pKern)	dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1
+	;;
+(pKern) ssm psr.i
+(pKern) st4 [r20]=r21
+	
 #if __GNUC__ < 3
 	br.call.spnt.many rp=invoke_schedule
 #else
@@ -811,6 +822,9 @@
 	rsm psr.i
 	;;
 	adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
+	adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
+	;;
+	st8 [r20]=r0
 	br.cond.sptk.many .work_processed		// re-check
 
 .notify:
@@ -844,7 +858,7 @@
 	br.cond.sptk ia64_leave_kernel
 END(handle_syscall_error)
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 	/*
 	 * Invoke schedule_tail(task) while preserving in0-in7, which may be needed
 	 * in case a system call gets restarted.
@@ -861,7 +875,7 @@
 	br.ret.sptk.many rp
 END(ia64_invoke_schedule_tail)
 
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_SMP || CONFIG_PREEMPT */
 
 #if __GNUC__ < 3
 
include/asm-ia64/hardirq.h +2 -2
diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h
@@ -83,13 +83,13 @@
 #define hardirq_trylock()	(!in_interrupt())
 #define hardirq_endlock()	do { } while (0)
 
-#define in_atomic()		(preempt_count() != 0)
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
 #if CONFIG_PREEMPT
-# error CONFIG_PREEMT currently not supported.
+# define in_atomic()		((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
+# define in_atomic()		(preempt_count() != 0)
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 
include/asm-ia64/thread_info.h +2 -1
diff -Nru a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
@@ -15,7 +15,8 @@
 #define TI_ADDR_LIMIT	0x10
 #define TI_PRE_COUNT	0x18
 
-#define PREEMPT_ACTIVE	0x4000000
+#define PREEMPT_ACTIVE_BIT 26
+#define PREEMPT_ACTIVE	(1<<PREEMPT_ACTIVE_BIT)
 
 #ifndef __ASSEMBLY__
 

--
Dr Peter Chubb [email protected]
You are lost in a maze of BitKeeper repositories, all almost the same.