summary refs log tree commit diff
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-19 16:09:43 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-19 16:09:43 -0700
commitb31a3bc3dbd2f42b61674d37de7f46022e1f6846 (patch)
treef497661f34009eff1455df8729ce750fdddad7e5 /arch
parentd5e2d00898bdfed9586472679760fc81a2ca2d02 (diff)
parentb15d53d009558d14c4f394a6d1fa2039c7f45c43 (diff)
downloadlinux-b31a3bc3dbd2f42b61674d37de7f46022e1f6846.tar.gz
Merge tag 'tag-sh-for-4.6' of git://git.libc.org/linux-sh
Pull arch/sh updates from Rich Felker:
 "This includes minor cleanups, a fix for a crash that likely affects
  all sh models with MMU, and introduction of a framework for boards
  described by device tree, which sets the stage for future J2 support"

* tag 'tag-sh-for-4.6' of git://git.libc.org/linux-sh:
  sched/preempt, sh: kmap_coherent relies on disabled preemption
  sh: add SMP method selection to device tree pseudo-board
  sh: add device tree support and generic board using device tree
  sh: remove arch-specific localtimer and use generic one
  sh: make MMU-specific SMP code conditional on CONFIG_MMU
  sh: provide unified syscall trap compatible with all SH models
  sh: New gcc support
  sh: Disable trace for kernel uncompressing.
  sh: Use generic clkdev.h header
Diffstat (limited to 'arch')
-rw-r--r--arch/sh/Kconfig1
-rw-r--r--arch/sh/boards/Kconfig15
-rw-r--r--arch/sh/boards/Makefile2
-rw-r--r--arch/sh/boards/of-generic.c196
-rw-r--r--arch/sh/boot/compressed/Makefile2
-rw-r--r--arch/sh/include/asm/Kbuild1
-rw-r--r--arch/sh/include/asm/clkdev.h33
-rw-r--r--arch/sh/include/asm/smp.h10
-rw-r--r--arch/sh/kernel/Makefile1
-rw-r--r--arch/sh/kernel/cpu/sh2/entry.S8
-rw-r--r--arch/sh/kernel/cpu/sh2a/entry.S8
-rw-r--r--arch/sh/kernel/entry-common.S21
-rw-r--r--arch/sh/kernel/head_32.S13
-rw-r--r--arch/sh/kernel/localtimer.c60
-rw-r--r--arch/sh/kernel/setup.c27
-rw-r--r--arch/sh/kernel/sh_ksyms_32.c3
-rw-r--r--arch/sh/kernel/smp.c24
-rw-r--r--arch/sh/lib/ashlsi3.S35
-rw-r--r--arch/sh/lib/ashrsi3.S33
-rw-r--r--arch/sh/lib/lshrsi3.S34
-rw-r--r--arch/sh/mm/kmap.c2
21 files changed, 384 insertions, 145 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 17a4f1593d65..7ed20fc3fc81 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -1,5 +1,6 @@
 config SUPERH
 	def_bool y
+	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select HAVE_PATA_PLATFORM
 	select CLKDEV_LOOKUP
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 89963d13f930..5e52d5362292 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -6,6 +6,21 @@ config SOLUTION_ENGINE
 config SH_ALPHA_BOARD
 	bool
 
+config SH_DEVICE_TREE
+	bool "Board Described by Device Tree"
+	select OF
+	select OF_EARLY_FLATTREE
+	select CLKSRC_OF
+	select GENERIC_CALIBRATE_DELAY
+	help
+	  Select Board Described by Device Tree to build a kernel that
+	  does not hard-code any board-specific knowledge but instead uses
+	  a device tree blob provided by the boot-loader. You must enable
+	  drivers for any hardware you want to use separately. At this
+	  time, only boards based on the open-hardware J-Core processors
+	  have sufficient driver coverage to use this option; do not
+	  select it if you are using original SuperH hardware.
+
 config SH_SOLUTION_ENGINE
 	bool "SolutionEngine"
 	select SOLUTION_ENGINE
diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile
index 975a0f64ff20..cea300362035 100644
--- a/arch/sh/boards/Makefile
+++ b/arch/sh/boards/Makefile
@@ -15,3 +15,5 @@ obj-$(CONFIG_SH_TITAN)		+= board-titan.o
 obj-$(CONFIG_SH_SH7757LCR)	+= board-sh7757lcr.o
 obj-$(CONFIG_SH_APSH4A3A)	+= board-apsh4a3a.o
 obj-$(CONFIG_SH_APSH4AD0A)	+= board-apsh4ad0a.o
