aboutsummaryrefslogtreecommitdiff
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-05-08 13:37:51 +1000
committerPaul Mackerras <paulus@samba.org>2007-05-08 13:37:51 +1000
commit02bbc0f09c90cefdb2837605c96a66c5ce4ba2e1 (patch)
tree04ef573cd4de095c500c9fc3477f4278c0b36300 /arch/sh/kernel
parent7487a2245b8841c77ba9db406cf99a483b9334e9 (diff)
parent5b94f675f57e4ff16c8fda09088d7480a84dcd91 (diff)
Merge branch 'linux-2.6'
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/Makefile1
-rw-r--r--arch/sh/kernel/cf-enabler.c28
-rw-r--r--arch/sh/kernel/cpu/clock.c102
-rw-r--r--arch/sh/kernel/cpu/init.c19
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile2
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c3
-rw-r--r--arch/sh/kernel/cpu/irq/pint.c56
-rw-r--r--arch/sh/kernel/cpu/sh3/Makefile1
-rw-r--r--arch/sh/kernel/cpu/sh3/probe.c3
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c54
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7709.c29
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c60
-rw-r--r--arch/sh/kernel/cpu/sh4/clock-sh4-202.c3
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c8
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c600
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7785.c162
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7785.c103
-rw-r--r--arch/sh/kernel/crash_dump.c46
-rw-r--r--arch/sh/kernel/irq.c5
-rw-r--r--arch/sh/kernel/kgdb_stub.c490
-rw-r--r--arch/sh/kernel/machine_kexec.c29
-rw-r--r--arch/sh/kernel/process.c14
-rw-r--r--arch/sh/kernel/setup.c267
-rw-r--r--arch/sh/kernel/sh_ksyms.c1
-rw-r--r--arch/sh/kernel/timers/timer-tmu.c4
-rw-r--r--arch/sh/kernel/traps.c73
-rw-r--r--arch/sh/kernel/vmlinux.lds.S49
28 files changed, 1473 insertions, 743 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index ff30d7f5804..9104b625764 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -20,5 +20,6 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
index 3e5fa1e24df..0758d48147a 100644
--- a/arch/sh/kernel/cf-enabler.c
+++ b/arch/sh/kernel/cf-enabler.c
@@ -29,7 +29,7 @@
* 0xB8001000 : Common Memory
* 0xBA000000 : I/O
*/
-#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4)
/* SH4 can't access PCMCIA interface through P2 area.
* we must remap it with appropreate attribute bit of the page set.
* this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */
@@ -71,7 +71,7 @@ static int __init cf_init_default(void)
/* You must have enabled the card, and set the level interrupt
* before reaching this point. Possibly in boot ROM or boot loader.
*/
-#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4)
allocate_cf_area();
#endif
#if defined(CONFIG_SH_UNKNOWN)
@@ -84,15 +84,25 @@ static int __init cf_init_default(void)
#if defined(CONFIG_SH_SOLUTION_ENGINE)
#include <asm/se.h>
+#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE)
+#include <asm/se7722.h>
+#endif
/*
- * SolutionEngine
+ * SolutionEngine Seriese
*
+ * about MS770xSE
* 0xB8400000 : Common Memory
* 0xB8500000 : Attribute
* 0xB8600000 : I/O
+ *
+ * about MS7722SE
+ * 0xB0400000 : Common Memory
+ * 0xB0500000 : Attribute
+ * 0xB0600000 : I/O
*/
+#if defined(CONFIG_SH_SOLUTION_ENGINE) || defined(CONFIG_SH_7722_SOLUTION_ENGINE)
static int __init cf_init_se(void)
{
if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0)
@@ -109,7 +119,7 @@ static int __init cf_init_se(void)
* flag == COMMON/ATTRIBUTE/IO
*/
/* common window open */
- ctrl_outw(0x8a84, MRSHPC_MW0CR1);/* window 0xb8400000 */
+ ctrl_outw(0x8a84, MRSHPC_MW0CR1);
if((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
/* common mode & bus width 16bit SWAP = 1*/
ctrl_outw(0x0b00, MRSHPC_MW0CR2);
@@ -118,7 +128,7 @@ static int __init cf_init_se(void)
ctrl_outw(0x0300, MRSHPC_MW0CR2);
/* attribute window open */
- ctrl_outw(0x8a85, MRSHPC_MW1CR1);/* window 0xb8500000 */
+ ctrl_outw(0x8a85, MRSHPC_MW1CR1);
if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
/* attribute mode & bus width 16bit SWAP = 1*/
ctrl_outw(0x0a00, MRSHPC_MW1CR2);
@@ -127,7 +137,7 @@ static int __init cf_init_se(void)
ctrl_outw(0x0200, MRSHPC_MW1CR2);
/* I/O window open */
- ctrl_outw(0x8a86, MRSHPC_IOWCR1);/* I/O window 0xb8600000 */
+ ctrl_outw(0x8a86, MRSHPC_IOWCR1);
ctrl_outw(0x0008, MRSHPC_CDCR); /* I/O card mode */
if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
ctrl_outw(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/
@@ -143,10 +153,10 @@ static int __init cf_init_se(void)
int __init cf_init(void)
{
-#if defined(CONFIG_SH_SOLUTION_ENGINE)
- if (MACH_SE)
+ if( mach_is_se() || mach_is_7722se() ){
return cf_init_se();
-#endif
+ }
+
return cf_init_default();
}
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index abb586b1256..014f318f5a0 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -1,7 +1,7 @@
/*
* arch/sh/kernel/cpu/clock.c - SuperH clock framework
*
- * Copyright (C) 2005, 2006 Paul Mundt
+ * Copyright (C) 2005, 2006, 2007 Paul Mundt
*
* This clock framework is derived from the OMAP version by:
*
@@ -23,6 +23,7 @@
#include <linux/seq_file.h>
#include <linux/err.h>
#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
#include <asm/clock.h>
#include <asm/timer.h>
@@ -98,15 +99,17 @@ int __clk_enable(struct clk *clk)
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
+ kref_get(&clk->kref);
+
if (clk->flags & CLK_ALWAYS_ENABLED)
return 0;
if (likely(clk->ops && clk->ops->enable))
clk->ops->enable(clk);
- kref_get(&clk->kref);
return 0;
}
+EXPORT_SYMBOL_GPL(__clk_enable);
int clk_enable(struct clk *clk)
{
@@ -119,6 +122,7 @@ int clk_enable(struct clk *clk)
return ret;
}
+EXPORT_SYMBOL_GPL(clk_enable);
static void clk_kref_release(struct kref *kref)
{
@@ -127,11 +131,17 @@ static void clk_kref_release(struct kref *kref)
void __clk_disable(struct clk *clk)
{
+ int count = kref_put(&clk->kref, clk_kref_release);
+
if (clk->flags & CLK_ALWAYS_ENABLED)
return;
- kref_put(&clk->kref, clk_kref_release);
+ if (!count) { /* count reaches zero, disable the clock */
+ if (likely(clk->ops && clk->ops->disable))
+ clk->ops->disable(clk);
+ }
}
+EXPORT_SYMBOL_GPL(__clk_disable);
void clk_disable(struct clk *clk)
{
@@ -141,6 +151,7 @@ void clk_disable(struct clk *clk)
__clk_disable(clk);
spin_unlock_irqrestore(&clock_lock, flags);
}
+EXPORT_SYMBOL_GPL(clk_disable);
int clk_register(struct clk *clk)
{
@@ -151,8 +162,18 @@ int clk_register(struct clk *clk)
mutex_unlock(&clock_list_sem);
+ if (clk->flags & CLK_ALWAYS_ENABLED) {
+ pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
+ if (clk->ops && clk->ops->init)
+ clk->ops->init(clk);
+ if (clk->ops && clk->ops->enable)
+ clk->ops->enable(clk);
+ pr_debug( "Enabled.");
+ }
+
return 0;
}
+EXPORT_SYMBOL_GPL(clk_register);
void clk_unregister(struct clk *clk)
{
@@ -160,21 +181,29 @@ void clk_unregister(struct clk *clk)
list_del(&clk->node);
mutex_unlock(&clock_list_sem);
}
+EXPORT_SYMBOL_GPL(clk_unregister);
-inline unsigned long clk_get_rate(struct clk *clk)
+unsigned long clk_get_rate(struct clk *clk)
{
return clk->rate;
}
+EXPORT_SYMBOL_GPL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
+ return clk_set_rate_ex(clk, rate, 0);
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
+{
int ret = -EOPNOTSUPP;
if (likely(clk->ops && clk->ops->set_rate)) {
unsigned long flags;
spin_lock_irqsave(&clock_lock, flags);
- ret = clk->ops->set_rate(clk, rate);
+ ret = clk->ops->set_rate(clk, rate, algo_id);
spin_unlock_irqrestore(&clock_lock, flags);
}
@@ -183,6 +212,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
return ret;
}
+EXPORT_SYMBOL_GPL(clk_set_rate_ex);
void clk_recalc_rate(struct clk *clk)
{
@@ -197,6 +227,7 @@ void clk_recalc_rate(struct clk *clk)
if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
propagate_rate(clk);
}
+EXPORT_SYMBOL_GPL(clk_recalc_rate);
/*
* Returns a clock. Note that we first try to use device id on the bus
@@ -233,18 +264,43 @@ found:
return clk;
}
+EXPORT_SYMBOL_GPL(clk_get);
void clk_put(struct clk *clk)
{
if (clk && !IS_ERR(clk))
module_put(clk->owner);
}
+EXPORT_SYMBOL_GPL(clk_put);
void __init __attribute__ ((weak))
arch_init_clk_ops(struct clk_ops **ops, int type)
{
}
+static int show_clocks(char *buf, char **start, off_t off,
+ int len, int *eof, void *data)
+{
+ struct clk *clk;
+ char *p = buf;
+
+ list_for_each_entry_reverse(clk, &clock_list, node) {
+ unsigned long rate = clk_get_rate(clk);
+
+ /*
+ * Don't bother listing dummy clocks with no ancestry
+ * that only support enable and disable ops.
+ */
+ if (unlikely(!rate && !clk->parent))
+ continue;
+
+ p += sprintf(p, "%-12s\t: %ld.%02ldMHz\n", clk->name,
+ rate / 1000000, (rate % 1000000) / 10000);
+ }
+
+ return p - buf;
+}
+
int __init clk_init(void)
{
int i, ret = 0;
@@ -256,7 +312,6 @@ int __init clk_init(void)
arch_init_clk_ops(&clk->ops, i);
ret |= clk_register(clk);
- clk_enable(clk);
}
/* Kick the child clocks.. */
@@ -266,35 +321,14 @@ int __init clk_init(void)
return ret;
}
-int show_clocks(struct seq_file *m)
+static int __init clk_proc_init(void)
{
- struct clk *clk;
-
- list_for_each_entry_reverse(clk, &clock_list, node) {
- unsigned long rate = clk_get_rate(clk);
-
- /*
- * Don't bother listing dummy clocks with no ancestry
- * that only support enable and disable ops.
- */
- if (unlikely(!rate && !clk->parent))
- continue;
-
- seq_printf(m, "%-12s\t: %ld.%02ldMHz\n", clk->name,
- rate / 1000000, (rate % 1000000) / 10000);
- }
+ struct proc_dir_entry *p;
+ p = create_proc_read_entry("clocks", S_IRUSR, NULL,
+ show_clocks, NULL);
+ if (unlikely(!p))
+ return -EINVAL;
return 0;
}
-
-EXPORT_SYMBOL_GPL(clk_register);
-EXPORT_SYMBOL_GPL(clk_unregister);
-EXPORT_SYMBOL_GPL(clk_get);
-EXPORT_SYMBOL_GPL(clk_put);
-EXPORT_SYMBOL_GPL(clk_enable);
-EXPORT_SYMBOL_GPL(clk_disable);
-EXPORT_SYMBOL_GPL(__clk_enable);
-EXPORT_SYMBOL_GPL(__clk_disable);
-EXPORT_SYMBOL_GPL(clk_get_rate);
-EXPORT_SYMBOL_GPL(clk_set_rate);
-EXPORT_SYMBOL_GPL(clk_recalc_rate);
+subsys_initcall(clk_proc_init);
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 726acfcb9b7..6451ad63017 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -41,6 +41,23 @@ __setup("no" __stringify(x), x##_setup);
onchip_setup(fpu);
onchip_setup(dsp);
+#ifdef CONFIG_SPECULATIVE_EXECUTION
+#define CPUOPM 0xff2f0000
+#define CPUOPM_RABD (1 << 5)
+
+static void __init speculative_execution_init(void)
+{
+ /* Clear RABD */
+ ctrl_outl(ctrl_inl(CPUOPM) & ~CPUOPM_RABD, CPUOPM);
+
+ /* Flush the update */
+ (void)ctrl_inl(CPUOPM);
+ ctrl_barrier();
+}
+#else
+#define speculative_execution_init() do { } while (0)
+#endif
+
/*
* Generic first-level cache init
*/
@@ -261,4 +278,6 @@ asmlinkage void __init sh_cpu_init(void)
*/
ubc_wakeup();
#endif
+
+ speculative_execution_init();
}
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 0049d217561..1c23308cfc2 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -4,6 +4,6 @@
obj-y += imask.o
obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o
-obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
+obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
index 74defe76a05..d8e22f4ff0f 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -18,7 +18,8 @@
#define INTC2_BASE 0xfe080000
#define INTC2_INTMSK (INTC2_BASE + 0x40)
#define INTC2_INTMSKCLR (INTC2_BASE + 0x60)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785)
#define INTC2_BASE 0xffd40000
#define INTC2_INTMSK (INTC2_BASE + 0x38)
#define INTC2_INTMSKCLR (INTC2_BASE + 0x3c)
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
index f60007783a2..67602685df1 100644
--- a/arch/sh/kernel/cpu/irq/pint.c
+++ b/arch/sh/kernel/cpu/irq/pint.c
@@ -18,6 +18,58 @@
#include <asm/io.h>
#include <asm/machvec.h>
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#define INTC_INTER 0xA4000014UL
+#define INTC_IPRD 0xA4000018UL
+#define INTC_ICR2 0xA4000012UL
+
+/* PFC */
+#define PORT_PACR 0xA4000100UL
+#define PORT_PBCR 0xA4000102UL
+#define PORT_PCCR 0xA4000104UL
+#define PORT_PDCR 0xA4000106UL
+#define PORT_PECR 0xA4000108UL
+#define PORT_PFCR 0xA400010AUL
+#define PORT_PGCR 0xA400010CUL
+#define PORT_PHCR 0xA400010EUL
+#define PORT_PJCR 0xA4000110UL
+#define PORT_PKCR 0xA4000112UL
+#define PORT_PLCR 0xA4000114UL
+#define PORT_PMCR 0xA4000118UL
+#define PORT_PNCR 0xA400011AUL
+#define PORT_PECR2 0xA4050148UL
+#define PORT_PFCR2 0xA405014AUL
+#define PORT_PNCR2 0xA405015AUL
+
+/* I/O port */
+#define PORT_PADR 0xA4000120UL
+#define PORT_PBDR 0xA4000122UL
+#define PORT_PCDR 0xA4000124UL
+#define PORT_PDDR 0xA4000126UL
+#define PORT_PEDR 0xA4000128UL
+#define PORT_PFDR 0xA400012AUL
+#define PORT_PGDR 0xA400012CUL
+#define PORT_PHDR 0xA400012EUL
+#define PORT_PJDR 0xA4000130UL
+#define PORT_PKDR 0xA4000132UL
+#define PORT_PLDR 0xA4000134UL
+#define PORT_PMDR 0xA4000138UL
+#define PORT_PNDR 0xA400013AUL
+
+#define PINT0_IRQ 40
+#define PINT8_IRQ 41
+#define PINT_IRQ_BASE 86
+
+#define PINT0_IPR_ADDR INTC_IPRD
+#define PINT0_IPR_POS 3
+#define PINT0_PRIORITY 2
+
+#define PINT8_IPR_ADDR INTC_IPRD
+#define PINT8_IPR_POS 2
+#define PINT8_PRIORITY 2
+
+#endif /* CONFIG_CPU_SUBTYPE_SH7705 */
+
static unsigned char pint_map[256];
static unsigned long portcr_mask;
@@ -126,7 +178,7 @@ int ipr_irq_demux(int irq)
unsigned long creg, dreg, d, sav;
if (irq == PINT0_IRQ) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707)
creg = PORT_PACR;
dreg = PORT_PADR;
#else
@@ -144,7 +196,7 @@ int ipr_irq_demux(int irq)
return PINT_IRQ_BASE + pint_map[d];
} else if (irq == PINT8_IRQ) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707)
creg = PORT_PBCR;
dreg = PORT_PBDR;
#else
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index 83905e4e438..09faa056cd4 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o
obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o
obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o
obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7712) += setup-sh7710.o
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH3) := clock-sh3.o
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index 821b0ab7b52..647623b22ed 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -78,6 +78,9 @@ int __init detect_cpu_and_cache_system(void)
#if defined(CONFIG_CPU_SUBTYPE_SH7710)
current_cpu_data.type = CPU_SH7710;
#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7712)
+ current_cpu_data.type = CPU_SH7712;
+#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
current_cpu_data.type = CPU_SH7705;
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index a8e41c5241f..1983fb7ad6e 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -2,6 +2,7 @@
* SH7705 Setup
*
* Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
*
* 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
@@ -14,15 +15,15 @@
static struct plat_sci_port sci_platform_data[] = {
{
- .mapbase = 0xa4400000,
+ .mapbase = 0xa4410000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 52, 53, 55, 54 },
+ .irqs = { 56, 57, 59 },
}, {
- .mapbase = 0xa4410000,
+ .mapbase = 0xa4400000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 56, 57, 59, 58 },
+ .irqs = { 52, 53, 55 },
}, {
.flags = 0,
}
@@ -46,3 +47,48 @@ static int __init sh7705_devices_setup(void)
ARRAY_SIZE(sh7705_devices));
}
__initcall(sh7705_devices_setup);
+
+static struct ipr_data sh7705_ipr_map[] = {
+ /* IRQ, IPR-idx, shift, priority */
+ { 16, 0, 12, 2 }, /* TMU0 TUNI*/
+ { 17, 0, 8, 2 }, /* TMU1 TUNI */
+ { 18, 0, 4, 2 }, /* TMU2 TUNI */
+ { 27, 1, 12, 2 }, /* WDT ITI */
+ { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
+ { 21, 0, 0, 2 }, /* RTC PRI (period) */
+ { 22, 0, 0, 2 }, /* RTC CUI (carry) */
+ { 48, 4, 12, 7 }, /* DMAC DMTE0 */
+ { 49, 4, 12, 7 }, /* DMAC DMTE1 */
+ { 50, 4, 12, 7 }, /* DMAC DMTE2 */
+ { 51, 4, 12, 7 }, /* DMAC DMTE3 */
+ { 52, 4, 8, 3 }, /* SCIF0 ERI */
+ { 53, 4, 8, 3 }, /* SCIF0 RXI */
+ { 55, 4, 8, 3 }, /* SCIF0 TXI */
+ { 56, 4, 4, 3 }, /* SCIF1 ERI */
+ { 57, 4, 4, 3 }, /* SCIF1 RXI */
+ { 59, 4, 4, 3 }, /* SCIF1 TXI */
+};
+
+static unsigned long ipr_offsets[] = {
+ 0xFFFFFEE2 /* 0: IPRA */
+, 0xFFFFFEE4 /* 1: IPRB */
+, 0xA4000016 /* 2: IPRC */
+, 0xA4000018 /* 3: IPRD */
+, 0xA400001A /* 4: IPRE */
+, 0xA4080000 /* 5: IPRF */
+, 0xA4080002 /* 6: IPRG */
+, 0xA4080004 /* 7: IPRH */
+};
+
+/* given the IPR index return the address of the IPR register */
+unsigned int map_ipridx_to_addr(int idx)
+{
+ if (idx >= ARRAY_SIZE(ipr_offsets))
+ return 0;
+ return ipr_offsets[idx];
+}
+
+void __init init_IRQ_ipr()
+{
+ make_ipr_irq(sh7705_ipr_map, ARRAY_SIZE(sh7705_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
index dc9b211cf87..c7d7c35fc83 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -48,24 +48,33 @@ static struct platform_device *sh7709_devices[] __initdata = {
static int __init sh7709_devices_setup(void)
{
return platform_add_devices(sh7709_devices,
- ARRAY_SIZE(sh7709_devices));
+ ARRAY_SIZE(sh7709_devices));
}
__initcall(sh7709_devices_setup);
-#define IPRx(A,N) .addr=A, .shift=0*N*-1
+#define IPRx(A,N) .addr=A, .shift=N
#define IPRA(N) IPRx(0xfffffee2UL,N)
#define IPRB(N) IPRx(0xfffffee4UL,N)
+#define IPRC(N) IPRx(0xa4000016UL,N)
+#define IPRD(N) IPRx(0xa4000018UL,N)
#define IPRE(N) IPRx(0xa400001aUL,N)
static struct ipr_data sh7709_ipr_map[] = {
- [16] = { IPRA(15-12), 2 }, /* TMU TUNI0 */
- [17] = { IPRA(11-8), 4 }, /* TMU TUNI1 */
- [22] = { IPRA(3-0), 2 }, /* RTC CUI */
- [23 ... 26] = { IPRB(7-4), 3 }, /* SCI */
- [27] = { IPRB(15-12), 2 }, /* WDT ITI */
- [48 ... 51] = { IPRE(15-12), 7 }, /* DMA */
- [52 ... 55] = { IPRE(11-8), 3 }, /* IRDA */
- [56 ... 59] = { IPRE(7-4), 3 }, /* SCIF */
+ [16] = { IPRA(12), 2 }, /* TMU TUNI0 */
+ [17] = { IPRA(8), 4 }, /* TMU TUNI1 */
+ [18 ... 19] = { IPRA(4), 1 }, /* TMU TUNI1 */
+ [20 ... 22] = { IPRA(0), 2 }, /* RTC CUI */
+ [23 ... 26] = { IPRB(4), 3 }, /* SCI */
+ [27] = { IPRB(12), 2 }, /* WDT ITI */
+ [32] = { IPRC(0), 1 }, /* IRQ 0 */
+ [33] = { IPRC(4), 1 }, /* IRQ 1 */
+ [34] = { IPRC(8), 1 }, /* IRQ 2 APM */
+ [35] = { IPRC(12), 1 }, /* IRQ 3 TOUCHSCREEN */
+ [36] = { IPRD(0), 1 }, /* IRQ 4 */
+ [37] = { IPRD(4), 1 }, /* IRQ 5 */
+ [48 ... 51] = { IPRE(12), 7 }, /* DMA */
+ [52 ... 55] = { IPRE(8), 3 }, /* IRDA */
+ [56 ... 59] = { IPRE(4), 3 }, /* SCIF */
};
void __init init_IRQ_ipr()
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 895f99ee6a9..51760a7e7f1 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -2,6 +2,7 @@
* SH7710 Setup
*
* Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
*
* 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
@@ -19,6 +20,12 @@ static struct plat_sci_port sci_platform_data[] = {
.type = PORT_SCIF,
.irqs = { 52, 53, 55, 54 },
}, {
+ .mapbase = 0xa4420000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 56, 57, 59, 58 },
+ }, {
+
.flags = 0,
}
};
@@ -41,3 +48,56 @@ static int __init sh7710_devices_setup(void)
ARRAY_SIZE(sh7710_devices));
}
__initcall(sh7710_devices_setup);
+
+static struct ipr_data sh7710_ipr_map[] = {
+ /* IRQ, IPR-idx, shift, priority */
+ { 16, 0, 12, 2 }, /* TMU0 TUNI*/
+ { 17, 0, 8, 2 }, /* TMU1 TUNI */
+ { 18, 0, 4, 2 }, /* TMU2 TUNI */
+ { 27, 1, 12, 2 }, /* WDT ITI */
+ { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
+ { 21, 0, 0, 2 }, /* RTC PRI (period) */
+ { 22, 0, 0, 2 }, /* RTC CUI (carry) */
+ { 48, 4, 12, 7 }, /* DMAC DMTE0 */
+ { 49, 4, 12, 7 }, /* DMAC DMTE1 */
+ { 50, 4, 12, 7 }, /* DMAC DMTE2 */
+ { 51, 4, 12, 7 }, /* DMAC DMTE3 */
+ { 52, 4, 8, 3 }, /* SCIF0 ERI */
+ { 53, 4, 8, 3 }, /* SCIF0 RXI */
+ { 54, 4, 8, 3 }, /* SCIF0 BRI */
+ { 55, 4, 8, 3 }, /* SCIF0 TXI */
+ { 56, 4, 4, 3 }, /* SCIF1 ERI */
+ { 57, 4, 4, 3 }, /* SCIF1 RXI */
+ { 58, 4, 4, 3 }, /* SCIF1 BRI */
+ { 59, 4, 4, 3 }, /* SCIF1 TXI */
+ { 76, 5, 8, 7 }, /* DMAC DMTE4 */
+ { 77, 5, 8, 7 }, /* DMAC DMTE5 */
+ { 80, 6, 12, 5 }, /* EDMAC EINT0 */
+ { 81, 6, 8, 5 }, /* EDMAC EINT1 */
+ { 82, 6, 4, 5 }, /* EDMAC EINT2 */
+};
+
+static unsigned long ipr_offsets[] = {
+ 0xA414FEE2 /* 0: IPRA */
+, 0xA414FEE4 /* 1: IPRB */
+, 0xA4140016 /* 2: IPRC */
+, 0xA4140018 /* 3: IPRD */
+, 0xA414001A /* 4: IPRE */
+, 0xA4080000 /* 5: IPRF */
+, 0xA4080002 /* 6: IPRG */
+, 0xA4080004 /* 7: IPRH */
+, 0xA4080006 /* 8: IPRI */
+};
+
+/* given the IPR index return the address of the IPR register */
+unsigned int map_ipridx_to_addr(int idx)
+{
+ if (idx >= ARRAY_SIZE(ipr_offsets))
+ return 0;
+ return ipr_offsets[idx];
+}
+
+void __init init_IRQ_ipr()
+{
+ make_ipr_irq(sh7710_ipr_map, ARRAY_SIZE(sh7710_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
index fa2019aabd7..fcb2c41bc34 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
@@ -82,7 +82,8 @@ static void shoc_clk_init(struct clk *clk)
for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) {
int divisor = frqcr3_divisors[i];
- if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0)
+ if (clk->ops->set_rate(clk, clk->parent->rate /
+ divisor, 0) == 0)
break;
}
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 58950de2696..8cd04904c77 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -124,6 +124,14 @@ int __init detect_cpu_and_cache_system(void)
current_cpu_data.dcache.ways = 4;
current_cpu_data.flags |= CPU_HAS_LLSC;
break;
+ case 0x3004:
+ case 0x3007:
+ current_cpu_data.type = CPU_SH7785;
+ current_cpu_data.icache.ways = 4;
+ current_cpu_data.dcache.ways = 4;
+ current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ CPU_HAS_LLSC;
+ break;
case 0x3008:
if (prr == 0xa0) {
current_cpu_data.type = CPU_SH7722;
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index a8f493f2f21..ab7422f8f82 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -5,6 +5,7 @@
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
@@ -13,7 +14,8 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7343.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
obj-y += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
new file mode 100644
index 00000000000..29090035bc5
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -0,0 +1,600 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+ *
+ * SH7722 support for the clock framework
+ *
+ * Copyright (c) 2006-2007 Nomad Global Solutions Inc
+ * Based on code for sh7343 by 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/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+
+#define SH7722_PLL_FREQ (32000000/8)
+#define N (-1)
+#define NM (-2)
+#define ROUND_NEAREST 0
+#define ROUND_DOWN -1
+#define ROUND_UP +1
+
+static int adjust_algos[][3] = {
+ {}, /* NO_CHANGE */
+ { NM, N, 1 }, /* N:1, N:1 */
+ { 3, 2, 2 }, /* 3:2:2 */
+ { 5, 2, 2 }, /* 5:2:2 */
+ { N, 1, 1 }, /* N:1:1 */
+
+ { N, 1 }, /* N:1 */
+
+ { N, 1 }, /* N:1 */
+ { 3, 2 },
+ { 4, 3 },
+ { 5, 4 },
+
+ { N, 1 }
+};
+
+static unsigned long adjust_pair_of_clocks(unsigned long r1, unsigned long r2,
+ int m1, int m2, int round_flag)
+{
+ unsigned long rem, div;
+ int the_one = 0;
+
+ pr_debug( "Actual values: r1 = %ld\n", r1);
+ pr_debug( "...............r2 = %ld\n", r2);
+
+ if (m1 == m2) {
+ r2 = r1;
+ pr_debug( "setting equal rates: r2 now %ld\n", r2);
+ } else if ((m2 == N && m1 == 1) ||
+ (m2 == NM && m1 == N)) { /* N:1 or NM:N */
+ pr_debug( "Setting rates as 1:N (N:N*M)\n");
+ rem = r2 % r1;
+ pr_debug( "...remainder = %ld\n", rem);
+ if (rem) {
+ div = r2 / r1;
+ pr_debug( "...div = %ld\n", div);
+ switch (round_flag) {
+ case ROUND_NEAREST:
+ the_one = rem >= r1/2 ? 1 : 0; break;
+ case ROUND_UP:
+ the_one = 1; break;
+ case ROUND_DOWN:
+ the_one = 0; break;
+ }
+
+ r2 = r1 * (div + the_one);
+ pr_debug( "...setting r2 to %ld\n", r2);
+ }
+ } else if ((m2 == 1 && m1 == N) ||
+ (m2 == N && m1 == NM)) { /* 1:N or N:NM */
+ pr_debug( "Setting rates as N:1 (N*M:N)\n");
+ rem = r1 % r2;
+ pr_debug( "...remainder = %ld\n", rem);
+ if (rem) {
+ div = r1 / r2;
+ pr_debug( "...div = %ld\n", div);
+ switch (round_flag) {
+ case ROUND_NEAREST:
+ the_one = rem > r2/2 ? 1 : 0; break;
+ case ROUND_UP:
+ the_one = 0; break;
+ case ROUND_DOWN:
+ the_one = 1; break;
+ }
+
+ r2 = r1 / (div + the_one);
+ pr_debug( "...setting r2 to %ld\n", r2);
+ }
+ } else { /* value:value */
+ pr_debug( "Setting rates as %d:%d\n", m1, m2);
+ div = r1 / m1;
+ r2 = div * m2;
+ pr_debug( "...div = %ld\n", div);
+ pr_debug( "...setting r2 to %ld\n", r2);
+ }
+
+ return r2;
+}
+
+static void adjust_clocks(int originate, int *l, unsigned long v[],
+ int n_in_line)
+{
+ int x;
+
+ pr_debug( "Go down from %d...\n", originate);
+ /* go up recalculation clocks */
+ for (x = originate; x>0; x -- )
+ v[x-1] = adjust_pair_of_clocks(v[x], v[x-1],
+ l[x], l[x-1],
+ ROUND_UP);
+
+ pr_debug( "Go up from %d...\n", originate);
+ /* go down recalculation clocks */
+ for (x = originate; x<n_in_line - 1; x ++ )
+ v[x+1] = adjust_pair_of_clocks(v[x], v[x+1],
+ l[x], l[x+1],
+ ROUND_UP);
+}
+
+
+/*
+ * SH7722 uses a common set of multipliers and divisors, so this
+ * is quite simple..
+ */
+
+/*
+ * Instead of having two separate multipliers/divisors set, like this:
+ *
+ * static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ * static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
+ *
+ * I created the divisors2 array, which is used to calculate rate like
+ * rate = parent * 2 / divisors2[ divisor ];
+*/
+static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 };
+
+static void master_clk_init(struct clk *clk)
+{
+ clk_set_rate(clk, clk_get_rate(clk));
+}
+
+static void master_clk_recalc(struct clk *clk)
+{
+ unsigned long frqcr = ctrl_inl(FRQCR);
+
+ clk->rate = CONFIG_SH_PCLK_FREQ * (1 + (frqcr >> 24 & 0xF));
+}
+
+static int master_clk_setrate(struct clk *clk, unsigned long rate, int id)
+{
+ int div = rate / SH7722_PLL_FREQ;
+ int master_divs[] = { 2, 3, 4, 6, 8, 16 };
+ int index;
+ unsigned long frqcr;
+
+ if (rate < SH7722_PLL_FREQ * 2)
+ return -EINVAL;
+
+ for (index = 1; index < ARRAY_SIZE(master_divs); index++)
+ if (div >= master_divs[index - 1] && div < master_divs[index])
+ break;
+
+ if (index >= ARRAY_SIZE(master_divs))
+ index = ARRAY_SIZE(master_divs);
+ div = master_divs[index - 1];
+
+ frqcr = ctrl_inl(FRQCR);
+ frqcr &= ~(0xF << 24);
+ frqcr |= ( (div-1) << 24);
+ ctrl_outl(frqcr, FRQCR);
+
+ return 0;
+}
+
+static struct clk_ops sh7722_master_clk_ops = {
+ .init = master_clk_init,
+ .recalc = master_clk_recalc,
+ .set_rate = master_clk_setrate,
+};
+
+struct frqcr_context {
+ unsigned mask;
+ unsigned shift;
+};
+
+struct frqcr_context sh7722_get_clk_context(const char *name)
+{
+ struct frqcr_context ctx = { 0, };
+
+ if (!strcmp(name, "peripheral_clk")) {
+ ctx.shift = 0;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "sdram_clk")) {
+ ctx.shift = 4;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "bus_clk")) {
+ ctx.shift = 8;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "sh_clk")) {
+ ctx.shift = 12;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "umem_clk")) {
+ ctx.shift = 16;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "cpu_clk")) {
+ ctx.shift = 20;
+ ctx.mask = 7;
+ }
+ return ctx;
+}
+
+/**
+ * sh7722_find_divisors - find divisor for setting rate
+ *
+ * All sh7722 clocks use the same set of multipliers/divisors. This function
+ * chooses correct divisor to set the rate of clock with parent clock that
+ * generates frequency of 'parent_rate'
+ *
+ * @parent_rate: rate of parent clock
+ * @rate: requested rate to be set
+ */
+static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate)
+{
+ unsigned div2 = parent_rate * 2 / rate;
+ int index;
+
+ if (rate > parent_rate)
+ return -EINVAL;
+
+ for (index = 1; index < ARRAY_SIZE(divisors2); index++) {
+ if (div2 > divisors2[index] && div2 <= divisors2[index])
+ break;
+ }
+ if (index >= ARRAY_SIZE(divisors2))
+ index = ARRAY_SIZE(divisors2) - 1;
+ return divisors2[index];
+}
+
+static void sh7722_frqcr_recalc(struct clk *clk)
+{
+ struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
+ unsigned long frqcr = ctrl_inl(FRQCR);
+ int index;
+
+ index = (frqcr >> ctx.shift) & ctx.mask;
+ clk->rate = clk->parent->rate * 2 / divisors2[index];
+}
+
+static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate,
+ int algo_id)
+{
+ struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
+ unsigned long parent_rate = clk->parent->rate;
+ int div;
+ unsigned long frqcr;
+ int err = 0;
+
+ /* pretty invalid */
+ if (parent_rate < rate)
+ return -EINVAL;
+
+ /* look for multiplier/divisor pair */
+ div = sh7722_find_divisors(parent_rate, rate);
+ if (div<0)
+ return div;
+
+ /* calculate new value of clock rate */
+ clk->rate = parent_rate * 2 / div;
+ frqcr = ctrl_inl(FRQCR);
+
+ /* FIXME: adjust as algo_id specifies */
+ if (algo_id != NO_CHANGE) {
+ int originator;
+ char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" };
+ char *algo_group_2[] = { "sh_clk", "bus_clk" };
+ char *algo_group_3[] = { "sh_clk", "sdram_clk" };
+ char *algo_group_4[] = { "bus_clk", "peripheral_clk" };
+ char *algo_group_5[] = { "cpu_clk", "peripheral_clk" };
+ char **algo_current = NULL;
+ /* 3 is the maximum number of clocks in relation */
+ struct clk *ck[3];
+ unsigned long values[3]; /* the same comment as above */
+ int part_length = -1;
+ int i;
+
+ /*
+ * all the steps below only required if adjustion was
+ * requested
+ */
+ if (algo_id == IUS_N1_N1 ||
+ algo_id == IUS_322 ||
+ algo_id == IUS_522 ||
+ algo_id == IUS_N11) {
+ algo_current = algo_group_1;
+ part_length = 3;
+ }
+ if (algo_id == SB_N1) {
+ algo_current = algo_group_2;
+ part_length = 2;
+ }
+ if (algo_id == SB3_N1 ||
+ algo_id == SB3_32 ||
+ algo_id == SB3_43 ||
+ algo_id == SB3_54) {
+ algo_current = algo_group_3;
+ part_length = 2;
+ }
+ if (algo_id == BP_N1) {
+ algo_current = algo_group_4;
+ part_length = 2;
+ }
+ if (algo_id == IP_N1) {
+ algo_current = algo_group_5;
+ part_length = 2;
+ }
+ if (!algo_current)
+ goto incorrect_algo_id;
+
+ originator = -1;
+ for (i = 0; i < part_length; i ++ ) {
+ if (originator >= 0 && !strcmp(clk->name,
+ algo_current[i]))
+ originator = i;
+ ck[i] = clk_get(NULL, algo_current[i]);
+ values[i] = clk_get_rate(ck[i]);
+ }
+
+ if (originator >= 0)
+ adjust_clocks(originator, adjust_algos[algo_id],
+ values, part_length);
+
+ for (i = 0; i < part_length; i ++ ) {
+ struct frqcr_context part_ctx;
+ int part_div;
+
+ if (likely(!err)) {
+ part_div = sh7722_find_divisors(parent_rate,
+ rate);
+ if (part_div > 0) {
+ part_ctx = sh7722_get_clk_context(
+ ck[i]->name);
+ frqcr &= ~(part_ctx.mask <<
+ part_ctx.shift);
+ frqcr |= part_div << part_ctx.shift;
+ } else
+ err = part_div;
+ }
+
+ ck[i]->ops->recalc(ck[i]);
+ clk_put(ck[i]);
+ }
+ }
+
+ /* was there any error during recalculation ? If so, bail out.. */
+ if (unlikely(err!=0))
+ goto out_err;
+
+ /* clear FRQCR bits */
+ frqcr &= ~(ctx.mask << ctx.shift);
+ frqcr |= div << ctx.shift;
+
+ /* ...and perform actual change */
+ ctrl_outl(frqcr, FRQCR);
+ return 0;
+
+incorrect_algo_id:
+ return -EINVAL;
+out_err:
+ return err;
+}
+
+static struct clk_ops sh7722_frqcr_clk_ops = {
+ .recalc = sh7722_frqcr_recalc,
+ .set_rate = sh7722_frqcr_set_rate,
+};
+
+/*
+ * clock ops methods for SIU A/B and IrDA clock
+ *
+ */
+static int sh7722_siu_which(struct clk *clk)
+{
+ if (!strcmp(clk->name, "siu_a_clk"))
+ return 0;
+ if (!strcmp(clk->name, "siu_b_clk"))
+ return 1;
+ if (!strcmp(clk->name, "irda_clk"))
+ return 2;
+ return -EINVAL;
+}
+
+static unsigned long sh7722_siu_regs[] = {
+ [0] = SCLKACR,
+ [1] = SCLKBCR,
+ [2] = IrDACLKCR,
+};
+
+static int sh7722_siu_start_stop(struct clk *clk, int enable)
+{
+ int siu = sh7722_siu_which(clk);
+ unsigned long r;
+
+ if (siu < 0)
+ return siu;
+ BUG_ON(siu > 2);
+ r = ctrl_inl(sh7722_siu_regs[siu]);
+ if (enable)
+ ctrl_outl(r & ~(1 << 8), sh7722_siu_regs[siu]);
+ else
+ ctrl_outl(r | (1 << 8), sh7722_siu_regs[siu]);
+ return 0;
+}
+
+static void sh7722_siu_enable(struct clk *clk)
+{
+ sh7722_siu_start_stop(clk, 1);
+}
+
+static void sh7722_siu_disable(struct clk *clk)
+{
+ sh7722_siu_start_stop(clk, 0);
+}
+
+static void sh7722_video_enable(struct clk *clk)
+{
+ unsigned long r;
+
+ r = ctrl_inl(VCLKCR);
+ ctrl_outl( r & ~(1<<8), VCLKCR);
+}
+
+static void sh7722_video_disable(struct clk *clk)
+{
+ unsigned long r;
+
+ r = ctrl_inl(VCLKCR);
+ ctrl_outl( r | (1<<8), VCLKCR);
+}
+
+static int sh7722_video_set_rate(struct clk *clk, unsigned long rate,
+ int algo_id)
+{
+ unsigned long r;
+
+ r = ctrl_inl(VCLKCR);
+ r &= ~0x3F;
+ r |= ((clk->parent->rate / rate - 1) & 0x3F);
+ ctrl_outl(r, VCLKCR);
+ return 0;
+}
+
+static void sh7722_video_recalc(struct clk *clk)
+{
+ unsigned long r;
+
+ r = ctrl_inl(VCLKCR);
+ clk->rate = clk->parent->rate / ((r & 0x3F) + 1);
+}
+
+static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+{
+ int siu = sh7722_siu_which(clk);
+ unsigned long r;
+ int div;
+
+ if (siu < 0)
+ return siu;
+ BUG_ON(siu > 2);
+ r = ctrl_inl(sh7722_siu_regs[siu]);
+ div = sh7722_find_divisors(clk->parent->rate, rate);
+ if (div < 0)
+ return div;
+ r = (r & ~0xF) | div;
+ ctrl_outl(r, sh7722_siu_regs[siu]);
+ return 0;
+}
+
+static void sh7722_siu_recalc(struct clk *clk)
+{
+ int siu = sh7722_siu_which(clk);
+ unsigned long r;
+
+ if (siu < 0)
+ return /* siu */ ;
+ BUG_ON(siu > 1);
+ r = ctrl_inl(sh7722_siu_regs[siu]);
+ clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
+}
+
+static struct clk_ops sh7722_siu_clk_ops = {
+ .recalc = sh7722_siu_recalc,
+ .set_rate = sh7722_siu_set_rate,
+ .enable = sh7722_siu_enable,
+ .disable = sh7722_siu_disable,
+};
+
+static struct clk_ops sh7722_video_clk_ops = {
+ .recalc = sh7722_video_recalc,
+ .set_rate = sh7722_video_set_rate,
+ .enable = sh7722_video_enable,
+ .disable = sh7722_video_disable,
+};
+/*
+ * and at last, clock definitions themselves
+ */
+static struct clk sh7722_umem_clock = {
+ .name = "umem_clk",
+ .ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_sh_clock = {
+ .name = "sh_clk",
+ .ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_peripheral_clock = {
+ .name = "peripheral_clk",
+ .ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_sdram_clock = {
+ .name = "sdram_clk",
+ .ops = &sh7722_frqcr_clk_ops,
+};
+
+/*
+ * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops
+ * methods of clk_ops determine which register they should access by
+ * examining clk->name field
+ */
+static struct clk sh7722_siu_a_clock = {
+ .name = "siu_a_clk",
+ .ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_siu_b_clock = {
+ .name = "siu_b_clk",
+ .ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_irda_clock = {
+ .name = "irda_clk",
+ .ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_video_clock = {
+ .name = "video_clk",
+ .ops = &sh7722_video_clk_ops,
+};
+
+static struct clk *sh7722_clocks[] = {
+ &sh7722_umem_clock,
+ &sh7722_sh_clock,
+ &sh7722_peripheral_clock,
+ &sh7722_sdram_clock,
+ &sh7722_siu_a_clock,
+ &sh7722_siu_b_clock,
+ &sh7722_irda_clock,
+ &sh7722_video_clock,
+};
+
+/*
+ * init in order: master, module, bus, cpu
+ */
+struct clk_ops *onchip_ops[] = {
+ &sh7722_master_clk_ops,
+ &sh7722_frqcr_clk_ops,
+ &sh7722_frqcr_clk_ops,
+ &sh7722_frqcr_clk_ops,
+};
+
+void __init
+arch_init_clk_ops(struct clk_ops **ops, int type)
+{
+ BUG_ON(type < 0 || type > ARRAY_SIZE(onchip_ops));
+ *ops = onchip_ops[type];
+}
+
+int __init sh7722_clock_init(void)
+{
+ struct clk *master;
+ int i;
+
+ master = clk_get(NULL, "master_clk");
+ for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) {
+ pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name);
+ sh7722_clocks[i]->parent = master;
+ clk_register(sh7722_clocks[i]);
+ }
+ clk_put(master);
+ return 0;
+}
+arch_initcall(sh7722_clock_init);
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
new file mode 100644
index 00000000000..805535aa505
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -0,0 +1,162 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7785.c
+ *
+ * SH7785 support for the clock framework
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int ifc_divisors[] = { 1, 2, 4, 6 };
+static int ufc_divisors[] = { 1, 1, 4, 6 };
+static int sfc_divisors[] = { 1, 1, 4, 6 };
+static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18,
+ 24, 32, 36, 48, 1, 1, 1, 1 };
+static int mfc_divisors[] = { 1, 1, 4, 6 };
+static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18,
+ 24, 32, 36, 48, 1, 1, 1, 1 };
+
+static void master_clk_init(struct clk *clk)
+{
+ clk->rate *= 36;
+}
+
+static struct clk_ops sh7785_master_clk_ops = {
+ .init = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+ int idx = (ctrl_inl(FRQMR1) & 0x000f);
+ clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_module_clk_ops = {
+ .recalc = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
+ clk->rate = clk->parent->rate / bfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_bus_clk_ops = {
+ .recalc = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
+ clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops sh7785_cpu_clk_ops = {
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7785_clk_ops[] = {
+ &sh7785_master_clk_ops,
+ &sh7785_module_clk_ops,
+ &sh7785_bus_clk_ops,
+ &sh7785_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(sh7785_clk_ops))
+ *ops = sh7785_clk_ops[idx];
+}
+
+static void shyway_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
+ clk->rate = clk->parent->rate / sfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_shyway_clk_ops = {
+ .recalc = shyway_clk_recalc,
+};
+
+static struct clk sh7785_shyway_clk = {
+ .name = "shyway_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &sh7785_shyway_clk_ops,
+};
+
+static void ddr_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
+ clk->rate = clk->parent->rate / mfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_ddr_clk_ops = {
+ .recalc = ddr_clk_recalc,
+};
+
+static struct clk sh7785_ddr_clk = {
+ .name = "ddr_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &sh7785_ddr_clk_ops,
+};
+
+static void ram_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 24) & 0x0003);
+ clk->rate = clk->parent->rate / ufc_divisors[idx];
+}
+
+static struct clk_ops sh7785_ram_clk_ops = {
+ .recalc = ram_clk_recalc,
+};
+
+static struct clk sh7785_ram_clk = {
+ .name = "ram_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &sh7785_ram_clk_ops,
+};
+
+/*
+ * Additional SH7785-specific on-chip clocks that aren't already part of the
+ * clock framework
+ */
+static struct clk *sh7785_onchip_clocks[] = {
+ &sh7785_shyway_clk,
+ &sh7785_ddr_clk,
+ &sh7785_ram_clk,
+};
+
+static int __init sh7785_clk_init(void)
+{
+ struct clk *clk = clk_get(NULL, "master_clk");
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sh7785_onchip_clocks); i++) {
+ struct clk *clkp = sh7785_onchip_clocks[i];
+
+ clkp->parent = clk;
+ clk_register(clkp);
+ clk_enable(clkp);
+ }
+
+ /*
+ * Now that we have the rest of the clocks registered, we need to
+ * force the parent clock to propagate so that these clocks will
+ * automatically figure out their rate. We cheat by handing the
+ * parent clock its current rate and forcing child propagation.
+ */
+ clk_set_rate(clk, clk_get_rate(clk));
+
+ clk_put(clk);
+
+ return 0;
+}
+arch_initcall(sh7785_clk_init);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
new file mode 100644
index 00000000000..07b0de82cfe
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -0,0 +1,103 @@
+/*
+ * SH7785 Setup
+ *
+ * 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffea0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .mapbase = 0xffeb0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 44, 45, 47, 46 },
+ },
+
+ /*
+ * The rest of these all have multiplexed IRQs
+ */
+ {
+ .mapbase = 0xffec0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 60, 60, 60, 60 },
+ }, {
+ .mapbase = 0xffed0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 61, 61, 61, 61 },
+ }, {
+ .mapbase = 0xffee0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 62, 62, 62, 62 },
+ }, {
+ .mapbase = 0xffef0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 63, 63, 63, 63 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7785_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7785_devices_setup(void)
+{
+ return platform_add_devices(sh7785_devices,
+ ARRAY_SIZE(sh7785_devices));
+}
+__initcall(sh7785_devices_setup);
+
+static struct intc2_data intc2_irq_table[] = {
+ { 28, 0, 24, 0, 0, 2 }, /* TMU0 */
+
+ { 40, 8, 24, 0, 2, 3 }, /* SCIF0 ERI */
+ { 41, 8, 24, 0, 2, 3 }, /* SCIF0 RXI */
+ { 42, 8, 24, 0, 2, 3 }, /* SCIF0 BRI */
+ { 43, 8, 24, 0, 2, 3 }, /* SCIF0 TXI */
+
+ { 44, 8, 16, 0, 3, 3 }, /* SCIF1 ERI */
+ { 45, 8, 16, 0, 3, 3 }, /* SCIF1 RXI */
+ { 46, 8, 16, 0, 3, 3 }, /* SCIF1 BRI */
+ { 47, 8, 16, 0, 3, 3 }, /* SCIF1 TXI */
+
+ { 64, 0x14, 8, 0, 14, 2 }, /* PCIC0 */
+ { 65, 0x14, 0, 0, 15, 2 }, /* PCIC1 */
+ { 66, 0x18, 24, 0, 16, 2 }, /* PCIC2 */
+ { 67, 0x18, 16, 0, 17, 2 }, /* PCIC3 */
+ { 68, 0x18, 8, 0, 18, 2 }, /* PCIC4 */
+
+ { 60, 8, 8, 0, 4, 3 }, /* SCIF2 ERI, RXI, BRI, TXI */
+ { 60, 8, 0, 0, 5, 3 }, /* SCIF3 ERI, RXI, BRI, TXI */
+ { 60, 12, 24, 0, 6, 3 }, /* SCIF4 ERI, RXI, BRI, TXI */
+ { 60, 12, 16, 0, 7, 3 }, /* SCIF5 ERI, RXI, BRI, TXI */
+};
+
+void __init init_IRQ_intc2(void)
+{
+ make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
+}
diff --git a/arch/sh/kernel/crash_dump.c b/arch/sh/kernel/crash_dump.c
new file mode 100644
index 00000000000..4a2ecbe27d8
--- /dev/null
+++ b/arch/sh/kernel/crash_dump.c
@@ -0,0 +1,46 @@
+/*
+ * crash_dump.c - Memory preserving reboot related code.
+ *
+ * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2004. All rights reserved
+ */
+
+#include <linux/errno.h>
+#include <linux/crash_dump.h>
+#include <linux/io.h>
+#include <asm/uaccess.h>
+
+/**
+ * copy_oldmem_page - copy one page from "oldmem"
+ * @pfn: page frame number to be copied
+ * @buf: target memory address for the copy; this can be in kernel address
+ * space or user address space (see @userbuf)
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page (based on pfn) to begin the copy
+ * @userbuf: if set, @buf is in user address space, use copy_to_user(),
+ * otherwise @buf is in kernel address space, use memcpy().
+ *
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+ size_t csize, unsigned long offset, int userbuf)
+{
+ void *vaddr;
+
+ if (!csize)
+ return 0;
+
+ vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+
+ if (userbuf) {
+ if (copy_to_user(buf, (vaddr + offset), csize)) {
+ iounmap(vaddr);
+ return -EFAULT;
+ }
+ } else
+ memcpy(buf, (vaddr + offset), csize);
+
+ iounmap(vaddr);
+ return csize;
+}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 9bdd8a00cd4..27b923c45b3 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -13,6 +13,7 @@
#include <linux/seq_file.h>
#include <linux/irq.h>
#include <asm/processor.h>
+#include <asm/machvec.h>
#include <asm/uaccess.h>
#include <asm/thread_info.h>
#include <asm/cpu/mmu_context.h>
@@ -44,7 +45,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
}
- if (i < NR_IRQS) {
+ if (i < sh_mv.mv_nr_irqs) {
spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action;
if (!action)
@@ -61,7 +62,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
unlock:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
- } else if (i == NR_IRQS)
+ } else if (i == sh_mv.mv_nr_irqs)
seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
return 0;
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
index d8927d85492..a5323364cbc 100644
--- a/arch/sh/kernel/kgdb_stub.c
+++ b/arch/sh/kernel/kgdb_stub.c
@@ -6,11 +6,11 @@
* David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
* Amit S. Kale <akale@veritas.com>, William Gatliff <bgat@open-widgets.com>,
* Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>.
- *
+ *
* This version by Henry Bell <henry.bell@st.com>
* Minor modifications by Jeremy Siegel <jsiegel@mvista.com>
- *
- * Contains low-level support for remote debug using GDB.
+ *
+ * Contains low-level support for remote debug using GDB.
*
* To enable debugger support, two things need to happen. A call to
* set_debug_traps() is necessary in order to allow any breakpoints
@@ -48,7 +48,7 @@
* k kill (Detach GDB)
*
* d Toggle debug flag
- * D Detach GDB
+ * D Detach GDB
*
* Hct Set thread t for operations, OK or ENN
* c = 'c' (step, cont), c = 'g' (other
@@ -58,7 +58,7 @@
* qfThreadInfo Get list of current threads (first) m<id>
* qsThreadInfo " " " " " (subsequent)
* qOffsets Get section offsets Text=x;Data=y;Bss=z
- *
+ *
* TXX Find if thread XX is alive OK or ENN
* ? What was the last sigval ? SNN (signal NN)
* O Output to GDB console
@@ -74,7 +74,7 @@
* '$' or '#'. If <data> starts with two characters followed by
* ':', then the existing stubs interpret this as a sequence number.
*
- * CSUM1 and CSUM2 are ascii hex representation of an 8-bit
+ * CSUM1 and CSUM2 are ascii hex representation of an 8-bit
* checksum of <data>, the most significant nibble is sent first.
* the hex digits 0-9,a-f are used.
*
@@ -86,8 +86,8 @@
* Responses can be run-length encoded to save space. A '*' means that
* the next character is an ASCII encoding giving a repeat count which
* stands for that many repititions of the character preceding the '*'.
- * The encoding is n+29, yielding a printable character where n >=3
- * (which is where RLE starts to win). Don't use an n > 126.
+ * The encoding is n+29, yielding a printable character where n >=3
+ * (which is where RLE starts to win). Don't use an n > 126.
*
* So "0* " means the same as "0000".
*/
@@ -100,12 +100,10 @@
#include <linux/delay.h>
#include <linux/linkage.h>
#include <linux/init.h>
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
#include <linux/console.h>
-#endif
-
+#include <linux/sysrq.h>
#include <asm/system.h>
+#include <asm/cacheflush.h>
#include <asm/current.h>
#include <asm/signal.h>
#include <asm/pgtable.h>
@@ -153,7 +151,6 @@ char kgdb_in_gdb_mode;
char in_nmi; /* Set during NMI to prevent reentry */
int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */
int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */
-int kgdb_halt;
/* Exposed for user access */
struct task_struct *kgdb_current;
@@ -246,14 +243,6 @@ static char out_buffer[OUTBUFMAX];
static void kgdb_to_gdb(const char *s);
-#ifdef CONFIG_KGDB_THREAD
-static struct task_struct *trapped_thread;
-static struct task_struct *current_thread;
-typedef unsigned char threadref[8];
-#define BUF_THREAD_ID_SIZE 16
-#endif
-
-
/* Convert ch to hex */
static int hex(const char ch)
{
@@ -328,7 +317,7 @@ static int hex_to_int(char **ptr, int *int_value)
}
/* Copy the binary array pointed to by buf into mem. Fix $, #,
- and 0x7d escaped with 0x7d. Return a pointer to the character
+ and 0x7d escaped with 0x7d. Return a pointer to the character
after the last byte written. */
static char *ebin_to_mem(const char *buf, char *mem, int count)
{
@@ -349,66 +338,6 @@ static char *pack_hex_byte(char *pkt, int byte)
return pkt;
}
-#ifdef CONFIG_KGDB_THREAD
-
-/* Pack a thread ID */
-static char *pack_threadid(char *pkt, threadref * id)
-{
- char *limit;
- unsigned char *altid;
-
- altid = (unsigned char *) id;
-
- limit = pkt + BUF_THREAD_ID_SIZE;
- while (pkt < limit)
- pkt = pack_hex_byte(pkt, *altid++);
- return pkt;
-}
-
-/* Convert an integer into our threadref */
-static void int_to_threadref(threadref * id, const int value)
-{
- unsigned char *scan = (unsigned char *) id;
- int i = 4;
-
- while (i--)
- *scan++ = 0;
-
- *scan++ = (value >> 24) & 0xff;
- *scan++ = (value >> 16) & 0xff;
- *scan++ = (value >> 8) & 0xff;
- *scan++ = (value & 0xff);
-}
-
-/* Return a task structure ptr for a particular pid */
-static struct task_struct *get_thread(int pid)
-{
- struct task_struct *thread;
-
- /* Use PID_MAX w/gdb for pid 0 */
- if (pid == PID_MAX) pid = 0;
-
- /* First check via PID */
- thread = find_task_by_pid(pid);
-
- if (thread)
- return thread;
-
- /* Start at the start */
- thread = init_tasks[0];
-
- /* Walk along the linked list of tasks */
- do {
- if (thread->pid == pid)
- return thread;
- thread = thread->next_task;
- } while (thread != init_tasks[0]);
-
- return NULL;
-}
-
-#endif /* CONFIG_KGDB_THREAD */
-
/* Scan for the start char '$', read the packet and check the checksum */
static void get_packet(char *buffer, int buflen)
{
@@ -452,7 +381,7 @@ static void get_packet(char *buffer, int buflen)
/* Ack successful transfer */
put_debug_char('+');
- /* If a sequence char is present, reply
+ /* If a sequence char is present, reply
the sequence ID */
if (buffer[2] == ':') {
put_debug_char(buffer[0]);
@@ -611,74 +540,6 @@ static void gdb_regs_to_kgdb_regs(const int *gdb_regs,
regs->vbr = gdb_regs[VBR];
}
-#ifdef CONFIG_KGDB_THREAD
-/* Make a local copy of registers from the specified thread */
-asmlinkage void ret_from_fork(void);
-static void thread_regs_to_gdb_regs(const struct task_struct *thread,
- int *gdb_regs)
-{
- int regno;
- int *tregs;
-
- /* Initialize to zero */
- for (regno = 0; regno < MAXREG; regno++)
- gdb_regs[regno] = 0;
-
- /* Just making sure... */
- if (thread == NULL)
- return;
-
- /* A new fork has pt_regs on the stack from a fork() call */
- if (thread->thread.pc == (unsigned long)ret_from_fork) {
-
- int vbr_val;
- struct pt_regs *kregs;
- kregs = (struct pt_regs*)thread->thread.sp;
-
- gdb_regs[R0] = kregs->regs[R0];
- gdb_regs[R1] = kregs->regs[R1];
- gdb_regs[R2] = kregs->regs[R2];
- gdb_regs[R3] = kregs->regs[R3];
- gdb_regs[R4] = kregs->regs[R4];
- gdb_regs[R5] = kregs->regs[R5];
- gdb_regs[R6] = kregs->regs[R6];
- gdb_regs[R7] = kregs->regs[R7];
- gdb_regs[R8] = kregs->regs[R8];
- gdb_regs[R9] = kregs->regs[R9];
- gdb_regs[R10] = kregs->regs[R10];
- gdb_regs[R11] = kregs->regs[R11];
- gdb_regs[R12] = kregs->regs[R12];
- gdb_regs[R13] = kregs->regs[R13];
- gdb_regs[R14] = kregs->regs[R14];
- gdb_regs[R15] = kregs->regs[R15];
- gdb_regs[PC] = kregs->pc;
- gdb_regs[PR] = kregs->pr;
- gdb_regs[GBR] = kregs->gbr;
- gdb_regs[MACH] = kregs->mach;
- gdb_regs[MACL] = kregs->macl;
- gdb_regs[SR] = kregs->sr;
-
- asm("stc vbr, %0":"=r"(vbr_val));
- gdb_regs[VBR] = vbr_val;
- return;
- }
-
- /* Otherwise, we have only some registers from switch_to() */
- tregs = (int *)thread->thread.sp;
- gdb_regs[R15] = (int)tregs;
- gdb_regs[R14] = *tregs++;
- gdb_regs[R13] = *tregs++;
- gdb_regs[R12] = *tregs++;
- gdb_regs[R11] = *tregs++;
- gdb_regs[R10] = *tregs++;
- gdb_regs[R9] = *tregs++;
- gdb_regs[R8] = *tregs++;
- gdb_regs[PR] = *tregs++;
- gdb_regs[GBR] = *tregs++;
- gdb_regs[PC] = thread->thread.pc;
-}
-#endif /* CONFIG_KGDB_THREAD */
-
/* Calculate the new address for after a step */
static short *get_step_address(void)
{
@@ -759,7 +620,7 @@ static short *get_step_address(void)
return (short *) addr;
}
-/* Set up a single-step. Replace the instruction immediately after the
+/* Set up a single-step. Replace the instruction immediately after the
current instruction (i.e. next in the expected flow of control) with a
trap instruction, so that returning will cause only a single instruction
to be executed. Note that this model is slightly broken for instructions
@@ -797,37 +658,11 @@ static void undo_single_step(void)
/* Send a signal message */
static void send_signal_msg(const int signum)
{
-#ifndef CONFIG_KGDB_THREAD
out_buffer[0] = 'S';
out_buffer[1] = highhex(signum);
out_buffer[2] = lowhex(signum);
out_buffer[3] = 0;
put_packet(out_buffer);
-#else /* CONFIG_KGDB_THREAD */
- int threadid;
- threadref thref;
- char *out = out_buffer;
- const char *tstring = "thread";
-
- *out++ = 'T';
- *out++ = highhex(signum);
- *out++ = lowhex(signum);
-
- while (*tstring) {
- *out++ = *tstring++;
- }
- *out++ = ':';
-
- threadid = trapped_thread->pid;
- if (threadid == 0) threadid = PID_MAX;
- int_to_threadref(&thref, threadid);
- pack_threadid(out, &thref);
- out += BUF_THREAD_ID_SIZE;
- *out++ = ';';
-
- *out = 0;
- put_packet(out_buffer);
-#endif /* CONFIG_KGDB_THREAD */
}
/* Reply that all was well */
@@ -962,15 +797,7 @@ static void step_with_sig_msg(void)
/* Send register contents */
static void send_regs_msg(void)
{
-#ifdef CONFIG_KGDB_THREAD
- if (!current_thread)
- kgdb_regs_to_gdb_regs(&trap_registers, registers);
- else
- thread_regs_to_gdb_regs(current_thread, registers);
-#else
kgdb_regs_to_gdb_regs(&trap_registers, registers);
-#endif
-
mem_to_hex((char *) registers, out_buffer, NUMREGBYTES);
put_packet(out_buffer);
}
@@ -978,201 +805,13 @@ static void send_regs_msg(void)
/* Set register contents - currently can't set other thread's registers */
static void set_regs_msg(void)
{
-#ifdef CONFIG_KGDB_THREAD
- if (!current_thread) {
-#endif
- kgdb_regs_to_gdb_regs(&trap_registers, registers);
- hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
- gdb_regs_to_kgdb_regs(registers, &trap_registers);
- send_ok_msg();
-#ifdef CONFIG_KGDB_THREAD
- } else
- send_err_msg();
-#endif
-}
-
-
-#ifdef CONFIG_KGDB_THREAD
-
-/* Set the status for a thread */
-void set_thread_msg(void)
-{
- int threadid;
- struct task_struct *thread = NULL;
- char *ptr;
-
- switch (in_buffer[1]) {
-
- /* To select which thread for gG etc messages, i.e. supported */
- case 'g':
-
- ptr = &in_buffer[2];
- hex_to_int(&ptr, &threadid);
- thread = get_thread(threadid);
-
- /* If we haven't found it */
- if (!thread) {
- send_err_msg();
- break;
- }
-
- /* Set current_thread (or not) */
- if (thread == trapped_thread)
- current_thread = NULL;
- else
- current_thread = thread;
- send_ok_msg();
- break;
-
- /* To select which thread for cCsS messages, i.e. unsupported */
- case 'c':
- send_ok_msg();
- break;
-
- default:
- send_empty_msg();
- break;
- }
-}
-
-/* Is a thread alive? */
-static void thread_status_msg(void)
-{
- char *ptr;
- int threadid;
- struct task_struct *thread = NULL;
-
- ptr = &in_buffer[1];
- hex_to_int(&ptr, &threadid);
- thread = get_thread(threadid);
- if (thread)
- send_ok_msg();
- else
- send_err_msg();
-}
-/* Send the current thread ID */
-static void thread_id_msg(void)
-{
- int threadid;
- threadref thref;
-
- out_buffer[0] = 'Q';
- out_buffer[1] = 'C';
-
- if (current_thread)
- threadid = current_thread->pid;
- else if (trapped_thread)
- threadid = trapped_thread->pid;
- else /* Impossible, but just in case! */
- {
- send_err_msg();
- return;
- }
-
- /* Translate pid 0 to PID_MAX for gdb */
- if (threadid == 0) threadid = PID_MAX;
-
- int_to_threadref(&thref, threadid);
- pack_threadid(out_buffer + 2, &thref);
- out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0';
- put_packet(out_buffer);
-}
-
-/* Send thread info */
-static void thread_info_msg(void)
-{
- struct task_struct *thread = NULL;
- int threadid;
- char *pos;
- threadref thref;
-
- /* Start with 'm' */
- out_buffer[0] = 'm';
- pos = &out_buffer[1];
-
- /* For all possible thread IDs - this will overrun if > 44 threads! */
- /* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */
- for (threadid = 1; threadid <= PID_MAX; threadid++) {
-
- read_lock(&tasklist_lock);
- thread = get_thread(threadid);
- read_unlock(&tasklist_lock);
-
- /* If it's a valid thread */
- if (thread) {
- int_to_threadref(&thref, threadid);
- pack_threadid(pos, &thref);
- pos += BUF_THREAD_ID_SIZE;
- *pos++ = ',';
- }
- }
- *--pos = 0; /* Lose final comma */
- put_packet(out_buffer);
-
-}
-
-/* Return printable info for gdb's 'info threads' command */
-static void thread_extra_info_msg(void)
-{
- int threadid;
- struct task_struct *thread = NULL;
- char buffer[20], *ptr;
- int i;
-
- /* Extract thread ID */
- ptr = &in_buffer[17];
- hex_to_int(&ptr, &threadid);
- thread = get_thread(threadid);
-
- /* If we don't recognise it, say so */
- if (thread == NULL)
- strcpy(buffer, "(unknown)");
- else
- strcpy(buffer, thread->comm);
-
- /* Construct packet */
- for (i = 0, ptr = out_buffer; buffer[i]; i++)
- ptr = pack_hex_byte(ptr, buffer[i]);
-
- if (thread->thread.pc == (unsigned long)ret_from_fork) {
- strcpy(buffer, "<new fork>");
- for (i = 0; buffer[i]; i++)
- ptr = pack_hex_byte(ptr, buffer[i]);
- }
-
- *ptr = '\0';
- put_packet(out_buffer);
-}
-
-/* Handle all qFooBarBaz messages - have to use an if statement as
- opposed to a switch because q messages can have > 1 char id. */
-static void query_msg(void)
-{
- const char *q_start = &in_buffer[1];
-
- /* qC = return current thread ID */
- if (strncmp(q_start, "C", 1) == 0)
- thread_id_msg();
-
- /* qfThreadInfo = query all threads (first) */
- else if (strncmp(q_start, "fThreadInfo", 11) == 0)
- thread_info_msg();
-
- /* qsThreadInfo = query all threads (subsequent). We know we have sent
- them all after the qfThreadInfo message, so there are no to send */
- else if (strncmp(q_start, "sThreadInfo", 11) == 0)
- put_packet("l"); /* el = last */
-
- /* qThreadExtraInfo = supply printable information per thread */
- else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0)
- thread_extra_info_msg();
-
- /* Unsupported - empty message as per spec */
- else
- send_empty_msg();
+ kgdb_regs_to_gdb_regs(&trap_registers, registers);
+ hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
+ gdb_regs_to_kgdb_regs(registers, &trap_registers);
+ send_ok_msg();
}
-#endif /* CONFIG_KGDB_THREAD */
+#ifdef CONFIG_SH_KGDB_CONSOLE
/*
* Bring up the ports..
*/
@@ -1185,6 +824,9 @@ static int kgdb_serial_setup(void)
return 0;
}
+#else
+#define kgdb_serial_setup() 0
+#endif
/* The command loop, read and act on requests */
static void kgdb_command_loop(const int excep_code, const int trapa_value)
@@ -1193,7 +835,7 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
if (excep_code == NMI_VEC) {
#ifndef CONFIG_KGDB_NMI
- KGDB_PRINTK("Ignoring unexpected NMI?\n");
+ printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n");
return;
#else /* CONFIG_KGDB_NMI */
if (!kgdb_enabled) {
@@ -1207,19 +849,10 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
if (!kgdb_enabled)
return;
-#ifdef CONFIG_KGDB_THREAD
- /* Until GDB specifies a thread */
- current_thread = NULL;
- trapped_thread = current;
-#endif
-
/* Enter GDB mode (e.g. after detach) */
if (!kgdb_in_gdb_mode) {
/* Do serial setup, notify user, issue preemptive ack */
- kgdb_serial_setup();
- KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n",
- (kgdb_porttype ? kgdb_porttype->name : ""),
- kgdb_portnum, kgdb_baud);
+ printk(KERN_NOTICE "KGDB: Waiting for GDB\n");
kgdb_in_gdb_mode = 1;
put_debug_char('+');
}
@@ -1233,21 +866,18 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
will later be replaced by its original one. Do NOT do this for
trap 0xff, since that indicates a compiled-in breakpoint which
will not be replaced (and we would retake the trap forever) */
- if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) {
+ if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2)))
trap_registers.pc -= 2;
- }
/* Undo any stepping we may have done */
undo_single_step();
while (1) {
-
out_buffer[0] = 0;
get_packet(in_buffer, BUFMAX);
/* Examine first char of buffer to see what we need to do */
switch (in_buffer[0]) {
-
case '?': /* Send which signal we've received */
send_signal_msg(sigval);
break;
@@ -1291,21 +921,6 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
step_msg();
return;
-#ifdef CONFIG_KGDB_THREAD
-
- case 'H': /* Task related */
- set_thread_msg();
- break;
-
- case 'T': /* Query thread status */
- thread_status_msg();
- break;
-
- case 'q': /* Handle query - currently thread-related */
- query_msg();
- break;
-#endif
-
case 'k': /* 'Kill the program' with a kernel ? */
break;
@@ -1323,11 +938,8 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
}
/* There has been an exception, most likely a breakpoint. */
-asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+static void handle_exception(struct pt_regs *regs)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
int excep_code, vbr_val;
int count;
int trapa_value = ctrl_inl(TRA);
@@ -1355,7 +967,7 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
kgdb_trapa_val = trapa_value;
/* Act on the exception */
- kgdb_command_loop(excep_code >> 5, trapa_value);
+ kgdb_command_loop(excep_code, trapa_value);
kgdb_current = NULL;
@@ -1373,14 +985,12 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
asm("ldc %0, vbr": :"r"(vbr_val));
}
-/* Trigger a breakpoint by function */
-void breakpoint(void)
+asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs)
{
- if (!kgdb_enabled) {
- kgdb_enabled = 1;
- kgdb_init();
- }
- BREAKPOINT();
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ handle_exception(regs);
}
/* Initialise the KGDB data structures and serial configuration */
@@ -1395,24 +1005,16 @@ int kgdb_init(void)
kgdb_in_gdb_mode = 0;
if (kgdb_serial_setup() != 0) {
- KGDB_PRINTK("serial setup error\n");
+ printk(KERN_NOTICE "KGDB: serial setup error\n");
return -1;
}
/* Init ptr to exception handler */
- kgdb_debug_hook = kgdb_handle_exception;
+ kgdb_debug_hook = handle_exception;
kgdb_bus_err_hook = kgdb_handle_bus_error;
/* Enter kgdb now if requested, or just report init done */
- if (kgdb_halt) {
- kgdb_in_gdb_mode = 1;
- put_debug_char('+');
- breakpoint();
- }
- else
- {
- KGDB_PRINTK("stub is initialized.\n");
- }
+ printk(KERN_NOTICE "KGDB: stub is initialized.\n");
return 0;
}
@@ -1437,7 +1039,7 @@ static void kgdb_msg_write(const char *s, unsigned count)
/* Calculate how many this time */
wcount = (count > MAXOUT) ? MAXOUT : count;
-
+
/* Pack in hex chars */
for (i = 0; i < wcount; i++)
bufptr = pack_hex_byte(bufptr, s[i]);
@@ -1467,3 +1069,25 @@ void kgdb_console_write(struct console *co, const char *s, unsigned count)
kgdb_msg_write(s, count);
}
#endif
+
+#ifdef CONFIG_KGDB_SYSRQ
+static void sysrq_handle_gdb(int key, struct tty_struct *tty)
+{
+ printk("Entering GDB stub\n");
+ breakpoint();
+}
+
+static struct sysrq_key_op sysrq_gdb_op = {
+ .handler = sysrq_handle_gdb,
+ .help_msg = "Gdb",
+ .action_msg = "GDB",
+};
+
+static int gdb_register_sysrq(void)
+{
+ printk("Registering GDB sysrq handler\n");
+ register_sysrq_key('g', &sysrq_gdb_op);
+ return 0;
+}
+module_init(gdb_register_sysrq);
+#endif
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 08587cdb64d..790ed69b866 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -59,13 +59,13 @@ static void kexec_info(struct kimage *image)
printk(" segment[%d]: 0x%08x - 0x%08x (0x%08x)\n",
i,
(unsigned int)image->segment[i].mem,
- (unsigned int)image->segment[i].mem + image->segment[i].memsz,
+ (unsigned int)image->segment[i].mem +
+ image->segment[i].memsz,
(unsigned int)image->segment[i].memsz);
- }
+ }
printk(" start : 0x%08x\n\n", (unsigned int)image->start);
}
-
/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now.
@@ -101,6 +101,27 @@ NORET_TYPE void machine_kexec(struct kimage *image)
/* now call it */
rnk = (relocate_new_kernel_t) reboot_code_buffer;
- (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
+ (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
}
+/* crashkernel=size@addr specifies the location to reserve for
+ * a crash kernel. By reserving this memory we guarantee
+ * that linux never sets it up as a DMA target.
+ * Useful for holding code to do something appropriate
+ * after a kernel panic.
+ */
+static int __init parse_crashkernel(char *arg)
+{
+ unsigned long size, base;
+ size = memparse(arg, &arg);
+ if (*arg == '@') {
+ base = memparse(arg+1, &arg);
+ /* FIXME: Do I want a sanity check
+ * to validate the memory range?
+ */
+ crashk_res.start = base;
+ crashk_res.end = base + size - 1;
+ }
+ return 0;
+}
+early_param("crashkernel", parse_crashkernel);
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index e7607366ac4..329b3f3051d 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -7,7 +7,7 @@
*
* 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>
@@ -15,6 +15,7 @@
#include <linux/pm.h>
#include <linux/kallsyms.h>
#include <linux/kexec.h>
+#include <asm/kdebug.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/ubc.h>
@@ -299,7 +300,8 @@ static void ubc_set_tracing(int asid, unsigned long pc)
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 {
@@ -495,6 +497,10 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
/* Rewind */
regs->pc -= 2;
+ if (notify_die(DIE_TRAP, regs, regs->tra & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
+
force_sig(SIGTRAP, current);
}
@@ -510,6 +516,10 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
/* Rewind */
regs->pc -= 2;
+ if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
+
#ifdef CONFIG_BUG
if (__kernel_text_address(instruction_pointer(regs))) {
u16 insn = *(u16 *)instruction_pointer(regs);
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 98802ab2821..477d2a854fc 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -4,7 +4,7 @@
* This file handles the architecture-dependent parts of initialization
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*/
#include <linux/screen_info.h>
#include <linux/ioport.h>
@@ -15,21 +15,22 @@
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/utsname.h>
+#include <linux/nodemask.h>
#include <linux/cpu.h>
#include <linux/pfn.h>
#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/kexec.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/clock.h>
+#include <asm/mmu_context.h>
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-static int kgdb_parse_options(char *options);
-#endif
extern void * __rd_start, * __rd_end;
+
/*
* Machine setup..
*/
@@ -205,53 +206,33 @@ static int __init sh_mv_setup(char **cmdline_p)
return 0;
}
-void __init setup_arch(char **cmdline_p)
+/*
+ * Register fully available low RAM pages with the bootmem allocator.
+ */
+static void __init register_bootmem_low_pages(void)
{
- unsigned long bootmap_size;
- unsigned long start_pfn, max_pfn, max_low_pfn;
-
-#ifdef CONFIG_CMDLINE_BOOL
- strcpy(COMMAND_LINE, CONFIG_CMDLINE);
-#endif
-
- ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
-
-#ifdef CONFIG_BLK_DEV_RAM
- rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
- rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
- rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-
- if (!MOUNT_ROOT_RDONLY)
- root_mountflags &= ~MS_RDONLY;
- init_mm.start_code = (unsigned long) _text;
- init_mm.end_code = (unsigned long) _etext;
- init_mm.end_data = (unsigned long) _edata;
- init_mm.brk = (unsigned long) _end;
-
- code_resource.start = (unsigned long)virt_to_phys(_text);
- code_resource.end = (unsigned long)virt_to_phys(_etext)-1;
- data_resource.start = (unsigned long)virt_to_phys(_etext);
- data_resource.end = (unsigned long)virt_to_phys(_edata)-1;
-
- sh_mv_setup(cmdline_p);
-
+ unsigned long curr_pfn, last_pfn, pages;
/*
- * Find the highest page frame number we have available
+ * We are rounding up the start address of usable memory:
*/
- max_pfn = PFN_DOWN(__pa(memory_end));
+ curr_pfn = PFN_UP(__MEMORY_START);
/*
- * Determine low and high memory ranges:
+ * ... and at the end of the usable range downwards:
*/
- max_low_pfn = max_pfn;
+ last_pfn = PFN_DOWN(__pa(memory_end));
- /*
- * Partially used pages are not usable - thus
- * we are rounding upwards:
- */
- start_pfn = PFN_UP(__pa(_end));
+ if (last_pfn > max_low_pfn)
+ last_pfn = max_low_pfn;
+
+ pages = last_pfn - curr_pfn;
+ free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages));
+}
+
+void __init setup_bootmem_allocator(unsigned long start_pfn)
+{
+ unsigned long bootmap_size;
/*
* Find a proper area for the bootmem bitmap. After this
@@ -259,31 +240,11 @@ void __init setup_arch(char **cmdline_p)
* is intact) must be done via bootmem_alloc().
*/
bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
- __MEMORY_START>>PAGE_SHIFT,
- max_low_pfn);
- /*
- * Register fully available low RAM pages with the bootmem allocator.
- */
- {
- unsigned long curr_pfn, last_pfn, pages;
-
- /*
- * We are rounding up the start address of usable memory:
- */
- curr_pfn = PFN_UP(__MEMORY_START);
- /*
- * ... and at the end of the usable range downwards:
- */
- last_pfn = PFN_DOWN(__pa(memory_end));
+ min_low_pfn, max_low_pfn);
- if (last_pfn > max_low_pfn)
- last_pfn = max_low_pfn;
-
- pages = last_pfn - curr_pfn;
- free_bootmem_node(NODE_DATA(0), PFN_PHYS(curr_pfn),
- PFN_PHYS(pages));
- }
+ register_bootmem_low_pages();
+ node_set_online(0);
/*
* Reserve the kernel text and
@@ -292,14 +253,14 @@ void __init setup_arch(char **cmdline_p)
* case of us accidentally initializing the bootmem allocator with
* an invalid RAM area.
*/
- reserve_bootmem_node(NODE_DATA(0), __MEMORY_START+PAGE_SIZE,
+ reserve_bootmem(__MEMORY_START+PAGE_SIZE,
(PFN_PHYS(start_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
* enabling clean reboots, SMP operation, laptop functions.
*/
- reserve_bootmem_node(NODE_DATA(0), __MEMORY_START, PAGE_SIZE);
+ reserve_bootmem(__MEMORY_START, PAGE_SIZE);
#ifdef CONFIG_BLK_DEV_INITRD
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
@@ -313,8 +274,8 @@ void __init setup_arch(char **cmdline_p)
if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
- reserve_bootmem_node(NODE_DATA(0), INITRD_START +
- __MEMORY_START, INITRD_SIZE);
+ reserve_bootmem(INITRD_START + __MEMORY_START,
+ INITRD_SIZE);
initrd_start = INITRD_START + PAGE_OFFSET +
__MEMORY_START;
initrd_end = initrd_start + INITRD_SIZE;
@@ -327,6 +288,76 @@ void __init setup_arch(char **cmdline_p)
}
}
#endif
+#ifdef CONFIG_KEXEC
+ if (crashk_res.start != crashk_res.end)
+ reserve_bootmem(crashk_res.start,
+ crashk_res.end - crashk_res.start + 1);
+#endif
+}
+
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+static void __init setup_memory(void)
+{
+ unsigned long start_pfn;
+
+ /*
+ * Partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+ start_pfn = PFN_UP(__pa(_end));
+ setup_bootmem_allocator(start_pfn);
+}
+#else
+extern void __init setup_memory(void);
+#endif
+
+void __init setup_arch(char **cmdline_p)
+{
+ enable_mmu();
+
+#ifdef CONFIG_CMDLINE_BOOL
+ strcpy(COMMAND_LINE, CONFIG_CMDLINE);
+#endif
+
+ ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
+
+#ifdef CONFIG_BLK_DEV_RAM
+ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+
+ if (!MOUNT_ROOT_RDONLY)
+ root_mountflags &= ~MS_RDONLY;
+ init_mm.start_code = (unsigned long) _text;
+ init_mm.end_code = (unsigned long) _etext;
+ init_mm.end_data = (unsigned long) _edata;
+ init_mm.brk = (unsigned long) _end;
+
+ code_resource.start = virt_to_phys(_text);
+ code_resource.end = virt_to_phys(_etext)-1;
+ data_resource.start = virt_to_phys(_etext);
+ data_resource.end = virt_to_phys(_edata)-1;
+
+ parse_early_param();
+
+ sh_mv_setup(cmdline_p);
+
+ /*
+ * Find the highest page frame number we have available
+ */
+ max_pfn = PFN_DOWN(__pa(memory_end));
+
+ /*
+ * Determine low and high memory ranges:
+ */
+ max_low_pfn = max_pfn;
+ min_low_pfn = __MEMORY_START >> PAGE_SHIFT;
+
+ nodes_clear(node_online_map);
+ setup_memory();
+ paging_init();
+ sparse_init();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -335,8 +366,6 @@ void __init setup_arch(char **cmdline_p)
/* Perform the machine specific initialisation */
if (likely(sh_mv.mv_setup))
sh_mv.mv_setup(cmdline_p);
-
- paging_init();
}
struct sh_machine_vector* __init get_mv_byname(const char* name)
@@ -380,6 +409,7 @@ static const char *cpu_name[] = {
[CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
[CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
[CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
+ [CPU_SH7712] = "SH7712",
[CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750",
[CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R",
[CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R",
@@ -477,7 +507,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
c->loops_per_jiffy/(500000/HZ),
(c->loops_per_jiffy/(5000/HZ)) % 100);
- return show_clocks(m);
+ return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
@@ -499,92 +529,3 @@ struct seq_operations cpuinfo_op = {
.show = show_cpuinfo,
};
#endif /* CONFIG_PROC_FS */
-
-#ifdef CONFIG_SH_KGDB
-/*
- * Parse command-line kgdb options. By default KGDB is enabled,
- * entered on error (or other action) using default serial info.
- * The command-line option can include a serial port specification
- * and an action to override default or configured behavior.
- */
-struct kgdb_sermap kgdb_sci_sermap =
-{ "ttySC", 5, kgdb_sci_setup, NULL };
-
-struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap;
-struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap;
-
-void kgdb_register_sermap(struct kgdb_sermap *map)
-{
- struct kgdb_sermap *last;
-
- for (last = kgdb_serlist; last->next; last = last->next)
- ;
- last->next = map;
- if (!map->namelen) {
- map->namelen = strlen(map->name);
- }
-}
-
-static int __init kgdb_parse_options(char *options)
-{
- char c;
- int baud;
-
- /* Check for port spec (or use default) */
-
- /* Determine port type and instance */
- if (!memcmp(options, "tty", 3)) {
- struct kgdb_sermap *map = kgdb_serlist;
-
- while (map && memcmp(options, map->name, map->namelen))
- map = map->next;
-
- if (!map) {
- KGDB_PRINTK("unknown port spec in %s\n", options);
- return -1;
- }
-
- kgdb_porttype = map;
- kgdb_serial_setup = map->setup_fn;
- kgdb_portnum = options[map->namelen] - '0';
- options += map->namelen + 1;
-
- options = (*options == ',') ? options+1 : options;
-
- /* Read optional parameters (baud/parity/bits) */
- baud = simple_strtoul(options, &options, 10);
- if (baud != 0) {
- kgdb_baud = baud;
-
- c = toupper(*options);
- if (c == 'E' || c == 'O' || c == 'N') {
- kgdb_parity = c;
- options++;
- }
-
- c = *options;
- if (c == '7' || c == '8') {
- kgdb_bits = c;
- options++;
- }
- options = (*options == ',') ? options+1 : options;
- }
- }
-
- /* Check for action specification */
- if (!memcmp(options, "halt", 4)) {
- kgdb_halt = 1;
- options += 4;
- } else if (!memcmp(options, "disabled", 8)) {
- kgdb_enabled = 0;
- options += 8;
- }
-
- if (*options) {
- KGDB_PRINTK("ignored unknown options: %s\n", options);
- return 0;
- }
- return 1;
-}
-__setup("kgdb=", kgdb_parse_options);
-#endif /* CONFIG_SH_KGDB */
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index 6e0d10fac4a..17f0b50c567 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -65,7 +65,6 @@ EXPORT_SYMBOL(__div64_32);
/* These symbols are generated by the compiler itself */
DECLARE_EXPORT(__udivsi3);
-DECLARE_EXPORT(__udivdi3);
DECLARE_EXPORT(__sdivsi3);
DECLARE_EXPORT(__ashrdi3);
DECLARE_EXPORT(__ashldi3);
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index e060e71d078..ad1ede52fc9 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -148,7 +148,9 @@ static int tmu_timer_init(void)
/* Start TMU0 */
tmu_timer_stop();
-#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
+#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7785)
ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
#endif
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index e9f168f60f9..7b40f0ff3df 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -5,7 +5,7 @@
* SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 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
@@ -18,10 +18,12 @@
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/io.h>
+#include <linux/bug.h>
#include <linux/debug_locks.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>
@@ -74,7 +76,21 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
}
}
-DEFINE_SPINLOCK(die_lock);
+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)
{
@@ -130,40 +146,6 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
return -EFAULT;
}
-#ifdef CONFIG_BUG
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-static inline void do_bug_verbose(struct pt_regs *regs)
-{
- struct bug_frame f;
- long len;
-
- if (__copy_from_user(&f, (const void __user *)regs->pc,
- sizeof(struct bug_frame)))
- return;
-
- len = __strnlen_user(f.file, PATH_MAX) - 1;
- if (unlikely(len < 0 || len >= PATH_MAX))
- f.file = "<bad filename>";
- len = __strnlen_user(f.func, PATH_MAX) - 1;
- if (unlikely(len < 0 || len >= PATH_MAX))
- f.func = "<bad function>";
-
- printk(KERN_ALERT "kernel BUG in %s() at %s:%d!\n",
- f.func, f.file, f.line);
-}
-#else
-static inline void do_bug_verbose(struct pt_regs *regs)
-{
-}
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
-
-void handle_BUG(struct pt_regs *regs)
-{
- do_bug_verbose(regs);
- die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
-}
-#endif /* CONFIG_BUG */
-
/*
* handle an instruction that does an unaligned memory access by emulating the
* desired behaviour
@@ -888,6 +870,25 @@ void __init trap_init(void)
per_cpu_trap_init();
}
+#ifdef CONFIG_BUG
+void handle_BUG(struct pt_regs *regs)
+{
+ enum bug_trap_type tt;
+ tt = report_bug(regs->pc);
+ if (tt == BUG_TRAP_TYPE_WARN) {
+ regs->pc += 2;
+ return;
+ }
+
+ die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
+}
+
+int is_valid_bugaddr(unsigned long addr)
+{
+ return addr >= PAGE_OFFSET;
+}
+#endif
+
void show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs)
{
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 78a6c09875b..d83143cc5ca 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -34,9 +34,11 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
+ _etext = .; /* End of text section */
+
RODATA
- _etext = .; /* End of text section */
+ BUG_TABLE
.data : { /* Data */
*(.data)
@@ -53,8 +55,12 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
.data.page_aligned : { *(.data.page_aligned) }
+ __nosave_begin = .;
+ .data_nosave : { *(.data.nosave) }
+ . = ALIGN(PAGE_SIZE);
+ __nosave_end = .;
- . = ALIGN(L1_CACHE_BYTES);
+ . = ALIGN(PAGE_SIZE);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
@@ -110,43 +116,10 @@ SECTIONS
* it's a module.
*/
/DISCARD/ : {
- *(.exit.text)
- *(.exit.data)
*(.exitcall.exit)
}
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging section are relative to the beginning
- of the section so we begin .debug at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
+ STABS_DEBUG
+
+ DWARF_DEBUG
}