X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Fprocess.c;fp=arch%2Fsparc64%2Fkernel%2Fprocess.c;h=059b0d0252245800bf415110644a659a9f6c5a8e;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=7d75cd4eb297bb08e016455fdfae71c89385e81e;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 7d75cd4eb..059b0d025 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -42,61 +44,83 @@ #include #include #include -#include #include -#include /* #define VERBOSE_SHOWREGS */ -static void sparc64_yield(void) +/* + * Nothing special yet... + */ +void default_idle(void) { - if (tlb_type != hypervisor) - return; +} - 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)); - } +#ifndef CONFIG_SMP - set_thread_flag(TIF_POLLING_NRFLAG); +/* + * the idle loop on a Sparc... ;) + */ +void cpu_idle(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(); + + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + check_pgt_cache(); + } } -/* The idle loop on sparc64. */ +#else + +/* + * the idle loop on a UltraMultiPenguin... + * + * TIF_POLLING_NRFLAG is set because we do not sleep the cpu + * inside of the idler task, so an interrupt is not needed + * to get a clean fast response. + * + * XXX Reverify this assumption... -DaveM + * + * Addendum: We do want it to do something for the signal + * delivery case, we detect that by just seeing + * if we are trying to send this to an idler or not. + */ void cpu_idle(void) { + cpuinfo_sparc *cpuinfo = &local_cpu_data(); set_thread_flag(TIF_POLLING_NRFLAG); while(1) { if (need_resched()) { + cpuinfo->idle_volume = 0; preempt_enable_no_resched(); schedule(); preempt_disable(); + check_pgt_cache(); } - sparc64_yield(); + cpuinfo->idle_volume++; + + /* The store ordering is so that IRQ handlers on + * other cpus see our increasing idleness for the buddy + * redistribution algorithm. -DaveM + */ + membar_storeload_storestore(); } } +#endif + extern char reboot_command []; extern void (*prom_palette)(int); @@ -330,7 +354,6 @@ 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); @@ -338,7 +361,6 @@ void show_regs(struct pt_regs *regs) smp_report_regs(); } #endif -#endif #ifdef VERBOSE_SHOWREGS if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && @@ -411,15 +433,30 @@ 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); - mm = t->task->mm; - if (mm) - tsb_context_switch(mm); + 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); + 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. */ @@ -518,18 +555,6 @@ 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(); @@ -545,17 +570,13 @@ void fault_in_user_windows(void) flush_user_windows(); window = get_thread_wsaved(); - if (likely(window != 0)) { + if (window != 0) { window -= 1; do { unsigned long sp = (t->rwbuf_stkptrs[window] + bias); struct reg_window *rwin = &t->reg_window[window]; - if (unlikely(sp & 0x7UL)) - stack_unaligned(sp); - - if (unlikely(copy_to_user((char __user *)sp, - rwin, winsize))) + if (copy_to_user((char __user *)sp, rwin, winsize)) goto barf; } while (window--); }