+
+obj-$(CONFIG_SH_DEVICE_TREE)	+= of-generic.o
diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
new file mode 100644
index 000000000000..bf3a166a5407
--- /dev/null
+++ b/arch/sh/boards/of-generic.c
@@ -0,0 +1,196 @@
+/*
+ * SH generic board support, using device tree
+ *
+ * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
+ *
+ * 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/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/of_iommu.h>
+#include <linux/clocksource.h>
+#include <linux/irqchip.h>
+#include <linux/clk-provider.h>
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+
+#ifdef CONFIG_SMP
+
+static void dummy_smp_setup(void)
+{
+}
+
+static void dummy_prepare_cpus(unsigned int max_cpus)
+{
+}
+
+static void dummy_start_cpu(unsigned int cpu, unsigned long entry_point)
+{
+}
+
+static unsigned int dummy_smp_processor_id(void)
+{
+	return 0;
+}
+
+static void dummy_send_ipi(unsigned int cpu, unsigned int message)
+{
+}
+
+static struct plat_smp_ops dummy_smp_ops = {
+	.smp_setup		= dummy_smp_setup,
+	.prepare_cpus		= dummy_prepare_cpus,
+	.start_cpu		= dummy_start_cpu,
+	.smp_processor_id	= dummy_smp_processor_id,
+	.send_ipi		= dummy_send_ipi,
+	.cpu_die		= native_cpu_die,
+	.cpu_disable		= native_cpu_disable,
+	.play_dead		= native_play_dead,
+};
+
+extern const struct of_cpu_method __cpu_method_of_table[];
+const struct of_cpu_method __cpu_method_of_table_sentinel
+	__section(__cpu_method_of_table_end);
+
+static void sh_of_smp_probe(void)
+{
+	struct device_node *np = 0;
+	const char *method = 0;
+	const struct of_cpu_method *m = __cpu_method_of_table;
+
+	pr_info("SH generic board support: scanning for cpus\n");
+
+	init_cpu_possible(cpumask_of(0));
+
+	while ((np = of_find_node_by_type(np, "cpu"))) {
+		const __be32 *cell = of_get_property(np, "reg", NULL);
+		u64 id = -1;
+		if (cell) id = of_read_number(cell, of_n_addr_cells(np));
+		if (id < NR_CPUS) {
+			if (!method)
+				of_property_read_string(np, "enable-method", &method);
+			set_cpu_possible(id, true);
+			set_cpu_present(id, true);
+			__cpu_number_map[id] = id;
+			__cpu_logical_map[id] = id;
+		}
+	}
+	if (!method) {
+		np = of_find_node_by_name(NULL, "cpus");
+		of_property_read_string(np, "enable-method", &method);
+	}
+
+	pr_info("CPU enable method: %s\n", method);
+	if (method)
+		for (; m->method; m++)
+			if (!strcmp(m->method, method)) {
+				register_smp_ops(m->ops);
+				return;
+			}
+
+	register_smp_ops(&dummy_smp_ops);
+}
+
+#else
+
+static void sh_of_smp_probe(void)
+{
+}
+
+#endif
+
+static void noop(void)
+{
+}
+
+static int noopi(void)
+{
+	return 0;
+}
+
+static void __init sh_of_mem_reserve(void)
+{
+	early_init_fdt_reserve_self();
+	early_init_fdt_scan_reserved_mem();
+}
+
+static void __init sh_of_time_init(void)
+{
+	pr_info("SH generic board support: scanning for clocksource devices\n");
+	clocksource_probe();
+}
+
+static void __init sh_of_setup(char **cmdline_p)
+{
+	unflatten_device_tree();
+
+	board_time_init = sh_of_time_init;
+
+	sh_mv.mv_name = of_flat_dt_get_machine_name();
+	if (!sh_mv.mv_name)
+		sh_mv.mv_name = "Unknown SH model";
+
+	sh_of_smp_probe();
+}
+
+static int sh_of_irq_demux(int irq)
+{
+	/* FIXME: eventually this should not be used at all;
+	 * the interrupt controller should set_handle_irq(). */
+	return irq;
+}
+
+static void __init sh_of_init_irq(void)
+{
+	pr_info("SH generic board support: scanning for interrupt controllers\n");
+	irqchip_init();
+}
+
+static int __init sh_of_clk_init(void)
+{
+#ifdef CONFIG_COMMON_CLK
+	/* Disabled pending move to COMMON_CLK framework. */
+	pr_info("SH generic board support: scanning for clk providers\n");
+	of_clk_init(NULL);
+#endif
+	return 0;
+}
+
+static struct sh_machine_vector __initmv sh_of_generic_mv = {
+	.mv_setup	= sh_of_setup,
+	.mv_name	= "devicetree", /* replaced by DT root's model */
+	.mv_irq_demux	= sh_of_irq_demux,
+	.mv_init_irq	= sh_of_init_irq,
+	.mv_clk_init	= sh_of_clk_init,
+	.mv_mode_pins	= noopi,
+	.mv_mem_init	= noop,
+	.mv_mem_reserve	= sh_of_mem_reserve,
+};
+
+struct sh_clk_ops;
+
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
+{
+}
+
+void __init plat_irq_setup(void)
+{
+}
+
+static int __init sh_of_device_init(void)
+{
+	pr_info("SH generic board support: populating platform devices\n");
+	if (of_have_populated_dt()) {
+		of_iommu_init();
+		of_platform_populate(NULL, of_default_bus_match_table,
+				     NULL, NULL);
+	} else {
+		pr_crit("Device tree not populated\n");
+	}
+	return 0;
+}
+arch_initcall_sync(sh_of_device_init);
diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
index 23bc849d9c64..6df826ee7316 100644
--- a/arch/sh/boot/compressed/Makefile
+++ b/arch/sh/boot/compressed/Makefile
@@ -48,7 +48,7 @@ ifeq ($(BITS),64)
 	lib1funcs-dir 	:= $(addsuffix $(BITS), $(lib1funcs-dir))
 endif
 
