/arch/arm/kernel/process.c
C | 517 lines | 363 code | 77 blank | 77 comment | 26 complexity | 7d48418420bd2260b4464800c7a6dcd7 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * linux/arch/arm/kernel/process.c
- *
- * Copyright (C) 1996-2000 Russell King - Converted to ARM.
- * Original Copyright (C) 1995 Linus Torvalds
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <stdarg.h>
- #include <linux/module.h>
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/mm.h>
- #include <linux/stddef.h>
- #include <linux/unistd.h>
- #include <linux/user.h>
- #include <linux/delay.h>
- #include <linux/reboot.h>
- #include <linux/interrupt.h>
- #include <linux/kallsyms.h>
- #include <linux/init.h>
- #include <linux/cpu.h>
- #include <linux/elfcore.h>
- #include <linux/pm.h>
- #include <linux/tick.h>
- #include <linux/utsname.h>
- #include <linux/uaccess.h>
- #include <asm/leds.h>
- #include <asm/processor.h>
- #include <asm/system.h>
- #include <asm/thread_notify.h>
- #include <asm/stacktrace.h>
- #include <asm/mach/time.h>
- static const char *processor_modes[] = {
- "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
- "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
- "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
- "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
- };
- static const char *isa_modes[] = {
- "ARM" , "Thumb" , "Jazelle", "ThumbEE"
- };
- extern void setup_mm_for_reboot(char mode);
- static volatile int hlt_counter;
- #include <mach/system.h>
- void disable_hlt(void)
- {
- hlt_counter++;
- }
- EXPORT_SYMBOL(disable_hlt);
- void enable_hlt(void)
- {
- hlt_counter--;
- }
- EXPORT_SYMBOL(enable_hlt);
- static int __init nohlt_setup(char *__unused)
- {
- hlt_counter = 1;
- return 1;
- }
- static int __init hlt_setup(char *__unused)
- {
- hlt_counter = 0;
- return 1;
- }
- __setup("nohlt", nohlt_setup);
- __setup("hlt", hlt_setup);
- void arm_machine_restart(char mode, const char *cmd)
- {
- /*
- * Clean and disable cache, and turn off interrupts
- */
- cpu_proc_fin();
- /*
- * Tell the mm system that we are going to reboot -
- * we may need it to insert some 1:1 mappings so that
- * soft boot works.
- */
- setup_mm_for_reboot(mode);
- /*
- * Now call the architecture specific reboot code.
- */
- arch_reset(mode, cmd);
- /*
- * Whoops - the architecture was unable to reboot.
- * Tell the user!
- */
- mdelay(1000);
- printk("Reboot failed -- System halted\n");
- while (1);
- }
- /*
- * Function pointers to optional machine specific functions
- */
- void (*pm_power_off)(void);
- EXPORT_SYMBOL(pm_power_off);
- void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
- EXPORT_SYMBOL_GPL(arm_pm_restart);
- /*
- * This is our default idle handler. We need to disable
- * interrupts here to ensure we don't miss a wakeup call.
- */
- static void default_idle(void)
- {
- if (!need_resched())
- arch_idle();
- local_irq_enable();
- }
- void (*pm_idle)(void) = default_idle;
- EXPORT_SYMBOL(pm_idle);
- /*
- * The idle thread, has rather strange semantics for calling pm_idle,
- * but this is what x86 does and we need to do the same, so that
- * things like cpuidle get called in the same way. The only difference
- * is that we always respect 'hlt_counter' to prevent low power idle.
- */
- void cpu_idle(void)
- {
- local_fiq_enable();
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_stop_sched_tick(1);
- leds_event(led_idle_start);
- while (!need_resched()) {
- #ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(smp_processor_id()))
- cpu_die();
- #endif
- local_irq_disable();
- if (hlt_counter) {
- local_irq_enable();
- cpu_relax();
- } else {
- stop_critical_timings();
- pm_idle();
- start_critical_timings();
- /*
- * This will eventually be removed - pm_idle
- * functions should always return with IRQs
- * enabled.
- */
- WARN_ON(irqs_disabled());
- local_irq_enable();
- }
- }
- leds_event(led_idle_end);
- tick_nohz_restart_sched_tick();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
- }
- static void do_nothing(void *unused)
- {
- }
- void cpu_idle_wait(void)
- {
- smp_mb();
- /* kick all the CPUs so that they exit out of pm_idle */
- smp_call_function(do_nothing, NULL, 1);
- }
- EXPORT_SYMBOL_GPL(cpu_idle_wait);
- static char reboot_mode = 'h';
- int __init reboot_setup(char *str)
- {
- reboot_mode = str[0];
- return 1;
- }
- __setup("reboot=", reboot_setup);
- void machine_halt(void)
- {
- }
- void machine_power_off(void)
- {
- if (pm_power_off)
- pm_power_off();
- }
- void machine_restart(char *cmd)
- {
- arm_pm_restart(reboot_mode, cmd);
- }
- /*
- * dump a block of kernel memory from around the given address
- */
- static void show_data(unsigned long addr, int nbytes, const char *name)
- {
- int i, j;
- int nlines;
- u32 *p;
- /*
- * don't attempt to dump non-kernel addresses or
- * values that are probably just small negative numbers
- */
- if (addr < PAGE_OFFSET || addr > -256UL)
- return;
- printk("\n%s: %#lx:\n", name, addr);
- /*
- * round address down to a 32 bit boundary
- * and always dump a multiple of 32 bytes
- */
- p = (u32 *)(addr & ~(sizeof(u32) - 1));
- nbytes += (addr & (sizeof(u32) - 1));
- nlines = (nbytes + 31) / 32;
-