diff options
Diffstat (limited to 'arch/sparc64/kernel/process.c')
| -rw-r--r-- | arch/sparc64/kernel/process.c | 133 |
1 files changed, 57 insertions, 76 deletions
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 059b0d025224..1c7ca2f712d9 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c | |||
| @@ -44,83 +44,61 @@ | |||
| 44 | #include <asm/fpumacro.h> | 44 | #include <asm/fpumacro.h> |
| 45 | #include <asm/head.h> | 45 | #include <asm/head.h> |
| 46 | #include <asm/cpudata.h> | 46 | #include <asm/cpudata.h> |
| 47 | #include <asm/mmu_context.h> | ||
| 47 | #include <asm/unistd.h> | 48 | #include <asm/unistd.h> |
| 49 | #include <asm/hypervisor.h> | ||
| 48 | 50 | ||
| 49 | /* #define VERBOSE_SHOWREGS */ | 51 | /* #define VERBOSE_SHOWREGS */ |
| 50 | 52 | ||
| 51 | /* | 53 | static void sparc64_yield(void) |
| 52 | * Nothing special yet... | ||
| 53 | */ | ||
| 54 | void default_idle(void) | ||
| 55 | { | ||
| 56 | } | ||
| 57 | |||
| 58 | #ifndef CONFIG_SMP | ||
| 59 | |||
| 60 | /* | ||
| 61 | * the idle loop on a Sparc... ;) | ||
| 62 | */ | ||
| 63 | void cpu_idle(void) | ||
| 64 | { | 54 | { |
| 65 | /* endless idle loop with no priority at all */ | 55 | if (tlb_type != hypervisor) |
| 66 | for (;;) { | 56 | return; |
| 67 | /* If current->work.need_resched is zero we should really | ||
| 68 | * setup for a system wakup event and execute a shutdown | ||
| 69 | * instruction. | ||
| 70 | * | ||
| 71 | * But this requires writing back the contents of the | ||
| 72 | * L2 cache etc. so implement this later. -DaveM | ||
| 73 | */ | ||
| 74 | while (!need_resched()) | ||
| 75 | barrier(); | ||
| 76 | 57 | ||
| 77 | preempt_enable_no_resched(); | 58 | clear_thread_flag(TIF_POLLING_NRFLAG); |
| 78 | schedule(); | 59 | smp_mb__after_clear_bit(); |
| 79 | preempt_disable(); | 60 | |
| 80 | check_pgt_cache(); | 61 | while (!need_resched()) { |
| 62 | unsigned long pstate; | ||
| 63 | |||
| 64 | /* Disable interrupts. */ | ||
| 65 | __asm__ __volatile__( | ||
| 66 | "rdpr %%pstate, %0\n\t" | ||
| 67 | "andn %0, %1, %0\n\t" | ||
| 68 | "wrpr %0, %%g0, %%pstate" | ||
| 69 | : "=&r" (pstate) | ||
| 70 | : "i" (PSTATE_IE)); | ||
| 71 | |||
| 72 | if (!need_resched()) | ||
| 73 | sun4v_cpu_yield(); | ||
| 74 | |||
| 75 | /* Re-enable interrupts. */ | ||
| 76 | __asm__ __volatile__( | ||
| 77 | "rdpr %%pstate, %0\n\t" | ||
| 78 | "or %0, %1, %0\n\t" | ||
| 79 | "wrpr %0, %%g0, %%pstate" | ||
| 80 | : "=&r" (pstate) | ||
| 81 | : "i" (PSTATE_IE)); | ||
| 81 | } | 82 | } |
| 82 | } | ||
| 83 | 83 | ||
| 84 | #else | 84 | set_thread_flag(TIF_POLLING_NRFLAG); |
| 85 | } | ||
| 85 | 86 | ||
| 86 | /* | 87 | /* The idle loop on sparc64. */ |
| 87 | * the idle loop on a UltraMultiPenguin... | ||
| 88 | * | ||
| 89 | * TIF_POLLING_NRFLAG is set because we do not sleep the cpu | ||
| 90 | * inside of the idler task, so an interrupt is not needed | ||
| 91 | * to get a clean fast response. | ||
| 92 | * | ||
| 93 | * XXX Reverify this assumption... -DaveM | ||
| 94 | * | ||
| 95 | * Addendum: We do want it to do something for the signal | ||
| 96 | * delivery case, we detect that by just seeing | ||
| 97 | * if we are trying to send this to an idler or not. | ||
| 98 | */ | ||
| 99 | void cpu_idle(void) | 88 | void cpu_idle(void) |
| 100 | { | 89 | { |
| 101 | cpuinfo_sparc *cpuinfo = &local_cpu_data(); | ||
| 102 | set_thread_flag(TIF_POLLING_NRFLAG); | 90 | set_thread_flag(TIF_POLLING_NRFLAG); |
| 103 | 91 | ||
| 104 | while(1) { | 92 | while(1) { |
| 105 | if (need_resched()) { | 93 | if (need_resched()) { |
| 106 | cpuinfo->idle_volume = 0; | ||
| 107 | preempt_enable_no_resched(); | 94 | preempt_enable_no_resched(); |
| 108 | schedule(); | 95 | schedule(); |
| 109 | preempt_disable(); | 96 | preempt_disable(); |
| 110 | check_pgt_cache(); | ||
| 111 | } | 97 | } |
| 112 | cpuinfo->idle_volume++; | 98 | sparc64_yield(); |
| 113 | |||
| 114 | /* The store ordering is so that IRQ handlers on | ||
| 115 | * other cpus see our increasing idleness for the buddy | ||
| 116 | * redistribution algorithm. -DaveM | ||
| 117 | */ | ||
| 118 | membar_storeload_storestore(); | ||
| 119 | } | 99 | } |
| 120 | } | 100 | } |
| 121 | 101 | ||
| 122 | #endif | ||
| 123 | |||
| 124 | extern char reboot_command []; | 102 | extern char reboot_command []; |
| 125 | 103 | ||
| 126 | extern void (*prom_palette)(int); | 104 | extern void (*prom_palette)(int); |
| @@ -354,6 +332,7 @@ void show_regs(struct pt_regs *regs) | |||
| 354 | extern long etrap, etraptl1; | 332 | extern long etrap, etraptl1; |
| 355 | #endif | 333 | #endif |
| 356 | __show_regs(regs); | 334 | __show_regs(regs); |
| 335 | #if 0 | ||
| 357 | #ifdef CONFIG_SMP | 336 | #ifdef CONFIG_SMP |
| 358 | { | 337 | { |
| 359 | extern void smp_report_regs(void); | 338 | extern void smp_report_regs(void); |
| @@ -361,6 +340,7 @@ void show_regs(struct pt_regs *regs) | |||
| 361 | smp_report_regs(); | 340 | smp_report_regs(); |
| 362 | } | 341 | } |
| 363 | #endif | 342 | #endif |
| 343 | #endif | ||
| 364 | 344 | ||
| 365 | #ifdef VERBOSE_SHOWREGS | 345 | #ifdef VERBOSE_SHOWREGS |
| 366 | if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && | 346 | if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && |
| @@ -433,30 +413,15 @@ void exit_thread(void) | |||
| 433 | void flush_thread(void) | 413 | void flush_thread(void) |
| 434 | { | 414 | { |
| 435 | struct thread_info *t = current_thread_info(); | 415 | struct thread_info *t = current_thread_info(); |
| 416 | struct mm_struct *mm; | ||
| 436 | 417 | ||
| 437 | if (t->flags & _TIF_ABI_PENDING) | 418 | if (t->flags & _TIF_ABI_PENDING) |
| 438 | t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); | 419 | t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); |
| 439 | 420 | ||
| 440 | if (t->task->mm) { | 421 | mm = t->task->mm; |
| 441 | unsigned long pgd_cache = 0UL; | 422 | if (mm) |
| 442 | if (test_thread_flag(TIF_32BIT)) { | 423 | tsb_context_switch(mm); |
| 443 | struct mm_struct *mm = t->task->mm; | ||
| 444 | pgd_t *pgd0 = &mm->pgd[0]; | ||
| 445 | pud_t *pud0 = pud_offset(pgd0, 0); | ||
| 446 | 424 | ||
| 447 | if (pud_none(*pud0)) { | ||
| 448 | pmd_t *page = pmd_alloc_one(mm, 0); | ||
| 449 | pud_set(pud0, page); | ||
| 450 | } | ||
| 451 | pgd_cache = get_pgd_cache(pgd0); | ||
| 452 | } | ||
| 453 | __asm__ __volatile__("stxa %0, [%1] %2\n\t" | ||
| 454 | "membar #Sync" | ||
| 455 | : /* no outputs */ | ||
| 456 | : "r" (pgd_cache), | ||
| 457 | "r" (TSB_REG), | ||
| 458 | "i" (ASI_DMMU)); | ||
| 459 | } | ||
| 460 | set_thread_wsaved(0); | 425 | set_thread_wsaved(0); |
| 461 | 426 | ||
| 462 | /* Turn off performance counters if on. */ | 427 | /* Turn off performance counters if on. */ |
| @@ -555,6 +520,18 @@ void synchronize_user_stack(void) | |||
| 555 | } | 520 | } |
| 556 | } | 521 | } |
| 557 | 522 | ||
| 523 | static void stack_unaligned(unsigned long sp) | ||
| 524 | { | ||
| 525 | siginfo_t info; | ||
| 526 | |||
| 527 | info.si_signo = SIGBUS; | ||
| 528 | info.si_errno = 0; | ||
| 529 | info.si_code = BUS_ADRALN; | ||
| 530 | info.si_addr = (void __user *) sp; | ||
| 531 | info.si_trapno = 0; | ||
| 532 | force_sig_info(SIGBUS, &info, current); | ||
| 533 | } | ||
| 534 | |||
| 558 | void fault_in_user_windows(void) | 535 | void fault_in_user_windows(void) |
| 559 | { | 536 | { |
| 560 | struct thread_info *t = current_thread_info(); | 537 | struct thread_info *t = current_thread_info(); |
| @@ -570,13 +547,17 @@ void fault_in_user_windows(void) | |||
| 570 | flush_user_windows(); | 547 | flush_user_windows(); |
| 571 | window = get_thread_wsaved(); | 548 | window = get_thread_wsaved(); |
| 572 | 549 | ||
| 573 | if (window != 0) { | 550 | if (likely(window != 0)) { |
| 574 | window -= 1; | 551 | window -= 1; |
| 575 | do { | 552 | do { |
| 576 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); | 553 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); |
| 577 | struct reg_window *rwin = &t->reg_window[window]; | 554 | struct reg_window *rwin = &t->reg_window[window]; |
| 578 | 555 | ||
| 579 | if (copy_to_user((char __user *)sp, rwin, winsize)) | 556 | if (unlikely(sp & 0x7UL)) |
| 557 | stack_unaligned(sp); | ||
| 558 | |||
| 559 | if (unlikely(copy_to_user((char __user *)sp, | ||
| 560 | rwin, winsize))) | ||
| 580 | goto barf; | 561 | goto barf; |
| 581 | } while (window--); | 562 | } while (window--); |
| 582 | } | 563 | } |