-KBUILD_CFLAGS += -I$(lib1funcs-dir)
+KBUILD_CFLAGS += -I$(lib1funcs-dir) -DDISABLE_BRANCH_PROFILING
 
 $(addprefix $(obj)/,$(lib1funcs-y)): $(obj)/%: $(lib1funcs-dir)/% FORCE
 	$(call cmd,shipped)
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index aac452b26aa8..a319745a7b63 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -1,5 +1,6 @@
 
 generic-y += bitsperlong.h
+generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += current.h
 generic-y += delay.h
diff --git a/arch/sh/include/asm/clkdev.h b/arch/sh/include/asm/clkdev.h
deleted file mode 100644
index c41901465fb0..000000000000
--- a/arch/sh/include/asm/clkdev.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  Copyright (C) 2010 Paul Mundt <lethal@linux-sh.org>
- *
- * 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.
- *
- * Helper for the clk API to assist looking up a struct clk.
- */
-
-#ifndef __CLKDEV__H_
-#define __CLKDEV__H_
-
-#include <linux/bootmem.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include <asm/clock.h>
-
-static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
-{
-	if (!slab_is_available())
-		return alloc_bootmem_low_pages(size);
-	else
-		return kzalloc(size, GFP_KERNEL);
-}
-
-#ifndef CONFIG_COMMON_CLK
-#define __clk_put(clk)
-#define __clk_get(clk) ({ 1; })
-#endif
-
-#endif /* __CLKDEV_H__ */
diff --git a/arch/sh/include/asm/smp.h b/arch/sh/include/asm/smp.h
index 78b0d0f4b24b..1baf0ba96242 100644
--- a/arch/sh/include/asm/smp.h
+++ b/arch/sh/include/asm/smp.h
@@ -69,6 +69,16 @@ static inline int hard_smp_processor_id(void)
 	return mp_ops->smp_processor_id();
 }
 
