fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / sparc64 / kernel / process.c
index 145ce7c..649131b 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <stdarg.h>
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -26,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
-#include <linux/config.h>
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/compat.h>
 #include <asm/fpumacro.h>
 #include <asm/head.h>
 #include <asm/cpudata.h>
+#include <asm/mmu_context.h>
 #include <asm/unistd.h>
+#include <asm/hypervisor.h>
 
 /* #define VERBOSE_SHOWREGS */
 
-/*
- * Nothing special yet...
- */
-void default_idle(void)
-{
-}
-
-#ifndef CONFIG_SMP
-
-/*
- * the idle loop on a Sparc... ;)
- */
-int cpu_idle(void)
+static void sparc64_yield(void)
 {
-       if (current->pid != 0)
-               return -EPERM;
-
-       /* endless idle loop with no priority at all */
-       for (;;) {
-               /* If current->work.need_resched is zero we should really
-                * setup for a system wakup event and execute a shutdown
-                * instruction.
-                *
-                * But this requires writing back the contents of the
-                * L2 cache etc. so implement this later. -DaveM
-                */
-               while (!need_resched())
-                       barrier();
+       if (tlb_type != hypervisor)
+               return;
 
-               schedule();
-               check_pgt_cache();
+       clear_thread_flag(TIF_POLLING_NRFLAG);
+       smp_mb__after_clear_bit();
+
+       while (!need_resched()) {
+               unsigned long pstate;
+
+               /* Disable interrupts. */
+               __asm__ __volatile__(
+                       "rdpr %%pstate, %0\n\t"
+                       "andn %0, %1, %0\n\t"
+                       "wrpr %0, %%g0, %%pstate"
+                       : "=&r" (pstate)
+                       : "i" (PSTATE_IE));
+
+               if (!need_resched())
+                       sun4v_cpu_yield();
+
+               /* Re-enable interrupts. */
+               __asm__ __volatile__(
+                       "rdpr %%pstate, %0\n\t"
+                       "or %0, %1, %0\n\t"
+                       "wrpr %0, %%g0, %%pstate"
+                       : "=&r" (pstate)
+                       : "i" (PSTATE_IE));
        }
-       return 0;
-}
 
-#else
+       set_thread_flag(TIF_POLLING_NRFLAG);
+}
 
-/*
- * the idle loop on a UltraMultiPenguin...
- */
-#define idle_me_harder()       (cpu_data(smp_processor_id()).idle_volume += 1)
-#define unidle_me()            (cpu_data(smp_processor_id()).idle_volume = 0)
-int cpu_idle(void)
+/* The idle loop on sparc64. */
+void cpu_idle(void)
 {
        set_thread_flag(TIF_POLLING_NRFLAG);
+
        while(1) {
                if (need_resched()) {
-                       unidle_me();
-                       clear_thread_flag(TIF_POLLING_NRFLAG);
+                       preempt_enable_no_resched();
                        schedule();
-                       set_thread_flag(TIF_POLLING_NRFLAG);
-                       check_pgt_cache();
+                       preempt_disable();
                }
-               idle_me_harder();
-
-               /* The store ordering is so that IRQ handlers on
-                * other cpus see our increasing idleness for the buddy
-                * redistribution algorithm.  -DaveM
-                */
-               membar("#StoreStore | #StoreLoad");
+               sparc64_yield();
        }
 }
 
-#endif
-
 extern char reboot_command [];
 
 extern void (*prom_palette)(int);
@@ -128,8 +112,6 @@ void machine_halt(void)
        panic("Halt failed!");
 }
 
-EXPORT_SYMBOL(machine_halt);
-
 void machine_alt_power_off(void)
 {
        if (!serial_console && prom_palette)
@@ -158,8 +140,7 @@ void machine_restart(char * cmd)
        panic("Reboot failed!");
 }
 
-EXPORT_SYMBOL(machine_restart);
-
+#ifdef CONFIG_COMPAT
 static void show_regwindow32(struct pt_regs *regs)
 {
        struct reg_window32 __user *rw;
@@ -167,7 +148,7 @@ static void show_regwindow32(struct pt_regs *regs)
        mm_segment_t old_fs;
        
        __asm__ __volatile__ ("flushw");
-       rw = (struct reg_window32 __user *)((long)(unsigned)regs->u_regs[14]);
+       rw = compat_ptr((unsigned)regs->u_regs[14]);
        old_fs = get_fs();
        set_fs (USER_DS);
        if (copy_from_user (&r_w, rw, sizeof(r_w))) {
@@ -185,6 +166,9 @@ static void show_regwindow32(struct pt_regs *regs)
               r_w.ins[0], r_w.ins[1], r_w.ins[2], r_w.ins[3],
               r_w.ins[4], r_w.ins[5], r_w.ins[6], r_w.ins[7]);
 }
+#else
+#define show_regwindow32(regs) do { } while (0)
+#endif
 
 static void show_regwindow(struct pt_regs *regs)
 {
@@ -282,7 +266,7 @@ void show_stackframe32(struct sparc_stackf32 *sf)
 }
 
 #ifdef CONFIG_SMP
-static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(regdump_lock);
 #endif
 
 void __show_regs(struct pt_regs * regs)
@@ -346,6 +330,7 @@ void show_regs(struct pt_regs *regs)
        extern long etrap, etraptl1;
 #endif
        __show_regs(regs);
