summaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-09 13:08:20 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-09 13:08:20 -0700
commitd84c4124c4b6611301b402e8611b7e36de3bd351 (patch)
treed83cfaabfb901755d85074815ad948028dc7b03f /arch/sh/kernel
parent932c37c375cca25175f9b6acee4c75d7a96d985f (diff)
parenta3cf4ea8729a5d448742fd5a0a003827c9f25cb6 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6: sh: Fix stacktrace simplification fallout. sh: SH7760 DMABRG support. sh: clockevent/clocksource/hrtimers/nohz TMU support. sh: Truncate MAX_ACTIVE_REGIONS for the common case. rtc: rtc-sh: Fix rtc_dev pointer for rtc_update_irq(). sh: Convert to common die chain. sh: Wire up utimensat syscall. sh: landisk mv_nr_irqs definition. sh: Fixup ndelay() xloops calculation for alternate HZ. sh: Add 32-bit opcode feature CPU flag. sh: Fix PC adjustments for varying opcode length. sh: Support for SH-2A 32-bit opcodes. sh: Kill off redundant __div64_32 symbol export. sh: Share exception vector table for SH-3/4. sh: Always define TRAPA_BUG_OPCODE. sh: __GFP_REPEAT for pte allocations, too. rtc: rtc-sh: Fix up dev_dbg() warnings. sh: generic quicklist support.
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/cpu/sh2a/Makefile5
-rw-r--r--arch/sh/kernel/cpu/sh2a/opcode_helper.c55
-rw-r--r--arch/sh/kernel/cpu/sh2a/probe.c1
-rw-r--r--arch/sh/kernel/cpu/sh3/ex.S13
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile6
-rw-r--r--arch/sh/kernel/cpu/sh4/ex.S62
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c3
-rw-r--r--arch/sh/kernel/process.c16
-rw-r--r--arch/sh/kernel/setup.c2
-rw-r--r--arch/sh/kernel/sh_ksyms.c2
-rw-r--r--arch/sh/kernel/signal.c13
-rw-r--r--arch/sh/kernel/stacktrace.c2
-rw-r--r--arch/sh/kernel/syscalls.S1
-rw-r--r--arch/sh/kernel/time.c172
-rw-r--r--arch/sh/kernel/timers/timer-tmu.c182
-rw-r--r--arch/sh/kernel/traps.c20
16 files changed, 260 insertions, 295 deletions
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
index 350972ae941..965fa2572b2 100644
--- a/arch/sh/kernel/cpu/sh2a/Makefile
+++ b/arch/sh/kernel/cpu/sh2a/Makefile
@@ -2,9 +2,8 @@
# Makefile for the Linux/SuperH SH-2A backends.
#
-obj-y := common.o probe.o
+obj-y := common.o probe.o opcode_helper.o
-common-y += $(addprefix ../sh2/, ex.o)
-common-y += $(addprefix ../sh2/, entry.o)
+common-y += $(addprefix ../sh2/, ex.o entry.o)
obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
diff --git a/arch/sh/kernel/cpu/sh2a/opcode_helper.c b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
new file mode 100644
index 00000000000..9704b7926d8
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
@@ -0,0 +1,55 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/opcode_helper.c
+ *
+ * Helper for the SH-2A 32-bit opcodes.
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+/*
+ * Instructions on SH are generally fixed at 16-bits, however, SH-2A
+ * introduces some 32-bit instructions. Since there are no real
+ * constraints on their use (and they can be mixed and matched), we need
+ * to check the instruction encoding to work out if it's a true 32-bit
+ * instruction or not.
+ *
+ * Presently, 32-bit opcodes have only slight variations in what the
+ * actual encoding looks like in the first-half of the instruction, which
+ * makes it fairly straightforward to differentiate from the 16-bit ones.
+ *
+ * First 16-bits of encoding Used by
+ *
+ * 0011nnnnmmmm0001 mov.b, mov.w, mov.l, fmov.d,
+ * fmov.s, movu.b, movu.w
+ *
+ * 0011nnnn0iii1001 bclr.b, bld.b, bset.b, bst.b, band.b,
+ * bandnot.b, bldnot.b, bor.b, bornot.b,
+ * bxor.b
+ *
+ * 0000nnnniiii0000 movi20
+ * 0000nnnniiii0001 movi20s
+ */
+unsigned int instruction_size(unsigned int insn)
+{
+ /* Look for the common cases */
+ switch ((insn & 0xf00f)) {
+ case 0x0000: /* movi20 */
+ case 0x0001: /* movi20s */
+ case 0x3001: /* 32-bit mov/fmov/movu variants */
+ return 4;
+ }
+
+ /* And the special cases.. */
+ switch ((insn & 0xf08f)) {
+ case 0x3009: /* 32-bit b*.b bit operations */
+ return 4;
+ }
+
+ return 2;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
index 426f6db01fc..f455c350978 100644
--- a/arch/sh/kernel/cpu/sh2a/probe.c
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -18,6 +18,7 @@ int __init detect_cpu_and_cache_system(void)
{
/* Just SH7206 for now .. */
current_cpu_data.type = CPU_SH7206;
+ current_cpu_data.flags |= CPU_HAS_OP32;
current_cpu_data.dcache.ways = 4;
current_cpu_data.dcache.way_incr = (1 << 11);
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index ba3082d640b..2b2a9e02fb7 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -1,7 +1,7 @@
/*
* arch/sh/kernel/cpu/sh3/ex.S
*
- * The SH-3 exception vector table.
+ * The SH-3 and SH-4 exception vector table.
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
* Copyright (C) 2003 - 2006 Paul Mundt
@@ -9,7 +9,6 @@
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
- *
*/
#include <linux/linkage.h>
@@ -36,8 +35,12 @@ ENTRY(exception_handling_table)
.long exception_error ! address error load
.long exception_error ! address error store /* 100 */
#endif
- .long exception_error ! fpu_exception /* 120 */
- .long exception_error /* 140 */
+#if defined(CONFIG_SH_FPU)
+ .long do_fpu_error /* 120 */
+#else
+ .long exception_error /* 120 */
+#endif
+ .long exception_error /* 140 */
.long system_call ! Unconditional Trap /* 160 */
.long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
.long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
@@ -55,4 +58,4 @@ ENTRY(user_break_point_trap)
* away offsets can be manually inserted in to their appropriate
* location via set_exception_table_{evt,vec}().
*/
- .balign 4096,0,4096
+ .balign 4096,0,4096
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 19ca68c7188..8add10bd826 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -2,10 +2,10 @@
# Makefile for the Linux/SuperH SH-4 backends.
#
-obj-y := ex.o probe.o common.o
-common-y += $(addprefix ../sh3/, entry.o)
+obj-y := probe.o common.o
+common-y += $(addprefix ../sh3/, entry.o ex.o)
-obj-$(CONFIG_SH_FPU) += fpu.o
+obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
# CPU subtype setup
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
deleted file mode 100644
index ac8ab57413c..00000000000
--- a/arch/sh/kernel/cpu/sh4/ex.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * arch/sh/kernel/cpu/sh4/ex.S
- *
- * The SH-4 exception vector table.
-
- * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2003 - 2006 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- */
-#include <linux/linkage.h>
-
- .align 2
- .data
-
-ENTRY(exception_handling_table)
- .long exception_error /* 000 */
- .long exception_error
-#if defined(CONFIG_MMU)
- .long tlb_miss_load /* 040 */
- .long tlb_miss_store
- .long initial_page_write
- .long tlb_protection_violation_load
- .long tlb_protection_violation_store
- .long address_error_load
- .long address_error_store /* 100 */
-#else
- .long exception_error ! tlb miss load /* 040 */
- .long exception_error ! tlb miss store
- .long exception_error ! initial page write
- .long exception_error ! tlb prot violation load
- .long exception_error ! tlb prot violation store
- .long exception_error ! address error load
- .long exception_error ! address error store /* 100 */
-#endif
-#if defined(CONFIG_SH_FPU)
- .long do_fpu_error /* 120 */
-#else
- .long exception_error /* 120 */
-#endif
- .long exception_error /* 140 */
- .long system_call ! Unconditional Trap /* 160 */
- .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
- .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
-ENTRY(nmi_slot)
-#if defined (CONFIG_KGDB_NMI)
- .long debug_enter /* 1C0 */ ! Allow trap to debugger
-#else
- .long exception_none /* 1C0 */ ! Not implemented yet
-#endif
-ENTRY(user_break_point_trap)
- .long break_point_trap /* 1E0 */
-
- /*
- * Pad the remainder of the table out, exceptions residing in far
- * away offsets can be manually inserted in to their appropriate
- * location via set_exception_table_{evt,vec}().
- */
- .balign 4096,0,4096
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index 7624677f662..d61dd599169 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -16,6 +16,7 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <asm/processor.h>
+#include <asm/system.h>
#include <asm/io.h>
/* The PR (precision) bit in the FP Status Register must be clear when
@@ -265,7 +266,7 @@ ieee_fpe_handler (struct pt_regs *regs)
nextpc = regs->pr;
finsn = *(unsigned short *) (regs->pc + 2);
} else {
- nextpc = regs->pc + 2;
+ nextpc = regs->pc + instruction_size(insn);
finsn = insn;
}
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 329b3f3051d..6b4f5748d0b 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -15,9 +15,12 @@
#include <linux/pm.h>
#include <linux/kallsyms.h>
#include <linux/kexec.h>
-#include <asm/kdebug.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;
@@ -58,12 +61,15 @@ void cpu_idle(void)
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();
}
}
@@ -495,9 +501,9 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
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, regs, regs->tra & 0xff,
+ if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
SIGTRAP) == NOTIFY_STOP)
return;
@@ -514,9 +520,9 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
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, regs, TRAPA_BUG_OPCODE & 0xff,
+ if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
SIGTRAP) == NOTIFY_STOP)
return;
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 477d2a854fc..c2772913593 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -431,7 +431,7 @@ const char *get_cpu_subtype(struct sh_cpuinfo *c)
/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
static const char *cpu_flags[] = {
"none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
- "ptea", "llsc", "l2", NULL
+ "ptea", "llsc", "l2", "op32", NULL
};
static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index fa91641c1f6..c1cfcb9f047 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -58,8 +58,6 @@ EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(__const_udelay);
-EXPORT_SYMBOL(__div64_32);
-
#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
/* These symbols are generated by the compiler itself */
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index eb0191c374b..b32c35a7c0a 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -23,7 +23,7 @@
#include <linux/personality.h>
#include <linux/binfmts.h>
#include <linux/freezer.h>
-
+#include <asm/system.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -500,7 +500,9 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
}
/* fallthrough */
case -ERESTARTNOINTR:
- regs->pc -= 2;
+ regs->pc -= instruction_size(
+ ctrl_inw(regs->pc - 4));
+ break;
}
} else {
/* gUSA handling */
@@ -516,7 +518,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
regs->regs[15] = regs->regs[1];
if (regs->pc < regs->regs[0])
/* Go to rewind point #1 */
- regs->pc = regs->regs[0] + offset - 2;
+ regs->pc = regs->regs[0] + offset -
+ instruction_size(ctrl_inw(regs->pc-4));
}
#ifdef CONFIG_PREEMPT
local_irq_restore(flags);
@@ -600,9 +603,9 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
regs->regs[0] == -ERESTARTSYS ||
regs->regs[0] == -ERESTARTNOINTR) {
regs->regs[0] = save_r0;
- regs->pc -= 2;
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
- regs->pc -= 2;
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
regs->regs[3] = __NR_restart_syscall;
}
}
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c
index 4bdd2f83535..d41e561be20 100644
--- a/arch/sh/kernel/stacktrace.c
+++ b/arch/sh/kernel/stacktrace.c
@@ -17,7 +17,7 @@
/*
* Save stack-backtrace addresses into a stack_trace buffer.
*/
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
{
unsigned long *sp = (unsigned long *)current_stack_pointer;
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index 38fc8cd3ea3..4357d1a6358 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -354,3 +354,4 @@ ENTRY(sys_call_table)
.long sys_move_pages
.long sys_getcpu
.long sys_epoll_pwait
+ .long sys_utimensat /* 320 */
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index d47e775962e..a3a67d151e5 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
* Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
*
* Some code taken from i386 version.
@@ -15,6 +15,7 @@
#include <linux/profile.h>
#include <linux/timex.h>
#include <linux/sched.h>
+#include <linux/clockchips.h>
#include <asm/clock.h>
#include <asm/rtc.h>
#include <asm/timer.h>
@@ -38,6 +39,14 @@ static int null_rtc_set_time(const time_t secs)
return 0;
}
+/*
+ * Null high precision timer functions for systems lacking one.
+ */
+static cycle_t null_hpt_read(void)
+{
+ return 0;
+}
+
void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
@@ -101,6 +110,7 @@ int do_settimeofday(struct timespec *tv)
EXPORT_SYMBOL(do_settimeofday);
#endif /* !CONFIG_GENERIC_TIME */
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
/* last time the RTC clock got updated */
static long last_rtc_update;
@@ -138,6 +148,7 @@ void handle_timer_tick(void)
last_rtc_update = xtime.tv_sec - 600;
}
}
+#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
#ifdef CONFIG_PM
int timer_suspend(struct sys_device *dev, pm_message_t state)
@@ -168,136 +179,58 @@ static struct sysdev_class timer_sysclass = {
.resume = timer_resume,
};
-#ifdef CONFIG_NO_IDLE_HZ
-static int timer_dyn_tick_enable(void)
+static int __init timer_init_sysfs(void)
{
- struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
- unsigned long flags;
- int ret = -ENODEV;
-
- if (dyn_tick) {
- spin_lock_irqsave(&dyn_tick->lock, flags);
- ret = 0;
- if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
- ret = dyn_tick->enable();
-
- if (ret == 0)
- dyn_tick->state |= DYN_TICK_ENABLED;
- }
- spin_unlock_irqrestore(&dyn_tick->lock, flags);
- }
+ int ret = sysdev_class_register(&timer_sysclass);
+ if (ret != 0)
+ return ret;
- return ret;
+ sys_timer->dev.cls = &timer_sysclass;
+ return sysdev_register(&sys_timer->dev);
}
+device_initcall(timer_init_sysfs);
-static int timer_dyn_tick_disable(void)
-{
- struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
- unsigned long flags;
- int ret = -ENODEV;
-
- if (dyn_tick) {
- spin_lock_irqsave(&dyn_tick->lock, flags);
- ret = 0;
- if (dyn_tick->state & DYN_TICK_ENABLED) {
- ret = dyn_tick->disable();
-
- if (ret == 0)
- dyn_tick->state &= ~DYN_TICK_ENABLED;
- }
- spin_unlock_irqrestore(&dyn_tick->lock, flags);
- }
-
- return ret;
-}
+void (*board_time_init)(void);
/*
- * Reprogram the system timer for at least the calculated time interval.
- * This function should be called from the idle thread with IRQs disabled,
- * immediately before sleeping.
+ * Shamelessly based on the MIPS and Sparc64 work.
*/
-void timer_dyn_reprogram(void)
-{
- struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
- unsigned long next, seq, flags;
-
- if (!dyn_tick)
- return;
-
- spin_lock_irqsave(&dyn_tick->lock, flags);
- if (dyn_tick->state & DYN_TICK_ENABLED) {
- next = next_timer_interrupt();
- do {
- seq = read_seqbegin(&xtime_lock);
- dyn_tick->reprogram(next - jiffies);
- } while (read_seqretry(&xtime_lock, seq));
- }
- spin_unlock_irqrestore(&dyn_tick->lock, flags);
-}
+static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
+unsigned long sh_hpt_frequency = 0;
+
+#define NSEC_PER_CYC_SHIFT 10
+
+struct clocksource clocksource_sh = {
+ .name = "SuperH",
+ .rating = 200,
+ .mask = CLOCKSOURCE_MASK(32),
+ .read = null_hpt_read,
+ .shift = 16,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
-static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
+static void __init init_sh_clocksource(void)
{
- return sprintf(buf, "%i\n",
- (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
-}
+ if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
+ return;
-static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
- size_t count)
-{
- unsigned int enable = simple_strtoul(buf, NULL, 2);
+ clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
+ clocksource_sh.shift);
- if (enable)
- timer_dyn_tick_enable();
- else
- timer_dyn_tick_disable();
+ timer_ticks_per_nsec_quotient =
+ clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
- return count;
+ clocksource_register(&clocksource_sh);
}
-static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
-/*
- * dyntick=enable|disable
- */
-static char dyntick_str[4] __initdata = "";
-
-static int __init dyntick_setup(char *str)
+#ifdef CONFIG_GENERIC_TIME
+unsigned long long sched_clock(void)
{
- if (str)
- strlcpy(dyntick_str, str, sizeof(dyntick_str));
- return 1;
+ unsigned long long ticks = clocksource_sh.read();
+ return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
}
-
-__setup("dyntick=", dyntick_setup);
-#endif
-
-static int __init timer_init_sysfs(void)
-{
- int ret = sysdev_class_register(&timer_sysclass);
- if (ret != 0)
- return ret;
-
- sys_timer->dev.cls = &timer_sysclass;
- ret = sysdev_register(&sys_timer->dev);
-
-#ifdef CONFIG_NO_IDLE_HZ
- if (ret == 0 && sys_timer->dyn_tick) {
- ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick);
-
- /*
- * Turn on dynamic tick after calibrate delay
- * for correct bogomips
- */
- if (ret == 0 && dyntick_str[0] == 'e')
- ret = timer_dyn_tick_enable();
- }
#endif
- return ret;
-}
-device_initcall(timer_init_sysfs);
-
-void (*board_time_init)(void);
-
void __init time_init(void)
{
if (board_time_init)
@@ -316,10 +249,15 @@ void __init time_init(void)
sys_timer = get_sys_timer();
printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
-#ifdef CONFIG_NO_IDLE_HZ
- if (sys_timer->dyn_tick)
- spin_lock_init(&sys_timer->dyn_tick->lock);
-#endif
+ if (sys_timer->ops->read)
+ clocksource_sh.read = sys_timer->ops->read;
+
+ init_sh_clocksource();
+
+ if (sh_hpt_frequency)
+ printk("Using %lu.%03lu MHz high precision timer.\n",
+ ((sh_hpt_frequency + 500) / 1000) / 1000,
+ ((sh_hpt_frequency + 500) / 1000) % 1000);
#if defined(CONFIG_SH_KGDB)
/*
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index d9e3151c891..2d997e2a5b6 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -1,7 +1,7 @@
/*
* arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support
*
- * Copyright (C) 2005 Paul Mundt
+ * Copyright (C) 2005 - 2007 Paul Mundt
*
* TMU handling code hacked out of arch/sh/kernel/time.c
*
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/seqlock.h>
+#include <linux/clockchips.h>
#include <asm/timer.h>
#include <asm/rtc.h>
#include <asm/io.h>
@@ -25,56 +26,75 @@
#include <asm/clock.h>
#define TMU_TOCR_INIT 0x00
-#define TMU0_TCR_INIT 0x0020
-#define TMU_TSTR_INIT 1
+#define TMU_TCR_INIT 0x0020
-#define TMU0_TCR_CALIB 0x0000
+static int tmu_timer_start(void)
+{
+ ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR);
+ return 0;
+}
-static unsigned long tmu_timer_get_offset(void)
+static void tmu0_timer_set_interval(unsigned long interval, unsigned int reload)
{
- int count;
- static int count_p = 0x7fffffff; /* for the first call after boot */
- static unsigned long jiffies_p = 0;
+ ctrl_outl(interval, TMU0_TCNT);
/*
- * cache volatile jiffies temporarily; we have IRQs turned off.
+ * TCNT reloads from TCOR on underflow, clear it if we don't
+ * intend to auto-reload
*/
- unsigned long jiffies_t;
+ if (reload)
+ ctrl_outl(interval, TMU0_TCOR);
+ else
+ ctrl_outl(0, TMU0_TCOR);
- /* timer count may underflow right here */
- count = ctrl_inl(TMU0_TCNT); /* read the latched count */
+ tmu_timer_start();
+}
- jiffies_t = jiffies;
+static int tmu_timer_stop(void)
+{
+ ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR);
+ return 0;
+}
- /*
- * avoiding timer inconsistencies (they are rare, but they happen)...
- * there is one kind of problem that must be avoided here:
- * 1. the timer counter underflows
- */
+static cycle_t tmu_timer_read(void)
+{
+ return ~ctrl_inl(TMU1_TCNT);
+}
+
+static int tmu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ tmu0_timer_set_interval(cycles, 1);
+ return 0;
+}
- if (jiffies_t == jiffies_p) {
- if (count > count_p) {
- /* the nutcase */
- if (ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */
- count -= LATCH;
- } else {
- printk("%s (): hardware timer problem?\n",
- __FUNCTION__);
- }
- }
- } else
- jiffies_p = jiffies_t;
-
- count_p = count;
-
- count = ((LATCH-1) - count) * TICK_SIZE;
- count = (count + LATCH/2) / LATCH;
-
- return count;
+static void tmu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ ctrl_outl(ctrl_inl(TMU0_TCNT), TMU0_TCOR);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ ctrl_outl(0, TMU0_TCOR);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ }
}
+static struct clock_event_device tmu0_clockevent = {
+ .name = "tmu0",
+ .shift = 32,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = tmu_set_mode,
+ .set_next_event = tmu_set_next_event,
+};
+
static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
{
+ struct clock_event_device *evt = &tmu0_clockevent;
unsigned long timer_status;
/* Clear UNF bit */
@@ -82,72 +102,76 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
timer_status &= ~0x100;
ctrl_outw(timer_status, TMU0_TCR);
- /*
- * Here we are in the timer irq handler. We just have irqs locally
- * disabled but we don't know if the timer_bh is running on the other
- * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
- * the irq version of write_lock because as just said we have irq
- * locally disabled. -arca
- */
- write_seqlock(&xtime_lock);
- handle_timer_tick();
- write_sequnlock(&xtime_lock);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
-static struct irqaction tmu_irq = {
- .name = "timer",
+static struct irqaction tmu0_irq = {
+ .name = "periodic timer",
.handler = tmu_timer_interrupt,
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.mask = CPU_MASK_NONE,
};
-static void tmu_clk_init(struct clk *clk)
+static void tmu0_clk_init(struct clk *clk)
{
- u8 divisor = TMU0_TCR_INIT & 0x7;
- ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
+ u8 divisor = TMU_TCR_INIT & 0x7;
+ ctrl_outw(TMU_TCR_INIT, TMU0_TCR);
clk->rate = clk->parent->rate / (4 << (divisor << 1));
}
-static void tmu_clk_recalc(struct clk *clk)
+static void tmu0_clk_recalc(struct clk *clk)
{
u8 divisor = ctrl_inw(TMU0_TCR) & 0x7;
clk->rate = clk->parent->rate / (4 << (divisor << 1));
}
-static struct clk_ops tmu_clk_ops = {
- .init = tmu_clk_init,
- .recalc = tmu_clk_recalc,
+static struct clk_ops tmu0_clk_ops = {
+ .init = tmu0_clk_init,
+ .recalc = tmu0_clk_recalc,
};
static struct clk tmu0_clk = {
.name = "tmu0_clk",
- .ops = &tmu_clk_ops,
+ .ops = &tmu0_clk_ops,
};
-static int tmu_timer_start(void)
+static void tmu1_clk_init(struct clk *clk)
{
- ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
- return 0;
+ u8 divisor = TMU_TCR_INIT & 0x7;
+ ctrl_outw(divisor, TMU1_TCR);
+ clk->rate = clk->parent->rate / (4 << (divisor << 1));
}
-static int tmu_timer_stop(void)
+static void tmu1_clk_recalc(struct clk *clk)
{
- ctrl_outb(0, TMU_TSTR);
- return 0;
+ u8 divisor = ctrl_inw(TMU1_TCR) & 0x7;
+ clk->rate = clk->parent->rate / (4 << (divisor << 1));
}
+static struct clk_ops tmu1_clk_ops = {
+ .init = tmu1_clk_init,
+ .recalc = tmu1_clk_recalc,
+};
+
+static struct clk tmu1_clk = {
+ .name = "tmu1_clk",
+ .ops = &tmu1_clk_ops,
+};
+
static int tmu_timer_init(void)
{
unsigned long interval;
+ unsigned long frequency;
- setup_irq(CONFIG_SH_TIMER_IRQ, &tmu_irq);
+ setup_irq(CONFIG_SH_TIMER_IRQ, &tmu0_irq);
tmu0_clk.parent = clk_get(NULL, "module_clk");
+ tmu1_clk.parent = clk_get(NULL, "module_clk");
- /* Start TMU0 */
tmu_timer_stop();
+
#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
!defined(CONFIG_CPU_SUBTYPE_SH7760) && \
!defined(CONFIG_CPU_SUBTYPE_SH7785)
@@ -155,15 +179,29 @@ static int tmu_timer_init(void)
#endif
clk_register(&tmu0_clk);
+ clk_register(&tmu1_clk);
clk_enable(&tmu0_clk);
+ clk_enable(&tmu1_clk);
- interval = (clk_get_rate(&tmu0_clk) + HZ / 2) / HZ;
- printk(KERN_INFO "Interval = %ld\n", interval);
+ frequency = clk_get_rate(&tmu0_clk);
+ interval = (frequency + HZ / 2) / HZ;
- ctrl_outl(interval, TMU0_TCOR);
- ctrl_outl(interval, TMU0_TCNT);
+ sh_hpt_frequency = clk_get_rate(&tmu1_clk);
+ ctrl_outl(~0, TMU1_TCNT);
+ ctrl_outl(~0, TMU1_TCOR);
- tmu_timer_start();
+ tmu0_timer_set_interval(interval, 1);
+
+ tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
+ tmu0_clockevent.shift);
+ tmu0_clockevent.max_delta_ns =
+ clockevent_delta2ns(-1, &tmu0_clockevent);
+ tmu0_clockevent.min_delta_ns =
+ clockevent_delta2ns(1, &tmu0_clockevent);
+
+ tmu0_clockevent.cpumask = cpumask_of_cpu(0);
+
+ clockevents_register_device(&tmu0_clockevent);
return 0;
}
@@ -172,9 +210,7 @@ struct sys_timer_ops tmu_timer_ops = {
.init = tmu_timer_init,
.start = tmu_timer_start,
.stop = tmu_timer_stop,
-#ifndef CONFIG_GENERIC_TIME
- .get_offset = tmu_timer_get_offset,
-#endif
+ .read = tmu_timer_read,
};
struct sys_timer tmu_timer = {
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 7b40f0ff3df..3a197649cd8 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -20,10 +20,10 @@
#include <linux/io.h>
#include <linux/bug.h>
#include <linux/debug_locks.h>
+#include <linux/kdebug.h>
#include <linux/limits.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include <asm/kdebug.h>
#ifdef CONFIG_SH_KGDB
#include <asm/kgdb.h>
@@ -76,20 +76,6 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
}
}
-ATOMIC_NOTIFIER_HEAD(shdie_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&shdie_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&shdie_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
-
static DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err)
@@ -505,7 +491,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
simple:
ret = handle_unaligned_ins(instruction,regs);
if (ret==0)
- regs->pc += 2;
+ regs->pc += instruction_size(instruction);
return ret;
}
#endif /* CONFIG_CPU_SH2A */
@@ -682,7 +668,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
err = do_fpu_inst(inst, regs);
if (!err) {
- regs->pc += 2;
+ regs->pc += instruction_size(inst);
return;
}
/* not a FPU inst. */