+struct of_cpu_method {
+	const char *method;
+	struct plat_smp_ops *ops;
+};
+
+#define CPU_METHOD_OF_DECLARE(name, _method, _ops)			\
+	static const struct of_cpu_method __cpu_method_of_table_##name	\
+		__used __section(__cpu_method_of_table)			\
+		= { .method = _method, .ops = _ops }
+
 #else
 
 #define hard_smp_processor_id()	(0)
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 2ccf36c824c6..09040fd07d2e 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -46,6 +46,5 @@ obj-$(CONFIG_DWARF_UNWINDER)	+= dwarf.o
 obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_callchain.o
 
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)		+= hw_breakpoint.o
-obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)	+= localtimer.o
 
 ccflags-y := -Werror
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S
index c8a4331d9b8d..a1505956ef28 100644
--- a/arch/sh/kernel/cpu/sh2/entry.S
+++ b/arch/sh/kernel/cpu/sh2/entry.S
@@ -144,9 +144,9 @@ ENTRY(exception_handler)
 	mov	#64,r8
 	cmp/hs	r8,r9
 	bt	interrupt_entry	! vec >= 64 is interrupt
-	mov	#32,r8
+	mov	#31,r8
 	cmp/hs	r8,r9
-	bt	trap_entry	! 64 > vec >= 32  is trap
+	bt	trap_entry	! 64 > vec >= 31  is trap
 
 	mov.l	4f,r8
 	mov	r9,r4
@@ -178,9 +178,9 @@ interrupt_entry:
 
 trap_entry:
 	mov	#0x30,r8
-	cmp/ge	r8,r9		! vector 0x20-0x2f is systemcall
+	cmp/ge	r8,r9		! vector 0x1f-0x2f is systemcall
 	bt	1f
-	add	#-0x10,r9	! convert SH2 to SH3/4 ABI
+	mov     #0x1f,r9	! convert to unified SH2/3/4 trap number
 1:	
 	shll2	r9			! TRA
 	bra	system_call	! jump common systemcall entry
diff --git a/arch/sh/kernel/cpu/sh2a/entry.S b/arch/sh/kernel/cpu/sh2a/entry.S
index 222742ddc0d6..da77a8ef4696 100644
--- a/arch/sh/kernel/cpu/sh2a/entry.S
+++ b/arch/sh/kernel/cpu/sh2a/entry.S
@@ -109,9 +109,9 @@ ENTRY(exception_handler)
 	mov	#64,r8
 	cmp/hs	r8,r9
 	bt	interrupt_entry	! vec >= 64 is interrupt
-	mov	#32,r8
+	mov	#31,r8
 	cmp/hs	r8,r9
-	bt	trap_entry	! 64 > vec >= 32  is trap
+	bt	trap_entry	! 64 > vec >= 31  is trap
 
 	mov.l	4f,r8
 	mov	r9,r4
@@ -143,9 +143,9 @@ interrupt_entry:
 
 trap_entry:
 	mov	#0x30,r8
-	cmp/ge	r8,r9		! vector 0x20-0x2f is systemcall
+	cmp/ge	r8,r9		! vector 0x1f-0x2f is systemcall
 	bt	1f
-	add	#-0x10,r9	! convert SH2 to SH3/4 ABI
+	mov     #0x1f,r9	! convert to unified SH2/3/4 trap number
 1:	
 	shll2	r9			! TRA
 	bra	system_call	! jump common systemcall entry
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index 13047a4facd2..c001f782c5f1 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -268,20 +268,29 @@ debug_trap:
  *	Syscall #: R3
  *	Arguments #0 to #3: R4--R7
  *	Arguments #4 to #6: R0, R1, R2
- *	TRA: (number of arguments + ABI revision) x 4
+ *	TRA: See following table.
  *
- * This code also handles delegating other traps to the BIOS/gdb stub
- * according to:
- *
- * Trap number
  * (TRA>>2)	Purpose
  * --------	-------
  * 0x00-0x0f	original SH-3/4 syscall ABI (not in general use).
  * 0x10-0x1f	general SH-3/4 syscall ABI.
- * 0x20-0x2f	syscall ABI for SH-2 parts.
+ *      0x1f	unified SH-2/3/4 syscall ABI (preferred).
+ * 0x20-0x2f	original SH-2 syscall ABI.
  * 0x30-0x3f	debug traps used by the kernel.
  * 0x40-0xff	Not supported by all parts, so left unhandled.
  *
