diff options
Diffstat (limited to 'arch/parisc/kernel/process.c')
| -rw-r--r-- | arch/parisc/kernel/process.c | 196 |
1 files changed, 94 insertions, 102 deletions
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 55f92b614182..e64ab5d2a40d 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * PARISC Architecture-dependent parts of process handling * based on the work for i386 @@ -13,51 +14,41 @@ * Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org> * Copyright (C) 2001 Alan Modra <amodra at parisc-linux.org> * Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org> - * Copyright (C) 2001-2007 Helge Deller <deller at parisc-linux.org> + * Copyright (C) 2001-2014 Helge Deller <deller@gmx.de> * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <stdarg.h> - #include <linux/elf.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/fs.h> +#include <linux/cpu.h> #include <linux/module.h> #include <linux/personality.h> #include <linux/ptrace.h> +#include <linux/reboot.h> #include <linux/sched.h> +#include <linux/sched/debug.h> +#include <linux/sched/task.h> +#include <linux/sched/task_stack.h> #include <linux/slab.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/kallsyms.h> #include <linux/uaccess.h> #include <linux/rcupdate.h> +#include <linux/random.h> +#include <linux/nmi.h> +#include <linux/sched/hotplug.h> #include <asm/io.h> #include <asm/asm-offsets.h> #include <asm/assembly.h> #include <asm/pdc.h> #include <asm/pdc_chassis.h> -#include <asm/pgalloc.h> #include <asm/unwind.h> #include <asm/sections.h> +#include <asm/cacheflush.h> #define COMMAND_GLOBAL F_EXTEND(0xfffe0030) #define CMD_RESET 5 /* reset any module */ @@ -106,48 +97,45 @@ void machine_restart(char *cmd) } -void machine_halt(void) -{ - /* - ** The LED/ChassisCodes are updated by the led_halt() - ** function, called by the reboot notifier chain. - */ -} - -void (*chassis_power_off)(void); - /* * This routine is called from sys_reboot to actually turn off the * machine */ void machine_power_off(void) { - /* If there is a registered power off handler, call it. */ - if (chassis_power_off) - chassis_power_off(); - /* Put the soft power button back under hardware control. * If the user had already pressed the power button, the * following call will immediately power off. */ pdc_soft_power_button(0); pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN); + + /* ipmi_poweroff may have been installed. */ + do_kernel_power_off(); /* It seems we have no way to power the system off via * software. The user has to press the button himself. */ - printk(KERN_EMERG "System shut down completed.\n" - "Please power this system off now."); + printk("Power off or press RETURN to reboot.\n"); + + /* prevent soft lockup/stalled CPU messages for endless loop. */ + rcu_sysrq_start(); + lockup_detector_soft_poweroff(); + while (1) { + /* reboot if user presses RETURN key */ + if (pdc_iodc_getc() == 13) { + printk("Rebooting...\n"); + machine_restart(NULL); + } + } } -void (*pm_power_off)(void) = machine_power_off; +void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) +void machine_halt(void) { + machine_power_off(); } void flush_thread(void) @@ -157,33 +145,65 @@ void flush_thread(void) */ } -void release_thread(struct task_struct *dead_task) -{ -} - /* - * Fill in the FPU structure for a core dump. + * Idle thread support + * + * Detect when running on QEMU with SeaBIOS PDC Firmware and let + * QEMU idle the host too. */ -int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r) +int running_on_qemu __ro_after_init; +EXPORT_SYMBOL(running_on_qemu); + +/* + * Called from the idle thread for the CPU which has been shutdown. + */ +void __noreturn arch_cpu_idle_dead(void) { - if (regs == NULL) - return 0; +#ifdef CONFIG_HOTPLUG_CPU + idle_task_exit(); + + local_irq_disable(); + + /* Tell the core that this CPU is now safe to dispose of. */ + cpuhp_ap_report_dead(); - memcpy(r, regs->fr, sizeof *r); - return 1; + /* Ensure that the cache lines are written out. */ + flush_cache_all_local(); + flush_tlb_all_local(NULL); + + /* Let PDC firmware put CPU into firmware idle loop. */ + __pdc_cpu_rendezvous(); + + pr_warn("PDC does not provide rendezvous function.\n"); +#endif + while (1); +} + +void __cpuidle arch_cpu_idle(void) +{ + /* nop on real hardware, qemu will idle sleep. */ + asm volatile("or %%r10,%%r10,%%r10\n":::); } -int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r) +static int __init parisc_idle_init(void) { - memcpy(r, tsk->thread.regs.fr, sizeof(*r)); - return 1; + if (!running_on_qemu) + cpu_idle_poll_ctrl(1); + + return 0; } +arch_initcall(parisc_idle_init); +/* + * Copy architecture-specific thread state + */ int -copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long arg, struct task_struct *p) +copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { + u64 clone_flags = args->flags; + unsigned long usp = args->stack; + unsigned long tls = args->tls; struct pt_regs *cregs = &(p->thread.regs); void *stack = task_stack_page(p); @@ -192,31 +212,28 @@ copy_thread(unsigned long clone_flags, unsigned long usp, * Make them const so the compiler knows they live in .text */ extern void * const ret_from_kernel_thread; extern void * const child_return; -#ifdef CONFIG_HPUX - extern void * const hpux_child_return; -#endif - if (unlikely(p->flags & PF_KTHREAD)) { - memset(cregs, 0, sizeof(struct pt_regs)); - if (!usp) /* idle thread */ - return 0; + if (unlikely(args->fn)) { /* kernel thread */ + memset(cregs, 0, sizeof(struct pt_regs)); + if (args->idle) /* idle thread */ + return 0; /* Must exit via ret_from_kernel_thread in order * to call schedule_tail() */ - cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; + cregs->ksp = (unsigned long) stack + FRAME_SIZE + PT_SZ_ALGN; cregs->kpc = (unsigned long) &ret_from_kernel_thread; /* * Copy function and argument to be called from * ret_from_kernel_thread. */ #ifdef CONFIG_64BIT - cregs->gr[27] = ((unsigned long *)usp)[3]; - cregs->gr[26] = ((unsigned long *)usp)[2]; + cregs->gr[27] = ((unsigned long *)args->fn)[3]; + cregs->gr[26] = ((unsigned long *)args->fn)[2]; #else - cregs->gr[26] = usp; + cregs->gr[26] = (unsigned long) args->fn; #endif - cregs->gr[25] = arg; + cregs->gr[25] = (unsigned long) args->fn_arg; } else { /* user thread */ /* usp must be word aligned. This also prevents users from @@ -227,39 +244,24 @@ copy_thread(unsigned long clone_flags, unsigned long usp, if (likely(usp)) cregs->gr[30] = usp; } - cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; - if (personality(p->personality) == PER_HPUX) { -#ifdef CONFIG_HPUX - cregs->kpc = (unsigned long) &hpux_child_return; -#else - BUG(); -#endif - } else { - cregs->kpc = (unsigned long) &child_return; - } - /* Setup thread TLS area from the 4th parameter in clone */ + cregs->ksp = (unsigned long) stack + FRAME_SIZE; + cregs->kpc = (unsigned long) &child_return; + + /* Setup thread TLS area */ if (clone_flags & CLONE_SETTLS) - cregs->cr27 = cregs->gr[23]; + cregs->cr27 = tls; } return 0; } -unsigned long thread_saved_pc(struct task_struct *t) -{ - return t->thread.regs.kpc; -} - unsigned long -get_wchan(struct task_struct *p) +__get_wchan(struct task_struct *p) { struct unwind_frame_info info; unsigned long ip; int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - /* * These bracket the sleeping functions.. */ @@ -268,21 +270,11 @@ get_wchan(struct task_struct *p) do { if (unwind_once(&info) < 0) return 0; + if (task_is_running(p)) + return 0; ip = info.ip; if (!in_sched_functions(ip)) return ip; - } while (count++ < 16); + } while (count++ < MAX_UNWIND_ENTRIES); return 0; } - -#ifdef CONFIG_64BIT -void *dereference_function_descriptor(void *ptr) -{ - Elf64_Fdesc *desc = ptr; - void *p; - - if (!probe_kernel_address(&desc->addr, p)) - ptr = p; - return ptr; -} -#endif |
