*
* SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
* Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pm.h>
#include <linux/kallsyms.h>
#include <linux/kexec.h>
+#include <linux/kdebug.h>
+#include <linux/tick.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
#include <asm/ubc.h>
static int hlt_counter;
int ubc_usercnt = 0;
-#define HARD_IDLE_TIMEOUT (HZ / 3)
-
void (*pm_idle)(void);
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
}
EXPORT_SYMBOL(enable_hlt);
+static int __init nohlt_setup(char *__unused)
+{
+ hlt_counter = 1;
+ return 1;
+}
+__setup("nohlt", nohlt_setup);
+
+static int __init hlt_setup(char *__unused)
+{
+ hlt_counter = 0;
+ return 1;
+}
+__setup("hlt", hlt_setup);
+
void default_idle(void)
{
- if (!hlt_counter)
- cpu_sleep();
- else
- cpu_relax();
+ if (!hlt_counter) {
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ smp_mb__after_clear_bit();
+ set_bl_bit();
+ while (!need_resched())
+ cpu_sleep();
+ clear_bl_bit();
+ set_thread_flag(TIF_POLLING_NRFLAG);
+ } else
+ while (!need_resched())
+ cpu_relax();
}
void cpu_idle(void)
{
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
/* endless idle loop with no priority at all */
while (1) {
void (*idle)(void) = pm_idle;
if (!idle)
idle = default_idle;
+ tick_nohz_stop_sched_tick();
while (!need_resched())
idle();
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
+ check_pgt_cache();
}
}
ctrl_outl(0, UBC_BAMRA);
if (current_cpu_data.type == CPU_SH7729 ||
- current_cpu_data.type == CPU_SH7710) {
+ current_cpu_data.type == CPU_SH7710 ||
+ current_cpu_data.type == CPU_SH7712) {
ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
} else {
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
/* Rewind */
- regs->pc -= 2;
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+
+ if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
force_sig(SIGTRAP, current);
}
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
/* Rewind */
- regs->pc -= 2;
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+
+ if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
#ifdef CONFIG_BUG
if (__kernel_text_address(instruction_pointer(regs))) {