+ * For making system calls, any trap number in the range for the
+ * given cpu model may be used, but the unified trap number 0x1f is
+ * preferred for compatibility with all models.
+ *
+ * The low bits of the trap number were once documented as matching
+ * the number of arguments, but they were never actually used as such
+ * by the kernel. SH-2 originally used its own separate trap range
+ * because several hardware exceptions fell in the range used for the
+ * SH-3/4 syscall ABI.
+ *
+ * This code also handles delegating other traps to the BIOS/gdb stub.
+ *
  * Note: When we're first called, the TRA value must be shifted
  * right 2 bits in order to get the value that was used as the "trapa"
  * argument.
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index 7db248936b60..974bc152cc84 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -66,6 +66,10 @@ ENTRY(_stext)
 	mov	#0, r0
 	ldc	r0, r6_bank
 #endif
+
+#ifdef CONFIG_OF
+	mov	r4, r12		! Store device tree blob pointer in r12
+#endif
 	
 	/*
 	 * Prefetch if possible to reduce cache miss penalty.
@@ -314,6 +318,12 @@ ENTRY(_stext)
 10:		
 #endif
 
+#ifdef CONFIG_OF
+	mov.l	8f, r0		! Make flat device tree available early.
+	jsr	@r0
+	 mov	r12, r4
+#endif
+
 	!			Additional CPU initialization
 	mov.l	6f, r0
 	jsr	@r0
@@ -339,6 +349,9 @@ ENTRY(stack_start)
 5:	.long	start_kernel
 6:	.long	cpu_init
 7:	.long	init_thread_union
+#if defined(CONFIG_OF)
+8:	.long	sh_fdt_init
+#endif
 
 #ifdef CONFIG_PMB
 .LPMB_ADDR:		.long	PMB_ADDR
diff --git a/arch/sh/kernel/localtimer.c b/arch/sh/kernel/localtimer.c
deleted file mode 100644
index cbb7d4636ec0..000000000000
--- a/arch/sh/kernel/localtimer.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Dummy local timer
- *
- * Copyright (C) 2008  Paul Mundt
- *
- * cloned from:
- *
- *  linux/arch/arm/mach-realview/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  All Rights Reserved
- *
- * 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 <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/smp.h>
-#include <linux/jiffies.h>
-#include <linux/percpu.h>
-#include <linux/clockchips.h>
-#include <linux/hardirq.h>
-#include <linux/irq.h>
-
-static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
-
-/*
- * Used on SMP for either the local timer or SMP_MSG_TIMER
- */
-void local_timer_interrupt(void)
-{
-	struct clock_event_device *clk = this_cpu_ptr(&local_clockevent);
-
-	irq_enter();
-	clk->event_handler(clk);
-	irq_exit();
-}
-
-void local_timer_setup(unsigned int cpu)
-{
-	struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
-
-	clk->name		= "dummy_timer";
-	clk->features		= CLOCK_EVT_FEAT_ONESHOT |
-				  CLOCK_EVT_FEAT_PERIODIC |
-				  CLOCK_EVT_FEAT_DUMMY;
-	clk->rating		= 400;
-	clk->mult		= 1;
-	clk->broadcast		= smp_timer_broadcast;
-	clk->cpumask		= cpumask_of(cpu);
-
-	clockevents_register_device(clk);
-}
-
-void local_timer_stop(unsigned int cpu)
-{
-}
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 3f1c18b28e8a..5d34605b58b5 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -29,6 +29,8 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/memblock.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
@@ -172,6 +174,7 @@ disable:
 #endif
 }
 
+#ifndef CONFIG_GENERIC_CALIBRATE_DELAY
 void calibrate_delay(void)
 {
 	struct clk *clk = clk_get(NULL, "cpu_clk");
@@ -187,6 +190,7 @@ void calibrate_delay(void)
 			 (loops_per_jiffy/(5000/HZ)) % 100,
 			 loops_per_jiffy);
 }
+#endif
 
 void __init __add_active_range(unsigned int nid, unsigned long start_pfn,
 						unsigned long end_pfn)
@@ -238,6 +242,29 @@ void __init __weak plat_early_device_setup(void)
 {
 }
 
