X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Fprocess.c;h=1c7ca2f712d99004106ba087aa021cd202cae2f7;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=a0cd2b2494d6cc5f111faeed82a42ab96ba99323;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index a0cd2b249..1c7ca2f71 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -44,71 +44,61 @@ #include #include #include +#include #include +#include /* #define VERBOSE_SHOWREGS */ -/* - * Nothing special yet... - */ -void default_idle(void) -{ -} - -#ifndef CONFIG_SMP - -/* - * the idle loop on a Sparc... ;) - */ -void cpu_idle(void) +static void sparc64_yield(void) { - /* 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)); } -} -#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) +/* 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); @@ -124,8 +114,6 @@ void machine_halt(void) panic("Halt failed!"); } -EXPORT_SYMBOL(machine_halt); - void machine_alt_power_off(void) { if (!serial_console && prom_palette) @@ -154,8 +142,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; @@ -181,6 +168,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) { @@ -342,6 +332,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); @@ -349,6 +340,7 @@ void show_regs(struct pt_regs *regs) smp_report_regs(); } #endif +#endif #ifdef VERBOSE_SHOWREGS if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && @@ -382,7 +374,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) { @@ -421,30 +413,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]; - pud_t *pud0 = pud_offset(pgd0, 0); + mm = t->task->mm; + if (mm) + tsb_context_switch(mm); - if (pud_none(*pud0)) { - pmd_t *page = pmd_alloc_one(mm, 0); - pud_set(pud0, page); - } - pgd_cache = get_pgd_cache(pgd0); - } - __asm__ __volatile__("stxa %0, [%1] %2\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (pgd_cache), - "r" (TSB_REG), - "i" (ASI_DMMU)); - } set_thread_wsaved(0); /* Turn off performance counters if on. */ @@ -543,6 +520,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(); @@ -558,13 +547,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--); } @@ -608,21 +601,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 - /* 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; @@ -842,9 +830,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? */