+#if 0
 #ifdef CONFIG_SMP
        {
                extern void smp_report_regs(void);
@@ -353,6 +338,7 @@ void show_regs(struct pt_regs *regs)
                smp_report_regs();
        }
 #endif
+#endif
 
 #ifdef VERBOSE_SHOWREGS        
        if (regs->tpc >= &etrap && regs->tpc < &etraptl1 &&
@@ -386,7 +372,7 @@ void show_regs32(struct pt_regs32 *regs)
 
 unsigned long thread_saved_pc(struct task_struct *tsk)
 {
-       struct thread_info *ti = tsk->thread_info;
+       struct thread_info *ti = task_thread_info(tsk);
        unsigned long ret = 0xdeadbeefUL;
        
        if (ti && ti->ksp) {
@@ -425,31 +411,15 @@ void exit_thread(void)
 void flush_thread(void)
 {
        struct thread_info *t = current_thread_info();
+       struct mm_struct *mm;
 
        if (t->flags & _TIF_ABI_PENDING)
                t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
 
-       if (t->task->mm) {
-               unsigned long pgd_cache = 0UL;
-               if (test_thread_flag(TIF_32BIT)) {
-                       struct mm_struct *mm = t->task->mm;
-                       pgd_t *pgd0 = &mm->pgd[0];
-
-                       if (pgd_none(*pgd0)) {
-                               pmd_t *page = pmd_alloc_one_fast(NULL, 0);
-                               if (!page)
-                                       page = pmd_alloc_one(NULL, 0);
-                               pgd_set(pgd0, page);
-                       }
-                       pgd_cache = ((unsigned long) pgd_val(*pgd0)) << 11UL;
-               }
-               __asm__ __volatile__("stxa %0, [%1] %2\n\t"
-                                    "membar #Sync"
-                                    : /* no outputs */
-                                    : "r" (pgd_cache),
-                                    "r" (TSB_REG),
-                                    "i" (ASI_DMMU));
-       }
+       mm = t->task->mm;
+       if (mm)
+               tsb_context_switch(mm);
+
        set_thread_wsaved(0);
 
        /* Turn off performance counters if on. */
@@ -548,6 +518,18 @@ void synchronize_user_stack(void)
        }
 }
 
+static void stack_unaligned(unsigned long sp)
+{
+       siginfo_t info;
+
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRALN;
+       info.si_addr = (void __user *) sp;
+       info.si_trapno = 0;
+       force_sig_info(SIGBUS, &info, current);
+}
+
 void fault_in_user_windows(void)
 {
        struct thread_info *t = current_thread_info();
@@ -563,13 +545,17 @@ void fault_in_user_windows(void)
        flush_user_windows();
        window = get_thread_wsaved();
 
-       if (window != 0) {
+       if (likely(window != 0)) {
                window -= 1;
                do {
                        unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
                        struct reg_window *rwin = &t->reg_window[window];
 
-                       if (copy_to_user((char __user *)sp, rwin, winsize))
+                       if (unlikely(sp & 0x7UL))
+                               stack_unaligned(sp);
+
+                       if (unlikely(copy_to_user((char __user *)sp,
+                                                 rwin, winsize)))
                                goto barf;
                } while (window--);
        }
@@ -588,8 +574,6 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
 {
        int __user *parent_tid_ptr, *child_tid_ptr;
 
-       clone_flags &= ~CLONE_IDLETASK;
-
 #ifdef CONFIG_COMPAT
        if (test_thread_flag(TIF_32BIT)) {
                parent_tid_ptr = compat_ptr(regs->u_regs[UREG_I2]);
@@ -615,23 +599,16 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                unsigned long unused,
                struct task_struct *p, struct pt_regs *regs)
 {
-       struct thread_info *t = p->thread_info;
+       struct thread_info *t = task_thread_info(p);
        char *child_trap_frame;
 
-#ifdef CONFIG_DEBUG_SPINLOCK
-       p->thread.smp_lock_count = 0;
-       p->thread.smp_lock_pc = 0;
-#endif
-
-       p->set_child_tid = p->clear_child_tid = NULL;
-
        /* Calculate offset to stack_frame & pt_regs */
-       child_trap_frame = ((char *)t) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ));
+       child_trap_frame = task_stack_page(p) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ));
        memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ));
 
        t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) | (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
-               _TIF_NEWCHILD |
                (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
+       t->new_child = 1;
        t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
        t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct sparc_stackf));
        t->fpsaved[0] = 0;
@@ -719,7 +696,8 @@ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
                             /* Notreached by child. */
                             "1:" :
                             "=r" (retval) :
-                            "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
+                            "i" (__NR_clone), "r" (flags |
+                               CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD),
                             "i" (__NR_exit),  "r" (fn), "r" (arg) :
                             "g1", "g2", "g3", "o0", "o1", "memory", "cc");
        return retval;
@@ -831,7 +809,6 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
                current_thread_info()->xfsr[0] = 0;
                current_thread_info()->fpsaved[0] = 0;
                regs->tstate &= ~TSTATE_PEF;
-               current->ptrace &= ~PT_DTRACE;
        }
 out:
        return error;
@@ -849,9 +826,9 @@ unsigned long get_wchan(struct task_struct *task)
             task->state == TASK_RUNNING)
                goto out;
 
-       thread_info_base = (unsigned long) task->thread_info;
+       thread_info_base = (unsigned long) task_stack_page(task);
        bias = STACK_BIAS;
-       fp = task->thread_info->ksp + bias;
+       fp = task_thread_info(task)->ksp + bias;
 
        do {
                /* Bogus frame pointer? */