+#ifdef CONFIG_OF
+void __ref sh_fdt_init(phys_addr_t dt_phys)
+{
+	static int done = 0;
+	void *dt_virt;
+
+	/* Avoid calling an __init function on secondary cpus. */
+	if (done) return;
+
+	dt_virt = phys_to_virt(dt_phys);
+
+	if (!dt_virt || !early_init_dt_scan(dt_virt)) {
+		pr_crit("Error: invalid device tree blob"
+			" at physical address %p\n", (void *)dt_phys);
+
+		while (true)
+			cpu_relax();
+	}
+
+	done = 1;
+}
+#endif
+
 void __init setup_arch(char **cmdline_p)
 {
 	enable_mmu();
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c
index d77f2f6c7ff0..0b30b9dfc87f 100644
--- a/arch/sh/kernel/sh_ksyms_32.c
+++ b/arch/sh/kernel/sh_ksyms_32.c
@@ -34,6 +34,9 @@ DECLARE_EXPORT(__sdivsi3);
 DECLARE_EXPORT(__lshrsi3);
 DECLARE_EXPORT(__ashrsi3);
 DECLARE_EXPORT(__ashlsi3);
+DECLARE_EXPORT(__lshrsi3_r0);
+DECLARE_EXPORT(__ashrsi3_r0);
+DECLARE_EXPORT(__ashlsi3_r0);
 DECLARE_EXPORT(__ashiftrt_r4_6);
 DECLARE_EXPORT(__ashiftrt_r4_7);
 DECLARE_EXPORT(__ashiftrt_r4_8);
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 13f633add29a..38e7860845db 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/atomic.h>
+#include <linux/clockchips.h>
 #include <asm/processor.h>
 #include <asm/mmu_context.h>
 #include <asm/smp.h>
@@ -141,16 +142,13 @@ int __cpu_disable(void)
 	migrate_irqs();
 
 	/*
-	 * Stop the local timer for this CPU.
-	 */
-	local_timer_stop(cpu);
-
-	/*
 	 * Flush user cache and TLB mappings, and then remove this CPU
 	 * from the vm mask set of all processes.
 	 */
 	flush_cache_all();
+#ifdef CONFIG_MMU
 	local_flush_tlb_all();
+#endif
 
 	clear_tasks_mm_cpumask(cpu);
 
@@ -183,8 +181,10 @@ asmlinkage void start_secondary(void)
 	atomic_inc(&mm->mm_count);
 	atomic_inc(&mm->mm_users);
 	current->active_mm = mm;
+#ifdef CONFIG_MMU
 	enter_lazy_tlb(mm, current);
 	local_flush_tlb_all();
+#endif
 
 	per_cpu_trap_init();
 
@@ -194,8 +194,6 @@ asmlinkage void start_secondary(void)
 
 	local_irq_enable();
 
-	/* Enable local timers */
-	local_timer_setup(cpu);
 	calibrate_delay();
 
 	smp_store_cpu_info(cpu);
@@ -285,7 +283,8 @@ void arch_send_call_function_single_ipi(int cpu)
 	mp_ops->send_ipi(cpu, SMP_MSG_FUNCTION_SINGLE);
 }
 
