diff -urN tslinux-3-0-x86/src/kernel/Makefile PA-timesys/kernel/Makefile --- tslinux-3-0-x86/src/kernel/Makefile Sun Nov 18 01:36:43 2001 +++ PA-timesys/kernel/Makefile Fri Mar 1 15:12:26 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 7 -EXTRAVERSION = -timesys-3.0.108 +EXTRAVERSION = -timesys-3.0.108-pa2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN tslinux-3-0-x86/src/kernel/arch/i386/kernel/entry.S PA-timesys/kernel/arch/i386/kernel/entry.S --- tslinux-3-0-x86/src/kernel/arch/i386/kernel/entry.S Wed Sep 26 15:24:16 2001 +++ PA-timesys/kernel/arch/i386/kernel/entry.S Fri Mar 1 15:41:40 2002 @@ -786,8 +786,18 @@ .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* 225 */ + .long SYMBOL_NAME(sys_ni_syscall) /* PAOS: reserve 226-230 */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_getboost) /* PAOS: get cpu boost */ + .long SYMBOL_NAME(sys_setboost) /* PAOS: set cpu boost */ - .rept 398 - 223 + .rept 398 - 233 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -urN tslinux-3-0-x86/src/kernel/arch/i386/kernel/process.c PA-timesys/kernel/arch/i386/kernel/process.c --- tslinux-3-0-x86/src/kernel/arch/i386/kernel/process.c Wed Sep 26 15:24:16 2001 +++ PA-timesys/kernel/arch/i386/kernel/process.c Fri Mar 1 18:54:17 2002 @@ -598,6 +598,88 @@ : /* no output */ \ :"r" (thread->debugreg[register])) + +/* =========================================================== + * PAOS: power-aware stuff + * + * To set the cpu speed, we simply write a value to + * the processor MSR (model-specific register) for + * longrun processor control. + * + * The hardware settings are taken from longrun.c, + * a utility which Transmeta has made available at + * ftp://ftp.kernel.org/pub/linux/utils/cpu/crusoe/ + * + * The functions for reading and writing to model- + * specific registers are taken from msr.c file in + * this directory. + * + * Enjoy! + * =========================================================== */ + +/* + * PAOS: Longrun Hardware settings (from longrun.c) + */ +#define MSR_TMx86_LONGRUN 0x80868010 +#define MSR_TMx86_LONGRUN_FLAGS 0x80868011 +#define LONGRUN_MASK(x) ((x) & 0x0000007f) +#define LONGRUN_RESERVED(x) ((x) & 0xffffff80) +#define LONGRUN_WRITE(x, y) (LONGRUN_RESERVED(x) | LONGRUN_MASK(y)) + +/* + * PAOS: Read from a model-specific register (from msr.c) + */ +inline int rd_msr(u32 reg, u32 *eax, u32 *edx) +{ + int err; + + asm volatile( + "1: rdmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "=&bDS" (err), "=a" (*eax), "=d" (*edx) + : "c" (reg), "i" (-EIO), "0" (0)); + + return err; +} + +/* + * PAOS: Write to a model-specific register (from msr.c) + */ +inline int wr_msr(u32 reg, u32 eax, u32 edx) +{ + int err; + + asm volatile( + "1: wrmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "=&bDS" (err) + : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0)); + + return err; +} + +/* =========================================================== + * PAOS: end of power-aware support functions + * =========================================================== */ + + + /* * switch_to(x,yn) should switch tasks from x to y. * @@ -620,6 +702,10 @@ * so the performance issues may eventually be a valid point. * More important, however, is the fact that this allows us much * more flexibility. + * + * PAOS: The switch_to function has been modified; it + * automatically boosts the CPU speed according + * to the user's preference */ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) { @@ -627,6 +713,42 @@ *next = &next_p->thread; struct tss_struct *tss = init_tss + smp_processor_id(); + + /* + * PAOS: we add the following variables, to keep track + * of the user-specified CPU boost for the process + */ + int lower = 0; + int upper = 0; + int next_boost = next_p->boost; + long save_the_interrupts; + + + /* + * PAOS: Before we do anything drastic, + * disable interrupts + */ + __save_flags(save_the_interrupts); + __cli(); + + /* + * PAOS: read the current Longrun MSR settings into + * 'lower' and 'upper', then write the user-specified + * CPU boost value into the Longrun MSR + * (if that value is different) + */ + if ((rd_msr(MSR_TMx86_LONGRUN, &lower, &upper) >= 0) + && ((lower != next_boost) || (upper != next_boost))) + { + wr_msr(MSR_TMx86_LONGRUN, LONGRUN_WRITE(lower, next_boost), + LONGRUN_WRITE(upper, next_boost)); + } + + /* + * PAOS: Ok, now we can restore the interrupts + */ + __restore_flags(save_the_interrupts); + unlazy_fpu(prev_p); /* diff -urN tslinux-3-0-x86/src/kernel/include/asm-i386/unistd.h PA-timesys/kernel/include/asm-i386/unistd.h --- tslinux-3-0-x86/src/kernel/include/asm-i386/unistd.h Mon Jun 4 16:20:10 2001 +++ PA-timesys/kernel/include/asm-i386/unistd.h Fri Mar 1 18:58:03 2002 @@ -228,6 +228,10 @@ #define __NR_getdents64 220 #define __NR_fcntl64 221 + /* PAOS: reserve 226-230 for expansion */ +#define __NR_getboost 231 /* PAOS: get value of CPU boost */ +#define __NR_setboost 232 /* PAOS: set value of CPU boost */ + /* Hopefully the standard syscalls won't grow this large for a while. */ #define __NR_sched_rr_set_interval 398 #define __NR_setname 399 diff -urN tslinux-3-0-x86/src/kernel/include/linux/sched-defs.h PA-timesys/kernel/include/linux/sched-defs.h --- tslinux-3-0-x86/src/kernel/include/linux/sched-defs.h Sun Nov 18 01:37:58 2001 +++ PA-timesys/kernel/include/linux/sched-defs.h Fri Mar 1 19:49:51 2002 @@ -599,6 +599,9 @@ /* used by measure module */ int sysno; + +/* PAOS: user-specified CPU boost value for the process */ + int boost; } task_struct; @@ -684,8 +687,12 @@ pending: { NULL, &tsk.pending.head, {{0}}}, \ blocked: {{0}}, \ alloc_lock: SPIN_LOCK_UNLOCKED, \ + boost: 0 \ } +/* PAOS: Please note that boost field is in INIT_TASK above */ + + #ifndef INIT_TASK_SIZE # define INIT_TASK_SIZE 2048*sizeof(long) #endif diff -urN tslinux-3-0-x86/src/kernel/kernel/sys.c PA-timesys/kernel/kernel/sys.c --- tslinux-3-0-x86/src/kernel/kernel/sys.c Mon Oct 22 18:37:32 2001 +++ PA-timesys/kernel/kernel/sys.c Fri Mar 1 19:22:15 2002 @@ -261,6 +261,100 @@ return retval; } +/* =========================================================== + * PAOS: power-aware stuff + * + * These functions take care of modifying CPU boost + * values for processes (get and set). If you look + * closely, you'll see that we have pretty much + * cloned the functionality of setpriority and + * getpriority. + * + * The boost value is an integer between 0 and 100 + * inclusive, as followed in the Transmeta Longrun + * utility. + * + * The Transmeta Longrun utility is available at + * ftp://ftp.kernel.org/pub/linux/utils/cpu/crusoe/ + * + * Enjoy! + * =========================================================== */ + +/* + * PAOS: Set the CPU boost for the specified process + */ +asmlinkage long sys_setboost(int which, int who, int boost) +{ + struct task_struct *p; + int error; + + if (which > 2 || which < 0) + return -EINVAL; + + error = -ESRCH; + + /* + * PAOS: We forcibly make sure the boost value is + * between 0 and 100 + */ + if (boost < 0) { + boost = 0; + } else if (boost > 100) { + boost = 100; + } + + read_lock(&tasklist_lock); + for_each_task(p) { + if (!proc_sel(p, which, who)) + continue; + if (p->uid != current->euid && + p->uid != current->uid && !capable(CAP_SYS_NICE)) { + error = -EPERM; + continue; + } + if (error == -ESRCH) + error = 0; + + /* + * PAOS: This is where we actually set the boost + * value within the task_struct + */ + p->boost = boost; + } + read_unlock(&tasklist_lock); + + return error; +} + + +/* + * PAOS: Get the CPU boost for the specified process + */ +asmlinkage long sys_getboost(int which, int who) +{ + struct task_struct *p; + long retval = -ESRCH; + + if (which > 2 || which < 0) + return -EINVAL; + + read_lock(&tasklist_lock); + for_each_task (p) { + if (!proc_sel(p, which, who)) + continue; + + retval = p->boost; + } + read_unlock(&tasklist_lock); + + return retval; +} + +/* =========================================================== + * PAOS: end of power-aware system calls + * =========================================================== */ + + /* * Reboot system call: for obvious reasons only root may call it,