summaryrefslogtreecommitdiff
path: root/arch/parisc/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc/kernel/process.c')
-rw-r--r--arch/parisc/kernel/process.c196
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