-void smp_timer_broadcast(const struct cpumask *mask)
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+void tick_broadcast(const struct cpumask *mask)
 {
 	int cpu;
 
@@ -296,9 +295,10 @@ void smp_timer_broadcast(const struct cpumask *mask)
 static void ipi_timer(void)
 {
 	irq_enter();
-	local_timer_interrupt();
+	tick_receive_broadcast();
 	irq_exit();
 }
+#endif
 
 void smp_message_recv(unsigned int msg)
 {
@@ -312,9 +312,11 @@ void smp_message_recv(unsigned int msg)
 	case SMP_MSG_FUNCTION_SINGLE:
 		generic_smp_call_function_single_interrupt();
 		break;
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 	case SMP_MSG_TIMER:
 		ipi_timer();
 		break;
+#endif
 	default:
 		printk(KERN_WARNING "SMP %d: %s(): unknown IPI %d\n",
 		       smp_processor_id(), __func__, msg);
@@ -328,6 +330,8 @@ int setup_profiling_timer(unsigned int multiplier)
 	return 0;
 }
 
+#ifdef CONFIG_MMU
+
 static void flush_tlb_all_ipi(void *info)
 {
 	local_flush_tlb_all();
@@ -467,3 +471,5 @@ void flush_tlb_one(unsigned long asid, unsigned long vaddr)
 	smp_call_function(flush_tlb_one_ipi, (void *)&fd, 1);
 	local_flush_tlb_one(asid, vaddr);
 }
+
+#endif
diff --git a/arch/sh/lib/ashlsi3.S b/arch/sh/lib/ashlsi3.S
index bd47e9b403a5..70a6434945ab 100644
--- a/arch/sh/lib/ashlsi3.S
+++ b/arch/sh/lib/ashlsi3.S
@@ -54,21 +54,38 @@ Boston, MA 02110-1301, USA.  */
 !
 ! (none)
 !
+! __ashlsi3_r0
+!
+! Entry:
+!
+! r4: Value to shift
+! r0: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
+
+
 	.global	__ashlsi3
+	.global	__ashlsi3_r0
 	
 	.align	2
 __ashlsi3:
-	mov	#31,r0
-	and	r0,r5
+	mov	r5,r0
+	.align	2
+__ashlsi3_r0:
+	and	#31,r0
+	mov.l	r4,@-r15
+	mov	r0,r4
 	mova	ashlsi3_table,r0
-	mov.b	@(r0,r5),r5
-#ifdef __sh1__
-	add	r5,r0
+	mov.b	@(r0,r4),r4
+	add	r4,r0
 	jmp	@r0
-#else
-	braf	r5
-#endif
-	mov	r4,r0
+	mov.l	@r15+,r0
 
 	.align	2
 ashlsi3_table:
diff --git a/arch/sh/lib/ashrsi3.S b/arch/sh/lib/ashrsi3.S
index 6f3cf46b77c2..602599d80209 100644
--- a/arch/sh/lib/ashrsi3.S
+++ b/arch/sh/lib/ashrsi3.S
@@ -54,22 +54,37 @@ Boston, MA 02110-1301, USA.  */
 !
 ! (none)
 !
+! __ashrsi3_r0
+!
+! Entry:
+!
+! r4: Value to shift
+! r0: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
 
 	.global	__ashrsi3
+	.global	__ashrsi3_r0
 	
 	.align	2
 __ashrsi3:
-	mov	#31,r0
-	and	r0,r5
+	mov	r5,r0
+	.align	2
+__ashrsi3_r0:
+	and	#31,r0
+	mov.l	r4,@-r15
+	mov	r0,r4
 	mova	ashrsi3_table,r0
-	mov.b	@(r0,r5),r5
-#ifdef __sh1__
-	add	r5,r0
+	mov.b	@(r0,r4),r4
+	add	r4,r0
 	jmp	@r0
-#else
-	braf	r5
-#endif
-	mov	r4,r0
+	mov.l	@r15+,r0
 
 	.align	2
 ashrsi3_table:
diff --git a/arch/sh/lib/lshrsi3.S b/arch/sh/lib/lshrsi3.S
index 1e7aaa557130..f2a6959f526d 100644
--- a/arch/sh/lib/lshrsi3.S
+++ b/arch/sh/lib/lshrsi3.S
@@ -54,21 +54,37 @@ Boston, MA 02110-1301, USA.  */
 !
 ! (none)
 !
+! __lshrsi3_r0
+!
+! Entry:
+!
+! r0: Value to shift
+! r5: Shifts
+!
+! Exit:
+!
+! r0: Result
+!
+! Destroys:
+!
+! (none)
+!
 	.global	__lshrsi3
+	.global	__lshrsi3_r0
 	
 	.align	2
 __lshrsi3:
-	mov	#31,r0
-	and	r0,r5
+	mov	r5,r0
+	.align	2
+__lshrsi3_r0:
+	and	#31,r0
+	mov.l	r4,@-r15
+	mov	r0,r4
 	mova	lshrsi3_table,r0
-	mov.b	@(r0,r5),r5
-#ifdef __sh1__
-	add	r5,r0
+	mov.b	@(r0,r4),r4
+	add	r4,r0
 	jmp	@r0
-#else
-	braf	r5
-#endif
-	mov	r4,r0
+	mov.l	@r15+,r0
 
 	.align	2
 lshrsi3_table:
diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c
index ec29e14ec5a8..bf25d7c79a2d 100644
--- a/arch/sh/mm/kmap.c
+++ b/arch/sh/mm/kmap.c
@@ -36,6 +36,7 @@ void *kmap_coherent(struct page *page, unsigned long addr)
 
 	BUG_ON(!test_bit(PG_dcache_clean, &page->flags));
 
+	preempt_disable();
 	pagefault_disable();
 
 	idx = FIX_CMAP_END -
@@ -64,4 +65,5 @@ void kunmap_coherent(void *kvaddr)
 	}
 
 	pagefault_enable();
+	preempt_enable();
 }