diff options
author | Dave Jones <davej@redhat.com> | 2006-12-12 17:41:41 -0500 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2006-12-12 17:41:41 -0500 |
commit | c4366889dda8110247be59ca41fddb82951a8c26 (patch) | |
tree | 705c1a996bed8fd48ce94ff33ec9fd00f9b94875 /arch/sh/kernel | |
parent | db2fb9db5735cc532fd4fc55e94b9a3c3750378e (diff) | |
parent | e1036502e5263851259d147771226161e5ccc85a (diff) |
Merge ../linus
Conflicts:
drivers/cpufreq/cpufreq.c
Diffstat (limited to 'arch/sh/kernel')
62 files changed, 3076 insertions, 945 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 5da88a43d350..99c7e5249f7a 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | extra-y := head.o init_task.o vmlinux.lds | 5 | extra-y := head.o init_task.o vmlinux.lds |
6 | 6 | ||
7 | obj-y := process.o signal.o entry.o traps.o irq.o \ | 7 | obj-y := process.o signal.o traps.o irq.o \ |
8 | ptrace.o setup.o time.o sys_sh.o semaphore.o \ | 8 | ptrace.o setup.o time.o sys_sh.o semaphore.o \ |
9 | io.o io_generic.o sh_ksyms.o syscalls.o | 9 | io.o io_generic.o sh_ksyms.o syscalls.o |
10 | 10 | ||
@@ -21,3 +21,4 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | |||
21 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 21 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
22 | obj-$(CONFIG_APM) += apm.o | 22 | obj-$(CONFIG_APM) += apm.o |
23 | obj-$(CONFIG_PM) += pm.o | 23 | obj-$(CONFIG_PM) += pm.o |
24 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | ||
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index fb5dac069382..d055a3ea6b4b 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile | |||
@@ -2,11 +2,13 @@ | |||
2 | # Makefile for the Linux/SuperH CPU-specifc backends. | 2 | # Makefile for the Linux/SuperH CPU-specifc backends. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += irq/ init.o clock.o | 5 | obj-$(CONFIG_CPU_SH2) = sh2/ |
6 | 6 | obj-$(CONFIG_CPU_SH2A) = sh2a/ | |
7 | obj-$(CONFIG_CPU_SH2) += sh2/ | 7 | obj-$(CONFIG_CPU_SH3) = sh3/ |
8 | obj-$(CONFIG_CPU_SH3) += sh3/ | 8 | obj-$(CONFIG_CPU_SH4) = sh4/ |
9 | obj-$(CONFIG_CPU_SH4) += sh4/ | 9 | obj-$(CONFIG_CPU_SH4A) += sh4a/ |
10 | 10 | ||
11 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o | 11 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o |
12 | obj-$(CONFIG_SH_ADC) += adc.o | 12 | obj-$(CONFIG_SH_ADC) += adc.o |
13 | |||
14 | obj-y += irq/ init.o clock.o | ||
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 51ec64cdf348..abb586b12565 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c | |||
@@ -5,9 +5,11 @@ | |||
5 | * | 5 | * |
6 | * This clock framework is derived from the OMAP version by: | 6 | * This clock framework is derived from the OMAP version by: |
7 | * | 7 | * |
8 | * Copyright (C) 2004 Nokia Corporation | 8 | * Copyright (C) 2004 - 2005 Nokia Corporation |
9 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | 9 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> |
10 | * | 10 | * |
11 | * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> | ||
12 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | 13 | * This file is subject to the terms and conditions of the GNU General Public |
12 | * License. See the file "COPYING" in the main directory of this archive | 14 | * License. See the file "COPYING" in the main directory of this archive |
13 | * for more details. | 15 | * for more details. |
@@ -20,6 +22,7 @@ | |||
20 | #include <linux/kref.h> | 22 | #include <linux/kref.h> |
21 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
22 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/platform_device.h> | ||
23 | #include <asm/clock.h> | 26 | #include <asm/clock.h> |
24 | #include <asm/timer.h> | 27 | #include <asm/timer.h> |
25 | 28 | ||
@@ -195,17 +198,37 @@ void clk_recalc_rate(struct clk *clk) | |||
195 | propagate_rate(clk); | 198 | propagate_rate(clk); |
196 | } | 199 | } |
197 | 200 | ||
198 | struct clk *clk_get(const char *id) | 201 | /* |
202 | * Returns a clock. Note that we first try to use device id on the bus | ||
203 | * and clock name. If this fails, we try to use clock name only. | ||
204 | */ | ||
205 | struct clk *clk_get(struct device *dev, const char *id) | ||
199 | { | 206 | { |
200 | struct clk *p, *clk = ERR_PTR(-ENOENT); | 207 | struct clk *p, *clk = ERR_PTR(-ENOENT); |
208 | int idno; | ||
209 | |||
210 | if (dev == NULL || dev->bus != &platform_bus_type) | ||
211 | idno = -1; | ||
212 | else | ||
213 | idno = to_platform_device(dev)->id; | ||
201 | 214 | ||
202 | mutex_lock(&clock_list_sem); | 215 | mutex_lock(&clock_list_sem); |
203 | list_for_each_entry(p, &clock_list, node) { | 216 | list_for_each_entry(p, &clock_list, node) { |
217 | if (p->id == idno && | ||
218 | strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
219 | clk = p; | ||
220 | goto found; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | list_for_each_entry(p, &clock_list, node) { | ||
204 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | 225 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { |
205 | clk = p; | 226 | clk = p; |
206 | break; | 227 | break; |
207 | } | 228 | } |
208 | } | 229 | } |
230 | |||
231 | found: | ||
209 | mutex_unlock(&clock_list_sem); | 232 | mutex_unlock(&clock_list_sem); |
210 | 233 | ||
211 | return clk; | 234 | return clk; |
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index bfb90eb0b7a6..48121766e8d2 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c | |||
@@ -68,12 +68,14 @@ static void __init cache_init(void) | |||
68 | 68 | ||
69 | waysize = cpu_data->dcache.sets; | 69 | waysize = cpu_data->dcache.sets; |
70 | 70 | ||
71 | #ifdef CCR_CACHE_ORA | ||
71 | /* | 72 | /* |
72 | * If the OC is already in RAM mode, we only have | 73 | * If the OC is already in RAM mode, we only have |
73 | * half of the entries to flush.. | 74 | * half of the entries to flush.. |
74 | */ | 75 | */ |
75 | if (ccr & CCR_CACHE_ORA) | 76 | if (ccr & CCR_CACHE_ORA) |
76 | waysize >>= 1; | 77 | waysize >>= 1; |
78 | #endif | ||
77 | 79 | ||
78 | waysize <<= cpu_data->dcache.entry_shift; | 80 | waysize <<= cpu_data->dcache.entry_shift; |
79 | 81 | ||
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile index 1c034c283f59..0049d217561a 100644 --- a/arch/sh/kernel/cpu/irq/Makefile +++ b/arch/sh/kernel/cpu/irq/Makefile | |||
@@ -1,8 +1,9 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the Linux/SuperH CPU-specifc IRQ handlers. | 2 | # Makefile for the Linux/SuperH CPU-specifc IRQ handlers. |
3 | # | 3 | # |
4 | obj-y += ipr.o imask.o | 4 | obj-y += imask.o |
5 | 5 | ||
6 | obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o | ||
6 | obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o | 7 | obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o |
7 | obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o | 8 | obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o |
8 | obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o | 9 | obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o |
diff --git a/arch/sh/kernel/cpu/irq/imask.c b/arch/sh/kernel/cpu/irq/imask.c index a33ae3e0a5a5..301b505c4278 100644 --- a/arch/sh/kernel/cpu/irq/imask.c +++ b/arch/sh/kernel/cpu/irq/imask.c | |||
@@ -53,7 +53,10 @@ void static inline set_interrupt_registers(int ip) | |||
53 | { | 53 | { |
54 | unsigned long __dummy; | 54 | unsigned long __dummy; |
55 | 55 | ||
56 | asm volatile("ldc %2, r6_bank\n\t" | 56 | asm volatile( |
57 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
58 | "ldc %2, r6_bank\n\t" | ||
59 | #endif | ||
57 | "stc sr, %0\n\t" | 60 | "stc sr, %0\n\t" |
58 | "and #0xf0, %0\n\t" | 61 | "and #0xf0, %0\n\t" |
59 | "shlr2 %0\n\t" | 62 | "shlr2 %0\n\t" |
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c index d4b2bb7e08c7..74defe76a058 100644 --- a/arch/sh/kernel/cpu/irq/intc2.c +++ b/arch/sh/kernel/cpu/irq/intc2.c | |||
@@ -11,27 +11,33 @@ | |||
11 | * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780. | 11 | * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780. |
12 | */ | 12 | */ |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/init.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/irq.h> | 15 | #include <linux/io.h> |
16 | #include <asm/system.h> | 16 | |
17 | #include <asm/io.h> | 17 | #if defined(CONFIG_CPU_SUBTYPE_SH7760) |
18 | #define INTC2_BASE 0xfe080000 | ||
19 | #define INTC2_INTMSK (INTC2_BASE + 0x40) | ||
20 | #define INTC2_INTMSKCLR (INTC2_BASE + 0x60) | ||
21 | #elif defined(CONFIG_CPU_SUBTYPE_SH7780) | ||
22 | #define INTC2_BASE 0xffd40000 | ||
23 | #define INTC2_INTMSK (INTC2_BASE + 0x38) | ||
24 | #define INTC2_INTMSKCLR (INTC2_BASE + 0x3c) | ||
25 | #endif | ||
18 | 26 | ||
19 | static void disable_intc2_irq(unsigned int irq) | 27 | static void disable_intc2_irq(unsigned int irq) |
20 | { | 28 | { |
21 | struct intc2_data *p = get_irq_chip_data(irq); | 29 | struct intc2_data *p = get_irq_chip_data(irq); |
22 | ctrl_outl(1 << p->msk_shift, | 30 | ctrl_outl(1 << p->msk_shift, INTC2_INTMSK + p->msk_offset); |
23 | INTC2_BASE + INTC2_INTMSK_OFFSET + p->msk_offset); | ||
24 | } | 31 | } |
25 | 32 | ||
26 | static void enable_intc2_irq(unsigned int irq) | 33 | static void enable_intc2_irq(unsigned int irq) |
27 | { | 34 | { |
28 | struct intc2_data *p = get_irq_chip_data(irq); | 35 | struct intc2_data *p = get_irq_chip_data(irq); |
29 | ctrl_outl(1 << p->msk_shift, | 36 | ctrl_outl(1 << p->msk_shift, INTC2_INTMSKCLR + p->msk_offset); |
30 | INTC2_BASE + INTC2_INTMSKCLR_OFFSET + p->msk_offset); | ||
31 | } | 37 | } |
32 | 38 | ||
33 | static struct irq_chip intc2_irq_chip = { | 39 | static struct irq_chip intc2_irq_chip = { |
34 | .typename = "intc2", | 40 | .name = "INTC2", |
35 | .mask = disable_intc2_irq, | 41 | .mask = disable_intc2_irq, |
36 | .unmask = enable_intc2_irq, | 42 | .unmask = enable_intc2_irq, |
37 | .mask_ack = disable_intc2_irq, | 43 | .mask_ack = disable_intc2_irq, |
@@ -45,150 +51,34 @@ static struct irq_chip intc2_irq_chip = { | |||
45 | * PIO1 which is INTPRI00[19,16] and INTMSK00[13] | 51 | * PIO1 which is INTPRI00[19,16] and INTMSK00[13] |
46 | * would be: ^ ^ ^ ^ | 52 | * would be: ^ ^ ^ ^ |
47 | * | | | | | 53 | * | | | | |
48 | * make_intc2_irq(84, 0, 16, 0, 13); | 54 | * { 84, 0, 16, 0, 13 }, |
55 | * | ||
56 | * in the intc2_data table. | ||
49 | */ | 57 | */ |
50 | void make_intc2_irq(struct intc2_data *p) | 58 | void make_intc2_irq(struct intc2_data *table, unsigned int nr_irqs) |
51 | { | 59 | { |
52 | unsigned int flags; | 60 | int i; |
53 | unsigned long ipr; | ||
54 | |||
55 | disable_irq_nosync(p->irq); | ||
56 | |||
57 | /* Set the priority level */ | ||
58 | local_irq_save(flags); | ||
59 | |||
60 | ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + p->ipr_offset); | ||
61 | ipr &= ~(0xf << p->ipr_shift); | ||
62 | ipr |= p->priority << p->ipr_shift; | ||
63 | ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + p->ipr_offset); | ||
64 | |||
65 | local_irq_restore(flags); | ||
66 | 61 | ||
67 | set_irq_chip_and_handler(p->irq, &intc2_irq_chip, handle_level_irq); | 62 | for (i = 0; i < nr_irqs; i++) { |
68 | set_irq_chip_data(p->irq, p); | 63 | unsigned long ipr, flags; |
64 | struct intc2_data *p = table + i; | ||
69 | 65 | ||
70 | enable_intc2_irq(p->irq); | 66 | disable_irq_nosync(p->irq); |
71 | } | ||
72 | 67 | ||
73 | static struct intc2_data intc2_irq_table[] = { | 68 | /* Set the priority level */ |
74 | #if defined(CONFIG_CPU_SUBTYPE_ST40) | 69 | local_irq_save(flags); |
75 | {64, 0, 0, 0, 0, 13}, /* PCI serr */ | ||
76 | {65, 0, 4, 0, 1, 13}, /* PCI err */ | ||
77 | {66, 0, 4, 0, 2, 13}, /* PCI ad */ | ||
78 | {67, 0, 4, 0, 3, 13}, /* PCI pwd down */ | ||
79 | {72, 0, 8, 0, 5, 13}, /* DMAC INT0 */ | ||
80 | {73, 0, 8, 0, 6, 13}, /* DMAC INT1 */ | ||
81 | {74, 0, 8, 0, 7, 13}, /* DMAC INT2 */ | ||
82 | {75, 0, 8, 0, 8, 13}, /* DMAC INT3 */ | ||
83 | {76, 0, 8, 0, 9, 13}, /* DMAC INT4 */ | ||
84 | {78, 0, 8, 0, 11, 13}, /* DMAC ERR */ | ||
85 | {80, 0, 12, 0, 12, 13}, /* PIO0 */ | ||
86 | {84, 0, 16, 0, 13, 13}, /* PIO1 */ | ||
87 | {88, 0, 20, 0, 14, 13}, /* PIO2 */ | ||
88 | {112, 4, 0, 4, 0, 13}, /* Mailbox */ | ||
89 | #ifdef CONFIG_CPU_SUBTYPE_ST40GX1 | ||
90 | {116, 4, 4, 4, 4, 13}, /* SSC0 */ | ||
91 | {120, 4, 8, 4, 8, 13}, /* IR Blaster */ | ||
92 | {124, 4, 12, 4, 12, 13}, /* USB host */ | ||
93 | {128, 4, 16, 4, 16, 13}, /* Video processor BLITTER */ | ||
94 | {132, 4, 20, 4, 20, 13}, /* UART0 */ | ||
95 | {134, 4, 20, 4, 22, 13}, /* UART2 */ | ||
96 | {136, 4, 24, 4, 24, 13}, /* IO_PIO0 */ | ||
97 | {140, 4, 28, 4, 28, 13}, /* EMPI */ | ||
98 | {144, 8, 0, 8, 0, 13}, /* MAFE */ | ||
99 | {148, 8, 4, 8, 4, 13}, /* PWM */ | ||
100 | {152, 8, 8, 8, 8, 13}, /* SSC1 */ | ||
101 | {156, 8, 12, 8, 12, 13}, /* IO_PIO1 */ | ||
102 | {160, 8, 16, 8, 16, 13}, /* USB target */ | ||
103 | {164, 8, 20, 8, 20, 13}, /* UART1 */ | ||
104 | {168, 8, 24, 8, 24, 13}, /* Teletext */ | ||
105 | {172, 8, 28, 8, 28, 13}, /* VideoSync VTG */ | ||
106 | {173, 8, 28, 8, 29, 13}, /* VideoSync DVP0 */ | ||
107 | {174, 8, 28, 8, 30, 13}, /* VideoSync DVP1 */ | ||
108 | #endif | ||
109 | #elif defined(CONFIG_CPU_SUBTYPE_SH7760) | ||
110 | /* | ||
111 | * SH7760 INTC2-Style interrupts, vectors IRQ48-111 INTEVT 0x800-0xFE0 | ||
112 | */ | ||
113 | /* INTPRIO0 | INTMSK0 */ | ||
114 | {48, 0, 28, 0, 31, 3}, /* IRQ 4 */ | ||
115 | {49, 0, 24, 0, 30, 3}, /* IRQ 3 */ | ||
116 | {50, 0, 20, 0, 29, 3}, /* IRQ 2 */ | ||
117 | {51, 0, 16, 0, 28, 3}, /* IRQ 1 */ | ||
118 | /* 52-55 (INTEVT 0x880-0x8E0) unused/reserved */ | ||
119 | /* INTPRIO4 | INTMSK0 */ | ||
120 | {56, 4, 28, 0, 25, 3}, /* HCAN2_CHAN0 */ | ||
121 | {57, 4, 24, 0, 24, 3}, /* HCAN2_CHAN1 */ | ||
122 | {58, 4, 20, 0, 23, 3}, /* I2S_CHAN0 */ | ||
123 | {59, 4, 16, 0, 22, 3}, /* I2S_CHAN1 */ | ||
124 | {60, 4, 12, 0, 21, 3}, /* AC97_CHAN0 */ | ||
125 | {61, 4, 8, 0, 20, 3}, /* AC97_CHAN1 */ | ||
126 | {62, 4, 4, 0, 19, 3}, /* I2C_CHAN0 */ | ||
127 | {63, 4, 0, 0, 18, 3}, /* I2C_CHAN1 */ | ||
128 | /* INTPRIO8 | INTMSK0 */ | ||
129 | {52, 8, 16, 0, 11, 3}, /* SCIF0_ERI_IRQ */ | ||
130 | {53, 8, 16, 0, 10, 3}, /* SCIF0_RXI_IRQ */ | ||
131 | {54, 8, 16, 0, 9, 3}, /* SCIF0_BRI_IRQ */ | ||
132 | {55, 8, 16, 0, 8, 3}, /* SCIF0_TXI_IRQ */ | ||
133 | {64, 8, 28, 0, 17, 3}, /* USBHI_IRQ */ | ||
134 | {65, 8, 24, 0, 16, 3}, /* LCDC */ | ||
135 | /* 66, 67 unused */ | ||
136 | {68, 8, 20, 0, 14, 13}, /* DMABRGI0_IRQ */ | ||
137 | {69, 8, 20, 0, 13, 13}, /* DMABRGI1_IRQ */ | ||
138 | {70, 8, 20, 0, 12, 13}, /* DMABRGI2_IRQ */ | ||
139 | /* 71 unused */ | ||
140 | {72, 8, 12, 0, 7, 3}, /* SCIF1_ERI_IRQ */ | ||
141 | {73, 8, 12, 0, 6, 3}, /* SCIF1_RXI_IRQ */ | ||
142 | {74, 8, 12, 0, 5, 3}, /* SCIF1_BRI_IRQ */ | ||
143 | {75, 8, 12, 0, 4, 3}, /* SCIF1_TXI_IRQ */ | ||
144 | {76, 8, 8, 0, 3, 3}, /* SCIF2_ERI_IRQ */ | ||
145 | {77, 8, 8, 0, 2, 3}, /* SCIF2_RXI_IRQ */ | ||
146 | {78, 8, 8, 0, 1, 3}, /* SCIF2_BRI_IRQ */ | ||
147 | {79, 8, 8, 0, 0, 3}, /* SCIF2_TXI_IRQ */ | ||
148 | /* | INTMSK4 */ | ||
149 | {80, 8, 4, 4, 23, 3}, /* SIM_ERI */ | ||
150 | {81, 8, 4, 4, 22, 3}, /* SIM_RXI */ | ||
151 | {82, 8, 4, 4, 21, 3}, /* SIM_TXI */ | ||
152 | {83, 8, 4, 4, 20, 3}, /* SIM_TEI */ | ||
153 | {84, 8, 0, 4, 19, 3}, /* HSPII */ | ||
154 | /* INTPRIOC | INTMSK4 */ | ||
155 | /* 85-87 unused/reserved */ | ||
156 | {88, 12, 20, 4, 18, 3}, /* MMCI0 */ | ||
157 | {89, 12, 20, 4, 17, 3}, /* MMCI1 */ | ||
158 | {90, 12, 20, 4, 16, 3}, /* MMCI2 */ | ||
159 | {91, 12, 20, 4, 15, 3}, /* MMCI3 */ | ||
160 | {92, 12, 12, 4, 6, 3}, /* MFI (unsure, bug? in my 7760 manual*/ | ||
161 | /* 93-107 reserved/undocumented */ | ||
162 | {108,12, 4, 4, 1, 3}, /* ADC */ | ||
163 | {109,12, 0, 4, 0, 3}, /* CMTI */ | ||
164 | /* 110-111 reserved/unused */ | ||
165 | #elif defined(CONFIG_CPU_SUBTYPE_SH7780) | ||
166 | { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2}, | ||
167 | { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY }, | ||
168 | { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY }, | ||
169 | { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY }, | ||
170 | { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, | ||
171 | { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, | ||
172 | { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, | ||
173 | { SCIF0_TXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, | ||
174 | 70 | ||
175 | { SCIF1_ERI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, | 71 | ipr = ctrl_inl(INTC2_BASE + p->ipr_offset); |
176 | { SCIF1_RXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, | 72 | ipr &= ~(0xf << p->ipr_shift); |
177 | { SCIF1_BRI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, | 73 | ipr |= p->priority << p->ipr_shift; |
178 | { SCIF1_TXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, | 74 | ctrl_outl(ipr, INTC2_BASE + p->ipr_offset); |
179 | 75 | ||
180 | { PCIC0_IRQ, 0x10, 8, 0, INTC_PCIC0_MSK, PCIC0_PRIORITY }, | 76 | local_irq_restore(flags); |
181 | { PCIC1_IRQ, 0x10, 0, 0, INTC_PCIC1_MSK, PCIC1_PRIORITY }, | ||
182 | { PCIC2_IRQ, 0x14, 24, 0, INTC_PCIC2_MSK, PCIC2_PRIORITY }, | ||
183 | { PCIC3_IRQ, 0x14, 16, 0, INTC_PCIC3_MSK, PCIC3_PRIORITY }, | ||
184 | { PCIC4_IRQ, 0x14, 8, 0, INTC_PCIC4_MSK, PCIC4_PRIORITY }, | ||
185 | #endif | ||
186 | }; | ||
187 | 77 | ||
188 | void __init init_IRQ_intc2(void) | 78 | set_irq_chip_and_handler_name(p->irq, &intc2_irq_chip, |
189 | { | 79 | handle_level_irq, "level"); |
190 | int i; | 80 | set_irq_chip_data(p->irq, p); |
191 | 81 | ||
192 | for (i = 0; i < ARRAY_SIZE(intc2_irq_table); i++) | 82 | enable_intc2_irq(p->irq); |
193 | make_intc2_irq(intc2_irq_table + i); | 83 | } |
194 | } | 84 | } |
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index 8944abdf6e1c..35eb5751a3aa 100644 --- a/arch/sh/kernel/cpu/irq/ipr.c +++ b/arch/sh/kernel/cpu/irq/ipr.c | |||
@@ -19,15 +19,8 @@ | |||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <asm/system.h> | 22 | #include <linux/io.h> |
23 | #include <asm/io.h> | 23 | #include <linux/interrupt.h> |
24 | #include <asm/machvec.h> | ||
25 | |||
26 | struct ipr_data { | ||
27 | unsigned int addr; /* Address of Interrupt Priority Register */ | ||
28 | int shift; /* Shifts of the 16-bit data */ | ||
29 | int priority; /* The priority */ | ||
30 | }; | ||
31 | 24 | ||
32 | static void disable_ipr_irq(unsigned int irq) | 25 | static void disable_ipr_irq(unsigned int irq) |
33 | { | 26 | { |
@@ -44,107 +37,30 @@ static void enable_ipr_irq(unsigned int irq) | |||
44 | } | 37 | } |
45 | 38 | ||
46 | static struct irq_chip ipr_irq_chip = { | 39 | static struct irq_chip ipr_irq_chip = { |
47 | .name = "ipr", | 40 | .name = "IPR", |
48 | .mask = disable_ipr_irq, | 41 | .mask = disable_ipr_irq, |
49 | .unmask = enable_ipr_irq, | 42 | .unmask = enable_ipr_irq, |
50 | .mask_ack = disable_ipr_irq, | 43 | .mask_ack = disable_ipr_irq, |
51 | }; | 44 | }; |
52 | 45 | ||
53 | void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority) | 46 | void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs) |
54 | { | ||
55 | struct ipr_data ipr_data; | ||
56 | |||
57 | disable_irq_nosync(irq); | ||
58 | |||
59 | ipr_data.addr = addr; | ||
60 | ipr_data.shift = pos*4; /* POSition (0-3) x 4 means shift */ | ||
61 | ipr_data.priority = priority; | ||
62 | |||
63 | set_irq_chip_and_handler(irq, &ipr_irq_chip, handle_level_irq); | ||
64 | set_irq_chip_data(irq, &ipr_data); | ||
65 | |||
66 | enable_ipr_irq(irq); | ||
67 | } | ||
68 | |||
69 | /* XXX: This needs to die a horrible death.. */ | ||
70 | void __init init_IRQ(void) | ||
71 | { | 47 | { |
72 | #ifndef CONFIG_CPU_SUBTYPE_SH7780 | 48 | int i; |
73 | make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); | 49 | |
74 | make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY); | 50 | for (i = 0; i < nr_irqs; i++) { |
75 | #ifdef RTC_IRQ | 51 | unsigned int irq = table[i].irq; |
76 | make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); | 52 | table[i].addr = map_ipridx_to_addr(table[i].ipr_idx); |
77 | #endif | 53 | /* could the IPR index be mapped, if not we ignore this */ |
78 | 54 | if (table[i].addr == 0) | |
79 | #ifdef SCI_ERI_IRQ | 55 | continue; |
80 | make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); | 56 | disable_irq_nosync(irq); |
81 | make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); | 57 | set_irq_chip_and_handler_name(irq, &ipr_irq_chip, |
82 | make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); | 58 | handle_level_irq, "level"); |
83 | #endif | 59 | set_irq_chip_data(irq, &table[i]); |
84 | 60 | enable_ipr_irq(irq); | |
85 | #ifdef SCIF1_ERI_IRQ | 61 | } |
86 | make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | ||
87 | make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | ||
88 | make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | ||
89 | make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | ||
90 | #endif | ||
91 | |||
92 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
93 | make_ipr_irq(SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY); | ||
94 | make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | ||
95 | make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | ||
96 | make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY); | ||
97 | #endif | ||
98 | |||
99 | #ifdef SCIF_ERI_IRQ | ||
100 | make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | ||
101 | make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | ||
102 | make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | ||
103 | make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | ||
104 | #endif | ||
105 | |||
106 | #ifdef IRDA_ERI_IRQ | ||
107 | make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | ||
108 | make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | ||
109 | make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | ||
110 | make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | ||
111 | #endif | ||
112 | |||
113 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | ||
114 | defined(CONFIG_CPU_SUBTYPE_SH7706) || \ | ||
115 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) | ||
116 | /* | ||
117 | * Initialize the Interrupt Controller (INTC) | ||
118 | * registers to their power on values | ||
119 | */ | ||
120 | |||
121 | /* | ||
122 | * Enable external irq (INTC IRQ mode). | ||
123 | * You should set corresponding bits of PFC to "00" | ||
124 | * to enable these interrupts. | ||
125 | */ | ||
126 | make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY); | ||
127 | make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY); | ||
128 | make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY); | ||
129 | make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY); | ||
130 | make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY); | ||
131 | make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY); | ||
132 | #endif | ||
133 | #endif | ||
134 | |||
135 | #ifdef CONFIG_CPU_HAS_PINT_IRQ | ||
136 | init_IRQ_pint(); | ||
137 | #endif | ||
138 | |||
139 | #ifdef CONFIG_CPU_HAS_INTC2_IRQ | ||
140 | init_IRQ_intc2(); | ||
141 | #endif | ||
142 | /* Perform the machine specific initialisation */ | ||
143 | if (sh_mv.mv_init_irq != NULL) | ||
144 | sh_mv.mv_init_irq(); | ||
145 | |||
146 | irq_ctx_init(smp_processor_id()); | ||
147 | } | 62 | } |
63 | EXPORT_SYMBOL(make_ipr_irq); | ||
148 | 64 | ||
149 | #if !defined(CONFIG_CPU_HAS_PINT_IRQ) | 65 | #if !defined(CONFIG_CPU_HAS_PINT_IRQ) |
150 | int ipr_irq_demux(int irq) | 66 | int ipr_irq_demux(int irq) |
@@ -152,5 +68,3 @@ int ipr_irq_demux(int irq) | |||
152 | return irq; | 68 | return irq; |
153 | } | 69 | } |
154 | #endif | 70 | #endif |
155 | |||
156 | EXPORT_SYMBOL(make_ipr_irq); | ||
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c index 17f47b373d6e..f60007783a21 100644 --- a/arch/sh/kernel/cpu/irq/pint.c +++ b/arch/sh/kernel/cpu/irq/pint.c | |||
@@ -84,12 +84,16 @@ void make_pint_irq(unsigned int irq) | |||
84 | disable_pint_irq(irq); | 84 | disable_pint_irq(irq); |
85 | } | 85 | } |
86 | 86 | ||
87 | static struct ipr_data pint_ipr_map[] = { | ||
88 | { PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY }, | ||
89 | { PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY }, | ||
90 | }; | ||
91 | |||
87 | void __init init_IRQ_pint(void) | 92 | void __init init_IRQ_pint(void) |
88 | { | 93 | { |
89 | int i; | 94 | int i; |
90 | 95 | ||
91 | make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY); | 96 | make_ipr_irq(pint_ipr_map, ARRAY_SIZE(pint_ipr_map)); |
92 | make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY); | ||
93 | 97 | ||
94 | enable_irq(PINT0_IRQ); | 98 | enable_irq(PINT0_IRQ); |
95 | enable_irq(PINT8_IRQ); | 99 | enable_irq(PINT8_IRQ); |
diff --git a/arch/sh/kernel/cpu/sh2/Makefile b/arch/sh/kernel/cpu/sh2/Makefile index 389353fba608..f0f059acfcfb 100644 --- a/arch/sh/kernel/cpu/sh2/Makefile +++ b/arch/sh/kernel/cpu/sh2/Makefile | |||
@@ -2,5 +2,6 @@ | |||
2 | # Makefile for the Linux/SuperH SH-2 backends. | 2 | # Makefile for the Linux/SuperH SH-2 backends. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := probe.o | 5 | obj-y := ex.o probe.o entry.o |
6 | 6 | ||
7 | obj-$(CONFIG_CPU_SUBTYPE_SH7619) += setup-sh7619.o clock-sh7619.o | ||
diff --git a/arch/sh/kernel/cpu/sh2/clock-sh7619.c b/arch/sh/kernel/cpu/sh2/clock-sh7619.c new file mode 100644 index 000000000000..d0440b269702 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/clock-sh7619.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh2/clock-sh7619.c | ||
3 | * | ||
4 | * SH7619 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2006 Yoshinori Sato | ||
7 | * | ||
8 | * Based on clock-sh4.c | ||
9 | * Copyright (C) 2005 Paul Mundt | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <asm/clock.h> | ||
18 | #include <asm/freq.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | const static int pll1rate[]={1,2}; | ||
22 | const static int pfc_divisors[]={1,2,0,4}; | ||
23 | |||
24 | #if (CONFIG_SH_CLK_MD == 1) || (CONFIG_SH_CLK_MD == 2) | ||
25 | #define PLL2 (4) | ||
26 | #elif (CONFIG_SH_CLK_MD == 5) || (CONFIG_SH_CLK_MD == 6) | ||
27 | #define PLL2 (2) | ||
28 | #else | ||
29 | #error "Illigal Clock Mode!" | ||
30 | #endif | ||
31 | |||
32 | static void master_clk_init(struct clk *clk) | ||
33 | { | ||
34 | clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 7]; | ||
35 | } | ||
36 | |||
37 | static struct clk_ops sh7619_master_clk_ops = { | ||
38 | .init = master_clk_init, | ||
39 | }; | ||
40 | |||
41 | static void module_clk_recalc(struct clk *clk) | ||
42 | { | ||
43 | int idx = (ctrl_inw(FREQCR) & 0x0007); | ||
44 | clk->rate = clk->parent->rate / pfc_divisors[idx]; | ||
45 | } | ||
46 | |||
47 | static struct clk_ops sh7619_module_clk_ops = { | ||
48 | .recalc = module_clk_recalc, | ||
49 | }; | ||
50 | |||
51 | static void bus_clk_recalc(struct clk *clk) | ||
52 | { | ||
53 | clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 7]; | ||
54 | } | ||
55 | |||
56 | static struct clk_ops sh7619_bus_clk_ops = { | ||
57 | .recalc = bus_clk_recalc, | ||
58 | }; | ||
59 | |||
60 | static void cpu_clk_recalc(struct clk *clk) | ||
61 | { | ||
62 | clk->rate = clk->parent->rate; | ||
63 | } | ||
64 | |||
65 | static struct clk_ops sh7619_cpu_clk_ops = { | ||
66 | .recalc = cpu_clk_recalc, | ||
67 | }; | ||
68 | |||
69 | static struct clk_ops *sh7619_clk_ops[] = { | ||
70 | &sh7619_master_clk_ops, | ||
71 | &sh7619_module_clk_ops, | ||
72 | &sh7619_bus_clk_ops, | ||
73 | &sh7619_cpu_clk_ops, | ||
74 | }; | ||
75 | |||
76 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
77 | { | ||
78 | if (idx < ARRAY_SIZE(sh7619_clk_ops)) | ||
79 | *ops = sh7619_clk_ops[idx]; | ||
80 | } | ||
81 | |||
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S new file mode 100644 index 000000000000..d51fa5e9904a --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/entry.S | |||
@@ -0,0 +1,337 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh2/entry.S | ||
3 | * | ||
4 | * The SH-2 exception entry | ||
5 | * | ||
6 | * Copyright (C) 2005,2006 Yoshinori Sato | ||
7 | * Copyright (C) 2005 AXE,Inc. | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/linkage.h> | ||
15 | #include <asm/asm-offsets.h> | ||
16 | #include <asm/thread_info.h> | ||
17 | #include <asm/cpu/mmu_context.h> | ||
18 | #include <asm/unistd.h> | ||
19 | #include <asm/errno.h> | ||
20 | #include <asm/page.h> | ||
21 | |||
22 | /* Offsets to the stack */ | ||
23 | OFF_R0 = 0 /* Return value. New ABI also arg4 */ | ||
24 | OFF_R1 = 4 /* New ABI: arg5 */ | ||
25 | OFF_R2 = 8 /* New ABI: arg6 */ | ||
26 | OFF_R3 = 12 /* New ABI: syscall_nr */ | ||
27 | OFF_R4 = 16 /* New ABI: arg0 */ | ||
28 | OFF_R5 = 20 /* New ABI: arg1 */ | ||
29 | OFF_R6 = 24 /* New ABI: arg2 */ | ||
30 | OFF_R7 = 28 /* New ABI: arg3 */ | ||
31 | OFF_SP = (15*4) | ||
32 | OFF_PC = (16*4) | ||
33 | OFF_SR = (16*4+2*4) | ||
34 | OFF_TRA = (16*4+6*4) | ||
35 | |||
36 | #include <asm/entry-macros.S> | ||
37 | |||
38 | ENTRY(exception_handler) | ||
39 | ! already saved r0/r1 | ||
40 | mov.l r2,@-sp | ||
41 | mov.l r3,@-sp | ||
42 | mov r0,r1 | ||
43 | cli | ||
44 | mov.l $cpu_mode,r2 | ||
45 | mov.l @r2,r0 | ||
46 | mov.l @(5*4,r15),r3 ! previous SR | ||
47 | shll2 r3 ! set "S" flag | ||
48 | rotl r0 ! T <- "S" flag | ||
49 | rotl r0 ! "S" flag is LSB | ||
50 | rotcr r3 ! T -> r3:b30 | ||
51 | shlr r3 | ||
52 | shlr r0 | ||
53 | bt/s 1f | ||
54 | mov.l r3,@(5*4,r15) ! copy cpu mode to SR | ||
55 | ! switch to kernel mode | ||
56 | mov #1,r0 | ||
57 | rotr r0 | ||
58 | rotr r0 | ||
59 | mov.l r0,@r2 ! enter kernel mode | ||
60 | mov.l $current_thread_info,r2 | ||
61 | mov.l @r2,r2 | ||
62 | mov #0x20,r0 | ||
63 | shll8 r0 | ||
64 | add r2,r0 | ||
65 | mov r15,r2 ! r2 = user stack top | ||
66 | mov r0,r15 ! switch kernel stack | ||
67 | add #-4,r15 ! dummy | ||
68 | mov.l r1,@-r15 ! TRA | ||
69 | sts.l macl, @-r15 | ||
70 | sts.l mach, @-r15 | ||
71 | stc.l gbr, @-r15 | ||
72 | mov.l @(4*4,r2),r0 | ||
73 | mov.l @(5*4,r2),r1 | ||
74 | mov.l r1,@-r15 ! original SR | ||
75 | sts.l pr,@-r15 | ||
76 | mov.l r0,@-r15 ! original PC | ||
77 | mov r2,r3 | ||
78 | add #(4+2)*4,r3 ! rewind r0 - r3 + exception frame | ||
79 | mov.l r3,@-r15 ! original SP | ||
80 | mov.l r14,@-r15 | ||
81 | mov.l r13,@-r15 | ||
82 | mov.l r12,@-r15 | ||
83 | mov.l r11,@-r15 | ||
84 | mov.l r10,@-r15 | ||
85 | mov.l r9,@-r15 | ||
86 | mov.l r8,@-r15 | ||
87 | mov.l r7,@-r15 | ||
88 | mov.l r6,@-r15 | ||
89 | mov.l r5,@-r15 | ||
90 | mov.l r4,@-r15 | ||
91 | mov r2,r8 ! copy user -> kernel stack | ||
92 | mov.l @r8+,r3 | ||
93 | mov.l r3,@-r15 | ||
94 | mov.l @r8+,r2 | ||
95 | mov.l r2,@-r15 | ||
96 | mov.l @r8+,r1 | ||
97 | mov.l r1,@-r15 | ||
98 | mov.l @r8+,r0 | ||
99 | bra 2f | ||
100 | mov.l r0,@-r15 | ||
101 | 1: | ||
102 | ! in kernel exception | ||
103 | mov #(22-4-4-1)*4+4,r0 | ||
104 | mov r15,r2 | ||
105 | sub r0,r15 | ||
106 | mov.l @r2+,r0 ! old R3 | ||
107 | mov.l r0,@-r15 | ||
108 | mov.l @r2+,r0 ! old R2 | ||
109 | mov.l r0,@-r15 | ||
110 | mov.l @r2+,r0 ! old R1 | ||
111 | mov.l r0,@-r15 | ||
112 | mov.l @r2+,r0 ! old R0 | ||
113 | mov.l r0,@-r15 | ||
114 | mov.l @r2+,r3 ! old PC | ||
115 | mov.l @r2+,r0 ! old SR | ||
116 | add #-4,r2 ! exception frame stub (sr) | ||
117 | mov.l r1,@-r2 ! TRA | ||
118 | sts.l macl, @-r2 | ||
119 | sts.l mach, @-r2 | ||
120 | stc.l gbr, @-r2 | ||
121 | mov.l r0,@-r2 ! save old SR | ||
122 | sts.l pr,@-r2 | ||
123 | mov.l r3,@-r2 ! save old PC | ||
124 | mov r2,r0 | ||
125 | add #8*4,r0 | ||
126 | mov.l r0,@-r2 ! save old SP | ||
127 | mov.l r14,@-r2 | ||
128 | mov.l r13,@-r2 | ||
129 | mov.l r12,@-r2 | ||
130 | mov.l r11,@-r2 | ||
131 | mov.l r10,@-r2 | ||
132 | mov.l r9,@-r2 | ||
133 | mov.l r8,@-r2 | ||
134 | mov.l r7,@-r2 | ||
135 | mov.l r6,@-r2 | ||
136 | mov.l r5,@-r2 | ||
137 | mov.l r4,@-r2 | ||
138 | mov.l @(OFF_R0,r15),r0 | ||
139 | mov.l @(OFF_R1,r15),r1 | ||
140 | mov.l @(OFF_R2,r15),r2 | ||
141 | mov.l @(OFF_R3,r15),r3 | ||
142 | 2: | ||
143 | mov #OFF_TRA,r8 | ||
144 | add r15,r8 | ||
145 | mov.l @r8,r9 | ||
146 | mov #64,r8 | ||
147 | cmp/hs r8,r9 | ||
148 | bt interrupt_entry ! vec >= 64 is interrupt | ||
149 | mov #32,r8 | ||
150 | cmp/hs r8,r9 | ||
151 | bt trap_entry ! 64 > vec >= 32 is trap | ||
152 | mov.l 4f,r8 | ||
153 | mov r9,r4 | ||
154 | shll2 r9 | ||
155 | add r9,r8 | ||
156 | mov.l @r8,r8 | ||
157 | mov #0,r9 | ||
158 | cmp/eq r9,r8 | ||
159 | bf 3f | ||
160 | mov.l 8f,r8 ! unhandled exception | ||
161 | 3: | ||
162 | mov.l 5f,r10 | ||
163 | jmp @r8 | ||
164 | lds r10,pr | ||
165 | |||
166 | interrupt_entry: | ||
167 | mov r9,r4 | ||
168 | mov.l 6f,r9 | ||
169 | mov.l 7f,r8 | ||
170 | jmp @r8 | ||
171 | lds r9,pr | ||
172 | |||
173 | .align 2 | ||
174 | 4: .long exception_handling_table | ||
175 | 5: .long ret_from_exception | ||
176 | 6: .long ret_from_irq | ||
177 | 7: .long do_IRQ | ||
178 | 8: .long do_exception_error | ||
179 | |||
180 | trap_entry: | ||
181 | /* verbose BUG trapa entry check */ | ||
182 | mov #0x3e,r8 | ||
183 | cmp/ge r8,r9 | ||
184 | bf/s 1f | ||
185 | add #-0x10,r9 | ||
186 | add #0x10,r9 | ||
187 | 1: | ||
188 | shll2 r9 ! TRA | ||
189 | mov #OFF_TRA,r8 | ||
190 | add r15,r8 | ||
191 | mov.l r9,@r8 | ||
192 | mov r9,r8 | ||
193 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
194 | mov.l 2f, r9 | ||
195 | jsr @r9 | ||
196 | nop | ||
197 | #endif | ||
198 | sti | ||
199 | bra system_call | ||
200 | nop | ||
201 | |||
202 | .align 2 | ||
203 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
204 | 2: .long trace_hardirqs_on | ||
205 | #endif | ||
206 | |||
207 | #if defined(CONFIG_SH_STANDARD_BIOS) | ||
208 | /* Unwind the stack and jmp to the debug entry */ | ||
209 | debug_kernel_fw: | ||
210 | mov r15,r0 | ||
211 | add #(22-4)*4-4,r0 | ||
212 | ldc.l @r0+,gbr | ||
213 | lds.l @r0+,mach | ||
214 | lds.l @r0+,macl | ||
215 | mov r15,r0 | ||
216 | mov.l @(OFF_SP,r0),r1 | ||
217 | mov #OFF_SR,r2 | ||
218 | mov.l @(r0,r2),r3 | ||
219 | mov.l r3,@-r1 | ||
220 | mov #OFF_SP,r2 | ||
221 | mov.l @(r0,r2),r3 | ||
222 | mov.l r3,@-r1 | ||
223 | mov r15,r0 | ||
224 | add #(22-4)*4-8,r0 | ||
225 | mov.l 1f,r2 | ||
226 | mov.l @r2,r2 | ||
227 | stc sr,r3 | ||
228 | mov.l r2,@r0 | ||
229 | mov.l r3,@r0 | ||
230 | mov.l r1,@(8,r0) | ||
231 | mov.l @r15+, r0 | ||
232 | mov.l @r15+, r1 | ||
233 | mov.l @r15+, r2 | ||
234 | mov.l @r15+, r3 | ||
235 | mov.l @r15+, r4 | ||
236 | mov.l @r15+, r5 | ||
237 | mov.l @r15+, r6 | ||
238 | mov.l @r15+, r7 | ||
239 | mov.l @r15+, r8 | ||
240 | mov.l @r15+, r9 | ||
241 | mov.l @r15+, r10 | ||
242 | mov.l @r15+, r11 | ||
243 | mov.l @r15+, r12 | ||
244 | mov.l @r15+, r13 | ||
245 | mov.l @r15+, r14 | ||
246 | add #8,r15 | ||
247 | lds.l @r15+, pr | ||
248 | rte | ||
249 | mov.l @r15+,r15 | ||
250 | .align 2 | ||
251 | 1: .long gdb_vbr_vector | ||
252 | #endif /* CONFIG_SH_STANDARD_BIOS */ | ||
253 | |||
254 | ENTRY(address_error_handler) | ||
255 | mov r15,r4 ! regs | ||
256 | add #4,r4 | ||
257 | mov #OFF_PC,r0 | ||
258 | mov.l @(r0,r15),r6 ! pc | ||
259 | mov.l 1f,r0 | ||
260 | jmp @r0 | ||
261 | mov #0,r5 ! writeaccess is unknown | ||
262 | .align 2 | ||
263 | |||
264 | 1: .long do_address_error | ||
265 | |||
266 | restore_all: | ||
267 | cli | ||
268 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
269 | mov.l 1f, r0 | ||
270 | jsr @r0 | ||
271 | nop | ||
272 | #endif | ||
273 | mov r15,r0 | ||
274 | mov.l $cpu_mode,r2 | ||
275 | mov #OFF_SR,r3 | ||
276 | mov.l @(r0,r3),r1 | ||
277 | mov.l r1,@r2 | ||
278 | shll2 r1 ! clear MD bit | ||
279 | shlr2 r1 | ||
280 | mov.l @(OFF_SP,r0),r2 | ||
281 | add #-8,r2 | ||
282 | mov.l r2,@(OFF_SP,r0) ! point exception frame top | ||
283 | mov.l r1,@(4,r2) ! set sr | ||
284 | mov #OFF_PC,r3 | ||
285 | mov.l @(r0,r3),r1 | ||
286 | mov.l r1,@r2 ! set pc | ||
287 | add #4*16+4,r0 | ||
288 | lds.l @r0+,pr | ||
289 | add #4,r0 ! skip sr | ||
290 | ldc.l @r0+,gbr | ||
291 | lds.l @r0+,mach | ||
292 | lds.l @r0+,macl | ||
293 | get_current_thread_info r0, r1 | ||
294 | mov.l $current_thread_info,r1 | ||
295 | mov.l r0,@r1 | ||
296 | mov.l @r15+,r0 | ||
297 | mov.l @r15+,r1 | ||
298 | mov.l @r15+,r2 | ||
299 | mov.l @r15+,r3 | ||
300 | mov.l @r15+,r4 | ||
301 | mov.l @r15+,r5 | ||
302 | mov.l @r15+,r6 | ||
303 | mov.l @r15+,r7 | ||
304 | mov.l @r15+,r8 | ||
305 | mov.l @r15+,r9 | ||
306 | mov.l @r15+,r10 | ||
307 | mov.l @r15+,r11 | ||
308 | mov.l @r15+,r12 | ||
309 | mov.l @r15+,r13 | ||
310 | mov.l @r15+,r14 | ||
311 | mov.l @r15,r15 | ||
312 | rte | ||
313 | nop | ||
314 | |||
315 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
316 | 1: .long trace_hardirqs_off | ||
317 | #endif | ||
318 | $current_thread_info: | ||
319 | .long __current_thread_info | ||
320 | $cpu_mode: | ||
321 | .long __cpu_mode | ||
322 | |||
323 | ! common exception handler | ||
324 | #include "../../entry-common.S" | ||
325 | |||
326 | .data | ||
327 | ! cpu operation mode | ||
328 | ! bit30 = MD (compatible SH3/4) | ||
329 | __cpu_mode: | ||
330 | .long 0x40000000 | ||
331 | |||
332 | .section .bss | ||
333 | __current_thread_info: | ||
334 | .long 0 | ||
335 | |||
336 | ENTRY(exception_handling_table) | ||
337 | .space 4*32 | ||
diff --git a/arch/sh/kernel/cpu/sh2/ex.S b/arch/sh/kernel/cpu/sh2/ex.S new file mode 100644 index 000000000000..6d285af7846c --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/ex.S | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh2/ex.S | ||
3 | * | ||
4 | * The SH-2 exception vector table | ||
5 | * | ||
6 | * Copyright (C) 2005 Yoshinori Sato | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/linkage.h> | ||
14 | |||
15 | ! | ||
16 | ! convert Exception Vector to Exception Number | ||
17 | ! | ||
18 | exception_entry: | ||
19 | no = 0 | ||
20 | .rept 256 | ||
21 | mov.l r0,@-sp | ||
22 | mov #no,r0 | ||
23 | bra exception_trampoline | ||
24 | and #0xff,r0 | ||
25 | no = no + 1 | ||
26 | .endr | ||
27 | exception_trampoline: | ||
28 | mov.l r1,@-sp | ||
29 | mov.l $exception_handler,r1 | ||
30 | jmp @r1 | ||
31 | |||
32 | .align 2 | ||
33 | $exception_entry: | ||
34 | .long exception_entry | ||
35 | $exception_handler: | ||
36 | .long exception_handler | ||
37 | ! | ||
38 | ! Exception Vector Base | ||
39 | ! | ||
40 | .align 2 | ||
41 | ENTRY(vbr_base) | ||
42 | vector = 0 | ||
43 | .rept 256 | ||
44 | .long exception_entry + vector * 8 | ||
45 | vector = vector + 1 | ||
46 | .endr | ||
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c index f17a2a0d588e..ba527d9b5024 100644 --- a/arch/sh/kernel/cpu/sh2/probe.c +++ b/arch/sh/kernel/cpu/sh2/probe.c | |||
@@ -17,17 +17,23 @@ | |||
17 | 17 | ||
18 | int __init detect_cpu_and_cache_system(void) | 18 | int __init detect_cpu_and_cache_system(void) |
19 | { | 19 | { |
20 | /* | 20 | #if defined(CONFIG_CPU_SUBTYPE_SH7604) |
21 | * For now, assume SH7604 .. fix this later. | ||
22 | */ | ||
23 | cpu_data->type = CPU_SH7604; | 21 | cpu_data->type = CPU_SH7604; |
24 | cpu_data->dcache.ways = 4; | 22 | cpu_data->dcache.ways = 4; |
25 | cpu_data->dcache.way_shift = 6; | 23 | cpu_data->dcache.way_incr = (1<<10); |
26 | cpu_data->dcache.sets = 64; | 24 | cpu_data->dcache.sets = 64; |
27 | cpu_data->dcache.entry_shift = 4; | 25 | cpu_data->dcache.entry_shift = 4; |
28 | cpu_data->dcache.linesz = L1_CACHE_BYTES; | 26 | cpu_data->dcache.linesz = L1_CACHE_BYTES; |
29 | cpu_data->dcache.flags = 0; | 27 | cpu_data->dcache.flags = 0; |
30 | 28 | #elif defined(CONFIG_CPU_SUBTYPE_SH7619) | |
29 | cpu_data->type = CPU_SH7619; | ||
30 | cpu_data->dcache.ways = 4; | ||
31 | cpu_data->dcache.way_incr = (1<<12); | ||
32 | cpu_data->dcache.sets = 256; | ||
33 | cpu_data->dcache.entry_shift = 4; | ||
34 | cpu_data->dcache.linesz = L1_CACHE_BYTES; | ||
35 | cpu_data->dcache.flags = 0; | ||
36 | #endif | ||
31 | /* | 37 | /* |
32 | * SH-2 doesn't have separate caches | 38 | * SH-2 doesn't have separate caches |
33 | */ | 39 | */ |
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c new file mode 100644 index 000000000000..79283e6c1d8f --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * SH7619 Setup | ||
3 | * | ||
4 | * Copyright (C) 2006 Yoshinori Sato | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/serial.h> | ||
13 | #include <asm/sci.h> | ||
14 | |||
15 | static struct plat_sci_port sci_platform_data[] = { | ||
16 | { | ||
17 | .mapbase = 0xf8400000, | ||
18 | .flags = UPF_BOOT_AUTOCONF, | ||
19 | .type = PORT_SCIF, | ||
20 | .irqs = { 88, 89, 91, 90}, | ||
21 | }, { | ||
22 | .mapbase = 0xf8410000, | ||
23 | .flags = UPF_BOOT_AUTOCONF, | ||
24 | .type = PORT_SCIF, | ||
25 | .irqs = { 92, 93, 95, 94}, | ||
26 | }, { | ||
27 | .mapbase = 0xf8420000, | ||
28 | .flags = UPF_BOOT_AUTOCONF, | ||
29 | .type = PORT_SCIF, | ||
30 | .irqs = { 96, 97, 99, 98}, | ||
31 | }, { | ||
32 | .flags = 0, | ||
33 | } | ||
34 | }; | ||
35 | |||
36 | static struct platform_device sci_device = { | ||
37 | .name = "sh-sci", | ||
38 | .id = -1, | ||
39 | .dev = { | ||
40 | .platform_data = sci_platform_data, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static struct platform_device *sh7619_devices[] __initdata = { | ||
45 | &sci_device, | ||
46 | }; | ||
47 | |||
48 | static int __init sh7619_devices_setup(void) | ||
49 | { | ||
50 | return platform_add_devices(sh7619_devices, | ||
51 | ARRAY_SIZE(sh7619_devices)); | ||
52 | } | ||
53 | __initcall(sh7619_devices_setup); | ||
54 | |||
55 | #define INTC_IPRC 0xf8080000UL | ||
56 | #define INTC_IPRD 0xf8080002UL | ||
57 | |||
58 | #define CMI0_IRQ 86 | ||
59 | |||
60 | #define SCIF0_ERI_IRQ 88 | ||
61 | #define SCIF0_RXI_IRQ 89 | ||
62 | #define SCIF0_BRI_IRQ 90 | ||
63 | #define SCIF0_TXI_IRQ 91 | ||
64 | |||
65 | #define SCIF1_ERI_IRQ 92 | ||
66 | #define SCIF1_RXI_IRQ 93 | ||
67 | #define SCIF1_BRI_IRQ 94 | ||
68 | #define SCIF1_TXI_IRQ 95 | ||
69 | |||
70 | #define SCIF2_BRI_IRQ 96 | ||
71 | #define SCIF2_ERI_IRQ 97 | ||
72 | #define SCIF2_RXI_IRQ 98 | ||
73 | #define SCIF2_TXI_IRQ 99 | ||
74 | |||
75 | static struct ipr_data sh7619_ipr_map[] = { | ||
76 | { CMI0_IRQ, INTC_IPRC, 1, 2 }, | ||
77 | { SCIF0_ERI_IRQ, INTC_IPRD, 3, 3 }, | ||
78 | { SCIF0_RXI_IRQ, INTC_IPRD, 3, 3 }, | ||
79 | { SCIF0_BRI_IRQ, INTC_IPRD, 3, 3 }, | ||
80 | { SCIF0_TXI_IRQ, INTC_IPRD, 3, 3 }, | ||
81 | { SCIF1_ERI_IRQ, INTC_IPRD, 2, 3 }, | ||
82 | { SCIF1_RXI_IRQ, INTC_IPRD, 2, 3 }, | ||
83 | { SCIF1_BRI_IRQ, INTC_IPRD, 2, 3 }, | ||
84 | { SCIF1_TXI_IRQ, INTC_IPRD, 2, 3 }, | ||
85 | { SCIF2_ERI_IRQ, INTC_IPRD, 1, 3 }, | ||
86 | { SCIF2_RXI_IRQ, INTC_IPRD, 1, 3 }, | ||
87 | { SCIF2_BRI_IRQ, INTC_IPRD, 1, 3 }, | ||
88 | { SCIF2_TXI_IRQ, INTC_IPRD, 1, 3 }, | ||
89 | }; | ||
90 | |||
91 | void __init init_IRQ_ipr(void) | ||
92 | { | ||
93 | make_ipr_irq(sh7619_ipr_map, ARRAY_SIZE(sh7619_ipr_map)); | ||
94 | } | ||
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile new file mode 100644 index 000000000000..350972ae9410 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for the Linux/SuperH SH-2A backends. | ||
3 | # | ||
4 | |||
5 | obj-y := common.o probe.o | ||
6 | |||
7 | common-y += $(addprefix ../sh2/, ex.o) | ||
8 | common-y += $(addprefix ../sh2/, entry.o) | ||
9 | |||
10 | obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o | ||
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c new file mode 100644 index 000000000000..a9ad309c6a33 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh2a/clock-sh7206.c | ||
3 | * | ||
4 | * SH7206 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2006 Yoshinori Sato | ||
7 | * | ||
8 | * Based on clock-sh4.c | ||
9 | * Copyright (C) 2005 Paul Mundt | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <asm/clock.h> | ||
18 | #include <asm/freq.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | const static int pll1rate[]={1,2,3,4,6,8}; | ||
22 | const static int pfc_divisors[]={1,2,3,4,6,8,12}; | ||
23 | #define ifc_divisors pfc_divisors | ||
24 | |||
25 | #if (CONFIG_SH_CLK_MD == 2) | ||
26 | #define PLL2 (4) | ||
27 | #elif (CONFIG_SH_CLK_MD == 6) | ||
28 | #define PLL2 (2) | ||
29 | #elif (CONFIG_SH_CLK_MD == 7) | ||
30 | #define PLL2 (1) | ||
31 | #else | ||
32 | #error "Illigal Clock Mode!" | ||
33 | #endif | ||
34 | |||
35 | static void master_clk_init(struct clk *clk) | ||
36 | { | ||
37 | clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007]; | ||
38 | } | ||
39 | |||
40 | static struct clk_ops sh7206_master_clk_ops = { | ||
41 | .init = master_clk_init, | ||
42 | }; | ||
43 | |||
44 | static void module_clk_recalc(struct clk *clk) | ||
45 | { | ||
46 | int idx = (ctrl_inw(FREQCR) & 0x0007); | ||
47 | clk->rate = clk->parent->rate / pfc_divisors[idx]; | ||
48 | } | ||
49 | |||
50 | static struct clk_ops sh7206_module_clk_ops = { | ||
51 | .recalc = module_clk_recalc, | ||
52 | }; | ||
53 | |||
54 | static void bus_clk_recalc(struct clk *clk) | ||
55 | { | ||
56 | clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007]; | ||
57 | } | ||
58 | |||
59 | static struct clk_ops sh7206_bus_clk_ops = { | ||
60 | .recalc = bus_clk_recalc, | ||
61 | }; | ||
62 | |||
63 | static void cpu_clk_recalc(struct clk *clk) | ||
64 | { | ||
65 | int idx = (ctrl_inw(FREQCR) & 0x0007); | ||
66 | clk->rate = clk->parent->rate / ifc_divisors[idx]; | ||
67 | } | ||
68 | |||
69 | static struct clk_ops sh7206_cpu_clk_ops = { | ||
70 | .recalc = cpu_clk_recalc, | ||
71 | }; | ||
72 | |||
73 | static struct clk_ops *sh7206_clk_ops[] = { | ||
74 | &sh7206_master_clk_ops, | ||
75 | &sh7206_module_clk_ops, | ||
76 | &sh7206_bus_clk_ops, | ||
77 | &sh7206_cpu_clk_ops, | ||
78 | }; | ||
79 | |||
80 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
81 | { | ||
82 | if (idx < ARRAY_SIZE(sh7206_clk_ops)) | ||
83 | *ops = sh7206_clk_ops[idx]; | ||
84 | } | ||
85 | |||
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c new file mode 100644 index 000000000000..87c6c0542089 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/probe.c | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh2a/probe.c | ||
3 | * | ||
4 | * CPU Subtype Probing for SH-2A. | ||
5 | * | ||
6 | * Copyright (C) 2004, 2005 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <asm/processor.h> | ||
15 | #include <asm/cache.h> | ||
16 | |||
17 | int __init detect_cpu_and_cache_system(void) | ||
18 | { | ||
19 | /* Just SH7206 for now .. */ | ||
20 | cpu_data->type = CPU_SH7206; | ||
21 | |||
22 | cpu_data->dcache.ways = 4; | ||
23 | cpu_data->dcache.way_incr = (1 << 11); | ||
24 | cpu_data->dcache.sets = 128; | ||
25 | cpu_data->dcache.entry_shift = 4; | ||
26 | cpu_data->dcache.linesz = L1_CACHE_BYTES; | ||
27 | cpu_data->dcache.flags = 0; | ||
28 | |||
29 | /* | ||
30 | * The icache is the same as the dcache as far as this setup is | ||
31 | * concerned. The only real difference in hardware is that the icache | ||
32 | * lacks the U bit that the dcache has, none of this has any bearing | ||
33 | * on the cache info. | ||
34 | */ | ||
35 | cpu_data->icache = cpu_data->dcache; | ||
36 | |||
37 | return 0; | ||
38 | } | ||
39 | |||
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c new file mode 100644 index 000000000000..4b60fcc7d667 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * SH7206 Setup | ||
3 | * | ||
4 | * Copyright (C) 2006 Yoshinori Sato | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/serial.h> | ||
13 | #include <asm/sci.h> | ||
14 | |||
15 | static struct plat_sci_port sci_platform_data[] = { | ||
16 | { | ||
17 | .mapbase = 0xfffe8000, | ||
18 | .flags = UPF_BOOT_AUTOCONF, | ||
19 | .type = PORT_SCIF, | ||
20 | .irqs = { 241, 242, 243, 240}, | ||
21 | }, { | ||
22 | .mapbase = 0xfffe8800, | ||
23 | .flags = UPF_BOOT_AUTOCONF, | ||
24 | .type = PORT_SCIF, | ||
25 | .irqs = { 247, 244, 245, 246}, | ||
26 | }, { | ||
27 | .mapbase = 0xfffe9000, | ||
28 | .flags = UPF_BOOT_AUTOCONF, | ||
29 | .type = PORT_SCIF, | ||
30 | .irqs = { 249, 250, 251, 248}, | ||
31 | }, { | ||
32 | .mapbase = 0xfffe9800, | ||
33 | .flags = UPF_BOOT_AUTOCONF, | ||
34 | .type = PORT_SCIF, | ||
35 | .irqs = { 253, 254, 255, 252}, | ||
36 | }, { | ||
37 | .flags = 0, | ||
38 | } | ||
39 | }; | ||
40 | |||
41 | static struct platform_device sci_device = { | ||
42 | .name = "sh-sci", | ||
43 | .id = -1, | ||
44 | .dev = { | ||
45 | .platform_data = sci_platform_data, | ||
46 | }, | ||
47 | }; | ||
48 | |||
49 | static struct platform_device *sh7206_devices[] __initdata = { | ||
50 | &sci_device, | ||
51 | }; | ||
52 | |||
53 | static int __init sh7206_devices_setup(void) | ||
54 | { | ||
55 | return platform_add_devices(sh7206_devices, | ||
56 | ARRAY_SIZE(sh7206_devices)); | ||
57 | } | ||
58 | __initcall(sh7206_devices_setup); | ||
59 | |||
60 | #define INTC_IPR08 0xfffe0c04UL | ||
61 | #define INTC_IPR09 0xfffe0c06UL | ||
62 | #define INTC_IPR14 0xfffe0c10UL | ||
63 | |||
64 | #define CMI0_IRQ 140 | ||
65 | |||
66 | #define MTU1_TGI1A 164 | ||
67 | |||
68 | #define SCIF0_BRI_IRQ 240 | ||
69 | #define SCIF0_ERI_IRQ 241 | ||
70 | #define SCIF0_RXI_IRQ 242 | ||
71 | #define SCIF0_TXI_IRQ 243 | ||
72 | |||
73 | #define SCIF1_BRI_IRQ 244 | ||
74 | #define SCIF1_ERI_IRQ 245 | ||
75 | #define SCIF1_RXI_IRQ 246 | ||
76 | #define SCIF1_TXI_IRQ 247 | ||
77 | |||
78 | #define SCIF2_BRI_IRQ 248 | ||
79 | #define SCIF2_ERI_IRQ 249 | ||
80 | #define SCIF2_RXI_IRQ 250 | ||
81 | #define SCIF2_TXI_IRQ 251 | ||
82 | |||
83 | #define SCIF3_BRI_IRQ 252 | ||
84 | #define SCIF3_ERI_IRQ 253 | ||
85 | #define SCIF3_RXI_IRQ 254 | ||
86 | #define SCIF3_TXI_IRQ 255 | ||
87 | |||
88 | static struct ipr_data sh7206_ipr_map[] = { | ||
89 | { CMI0_IRQ, INTC_IPR08, 3, 2 }, | ||
90 | { MTU2_TGI1A, INTC_IPR09, 1, 2 }, | ||
91 | { SCIF0_ERI_IRQ, INTC_IPR14, 3, 3 }, | ||
92 | { SCIF0_RXI_IRQ, INTC_IPR14, 3, 3 }, | ||
93 | { SCIF0_BRI_IRQ, INTC_IPR14, 3, 3 }, | ||
94 | { SCIF0_TXI_IRQ, INTC_IPR14, 3, 3 }, | ||
95 | { SCIF1_ERI_IRQ, INTC_IPR14, 2, 3 }, | ||
96 | { SCIF1_RXI_IRQ, INTC_IPR14, 2, 3 }, | ||
97 | { SCIF1_BRI_IRQ, INTC_IPR14, 2, 3 }, | ||
98 | { SCIF1_TXI_IRQ, INTC_IPR14, 2, 3 }, | ||
99 | { SCIF2_ERI_IRQ, INTC_IPR14, 1, 3 }, | ||
100 | { SCIF2_RXI_IRQ, INTC_IPR14, 1, 3 }, | ||
101 | { SCIF2_BRI_IRQ, INTC_IPR14, 1, 3 }, | ||
102 | { SCIF2_TXI_IRQ, INTC_IPR14, 1, 3 }, | ||
103 | { SCIF3_ERI_IRQ, INTC_IPR14, 0, 3 }, | ||
104 | { SCIF3_RXI_IRQ, INTC_IPR14, 0, 3 }, | ||
105 | { SCIF3_BRI_IRQ, INTC_IPR14, 0, 3 }, | ||
106 | { SCIF3_TXI_IRQ, INTC_IPR14, 0, 3 }, | ||
107 | }; | ||
108 | |||
109 | void __init init_IRQ_ipr(void) | ||
110 | { | ||
111 | make_ipr_irq(sh7206_ipr_map, ARRAY_SIZE(sh7206_ipr_map)); | ||
112 | } | ||
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile index 58d3815695ff..83905e4e4387 100644 --- a/arch/sh/kernel/cpu/sh3/Makefile +++ b/arch/sh/kernel/cpu/sh3/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for the Linux/SuperH SH-3 backends. | 2 | # Makefile for the Linux/SuperH SH-3 backends. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := ex.o probe.o | 5 | obj-y := ex.o probe.o entry.o |
6 | 6 | ||
7 | # CPU subtype setup | 7 | # CPU subtype setup |
8 | obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o | 8 | obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o |
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7709.c b/arch/sh/kernel/cpu/sh3/clock-sh7709.c index 10461a745e5f..b791a29fdb62 100644 --- a/arch/sh/kernel/cpu/sh3/clock-sh7709.c +++ b/arch/sh/kernel/cpu/sh3/clock-sh7709.c | |||
@@ -24,7 +24,7 @@ static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; | |||
24 | 24 | ||
25 | static void set_bus_parent(struct clk *clk) | 25 | static void set_bus_parent(struct clk *clk) |
26 | { | 26 | { |
27 | struct clk *bus_clk = clk_get("bus_clk"); | 27 | struct clk *bus_clk = clk_get(NULL, "bus_clk"); |
28 | clk->parent = bus_clk; | 28 | clk->parent = bus_clk; |
29 | clk_put(bus_clk); | 29 | clk_put(bus_clk); |
30 | } | 30 | } |
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 39aaefb2d83f..8c0dc2700c69 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/sh/entry.S | 2 | * arch/sh/kernel/entry.S |
3 | * | 3 | * |
4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | 4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka |
5 | * Copyright (C) 2003 - 2006 Paul Mundt | 5 | * Copyright (C) 2003 - 2006 Paul Mundt |
@@ -7,15 +7,16 @@ | |||
7 | * This file is subject to the terms and conditions of the GNU General Public | 7 | * This file is subject to the terms and conditions of the GNU General Public |
8 | * License. See the file "COPYING" in the main directory of this archive | 8 | * License. See the file "COPYING" in the main directory of this archive |
9 | * for more details. | 9 | * for more details. |
10 | * | ||
11 | */ | 10 | */ |
12 | #include <linux/sys.h> | 11 | #include <linux/sys.h> |
13 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
14 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
15 | #include <asm/asm-offsets.h> | 14 | #include <asm/asm-offsets.h> |
16 | #include <asm/thread_info.h> | 15 | #include <asm/thread_info.h> |
17 | #include <asm/cpu/mmu_context.h> | ||
18 | #include <asm/unistd.h> | 16 | #include <asm/unistd.h> |
17 | #include <asm/cpu/mmu_context.h> | ||
18 | #include <asm/pgtable.h> | ||
19 | #include <asm/page.h> | ||
19 | 20 | ||
20 | ! NOTE: | 21 | ! NOTE: |
21 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address | 22 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address |
@@ -81,6 +82,8 @@ OFF_TRA = (16*4+6*4) | |||
81 | #define k_g_imask r6_bank /* r6_bank1 */ | 82 | #define k_g_imask r6_bank /* r6_bank1 */ |
82 | #define current r7 /* r7_bank1 */ | 83 | #define current r7 /* r7_bank1 */ |
83 | 84 | ||
85 | #include <asm/entry-macros.S> | ||
86 | |||
84 | /* | 87 | /* |
85 | * Kernel mode register usage: | 88 | * Kernel mode register usage: |
86 | * k0 scratch | 89 | * k0 scratch |
@@ -107,26 +110,6 @@ OFF_TRA = (16*4+6*4) | |||
107 | ! this first version depends *much* on C implementation. | 110 | ! this first version depends *much* on C implementation. |
108 | ! | 111 | ! |
109 | 112 | ||
110 | #define CLI() \ | ||
111 | stc sr, r0; \ | ||
112 | or #0xf0, r0; \ | ||
113 | ldc r0, sr | ||
114 | |||
115 | #define STI() \ | ||
116 | mov.l __INV_IMASK, r11; \ | ||
117 | stc sr, r10; \ | ||
118 | and r11, r10; \ | ||
119 | stc k_g_imask, r11; \ | ||
120 | or r11, r10; \ | ||
121 | ldc r10, sr | ||
122 | |||
123 | #if defined(CONFIG_PREEMPT) | ||
124 | # define preempt_stop() CLI() | ||
125 | #else | ||
126 | # define preempt_stop() | ||
127 | # define resume_kernel restore_all | ||
128 | #endif | ||
129 | |||
130 | #if defined(CONFIG_MMU) | 113 | #if defined(CONFIG_MMU) |
131 | .align 2 | 114 | .align 2 |
132 | ENTRY(tlb_miss_load) | 115 | ENTRY(tlb_miss_load) |
@@ -155,29 +138,14 @@ ENTRY(tlb_protection_violation_store) | |||
155 | 138 | ||
156 | call_dpf: | 139 | call_dpf: |
157 | mov.l 1f, r0 | 140 | mov.l 1f, r0 |
158 | mov r5, r8 | 141 | mov.l @r0, r6 ! address |
159 | mov.l @r0, r6 | ||
160 | mov r6, r9 | ||
161 | mov.l 2f, r0 | ||
162 | sts pr, r10 | ||
163 | jsr @r0 | ||
164 | mov r15, r4 | ||
165 | ! | ||
166 | tst r0, r0 | ||
167 | bf/s 0f | ||
168 | lds r10, pr | ||
169 | rts | ||
170 | nop | ||
171 | 0: STI() | ||
172 | mov.l 3f, r0 | 142 | mov.l 3f, r0 |
173 | mov r9, r6 | 143 | |
174 | mov r8, r5 | ||
175 | jmp @r0 | 144 | jmp @r0 |
176 | mov r15, r4 | 145 | mov r15, r4 ! regs |
177 | 146 | ||
178 | .align 2 | 147 | .align 2 |
179 | 1: .long MMU_TEA | 148 | 1: .long MMU_TEA |
180 | 2: .long __do_page_fault | ||
181 | 3: .long do_page_fault | 149 | 3: .long do_page_fault |
182 | 150 | ||
183 | .align 2 | 151 | .align 2 |
@@ -203,32 +171,6 @@ call_dae: | |||
203 | 2: .long do_address_error | 171 | 2: .long do_address_error |
204 | #endif /* CONFIG_MMU */ | 172 | #endif /* CONFIG_MMU */ |
205 | 173 | ||
206 | #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) | ||
207 | ! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present. | ||
208 | ! If both are configured, handle the debug traps (breakpoints) in SW, | ||
209 | ! but still allow BIOS traps to FW. | ||
210 | |||
211 | .align 2 | ||
212 | debug_kernel: | ||
213 | #if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB) | ||
214 | /* Force BIOS call to FW (debug_trap put TRA in r8) */ | ||
215 | mov r8,r0 | ||
216 | shlr2 r0 | ||
217 | cmp/eq #0x3f,r0 | ||
218 | bt debug_kernel_fw | ||
219 | #endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */ | ||
220 | |||
221 | debug_enter: | ||
222 | #if defined(CONFIG_SH_KGDB) | ||
223 | /* Jump to kgdb, pass stacked regs as arg */ | ||
224 | debug_kernel_sw: | ||
225 | mov.l 3f, r0 | ||
226 | jmp @r0 | ||
227 | mov r15, r4 | ||
228 | .align 2 | ||
229 | 3: .long kgdb_handle_exception | ||
230 | #endif /* CONFIG_SH_KGDB */ | ||
231 | |||
232 | #if defined(CONFIG_SH_STANDARD_BIOS) | 174 | #if defined(CONFIG_SH_STANDARD_BIOS) |
233 | /* Unwind the stack and jmp to the debug entry */ | 175 | /* Unwind the stack and jmp to the debug entry */ |
234 | debug_kernel_fw: | 176 | debug_kernel_fw: |
@@ -269,276 +211,6 @@ debug_kernel_fw: | |||
269 | 2: .long gdb_vbr_vector | 211 | 2: .long gdb_vbr_vector |
270 | #endif /* CONFIG_SH_STANDARD_BIOS */ | 212 | #endif /* CONFIG_SH_STANDARD_BIOS */ |
271 | 213 | ||
272 | #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ | ||
273 | |||
274 | |||
275 | .align 2 | ||
276 | debug_trap: | ||
277 | #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) | ||
278 | mov #OFF_SR, r0 | ||
279 | mov.l @(r0,r15), r0 ! get status register | ||
280 | shll r0 | ||
281 | shll r0 ! kernel space? | ||
282 | bt/s debug_kernel | ||
283 | #endif | ||
284 | mov.l @r15, r0 ! Restore R0 value | ||
285 | mov.l 1f, r8 | ||
286 | jmp @r8 | ||
287 | nop | ||
288 | |||
289 | .align 2 | ||
290 | ENTRY(exception_error) | ||
291 | ! | ||
292 | STI() | ||
293 | mov.l 2f, r0 | ||
294 | jmp @r0 | ||
295 | nop | ||
296 | |||
297 | ! | ||
298 | .align 2 | ||
299 | 1: .long break_point_trap_software | ||
300 | 2: .long do_exception_error | ||
301 | |||
302 | .align 2 | ||
303 | ret_from_exception: | ||
304 | preempt_stop() | ||
305 | ENTRY(ret_from_irq) | ||
306 | ! | ||
307 | mov #OFF_SR, r0 | ||
308 | mov.l @(r0,r15), r0 ! get status register | ||
309 | shll r0 | ||
310 | shll r0 ! kernel space? | ||
311 | bt/s resume_kernel ! Yes, it's from kernel, go back soon | ||
312 | GET_THREAD_INFO(r8) | ||
313 | |||
314 | #ifdef CONFIG_PREEMPT | ||
315 | bra resume_userspace | ||
316 | nop | ||
317 | ENTRY(resume_kernel) | ||
318 | mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count | ||
319 | tst r0, r0 | ||
320 | bf noresched | ||
321 | need_resched: | ||
322 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
323 | tst #_TIF_NEED_RESCHED, r0 ! need_resched set? | ||
324 | bt noresched | ||
325 | |||
326 | mov #OFF_SR, r0 | ||
327 | mov.l @(r0,r15), r0 ! get status register | ||
328 | and #0xf0, r0 ! interrupts off (exception path)? | ||
329 | cmp/eq #0xf0, r0 | ||
330 | bt noresched | ||
331 | |||
332 | mov.l 1f, r0 | ||
333 | mov.l r0, @(TI_PRE_COUNT,r8) | ||
334 | |||
335 | STI() | ||
336 | mov.l 2f, r0 | ||
337 | jsr @r0 | ||
338 | nop | ||
339 | mov #0, r0 | ||
340 | mov.l r0, @(TI_PRE_COUNT,r8) | ||
341 | CLI() | ||
342 | |||
343 | bra need_resched | ||
344 | nop | ||
345 | noresched: | ||
346 | bra restore_all | ||
347 | nop | ||
348 | |||
349 | .align 2 | ||
350 | 1: .long PREEMPT_ACTIVE | ||
351 | 2: .long schedule | ||
352 | #endif | ||
353 | |||
354 | ENTRY(resume_userspace) | ||
355 | ! r8: current_thread_info | ||
356 | CLI() | ||
357 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
358 | tst #_TIF_WORK_MASK, r0 | ||
359 | bt/s restore_all | ||
360 | tst #_TIF_NEED_RESCHED, r0 | ||
361 | |||
362 | .align 2 | ||
363 | work_pending: | ||
364 | ! r0: current_thread_info->flags | ||
365 | ! r8: current_thread_info | ||
366 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" | ||
367 | bf/s work_resched | ||
368 | tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0 | ||
369 | work_notifysig: | ||
370 | bt/s restore_all | ||
371 | mov r15, r4 | ||
372 | mov r12, r5 ! set arg1(save_r0) | ||
373 | mov r0, r6 | ||
374 | mov.l 2f, r1 | ||
375 | mova restore_all, r0 | ||
376 | jmp @r1 | ||
377 | lds r0, pr | ||
378 | work_resched: | ||
379 | #ifndef CONFIG_PREEMPT | ||
380 | ! gUSA handling | ||
381 | mov.l @(OFF_SP,r15), r0 ! get user space stack pointer | ||
382 | mov r0, r1 | ||
383 | shll r0 | ||
384 | bf/s 1f | ||
385 | shll r0 | ||
386 | bf/s 1f | ||
387 | mov #OFF_PC, r0 | ||
388 | ! SP >= 0xc0000000 : gUSA mark | ||
389 | mov.l @(r0,r15), r2 ! get user space PC (program counter) | ||
390 | mov.l @(OFF_R0,r15), r3 ! end point | ||
391 | cmp/hs r3, r2 ! r2 >= r3? | ||
392 | bt 1f | ||
393 | add r3, r1 ! rewind point #2 | ||
394 | mov.l r1, @(r0,r15) ! reset PC to rewind point #2 | ||
395 | ! | ||
396 | 1: | ||
397 | #endif | ||
398 | mov.l 1f, r1 | ||
399 | jsr @r1 ! schedule | ||
400 | nop | ||
401 | CLI() | ||
402 | ! | ||
403 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
404 | tst #_TIF_WORK_MASK, r0 | ||
405 | bt restore_all | ||
406 | bra work_pending | ||
407 | tst #_TIF_NEED_RESCHED, r0 | ||
408 | |||
409 | .align 2 | ||
410 | 1: .long schedule | ||
411 | 2: .long do_notify_resume | ||
412 | |||
413 | .align 2 | ||
414 | syscall_exit_work: | ||
415 | ! r0: current_thread_info->flags | ||
416 | ! r8: current_thread_info | ||
417 | tst #_TIF_SYSCALL_TRACE, r0 | ||
418 | bt/s work_pending | ||
419 | tst #_TIF_NEED_RESCHED, r0 | ||
420 | STI() | ||
421 | ! XXX setup arguments... | ||
422 | mov.l 4f, r0 ! do_syscall_trace | ||
423 | jsr @r0 | ||
424 | nop | ||
425 | bra resume_userspace | ||
426 | nop | ||
427 | |||
428 | .align 2 | ||
429 | syscall_trace_entry: | ||
430 | ! Yes it is traced. | ||
431 | ! XXX setup arguments... | ||
432 | mov.l 4f, r11 ! Call do_syscall_trace which notifies | ||
433 | jsr @r11 ! superior (will chomp R[0-7]) | ||
434 | nop | ||
435 | ! Reload R0-R4 from kernel stack, where the | ||
436 | ! parent may have modified them using | ||
437 | ! ptrace(POKEUSR). (Note that R0-R2 are | ||
438 | ! used by the system call handler directly | ||
439 | ! from the kernel stack anyway, so don't need | ||
440 | ! to be reloaded here.) This allows the parent | ||
441 | ! to rewrite system calls and args on the fly. | ||
442 | mov.l @(OFF_R4,r15), r4 ! arg0 | ||
443 | mov.l @(OFF_R5,r15), r5 | ||
444 | mov.l @(OFF_R6,r15), r6 | ||
445 | mov.l @(OFF_R7,r15), r7 ! arg3 | ||
446 | mov.l @(OFF_R3,r15), r3 ! syscall_nr | ||
447 | ! Arrange for do_syscall_trace to be called | ||
448 | ! again as the system call returns. | ||
449 | mov.l 2f, r10 ! Number of syscalls | ||
450 | cmp/hs r10, r3 | ||
451 | bf syscall_call | ||
452 | mov #-ENOSYS, r0 | ||
453 | bra syscall_exit | ||
454 | mov.l r0, @(OFF_R0,r15) ! Return value | ||
455 | |||
456 | /* | ||
457 | * Syscall interface: | ||
458 | * | ||
459 | * Syscall #: R3 | ||
460 | * Arguments #0 to #3: R4--R7 | ||
461 | * Arguments #4 to #6: R0, R1, R2 | ||
462 | * TRA: (number of arguments + 0x10) x 4 | ||
463 | * | ||
464 | * This code also handles delegating other traps to the BIOS/gdb stub | ||
465 | * according to: | ||
466 | * | ||
467 | * Trap number | ||
468 | * (TRA>>2) Purpose | ||
469 | * -------- ------- | ||
470 | * 0x0-0xf old syscall ABI | ||
471 | * 0x10-0x1f new syscall ABI | ||
472 | * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. | ||
473 | * | ||
474 | * Note: When we're first called, the TRA value must be shifted | ||
475 | * right 2 bits in order to get the value that was used as the "trapa" | ||
476 | * argument. | ||
477 | */ | ||
478 | |||
479 | .align 2 | ||
480 | .globl ret_from_fork | ||
481 | ret_from_fork: | ||
482 | mov.l 1f, r8 | ||
483 | jsr @r8 | ||
484 | mov r0, r4 | ||
485 | bra syscall_exit | ||
486 | nop | ||
487 | .align 2 | ||
488 | 1: .long schedule_tail | ||
489 | ! | ||
490 | ENTRY(system_call) | ||
491 | mov.l 1f, r9 | ||
492 | mov.l @r9, r8 ! Read from TRA (Trap Address) Register | ||
493 | ! | ||
494 | ! Is the trap argument >= 0x20? (TRA will be >= 0x80) | ||
495 | mov #0x7f, r9 | ||
496 | cmp/hi r9, r8 | ||
497 | bt/s 0f | ||
498 | mov #OFF_TRA, r9 | ||
499 | add r15, r9 | ||
500 | ! | ||
501 | mov.l r8, @r9 ! set TRA value to tra | ||
502 | STI() | ||
503 | ! Call the system call handler through the table. | ||
504 | ! First check for bad syscall number | ||
505 | mov r3, r9 | ||
506 | mov.l 2f, r8 ! Number of syscalls | ||
507 | cmp/hs r8, r9 | ||
508 | bf/s good_system_call | ||
509 | GET_THREAD_INFO(r8) | ||
510 | syscall_badsys: ! Bad syscall number | ||
511 | mov #-ENOSYS, r0 | ||
512 | bra resume_userspace | ||
513 | mov.l r0, @(OFF_R0,r15) ! Return value | ||
514 | ! | ||
515 | 0: | ||
516 | bra debug_trap | ||
517 | nop | ||
518 | ! | ||
519 | good_system_call: ! Good syscall number | ||
520 | mov.l @(TI_FLAGS,r8), r8 | ||
521 | mov #_TIF_SYSCALL_TRACE, r10 | ||
522 | tst r10, r8 | ||
523 | bf syscall_trace_entry | ||
524 | ! | ||
525 | syscall_call: | ||
526 | shll2 r9 ! x4 | ||
527 | mov.l 3f, r8 ! Load the address of sys_call_table | ||
528 | add r8, r9 | ||
529 | mov.l @r9, r8 | ||
530 | jsr @r8 ! jump to specific syscall handler | ||
531 | nop | ||
532 | mov.l @(OFF_R0,r15), r12 ! save r0 | ||
533 | mov.l r0, @(OFF_R0,r15) ! save the return value | ||
534 | ! | ||
535 | syscall_exit: | ||
536 | CLI() | ||
537 | ! | ||
538 | GET_THREAD_INFO(r8) | ||
539 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
540 | tst #_TIF_ALLWORK_MASK, r0 | ||
541 | bf syscall_exit_work | ||
542 | restore_all: | 214 | restore_all: |
543 | mov.l @r15+, r0 | 215 | mov.l @r15+, r0 |
544 | mov.l @r15+, r1 | 216 | mov.l @r15+, r1 |
@@ -606,7 +278,9 @@ skip_restore: | |||
606 | ! | 278 | ! |
607 | ! Calculate new SR value | 279 | ! Calculate new SR value |
608 | mov k3, k2 ! original SR value | 280 | mov k3, k2 ! original SR value |
609 | mov.l 9f, k1 | 281 | mov #0xf0, k1 |
282 | extu.b k1, k1 | ||
283 | not k1, k1 | ||
610 | and k1, k2 ! Mask orignal SR value | 284 | and k1, k2 ! Mask orignal SR value |
611 | ! | 285 | ! |
612 | mov k3, k0 ! Calculate IMASK-bits | 286 | mov k3, k0 ! Calculate IMASK-bits |
@@ -632,16 +306,12 @@ skip_restore: | |||
632 | nop | 306 | nop |
633 | 307 | ||
634 | .align 2 | 308 | .align 2 |
635 | 1: .long TRA | ||
636 | 2: .long NR_syscalls | ||
637 | 3: .long sys_call_table | ||
638 | 4: .long do_syscall_trace | ||
639 | 5: .long 0x00001000 ! DSP | 309 | 5: .long 0x00001000 ! DSP |
640 | 7: .long 0x30000000 | 310 | 7: .long 0x30000000 |
641 | 9: | ||
642 | __INV_IMASK: | ||
643 | .long 0xffffff0f ! ~(IMASK) | ||
644 | 311 | ||
312 | ! common exception handler | ||
313 | #include "../../entry-common.S" | ||
314 | |||
645 | ! Exception Vector Base | 315 | ! Exception Vector Base |
646 | ! | 316 | ! |
647 | ! Should be aligned page boundary. | 317 | ! Should be aligned page boundary. |
@@ -661,9 +331,176 @@ general_exception: | |||
661 | 2: .long ret_from_exception | 331 | 2: .long ret_from_exception |
662 | ! | 332 | ! |
663 | ! | 333 | ! |
334 | |||
335 | /* This code makes some assumptions to improve performance. | ||
336 | * Make sure they are stil true. */ | ||
337 | #if PTRS_PER_PGD != PTRS_PER_PTE | ||
338 | #error PGD and PTE sizes don't match | ||
339 | #endif | ||
340 | |||
341 | /* gas doesn't flag impossible values for mov #immediate as an error */ | ||
342 | #if (_PAGE_PRESENT >> 2) > 0x7f | ||
343 | #error cannot load PAGE_PRESENT as an immediate | ||
344 | #endif | ||
345 | #if _PAGE_DIRTY > 0x7f | ||
346 | #error cannot load PAGE_DIRTY as an immediate | ||
347 | #endif | ||
348 | #if (_PAGE_PRESENT << 2) != _PAGE_ACCESSED | ||
349 | #error cannot derive PAGE_ACCESSED from PAGE_PRESENT | ||
350 | #endif | ||
351 | |||
352 | #if defined(CONFIG_CPU_SH4) | ||
353 | #define ldmmupteh(r) mov.l 8f, r | ||
354 | #else | ||
355 | #define ldmmupteh(r) mov #MMU_PTEH, r | ||
356 | #endif | ||
357 | |||
664 | .balign 1024,0,1024 | 358 | .balign 1024,0,1024 |
665 | tlb_miss: | 359 | tlb_miss: |
666 | mov.l 1f, k2 | 360 | #ifdef COUNT_EXCEPTIONS |
361 | ! Increment the counts | ||
362 | mov.l 9f, k1 | ||
363 | mov.l @k1, k2 | ||
364 | add #1, k2 | ||
365 | mov.l k2, @k1 | ||
366 | #endif | ||
367 | |||
368 | ! k0 scratch | ||
369 | ! k1 pgd and pte pointers | ||
370 | ! k2 faulting address | ||
371 | ! k3 pgd and pte index masks | ||
372 | ! k4 shift | ||
373 | |||
374 | ! Load up the pgd entry (k1) | ||
375 | |||
376 | ldmmupteh(k0) ! 9 LS (latency=2) MMU_PTEH | ||
377 | |||
378 | mov.w 4f, k3 ! 8 LS (latency=2) (PTRS_PER_PGD-1) << 2 | ||
379 | mov #-(PGDIR_SHIFT-2), k4 ! 6 EX | ||
380 | |||
381 | mov.l @(MMU_TEA-MMU_PTEH,k0), k2 ! 18 LS (latency=2) | ||
382 | |||
383 | mov.l @(MMU_TTB-MMU_PTEH,k0), k1 ! 18 LS (latency=2) | ||
384 | |||
385 | mov k2, k0 ! 5 MT (latency=0) | ||
386 | shld k4, k0 ! 99 EX | ||
387 | |||
388 | and k3, k0 ! 78 EX | ||
389 | |||
390 | mov.l @(k0, k1), k1 ! 21 LS (latency=2) | ||
391 | mov #-(PAGE_SHIFT-2), k4 ! 6 EX | ||
392 | |||
393 | ! Load up the pte entry (k2) | ||
394 | |||
395 | mov k2, k0 ! 5 MT (latency=0) | ||
396 | shld k4, k0 ! 99 EX | ||
397 | |||
398 | tst k1, k1 ! 86 MT | ||
399 | |||
400 | bt 20f ! 110 BR | ||
401 | |||
402 | and k3, k0 ! 78 EX | ||
403 | mov.w 5f, k4 ! 8 LS (latency=2) _PAGE_PRESENT | ||
404 | |||
405 | mov.l @(k0, k1), k2 ! 21 LS (latency=2) | ||
406 | add k0, k1 ! 49 EX | ||
407 | |||
408 | #ifdef CONFIG_CPU_HAS_PTEA | ||
409 | ! Test the entry for present and _PAGE_ACCESSED | ||
410 | |||
411 | mov #-28, k3 ! 6 EX | ||
412 | mov k2, k0 ! 5 MT (latency=0) | ||
413 | |||
414 | tst k4, k2 ! 68 MT | ||
415 | shld k3, k0 ! 99 EX | ||
416 | |||
417 | bt 20f ! 110 BR | ||
418 | |||
419 | ! Set PTEA register | ||
420 | ! MMU_PTEA = ((pteval >> 28) & 0xe) | (pteval & 0x1) | ||
421 | ! | ||
422 | ! k0=pte>>28, k1=pte*, k2=pte, k3=<unused>, k4=_PAGE_PRESENT | ||
423 | |||
424 | and #0xe, k0 ! 79 EX | ||
425 | |||
426 | mov k0, k3 ! 5 MT (latency=0) | ||
427 | mov k2, k0 ! 5 MT (latency=0) | ||
428 | |||
429 | and #1, k0 ! 79 EX | ||
430 | |||
431 | or k0, k3 ! 82 EX | ||
432 | |||
433 | ldmmupteh(k0) ! 9 LS (latency=2) | ||
434 | shll2 k4 ! 101 EX _PAGE_ACCESSED | ||
435 | |||
436 | tst k4, k2 ! 68 MT | ||
437 | |||
438 | mov.l k3, @(MMU_PTEA-MMU_PTEH,k0) ! 27 LS | ||
439 | |||
440 | mov.l 7f, k3 ! 9 LS (latency=2) _PAGE_FLAGS_HARDWARE_MASK | ||
441 | |||
442 | ! k0=MMU_PTEH, k1=pte*, k2=pte, k3=_PAGE_FLAGS_HARDWARE, k4=_PAGE_ACCESSED | ||
443 | #else | ||
444 | |||
445 | ! Test the entry for present and _PAGE_ACCESSED | ||
446 | |||
447 | mov.l 7f, k3 ! 9 LS (latency=2) _PAGE_FLAGS_HARDWARE_MASK | ||
448 | tst k4, k2 ! 68 MT | ||
449 | |||
450 | shll2 k4 ! 101 EX _PAGE_ACCESSED | ||
451 | ldmmupteh(k0) ! 9 LS (latency=2) | ||
452 | |||
453 | bt 20f ! 110 BR | ||
454 | tst k4, k2 ! 68 MT | ||
455 | |||
456 | ! k0=MMU_PTEH, k1=pte*, k2=pte, k3=_PAGE_FLAGS_HARDWARE, k4=_PAGE_ACCESSED | ||
457 | |||
458 | #endif | ||
459 | |||
460 | ! Set up the entry | ||
461 | |||
462 | and k2, k3 ! 78 EX | ||
463 | bt/s 10f ! 108 BR | ||
464 | |||
465 | mov.l k3, @(MMU_PTEL-MMU_PTEH,k0) ! 27 LS | ||
466 | |||
467 | ldtlb ! 128 CO | ||
468 | |||
469 | ! At least one instruction between ldtlb and rte | ||
470 | nop ! 119 NOP | ||
471 | |||
472 | rte ! 126 CO | ||
473 | |||
474 | nop ! 119 NOP | ||
475 | |||
476 | |||
477 | 10: or k4, k2 ! 82 EX | ||
478 | |||
479 | ldtlb ! 128 CO | ||
480 | |||
481 | ! At least one instruction between ldtlb and rte | ||
482 | mov.l k2, @k1 ! 27 LS | ||
483 | |||
484 | rte ! 126 CO | ||
485 | |||
486 | ! Note we cannot execute mov here, because it is executed after | ||
487 | ! restoring SSR, so would be executed in user space. | ||
488 | nop ! 119 NOP | ||
489 | |||
490 | |||
491 | .align 5 | ||
492 | ! Once cache line if possible... | ||
493 | 1: .long swapper_pg_dir | ||
494 | 4: .short (PTRS_PER_PGD-1) << 2 | ||
495 | 5: .short _PAGE_PRESENT | ||
496 | 7: .long _PAGE_FLAGS_HARDWARE_MASK | ||
497 | 8: .long MMU_PTEH | ||
498 | #ifdef COUNT_EXCEPTIONS | ||
499 | 9: .long exception_count_miss | ||
500 | #endif | ||
501 | |||
502 | ! Either pgd or pte not present | ||
503 | 20: mov.l 1f, k2 | ||
667 | mov.l 4f, k3 | 504 | mov.l 4f, k3 |
668 | bra handle_exception | 505 | bra handle_exception |
669 | mov.l @k2, k2 | 506 | mov.l @k2, k2 |
@@ -710,8 +547,9 @@ ENTRY(handle_exception) | |||
710 | bt/s 1f ! It's a kernel to kernel transition. | 547 | bt/s 1f ! It's a kernel to kernel transition. |
711 | mov r15, k0 ! save original stack to k0 | 548 | mov r15, k0 ! save original stack to k0 |
712 | /* User space to kernel */ | 549 | /* User space to kernel */ |
713 | mov #(THREAD_SIZE >> 8), k1 | 550 | mov #(THREAD_SIZE >> 10), k1 |
714 | shll8 k1 ! k1 := THREAD_SIZE | 551 | shll8 k1 ! k1 := THREAD_SIZE |
552 | shll2 k1 | ||
715 | add current, k1 | 553 | add current, k1 |
716 | mov k1, r15 ! change to kernel stack | 554 | mov k1, r15 ! change to kernel stack |
717 | ! | 555 | ! |
@@ -761,7 +599,7 @@ skip_save: | |||
761 | ! Save the user registers on the stack. | 599 | ! Save the user registers on the stack. |
762 | mov.l k2, @-r15 ! EXPEVT | 600 | mov.l k2, @-r15 ! EXPEVT |
763 | 601 | ||
764 | mov #-1, k4 | 602 | mov #-1, k4 |
765 | mov.l k4, @-r15 ! set TRA (default: -1) | 603 | mov.l k4, @-r15 ! set TRA (default: -1) |
766 | ! | 604 | ! |
767 | sts.l macl, @-r15 | 605 | sts.l macl, @-r15 |
@@ -813,6 +651,15 @@ skip_save: | |||
813 | bf interrupt_exception | 651 | bf interrupt_exception |
814 | shlr2 r8 | 652 | shlr2 r8 |
815 | shlr r8 | 653 | shlr r8 |
654 | |||
655 | #ifdef COUNT_EXCEPTIONS | ||
656 | mov.l 5f, r9 | ||
657 | add r8, r9 | ||
658 | mov.l @r9, r10 | ||
659 | add #1, r10 | ||
660 | mov.l r10, @r9 | ||
661 | #endif | ||
662 | |||
816 | mov.l 4f, r9 | 663 | mov.l 4f, r9 |
817 | add r8, r9 | 664 | add r8, r9 |
818 | mov.l @r9, r9 | 665 | mov.l @r9, r9 |
@@ -826,6 +673,9 @@ skip_save: | |||
826 | 2: .long 0x000080f0 ! FD=1, IMASK=15 | 673 | 2: .long 0x000080f0 ! FD=1, IMASK=15 |
827 | 3: .long 0xcfffffff ! RB=0, BL=0 | 674 | 3: .long 0xcfffffff ! RB=0, BL=0 |
828 | 4: .long exception_handling_table | 675 | 4: .long exception_handling_table |
676 | #ifdef COUNT_EXCEPTIONS | ||
677 | 5: .long exception_count_table | ||
678 | #endif | ||
829 | 679 | ||
830 | interrupt_exception: | 680 | interrupt_exception: |
831 | mov.l 1f, r9 | 681 | mov.l 1f, r9 |
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S index 6be46f0686b7..ba3082d640b5 100644 --- a/arch/sh/kernel/cpu/sh3/ex.S +++ b/arch/sh/kernel/cpu/sh3/ex.S | |||
@@ -4,7 +4,7 @@ | |||
4 | * The SH-3 exception vector table. | 4 | * The SH-3 exception vector table. |
5 | 5 | ||
6 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | 6 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka |
7 | * Copyright (C) 2003 Paul Mundt | 7 | * Copyright (C) 2003 - 2006 Paul Mundt |
8 | * | 8 | * |
9 | * This file is subject to the terms and conditions of the GNU General Public | 9 | * This file is subject to the terms and conditions of the GNU General Public |
10 | * License. See the file "COPYING" in the main directory of this archive | 10 | * License. See the file "COPYING" in the main directory of this archive |
@@ -49,3 +49,10 @@ ENTRY(nmi_slot) | |||
49 | #endif | 49 | #endif |
50 | ENTRY(user_break_point_trap) | 50 | ENTRY(user_break_point_trap) |
51 | .long break_point_trap /* 1E0 */ | 51 | .long break_point_trap /* 1E0 */ |
52 | |||
53 | /* | ||
54 | * Pad the remainder of the table out, exceptions residing in far | ||
55 | * away offsets can be manually inserted in to their appropriate | ||
56 | * location via set_exception_table_{evt,vec}(). | ||
57 | */ | ||
58 | .balign 4096,0,4096 | ||
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile index 8dbf3895ece7..19ca68c71884 100644 --- a/arch/sh/kernel/cpu/sh4/Makefile +++ b/arch/sh/kernel/cpu/sh4/Makefile | |||
@@ -2,7 +2,8 @@ | |||
2 | # Makefile for the Linux/SuperH SH-4 backends. | 2 | # Makefile for the Linux/SuperH SH-4 backends. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := ex.o probe.o | 5 | obj-y := ex.o probe.o common.o |
6 | common-y += $(addprefix ../sh3/, entry.o) | ||
6 | 7 | ||
7 | obj-$(CONFIG_SH_FPU) += fpu.o | 8 | obj-$(CONFIG_SH_FPU) += fpu.o |
8 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o | 9 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o |
@@ -11,17 +12,12 @@ obj-$(CONFIG_SH_STORE_QUEUES) += sq.o | |||
11 | obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o | 12 | obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o |
12 | obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o | 13 | obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o |
13 | obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o | 14 | obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o |
14 | obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o | ||
15 | obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o | ||
16 | obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o | ||
17 | obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o | ||
18 | obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o | 15 | obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o |
19 | 16 | ||
20 | # Primary on-chip clocks (common) | 17 | # Primary on-chip clocks (common) |
18 | ifndef CONFIG_CPU_SH4A | ||
21 | clock-$(CONFIG_CPU_SH4) := clock-sh4.o | 19 | clock-$(CONFIG_CPU_SH4) := clock-sh4.o |
22 | clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o | 20 | endif |
23 | clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o | ||
24 | clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o | ||
25 | 21 | ||
26 | # Additional clocks by subtype | 22 | # Additional clocks by subtype |
27 | clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o | 23 | clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o |
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c index bfdf5fe8d948..fa2019aabd74 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c | |||
@@ -97,7 +97,7 @@ static void shoc_clk_recalc(struct clk *clk) | |||
97 | 97 | ||
98 | static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate) | 98 | static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate) |
99 | { | 99 | { |
100 | struct clk *bclk = clk_get("bus_clk"); | 100 | struct clk *bclk = clk_get(NULL, "bus_clk"); |
101 | unsigned long bclk_rate = clk_get_rate(bclk); | 101 | unsigned long bclk_rate = clk_get_rate(bclk); |
102 | 102 | ||
103 | clk_put(bclk); | 103 | clk_put(bclk); |
@@ -151,7 +151,7 @@ static struct clk *sh4202_onchip_clocks[] = { | |||
151 | 151 | ||
152 | static int __init sh4202_clk_init(void) | 152 | static int __init sh4202_clk_init(void) |
153 | { | 153 | { |
154 | struct clk *clk = clk_get("master_clk"); | 154 | struct clk *clk = clk_get(NULL, "master_clk"); |
155 | int i; | 155 | int i; |
156 | 156 | ||
157 | for (i = 0; i < ARRAY_SIZE(sh4202_onchip_clocks); i++) { | 157 | for (i = 0; i < ARRAY_SIZE(sh4202_onchip_clocks); i++) { |
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S index 3f4cd043e900..ac8ab57413cc 100644 --- a/arch/sh/kernel/cpu/sh4/ex.S +++ b/arch/sh/kernel/cpu/sh4/ex.S | |||
@@ -4,7 +4,7 @@ | |||
4 | * The SH-4 exception vector table. | 4 | * The SH-4 exception vector table. |
5 | 5 | ||
6 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | 6 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka |
7 | * Copyright (C) 2003 Paul Mundt | 7 | * Copyright (C) 2003 - 2006 Paul Mundt |
8 | * | 8 | * |
9 | * This file is subject to the terms and conditions of the GNU General Public | 9 | * This file is subject to the terms and conditions of the GNU General Public |
10 | * License. See the file "COPYING" in the main directory of this archive | 10 | * License. See the file "COPYING" in the main directory of this archive |
@@ -53,3 +53,10 @@ ENTRY(nmi_slot) | |||
53 | #endif | 53 | #endif |
54 | ENTRY(user_break_point_trap) | 54 | ENTRY(user_break_point_trap) |
55 | .long break_point_trap /* 1E0 */ | 55 | .long break_point_trap /* 1E0 */ |
56 | |||
57 | /* | ||
58 | * Pad the remainder of the table out, exceptions residing in far | ||
59 | * away offsets can be manually inserted in to their appropriate | ||
60 | * location via set_exception_table_{evt,vec}(). | ||
61 | */ | ||
62 | .balign 4096,0,4096 | ||
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index f486c07e10e2..7624677f6628 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c | |||
@@ -282,11 +282,8 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
282 | grab_fpu(regs); | 282 | grab_fpu(regs); |
283 | restore_fpu(tsk); | 283 | restore_fpu(tsk); |
284 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 284 | set_tsk_thread_flag(tsk, TIF_USEDFPU); |
285 | } else { | 285 | } else |
286 | tsk->thread.trap_no = 11; | ||
287 | tsk->thread.error_code = 0; | ||
288 | force_sig(SIGFPE, tsk); | 286 | force_sig(SIGFPE, tsk); |
289 | } | ||
290 | 287 | ||
291 | regs->pc = nextpc; | 288 | regs->pc = nextpc; |
292 | return 1; | 289 | return 1; |
@@ -296,29 +293,29 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
296 | } | 293 | } |
297 | 294 | ||
298 | asmlinkage void | 295 | asmlinkage void |
299 | do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, | 296 | do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, |
300 | struct pt_regs regs) | 297 | unsigned long r7, struct pt_regs __regs) |
301 | { | 298 | { |
299 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
302 | struct task_struct *tsk = current; | 300 | struct task_struct *tsk = current; |
303 | 301 | ||
304 | if (ieee_fpe_handler (®s)) | 302 | if (ieee_fpe_handler(regs)) |
305 | return; | 303 | return; |
306 | 304 | ||
307 | regs.pc += 2; | 305 | regs->pc += 2; |
308 | save_fpu(tsk, ®s); | 306 | save_fpu(tsk, regs); |
309 | tsk->thread.trap_no = 11; | ||
310 | tsk->thread.error_code = 0; | ||
311 | force_sig(SIGFPE, tsk); | 307 | force_sig(SIGFPE, tsk); |
312 | } | 308 | } |
313 | 309 | ||
314 | asmlinkage void | 310 | asmlinkage void |
315 | do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6, | 311 | do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6, |
316 | unsigned long r7, struct pt_regs regs) | 312 | unsigned long r7, struct pt_regs __regs) |
317 | { | 313 | { |
314 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
318 | struct task_struct *tsk = current; | 315 | struct task_struct *tsk = current; |
319 | 316 | ||
320 | grab_fpu(®s); | 317 | grab_fpu(regs); |
321 | if (!user_mode(®s)) { | 318 | if (!user_mode(regs)) { |
322 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); | 319 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); |
323 | return; | 320 | return; |
324 | } | 321 | } |
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index c294de1e14a3..9031a22a2ce7 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c | |||
@@ -79,16 +79,16 @@ int __init detect_cpu_and_cache_system(void) | |||
79 | case 0x205: | 79 | case 0x205: |
80 | cpu_data->type = CPU_SH7750; | 80 | cpu_data->type = CPU_SH7750; |
81 | cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | | 81 | cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | |
82 | CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA; | 82 | CPU_HAS_PERF_COUNTER; |
83 | break; | 83 | break; |
84 | case 0x206: | 84 | case 0x206: |
85 | cpu_data->type = CPU_SH7750S; | 85 | cpu_data->type = CPU_SH7750S; |
86 | cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | | 86 | cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | |
87 | CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA; | 87 | CPU_HAS_PERF_COUNTER; |
88 | break; | 88 | break; |
89 | case 0x1100: | 89 | case 0x1100: |
90 | cpu_data->type = CPU_SH7751; | 90 | cpu_data->type = CPU_SH7751; |
91 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 91 | cpu_data->flags |= CPU_HAS_FPU; |
92 | break; | 92 | break; |
93 | case 0x2000: | 93 | case 0x2000: |
94 | cpu_data->type = CPU_SH73180; | 94 | cpu_data->type = CPU_SH73180; |
@@ -119,30 +119,38 @@ int __init detect_cpu_and_cache_system(void) | |||
119 | break; | 119 | break; |
120 | case 0x3000: | 120 | case 0x3000: |
121 | case 0x3003: | 121 | case 0x3003: |
122 | case 0x3009: | ||
122 | cpu_data->type = CPU_SH7343; | 123 | cpu_data->type = CPU_SH7343; |
123 | cpu_data->icache.ways = 4; | 124 | cpu_data->icache.ways = 4; |
124 | cpu_data->dcache.ways = 4; | 125 | cpu_data->dcache.ways = 4; |
125 | cpu_data->flags |= CPU_HAS_LLSC; | 126 | cpu_data->flags |= CPU_HAS_LLSC; |
126 | break; | 127 | break; |
128 | case 0x3008: | ||
129 | if (prr == 0xa0) { | ||
130 | cpu_data->type = CPU_SH7722; | ||
131 | cpu_data->icache.ways = 4; | ||
132 | cpu_data->dcache.ways = 4; | ||
133 | cpu_data->flags |= CPU_HAS_LLSC; | ||
134 | } | ||
135 | break; | ||
127 | case 0x8000: | 136 | case 0x8000: |
128 | cpu_data->type = CPU_ST40RA; | 137 | cpu_data->type = CPU_ST40RA; |
129 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 138 | cpu_data->flags |= CPU_HAS_FPU; |
130 | break; | 139 | break; |
131 | case 0x8100: | 140 | case 0x8100: |
132 | cpu_data->type = CPU_ST40GX1; | 141 | cpu_data->type = CPU_ST40GX1; |
133 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 142 | cpu_data->flags |= CPU_HAS_FPU; |
134 | break; | 143 | break; |
135 | case 0x700: | 144 | case 0x700: |
136 | cpu_data->type = CPU_SH4_501; | 145 | cpu_data->type = CPU_SH4_501; |
137 | cpu_data->icache.ways = 2; | 146 | cpu_data->icache.ways = 2; |
138 | cpu_data->dcache.ways = 2; | 147 | cpu_data->dcache.ways = 2; |
139 | cpu_data->flags |= CPU_HAS_PTEA; | ||
140 | break; | 148 | break; |
141 | case 0x600: | 149 | case 0x600: |
142 | cpu_data->type = CPU_SH4_202; | 150 | cpu_data->type = CPU_SH4_202; |
143 | cpu_data->icache.ways = 2; | 151 | cpu_data->icache.ways = 2; |
144 | cpu_data->dcache.ways = 2; | 152 | cpu_data->dcache.ways = 2; |
145 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 153 | cpu_data->flags |= CPU_HAS_FPU; |
146 | break; | 154 | break; |
147 | case 0x500 ... 0x501: | 155 | case 0x500 ... 0x501: |
148 | switch (prr) { | 156 | switch (prr) { |
@@ -160,7 +168,7 @@ int __init detect_cpu_and_cache_system(void) | |||
160 | cpu_data->icache.ways = 2; | 168 | cpu_data->icache.ways = 2; |
161 | cpu_data->dcache.ways = 2; | 169 | cpu_data->dcache.ways = 2; |
162 | 170 | ||
163 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 171 | cpu_data->flags |= CPU_HAS_FPU; |
164 | 172 | ||
165 | break; | 173 | break; |
166 | default: | 174 | default: |
@@ -173,6 +181,10 @@ int __init detect_cpu_and_cache_system(void) | |||
173 | cpu_data->dcache.ways = 1; | 181 | cpu_data->dcache.ways = 1; |
174 | #endif | 182 | #endif |
175 | 183 | ||
184 | #ifdef CONFIG_CPU_HAS_PTEA | ||
185 | cpu_data->flags |= CPU_HAS_PTEA; | ||
186 | #endif | ||
187 | |||
176 | /* | 188 | /* |
177 | * On anything that's not a direct-mapped cache, look to the CVR | 189 | * On anything that's not a direct-mapped cache, look to the CVR |
178 | * for I/D-cache specifics. | 190 | * for I/D-cache specifics. |
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c index 50812d57c1c1..cbac27634c0b 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * SH7750/SH7751 Setup | 2 | * SH7750/SH7751 Setup |
3 | * | 3 | * |
4 | * Copyright (C) 2006 Paul Mundt | 4 | * Copyright (C) 2006 Paul Mundt |
5 | * Copyright (C) 2006 Jamie Lenehan | ||
5 | * | 6 | * |
6 | * This file is subject to the terms and conditions of the GNU General Public | 7 | * This file is subject to the terms and conditions of the GNU General Public |
7 | * License. See the file "COPYING" in the main directory of this archive | 8 | * License. See the file "COPYING" in the main directory of this archive |
@@ -10,8 +11,39 @@ | |||
10 | #include <linux/platform_device.h> | 11 | #include <linux/platform_device.h> |
11 | #include <linux/init.h> | 12 | #include <linux/init.h> |
12 | #include <linux/serial.h> | 13 | #include <linux/serial.h> |
14 | #include <linux/io.h> | ||
13 | #include <asm/sci.h> | 15 | #include <asm/sci.h> |
14 | 16 | ||
17 | static struct resource rtc_resources[] = { | ||
18 | [0] = { | ||
19 | .start = 0xffc80000, | ||
20 | .end = 0xffc80000 + 0x58 - 1, | ||
21 | .flags = IORESOURCE_IO, | ||
22 | }, | ||
23 | [1] = { | ||
24 | /* Period IRQ */ | ||
25 | .start = 21, | ||
26 | .flags = IORESOURCE_IRQ, | ||
27 | }, | ||
28 | [2] = { | ||
29 | /* Carry IRQ */ | ||
30 | .start = 22, | ||
31 | .flags = IORESOURCE_IRQ, | ||
32 | }, | ||
33 | [3] = { | ||
34 | /* Alarm IRQ */ | ||
35 | .start = 20, | ||
36 | .flags = IORESOURCE_IRQ, | ||
37 | }, | ||
38 | }; | ||
39 | |||
40 | static struct platform_device rtc_device = { | ||
41 | .name = "sh-rtc", | ||
42 | .id = -1, | ||
43 | .num_resources = ARRAY_SIZE(rtc_resources), | ||
44 | .resource = rtc_resources, | ||
45 | }; | ||
46 | |||
15 | static struct plat_sci_port sci_platform_data[] = { | 47 | static struct plat_sci_port sci_platform_data[] = { |
16 | { | 48 | { |
17 | .mapbase = 0xffe00000, | 49 | .mapbase = 0xffe00000, |
@@ -37,6 +69,7 @@ static struct platform_device sci_device = { | |||
37 | }; | 69 | }; |
38 | 70 | ||
39 | static struct platform_device *sh7750_devices[] __initdata = { | 71 | static struct platform_device *sh7750_devices[] __initdata = { |
72 | &rtc_device, | ||
40 | &sci_device, | 73 | &sci_device, |
41 | }; | 74 | }; |
42 | 75 | ||
@@ -46,3 +79,71 @@ static int __init sh7750_devices_setup(void) | |||
46 | ARRAY_SIZE(sh7750_devices)); | 79 | ARRAY_SIZE(sh7750_devices)); |
47 | } | 80 | } |
48 | __initcall(sh7750_devices_setup); | 81 | __initcall(sh7750_devices_setup); |
82 | |||
83 | static struct ipr_data sh7750_ipr_map[] = { | ||
84 | /* IRQ, IPR-idx, shift, priority */ | ||
85 | { 16, 0, 12, 2 }, /* TMU0 TUNI*/ | ||
86 | { 17, 0, 12, 2 }, /* TMU1 TUNI */ | ||
87 | { 18, 0, 4, 2 }, /* TMU2 TUNI */ | ||
88 | { 19, 0, 4, 2 }, /* TMU2 TIPCI */ | ||
89 | { 27, 1, 12, 2 }, /* WDT ITI */ | ||
90 | { 20, 0, 0, 2 }, /* RTC ATI (alarm) */ | ||
91 | { 21, 0, 0, 2 }, /* RTC PRI (period) */ | ||
92 | { 22, 0, 0, 2 }, /* RTC CUI (carry) */ | ||
93 | { 23, 1, 4, 3 }, /* SCI ERI */ | ||
94 | { 24, 1, 4, 3 }, /* SCI RXI */ | ||
95 | { 25, 1, 4, 3 }, /* SCI TXI */ | ||
96 | { 40, 2, 4, 3 }, /* SCIF ERI */ | ||
97 | { 41, 2, 4, 3 }, /* SCIF RXI */ | ||
98 | { 42, 2, 4, 3 }, /* SCIF BRI */ | ||
99 | { 43, 2, 4, 3 }, /* SCIF TXI */ | ||
100 | { 34, 2, 8, 7 }, /* DMAC DMTE0 */ | ||
101 | { 35, 2, 8, 7 }, /* DMAC DMTE1 */ | ||
102 | { 36, 2, 8, 7 }, /* DMAC DMTE2 */ | ||
103 | { 37, 2, 8, 7 }, /* DMAC DMTE3 */ | ||
104 | { 28, 2, 8, 7 }, /* DMAC DMAE */ | ||
105 | }; | ||
106 | |||
107 | static struct ipr_data sh7751_ipr_map[] = { | ||
108 | { 44, 2, 8, 7 }, /* DMAC DMTE4 */ | ||
109 | { 45, 2, 8, 7 }, /* DMAC DMTE5 */ | ||
110 | { 46, 2, 8, 7 }, /* DMAC DMTE6 */ | ||
111 | { 47, 2, 8, 7 }, /* DMAC DMTE7 */ | ||
112 | /* The following use INTC_INPRI00 for masking, which is a 32-bit | ||
113 | register, not a 16-bit register like the IPRx registers, so it | ||
114 | would need special support */ | ||
115 | /*{ 72, INTPRI00, 8, ? },*/ /* TMU3 TUNI */ | ||
116 | /*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */ | ||
117 | }; | ||
118 | |||
119 | static unsigned long ipr_offsets[] = { | ||
120 | 0xffd00004UL, /* 0: IPRA */ | ||
121 | 0xffd00008UL, /* 1: IPRB */ | ||
122 | 0xffd0000cUL, /* 2: IPRC */ | ||
123 | 0xffd00010UL, /* 3: IPRD */ | ||
124 | }; | ||
125 | |||
126 | /* given the IPR index return the address of the IPR register */ | ||
127 | unsigned int map_ipridx_to_addr(int idx) | ||
128 | { | ||
129 | if (idx >= ARRAY_SIZE(ipr_offsets)) | ||
130 | return 0; | ||
131 | return ipr_offsets[idx]; | ||
132 | } | ||
133 | |||
134 | #define INTC_ICR 0xffd00000UL | ||
135 | #define INTC_ICR_IRLM (1<<7) | ||
136 | |||
137 | /* enable individual interrupt mode for external interupts */ | ||
138 | void ipr_irq_enable_irlm(void) | ||
139 | { | ||
140 | ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); | ||
141 | } | ||
142 | |||
143 | void __init init_IRQ_ipr() | ||
144 | { | ||
145 | make_ipr_irq(sh7750_ipr_map, ARRAY_SIZE(sh7750_ipr_map)); | ||
146 | #ifdef CONFIG_CPU_SUBTYPE_SH7751 | ||
147 | make_ipr_irq(sh7751_ipr_map, ARRAY_SIZE(sh7751_ipr_map)); | ||
148 | #endif | ||
149 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c index 97f1c9af35d6..07e5377bf550 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c | |||
@@ -51,3 +51,66 @@ static int __init sh7760_devices_setup(void) | |||
51 | ARRAY_SIZE(sh7760_devices)); | 51 | ARRAY_SIZE(sh7760_devices)); |
52 | } | 52 | } |
53 | __initcall(sh7760_devices_setup); | 53 | __initcall(sh7760_devices_setup); |
54 | |||
55 | /* | ||
56 | * SH7760 INTC2-Style interrupts, vectors IRQ48-111 INTEVT 0x800-0xFE0 | ||
57 | */ | ||
58 | static struct intc2_data intc2_irq_table[] = { | ||
59 | /* INTPRIO0 | INTMSK0 */ | ||
60 | {48, 0, 28, 0, 31, 3}, /* IRQ 4 */ | ||
61 | {49, 0, 24, 0, 30, 3}, /* IRQ 3 */ | ||
62 | {50, 0, 20, 0, 29, 3}, /* IRQ 2 */ | ||
63 | {51, 0, 16, 0, 28, 3}, /* IRQ 1 */ | ||
64 | /* 52-55 (INTEVT 0x880-0x8E0) unused/reserved */ | ||
65 | /* INTPRIO4 | INTMSK0 */ | ||
66 | {56, 4, 28, 0, 25, 3}, /* HCAN2_CHAN0 */ | ||
67 | {57, 4, 24, 0, 24, 3}, /* HCAN2_CHAN1 */ | ||
68 | {58, 4, 20, 0, 23, 3}, /* I2S_CHAN0 */ | ||
69 | {59, 4, 16, 0, 22, 3}, /* I2S_CHAN1 */ | ||
70 | {60, 4, 12, 0, 21, 3}, /* AC97_CHAN0 */ | ||
71 | {61, 4, 8, 0, 20, 3}, /* AC97_CHAN1 */ | ||
72 | {62, 4, 4, 0, 19, 3}, /* I2C_CHAN0 */ | ||
73 | {63, 4, 0, 0, 18, 3}, /* I2C_CHAN1 */ | ||
74 | /* INTPRIO8 | INTMSK0 */ | ||
75 | {52, 8, 16, 0, 11, 3}, /* SCIF0_ERI_IRQ */ | ||
76 | {53, 8, 16, 0, 10, 3}, /* SCIF0_RXI_IRQ */ | ||
77 | {54, 8, 16, 0, 9, 3}, /* SCIF0_BRI_IRQ */ | ||
78 | {55, 8, 16, 0, 8, 3}, /* SCIF0_TXI_IRQ */ | ||
79 | {64, 8, 28, 0, 17, 3}, /* USBHI_IRQ */ | ||
80 | {65, 8, 24, 0, 16, 3}, /* LCDC */ | ||
81 | /* 66, 67 unused */ | ||
82 | {68, 8, 20, 0, 14, 13}, /* DMABRGI0_IRQ */ | ||
83 | {69, 8, 20, 0, 13, 13}, /* DMABRGI1_IRQ */ | ||
84 | {70, 8, 20, 0, 12, 13}, /* DMABRGI2_IRQ */ | ||
85 | /* 71 unused */ | ||
86 | {72, 8, 12, 0, 7, 3}, /* SCIF1_ERI_IRQ */ | ||
87 | {73, 8, 12, 0, 6, 3}, /* SCIF1_RXI_IRQ */ | ||
88 | {74, 8, 12, 0, 5, 3}, /* SCIF1_BRI_IRQ */ | ||
89 | {75, 8, 12, 0, 4, 3}, /* SCIF1_TXI_IRQ */ | ||
90 | {76, 8, 8, 0, 3, 3}, /* SCIF2_ERI_IRQ */ | ||
91 | {77, 8, 8, 0, 2, 3}, /* SCIF2_RXI_IRQ */ | ||
92 | {78, 8, 8, 0, 1, 3}, /* SCIF2_BRI_IRQ */ | ||
93 | {79, 8, 8, 0, 0, 3}, /* SCIF2_TXI_IRQ */ | ||
94 | /* | INTMSK4 */ | ||
95 | {80, 8, 4, 4, 23, 3}, /* SIM_ERI */ | ||
96 | {81, 8, 4, 4, 22, 3}, /* SIM_RXI */ | ||
97 | {82, 8, 4, 4, 21, 3}, /* SIM_TXI */ | ||
98 | {83, 8, 4, 4, 20, 3}, /* SIM_TEI */ | ||
99 | {84, 8, 0, 4, 19, 3}, /* HSPII */ | ||
100 | /* INTPRIOC | INTMSK4 */ | ||
101 | /* 85-87 unused/reserved */ | ||
102 | {88, 12, 20, 4, 18, 3}, /* MMCI0 */ | ||
103 | {89, 12, 20, 4, 17, 3}, /* MMCI1 */ | ||
104 | {90, 12, 20, 4, 16, 3}, /* MMCI2 */ | ||
105 | {91, 12, 20, 4, 15, 3}, /* MMCI3 */ | ||
106 | {92, 12, 12, 4, 6, 3}, /* MFI (unsure, bug? in my 7760 manual*/ | ||
107 | /* 93-107 reserved/undocumented */ | ||
108 | {108,12, 4, 4, 1, 3}, /* ADC */ | ||
109 | {109,12, 0, 4, 0, 3}, /* CMTI */ | ||
110 | /* 110-111 reserved/unused */ | ||
111 | }; | ||
112 | |||
113 | void __init init_IRQ_intc2(void) | ||
114 | { | ||
115 | make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table)); | ||
116 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 7bcc73f9b8df..d7fff752e569 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
22 | #include <asm/io.h> | 22 | #include <linux/io.h> |
23 | #include <asm/page.h> | 23 | #include <asm/page.h> |
24 | #include <asm/cacheflush.h> | 24 | #include <asm/cacheflush.h> |
25 | #include <asm/cpu/sq.h> | 25 | #include <asm/cpu/sq.h> |
@@ -38,7 +38,7 @@ struct sq_mapping { | |||
38 | 38 | ||
39 | static struct sq_mapping *sq_mapping_list; | 39 | static struct sq_mapping *sq_mapping_list; |
40 | static DEFINE_SPINLOCK(sq_mapping_lock); | 40 | static DEFINE_SPINLOCK(sq_mapping_lock); |
41 | static kmem_cache_t *sq_cache; | 41 | static struct kmem_cache *sq_cache; |
42 | static unsigned long *sq_bitmap; | 42 | static unsigned long *sq_bitmap; |
43 | 43 | ||
44 | #define store_queue_barrier() \ | 44 | #define store_queue_barrier() \ |
@@ -67,6 +67,7 @@ void sq_flush_range(unsigned long start, unsigned int len) | |||
67 | /* Wait for completion */ | 67 | /* Wait for completion */ |
68 | store_queue_barrier(); | 68 | store_queue_barrier(); |
69 | } | 69 | } |
70 | EXPORT_SYMBOL(sq_flush_range); | ||
70 | 71 | ||
71 | static inline void sq_mapping_list_add(struct sq_mapping *map) | 72 | static inline void sq_mapping_list_add(struct sq_mapping *map) |
72 | { | 73 | { |
@@ -110,8 +111,9 @@ static int __sq_remap(struct sq_mapping *map, unsigned long flags) | |||
110 | 111 | ||
111 | vma->phys_addr = map->addr; | 112 | vma->phys_addr = map->addr; |
112 | 113 | ||
113 | if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr, | 114 | if (ioremap_page_range((unsigned long)vma->addr, |
114 | map->size, flags)) { | 115 | (unsigned long)vma->addr + map->size, |
116 | vma->phys_addr, __pgprot(flags))) { | ||
115 | vunmap(vma->addr); | 117 | vunmap(vma->addr); |
116 | return -EAGAIN; | 118 | return -EAGAIN; |
117 | } | 119 | } |
@@ -166,7 +168,7 @@ unsigned long sq_remap(unsigned long phys, unsigned int size, | |||
166 | map->size = size; | 168 | map->size = size; |
167 | map->name = name; | 169 | map->name = name; |
168 | 170 | ||
169 | page = bitmap_find_free_region(sq_bitmap, 0x04000000, | 171 | page = bitmap_find_free_region(sq_bitmap, 0x04000000 >> PAGE_SHIFT, |
170 | get_order(map->size)); | 172 | get_order(map->size)); |
171 | if (unlikely(page < 0)) { | 173 | if (unlikely(page < 0)) { |
172 | ret = -ENOSPC; | 174 | ret = -ENOSPC; |
@@ -175,7 +177,7 @@ unsigned long sq_remap(unsigned long phys, unsigned int size, | |||
175 | 177 | ||
176 | map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT); | 178 | map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT); |
177 | 179 | ||
178 | ret = __sq_remap(map, flags); | 180 | ret = __sq_remap(map, pgprot_val(PAGE_KERNEL_NOCACHE) | flags); |
179 | if (unlikely(ret != 0)) | 181 | if (unlikely(ret != 0)) |
180 | goto out; | 182 | goto out; |
181 | 183 | ||
@@ -193,6 +195,7 @@ out: | |||
193 | kmem_cache_free(sq_cache, map); | 195 | kmem_cache_free(sq_cache, map); |
194 | return ret; | 196 | return ret; |
195 | } | 197 | } |
198 | EXPORT_SYMBOL(sq_remap); | ||
196 | 199 | ||
197 | /** | 200 | /** |
198 | * sq_unmap - Unmap a Store Queue allocation | 201 | * sq_unmap - Unmap a Store Queue allocation |
@@ -234,6 +237,7 @@ void sq_unmap(unsigned long vaddr) | |||
234 | 237 | ||
235 | kmem_cache_free(sq_cache, map); | 238 | kmem_cache_free(sq_cache, map); |
236 | } | 239 | } |
240 | EXPORT_SYMBOL(sq_unmap); | ||
237 | 241 | ||
238 | /* | 242 | /* |
239 | * Needlessly complex sysfs interface. Unfortunately it doesn't seem like | 243 | * Needlessly complex sysfs interface. Unfortunately it doesn't seem like |
@@ -402,7 +406,3 @@ module_exit(sq_api_exit); | |||
402 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); | 406 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); |
403 | MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); | 407 | MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); |
404 | MODULE_LICENSE("GPL"); | 408 | MODULE_LICENSE("GPL"); |
405 | |||
406 | EXPORT_SYMBOL(sq_remap); | ||
407 | EXPORT_SYMBOL(sq_unmap); | ||
408 | EXPORT_SYMBOL(sq_flush_range); | ||
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile new file mode 100644 index 000000000000..a8f493f2f21f --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/Makefile | |||
@@ -0,0 +1,19 @@ | |||
1 | # | ||
2 | # Makefile for the Linux/SuperH SH-4 backends. | ||
3 | # | ||
4 | |||
5 | # CPU subtype setup | ||
6 | obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o | ||
7 | obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o | ||
8 | obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o | ||
9 | obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o | ||
10 | obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o | ||
11 | |||
12 | # Primary on-chip clocks (common) | ||
13 | clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o | ||
14 | clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o | ||
15 | clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o | ||
16 | clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o | ||
17 | clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7343.o | ||
18 | |||
19 | obj-y += $(clock-y) | ||
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh73180.c b/arch/sh/kernel/cpu/sh4a/clock-sh73180.c index 2fa5cb2ae68d..2fa5cb2ae68d 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh73180.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh73180.c | |||
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c new file mode 100644 index 000000000000..1707a213f0cf --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4/clock-sh7343.c | ||
3 | * | ||
4 | * SH7343/SH7722 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2006 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <asm/clock.h> | ||
16 | #include <asm/freq.h> | ||
17 | |||
18 | /* | ||
19 | * SH7343/SH7722 uses a common set of multipliers and divisors, so this | ||
20 | * is quite simple.. | ||
21 | */ | ||
22 | static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; | ||
23 | static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 }; | ||
24 | |||
25 | #define pll_calc() (((ctrl_inl(FRQCR) >> 24) & 0x1f) + 1) | ||
26 | |||
27 | static void master_clk_init(struct clk *clk) | ||
28 | { | ||
29 | clk->parent = clk_get(NULL, "cpu_clk"); | ||
30 | } | ||
31 | |||
32 | static void master_clk_recalc(struct clk *clk) | ||
33 | { | ||
34 | int idx = (ctrl_inl(FRQCR) & 0x000f); | ||
35 | clk->rate *= clk->parent->rate * multipliers[idx] / divisors[idx]; | ||
36 | } | ||
37 | |||
38 | static struct clk_ops sh7343_master_clk_ops = { | ||
39 | .init = master_clk_init, | ||
40 | .recalc = master_clk_recalc, | ||
41 | }; | ||
42 | |||
43 | static void module_clk_init(struct clk *clk) | ||
44 | { | ||
45 | clk->parent = NULL; | ||
46 | clk->rate = CONFIG_SH_PCLK_FREQ; | ||
47 | } | ||
48 | |||
49 | static struct clk_ops sh7343_module_clk_ops = { | ||
50 | .init = module_clk_init, | ||
51 | }; | ||
52 | |||
53 | static void bus_clk_init(struct clk *clk) | ||
54 | { | ||
55 | clk->parent = clk_get(NULL, "cpu_clk"); | ||
56 | } | ||
57 | |||
58 | static void bus_clk_recalc(struct clk *clk) | ||
59 | { | ||
60 | int idx = (ctrl_inl(FRQCR) >> 8) & 0x000f; | ||
61 | clk->rate = clk->parent->rate * multipliers[idx] / divisors[idx]; | ||
62 | } | ||
63 | |||
64 | static struct clk_ops sh7343_bus_clk_ops = { | ||
65 | .init = bus_clk_init, | ||
66 | .recalc = bus_clk_recalc, | ||
67 | }; | ||
68 | |||
69 | static void cpu_clk_init(struct clk *clk) | ||
70 | { | ||
71 | clk->parent = clk_get(NULL, "module_clk"); | ||
72 | clk->flags |= CLK_RATE_PROPAGATES; | ||
73 | clk_set_rate(clk, clk_get_rate(clk)); | ||
74 | } | ||
75 | |||
76 | static void cpu_clk_recalc(struct clk *clk) | ||
77 | { | ||
78 | int idx = (ctrl_inl(FRQCR) >> 20) & 0x000f; | ||
79 | clk->rate = clk->parent->rate * pll_calc() * | ||
80 | multipliers[idx] / divisors[idx]; | ||
81 | } | ||
82 | |||
83 | static struct clk_ops sh7343_cpu_clk_ops = { | ||
84 | .init = cpu_clk_init, | ||
85 | .recalc = cpu_clk_recalc, | ||
86 | }; | ||
87 | |||
88 | static struct clk_ops *sh7343_clk_ops[] = { | ||
89 | &sh7343_master_clk_ops, | ||
90 | &sh7343_module_clk_ops, | ||
91 | &sh7343_bus_clk_ops, | ||
92 | &sh7343_cpu_clk_ops, | ||
93 | }; | ||
94 | |||
95 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
96 | { | ||
97 | if (idx < ARRAY_SIZE(sh7343_clk_ops)) | ||
98 | *ops = sh7343_clk_ops[idx]; | ||
99 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh7770.c b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c index c8694bac6477..c8694bac6477 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh7770.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c | |||
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh7780.c b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c index 93ad367342c9..9e6a216750c8 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c | |||
@@ -98,7 +98,7 @@ static struct clk *sh7780_onchip_clocks[] = { | |||
98 | 98 | ||
99 | static int __init sh7780_clk_init(void) | 99 | static int __init sh7780_clk_init(void) |
100 | { | 100 | { |
101 | struct clk *clk = clk_get("master_clk"); | 101 | struct clk *clk = clk_get(NULL, "master_clk"); |
102 | int i; | 102 | int i; |
103 | 103 | ||
104 | for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) { | 104 | for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) { |
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh73180.c b/arch/sh/kernel/cpu/sh4a/setup-sh73180.c index cc9ea1e2e5df..cc9ea1e2e5df 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh73180.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh73180.c | |||
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c index 91d61cf91ba1..91d61cf91ba1 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7343.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c | |||
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c new file mode 100644 index 000000000000..1143fbf65faf --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * SH7722 Setup | ||
3 | * | ||
4 | * Copyright (C) 2006 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/serial.h> | ||
13 | #include <asm/sci.h> | ||
14 | |||
15 | static struct plat_sci_port sci_platform_data[] = { | ||
16 | { | ||
17 | .mapbase = 0xffe00000, | ||
18 | .flags = UPF_BOOT_AUTOCONF, | ||
19 | .type = PORT_SCIF, | ||
20 | .irqs = { 80, 81, 83, 82 }, | ||
21 | }, { | ||
22 | .flags = 0, | ||
23 | } | ||
24 | }; | ||
25 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7722_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static int __init sh7722_devices_setup(void) | ||
39 | { | ||
40 | return platform_add_devices(sh7722_devices, | ||
41 | ARRAY_SIZE(sh7722_devices)); | ||
42 | } | ||
43 | __initcall(sh7722_devices_setup); | ||
44 | |||
45 | static struct ipr_data sh7722_ipr_map[] = { | ||
46 | /* IRQ, IPR-idx, shift, prio */ | ||
47 | { 16, 0, 12, 2 }, /* TMU0 */ | ||
48 | { 17, 0, 8, 2 }, /* TMU1 */ | ||
49 | { 80, 6, 12, 3 }, /* SCIF ERI */ | ||
50 | { 81, 6, 12, 3 }, /* SCIF RXI */ | ||
51 | { 82, 6, 12, 3 }, /* SCIF BRI */ | ||
52 | { 83, 6, 12, 3 }, /* SCIF TXI */ | ||
53 | }; | ||
54 | |||
55 | static unsigned long ipr_offsets[] = { | ||
56 | 0xa4080000, /* 0: IPRA */ | ||
57 | 0xa4080004, /* 1: IPRB */ | ||
58 | 0xa4080008, /* 2: IPRC */ | ||
59 | 0xa408000c, /* 3: IPRD */ | ||
60 | 0xa4080010, /* 4: IPRE */ | ||
61 | 0xa4080014, /* 5: IPRF */ | ||
62 | 0xa4080018, /* 6: IPRG */ | ||
63 | 0xa408001c, /* 7: IPRH */ | ||
64 | 0xa4080020, /* 8: IPRI */ | ||
65 | 0xa4080024, /* 9: IPRJ */ | ||
66 | 0xa4080028, /* 10: IPRK */ | ||
67 | 0xa408002c, /* 11: IPRL */ | ||
68 | }; | ||
69 | |||
70 | unsigned int map_ipridx_to_addr(int idx) | ||
71 | { | ||
72 | if (unlikely(idx >= ARRAY_SIZE(ipr_offsets))) | ||
73 | return 0; | ||
74 | return ipr_offsets[idx]; | ||
75 | } | ||
76 | |||
77 | void __init init_IRQ_ipr(void) | ||
78 | { | ||
79 | make_ipr_irq(sh7722_ipr_map, ARRAY_SIZE(sh7722_ipr_map)); | ||
80 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c index 6a04cc5f5aca..6a04cc5f5aca 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7770.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c | |||
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c index 72493f259edc..9aeaa2ddaa28 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c | |||
@@ -77,3 +77,32 @@ static int __init sh7780_devices_setup(void) | |||
77 | ARRAY_SIZE(sh7780_devices)); | 77 | ARRAY_SIZE(sh7780_devices)); |
78 | } | 78 | } |
79 | __initcall(sh7780_devices_setup); | 79 | __initcall(sh7780_devices_setup); |
80 | |||
81 | static struct intc2_data intc2_irq_table[] = { | ||
82 | { 28, 0, 24, 0, 0, 2 }, /* TMU0 */ | ||
83 | |||
84 | { 21, 1, 0, 0, 2, 2 }, | ||
85 | { 22, 1, 1, 0, 2, 2 }, | ||
86 | { 23, 1, 2, 0, 2, 2 }, | ||
87 | |||
88 | { 40, 8, 24, 0, 3, 3 }, /* SCIF0 ERI */ | ||
89 | { 41, 8, 24, 0, 3, 3 }, /* SCIF0 RXI */ | ||
90 | { 42, 8, 24, 0, 3, 3 }, /* SCIF0 BRI */ | ||
91 | { 43, 8, 24, 0, 3, 3 }, /* SCIF0 TXI */ | ||
92 | |||
93 | { 76, 8, 16, 0, 4, 3 }, /* SCIF1 ERI */ | ||
94 | { 77, 8, 16, 0, 4, 3 }, /* SCIF1 RXI */ | ||
95 | { 78, 8, 16, 0, 4, 3 }, /* SCIF1 BRI */ | ||
96 | { 79, 8, 16, 0, 4, 3 }, /* SCIF1 TXI */ | ||
97 | |||
98 | { 64, 0x10, 8, 0, 14, 2 }, /* PCIC0 */ | ||
99 | { 65, 0x10, 0, 0, 15, 2 }, /* PCIC1 */ | ||
100 | { 66, 0x14, 24, 0, 16, 2 }, /* PCIC2 */ | ||
101 | { 67, 0x14, 16, 0, 17, 2 }, /* PCIC3 */ | ||
102 | { 68, 0x14, 8, 0, 18, 2 }, /* PCIC4 */ | ||
103 | }; | ||
104 | |||
105 | void __init init_IRQ_intc2(void) | ||
106 | { | ||
107 | make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table)); | ||
108 | } | ||
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c index a00022722e9e..560b91cdd15c 100644 --- a/arch/sh/kernel/early_printk.c +++ b/arch/sh/kernel/early_printk.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/console.h> | 12 | #include <linux/console.h> |
13 | #include <linux/tty.h> | 13 | #include <linux/tty.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <asm/io.h> | 15 | #include <linux/io.h> |
16 | 16 | ||
17 | #ifdef CONFIG_SH_STANDARD_BIOS | 17 | #ifdef CONFIG_SH_STANDARD_BIOS |
18 | #include <asm/sh_bios.h> | 18 | #include <asm/sh_bios.h> |
@@ -62,17 +62,9 @@ static struct console bios_console = { | |||
62 | #include <linux/serial_core.h> | 62 | #include <linux/serial_core.h> |
63 | #include "../../../drivers/serial/sh-sci.h" | 63 | #include "../../../drivers/serial/sh-sci.h" |
64 | 64 | ||
65 | #ifdef CONFIG_CPU_SH4 | ||
66 | #define SCIF_REG 0xffe80000 | ||
67 | #elif defined(CONFIG_CPU_SUBTYPE_SH72060) | ||
68 | #define SCIF_REG 0xfffe9800 | ||
69 | #else | ||
70 | #error "Undefined SCIF for this subtype" | ||
71 | #endif | ||
72 | |||
73 | static struct uart_port scif_port = { | 65 | static struct uart_port scif_port = { |
74 | .mapbase = SCIF_REG, | 66 | .mapbase = CONFIG_EARLY_SCIF_CONSOLE_PORT, |
75 | .membase = (char __iomem *)SCIF_REG, | 67 | .membase = (char __iomem *)CONFIG_EARLY_SCIF_CONSOLE_PORT, |
76 | }; | 68 | }; |
77 | 69 | ||
78 | static void scif_sercon_putc(int c) | 70 | static void scif_sercon_putc(int c) |
@@ -113,23 +105,29 @@ static struct console scif_console = { | |||
113 | .index = -1, | 105 | .index = -1, |
114 | }; | 106 | }; |
115 | 107 | ||
108 | #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) | ||
109 | /* | ||
110 | * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4 | ||
111 | * devices that aren't using sh-ipl+g. | ||
112 | */ | ||
116 | static void scif_sercon_init(int baud) | 113 | static void scif_sercon_init(int baud) |
117 | { | 114 | { |
118 | ctrl_outw(0, SCIF_REG + 8); | 115 | ctrl_outw(0, scif_port.mapbase + 8); |
119 | ctrl_outw(0, SCIF_REG); | 116 | ctrl_outw(0, scif_port.mapbase); |
120 | 117 | ||
121 | /* Set baud rate */ | 118 | /* Set baud rate */ |
122 | ctrl_outb((CONFIG_SH_PCLK_FREQ + 16 * baud) / | 119 | ctrl_outb((CONFIG_SH_PCLK_FREQ + 16 * baud) / |
123 | (32 * baud) - 1, SCIF_REG + 4); | 120 | (32 * baud) - 1, scif_port.mapbase + 4); |
124 | 121 | ||
125 | ctrl_outw(12, SCIF_REG + 24); | 122 | ctrl_outw(12, scif_port.mapbase + 24); |
126 | ctrl_outw(8, SCIF_REG + 24); | 123 | ctrl_outw(8, scif_port.mapbase + 24); |
127 | ctrl_outw(0, SCIF_REG + 32); | 124 | ctrl_outw(0, scif_port.mapbase + 32); |
128 | ctrl_outw(0x60, SCIF_REG + 16); | 125 | ctrl_outw(0x60, scif_port.mapbase + 16); |
129 | ctrl_outw(0, SCIF_REG + 36); | 126 | ctrl_outw(0, scif_port.mapbase + 36); |
130 | ctrl_outw(0x30, SCIF_REG + 8); | 127 | ctrl_outw(0x30, scif_port.mapbase + 8); |
131 | } | 128 | } |
132 | #endif | 129 | #endif /* CONFIG_CPU_SH4 && !CONFIG_SH_STANDARD_BIOS */ |
130 | #endif /* CONFIG_EARLY_SCIF_CONSOLE */ | ||
133 | 131 | ||
134 | /* | 132 | /* |
135 | * Setup a default console, if more than one is compiled in, rely on the | 133 | * Setup a default console, if more than one is compiled in, rely on the |
@@ -146,16 +144,16 @@ static struct console *early_console = | |||
146 | ; | 144 | ; |
147 | 145 | ||
148 | static int __initdata keep_early; | 146 | static int __initdata keep_early; |
147 | static int early_console_initialized; | ||
149 | 148 | ||
150 | int __init setup_early_printk(char *opt) | 149 | int __init setup_early_printk(char *buf) |
151 | { | 150 | { |
152 | char *space; | 151 | if (!buf) |
153 | char buf[256]; | 152 | return 0; |
154 | 153 | ||
155 | strlcpy(buf, opt, sizeof(buf)); | 154 | if (early_console_initialized) |
156 | space = strchr(buf, ' '); | 155 | return 0; |
157 | if (space) | 156 | early_console_initialized = 1; |
158 | *space = 0; | ||
159 | 157 | ||
160 | if (strstr(buf, "keep")) | 158 | if (strstr(buf, "keep")) |
161 | keep_early = 1; | 159 | keep_early = 1; |
@@ -168,7 +166,7 @@ int __init setup_early_printk(char *opt) | |||
168 | if (!strncmp(buf, "serial", 6)) { | 166 | if (!strncmp(buf, "serial", 6)) { |
169 | early_console = &scif_console; | 167 | early_console = &scif_console; |
170 | 168 | ||
171 | #ifdef CONFIG_CPU_SH4 | 169 | #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) |
172 | scif_sercon_init(115200); | 170 | scif_sercon_init(115200); |
173 | #endif | 171 | #endif |
174 | } | 172 | } |
@@ -177,12 +175,14 @@ int __init setup_early_printk(char *opt) | |||
177 | if (likely(early_console)) | 175 | if (likely(early_console)) |
178 | register_console(early_console); | 176 | register_console(early_console); |
179 | 177 | ||
180 | return 1; | 178 | return 0; |
181 | } | 179 | } |
182 | __setup("earlyprintk=", setup_early_printk); | 180 | early_param("earlyprintk", setup_early_printk); |
183 | 181 | ||
184 | void __init disable_early_printk(void) | 182 | void __init disable_early_printk(void) |
185 | { | 183 | { |
184 | if (!early_console_initialized || !early_console) | ||
185 | return; | ||
186 | if (!keep_early) { | 186 | if (!keep_early) { |
187 | printk("disabling early console\n"); | 187 | printk("disabling early console\n"); |
188 | unregister_console(early_console); | 188 | unregister_console(early_console); |
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S new file mode 100644 index 000000000000..fc279aeb73ab --- /dev/null +++ b/arch/sh/kernel/entry-common.S | |||
@@ -0,0 +1,444 @@ | |||
1 | /* $Id: entry.S,v 1.37 2004/06/11 13:02:46 doyu Exp $ | ||
2 | * | ||
3 | * linux/arch/sh/entry.S | ||
4 | * | ||
5 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | ||
6 | * Copyright (C) 2003 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | ! NOTE: | ||
15 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address | ||
16 | ! to be jumped is too far, but it causes illegal slot exception. | ||
17 | |||
18 | /* | ||
19 | * entry.S contains the system-call and fault low-level handling routines. | ||
20 | * This also contains the timer-interrupt handler, as well as all interrupts | ||
21 | * and faults that can result in a task-switch. | ||
22 | * | ||
23 | * NOTE: This code handles signal-recognition, which happens every time | ||
24 | * after a timer-interrupt and after each system call. | ||
25 | * | ||
26 | * NOTE: This code uses a convention that instructions in the delay slot | ||
27 | * of a transfer-control instruction are indented by an extra space, thus: | ||
28 | * | ||
29 | * jmp @k0 ! control-transfer instruction | ||
30 | * ldc k1, ssr ! delay slot | ||
31 | * | ||
32 | * Stack layout in 'ret_from_syscall': | ||
33 | * ptrace needs to have all regs on the stack. | ||
34 | * if the order here is changed, it needs to be | ||
35 | * updated in ptrace.c and ptrace.h | ||
36 | * | ||
37 | * r0 | ||
38 | * ... | ||
39 | * r15 = stack pointer | ||
40 | * spc | ||
41 | * pr | ||
42 | * ssr | ||
43 | * gbr | ||
44 | * mach | ||
45 | * macl | ||
46 | * syscall # | ||
47 | * | ||
48 | */ | ||
49 | |||
50 | #if defined(CONFIG_PREEMPT) | ||
51 | # define preempt_stop() cli | ||
52 | #else | ||
53 | # define preempt_stop() | ||
54 | # define resume_kernel __restore_all | ||
55 | #endif | ||
56 | |||
57 | #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) | ||
58 | ! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present. | ||
59 | ! If both are configured, handle the debug traps (breakpoints) in SW, | ||
60 | ! but still allow BIOS traps to FW. | ||
61 | |||
62 | .align 2 | ||
63 | debug_kernel: | ||
64 | #if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB) | ||
65 | /* Force BIOS call to FW (debug_trap put TRA in r8) */ | ||
66 | mov r8,r0 | ||
67 | shlr2 r0 | ||
68 | cmp/eq #0x3f,r0 | ||
69 | bt debug_kernel_fw | ||
70 | #endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */ | ||
71 | |||
72 | debug_enter: | ||
73 | #if defined(CONFIG_SH_KGDB) | ||
74 | /* Jump to kgdb, pass stacked regs as arg */ | ||
75 | debug_kernel_sw: | ||
76 | mov.l 3f, r0 | ||
77 | jmp @r0 | ||
78 | mov r15, r4 | ||
79 | .align 2 | ||
80 | 3: .long kgdb_handle_exception | ||
81 | #endif /* CONFIG_SH_KGDB */ | ||
82 | #ifdef CONFIG_SH_STANDARD_BIOS | ||
83 | bra debug_kernel_fw | ||
84 | nop | ||
85 | #endif | ||
86 | #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ | ||
87 | |||
88 | .align 2 | ||
89 | debug_trap: | ||
90 | #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) | ||
91 | mov r8, r0 | ||
92 | shlr2 r0 | ||
93 | cmp/eq #0x3f, r0 ! sh_bios() trap | ||
94 | bf 1f | ||
95 | #ifdef CONFIG_SH_KGDB | ||
96 | cmp/eq #0xff, r0 ! XXX: KGDB trap, fix for SH-2. | ||
97 | bf 1f | ||
98 | #endif | ||
99 | mov #OFF_SR, r0 | ||
100 | mov.l @(r0,r15), r0 ! get status register | ||
101 | shll r0 | ||
102 | shll r0 ! kernel space? | ||
103 | bt/s debug_kernel | ||
104 | 1: | ||
105 | #endif | ||
106 | mov.l @r15, r0 ! Restore R0 value | ||
107 | mov.l 1f, r8 | ||
108 | jmp @r8 | ||
109 | nop | ||
110 | |||
111 | .align 2 | ||
112 | ENTRY(exception_error) | ||
113 | ! | ||
114 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
115 | mov.l 3f, r0 | ||
116 | jsr @r0 | ||
117 | nop | ||
118 | #endif | ||
119 | sti | ||
120 | mov.l 2f, r0 | ||
121 | jmp @r0 | ||
122 | nop | ||
123 | |||
124 | ! | ||
125 | .align 2 | ||
126 | 1: .long break_point_trap_software | ||
127 | 2: .long do_exception_error | ||
128 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
129 | 3: .long trace_hardirqs_on | ||
130 | #endif | ||
131 | |||
132 | .align 2 | ||
133 | ret_from_exception: | ||
134 | preempt_stop() | ||
135 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
136 | mov.l 4f, r0 | ||
137 | jsr @r0 | ||
138 | nop | ||
139 | #endif | ||
140 | ENTRY(ret_from_irq) | ||
141 | ! | ||
142 | mov #OFF_SR, r0 | ||
143 | mov.l @(r0,r15), r0 ! get status register | ||
144 | shll r0 | ||
145 | shll r0 ! kernel space? | ||
146 | get_current_thread_info r8, r0 | ||
147 | bt resume_kernel ! Yes, it's from kernel, go back soon | ||
148 | |||
149 | #ifdef CONFIG_PREEMPT | ||
150 | bra resume_userspace | ||
151 | nop | ||
152 | ENTRY(resume_kernel) | ||
153 | mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count | ||
154 | tst r0, r0 | ||
155 | bf noresched | ||
156 | need_resched: | ||
157 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
158 | tst #_TIF_NEED_RESCHED, r0 ! need_resched set? | ||
159 | bt noresched | ||
160 | |||
161 | mov #OFF_SR, r0 | ||
162 | mov.l @(r0,r15), r0 ! get status register | ||
163 | and #0xf0, r0 ! interrupts off (exception path)? | ||
164 | cmp/eq #0xf0, r0 | ||
165 | bt noresched | ||
166 | |||
167 | mov.l 1f, r0 | ||
168 | mov.l r0, @(TI_PRE_COUNT,r8) | ||
169 | |||
170 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
171 | mov.l 3f, r0 | ||
172 | jsr @r0 | ||
173 | nop | ||
174 | #endif | ||
175 | sti | ||
176 | mov.l 2f, r0 | ||
177 | jsr @r0 | ||
178 | nop | ||
179 | mov #0, r0 | ||
180 | mov.l r0, @(TI_PRE_COUNT,r8) | ||
181 | cli | ||
182 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
183 | mov.l 4f, r0 | ||
184 | jsr @r0 | ||
185 | nop | ||
186 | #endif | ||
187 | |||
188 | bra need_resched | ||
189 | nop | ||
190 | |||
191 | noresched: | ||
192 | bra __restore_all | ||
193 | nop | ||
194 | |||
195 | .align 2 | ||
196 | 1: .long PREEMPT_ACTIVE | ||
197 | 2: .long schedule | ||
198 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
199 | 3: .long trace_hardirqs_on | ||
200 | 4: .long trace_hardirqs_off | ||
201 | #endif | ||
202 | #endif | ||
203 | |||
204 | ENTRY(resume_userspace) | ||
205 | ! r8: current_thread_info | ||
206 | cli | ||
207 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
208 | mov.l 5f, r0 | ||
209 | jsr @r0 | ||
210 | nop | ||
211 | #endif | ||
212 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
213 | tst #_TIF_WORK_MASK, r0 | ||
214 | bt/s __restore_all | ||
215 | tst #_TIF_NEED_RESCHED, r0 | ||
216 | |||
217 | .align 2 | ||
218 | work_pending: | ||
219 | ! r0: current_thread_info->flags | ||
220 | ! r8: current_thread_info | ||
221 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" | ||
222 | bf/s work_resched | ||
223 | tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0 | ||
224 | work_notifysig: | ||
225 | bt/s __restore_all | ||
226 | mov r15, r4 | ||
227 | mov r12, r5 ! set arg1(save_r0) | ||
228 | mov r0, r6 | ||
229 | mov.l 2f, r1 | ||
230 | mov.l 3f, r0 | ||
231 | jmp @r1 | ||
232 | lds r0, pr | ||
233 | work_resched: | ||
234 | #ifndef CONFIG_PREEMPT | ||
235 | ! gUSA handling | ||
236 | mov.l @(OFF_SP,r15), r0 ! get user space stack pointer | ||
237 | mov r0, r1 | ||
238 | shll r0 | ||
239 | bf/s 1f | ||
240 | shll r0 | ||
241 | bf/s 1f | ||
242 | mov #OFF_PC, r0 | ||
243 | ! SP >= 0xc0000000 : gUSA mark | ||
244 | mov.l @(r0,r15), r2 ! get user space PC (program counter) | ||
245 | mov.l @(OFF_R0,r15), r3 ! end point | ||
246 | cmp/hs r3, r2 ! r2 >= r3? | ||
247 | bt 1f | ||
248 | add r3, r1 ! rewind point #2 | ||
249 | mov.l r1, @(r0,r15) ! reset PC to rewind point #2 | ||
250 | ! | ||
251 | 1: | ||
252 | #endif | ||
253 | mov.l 1f, r1 | ||
254 | jsr @r1 ! schedule | ||
255 | nop | ||
256 | cli | ||
257 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
258 | mov.l 5f, r0 | ||
259 | jsr @r0 | ||
260 | nop | ||
261 | #endif | ||
262 | ! | ||
263 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
264 | tst #_TIF_WORK_MASK, r0 | ||
265 | bt __restore_all | ||
266 | bra work_pending | ||
267 | tst #_TIF_NEED_RESCHED, r0 | ||
268 | |||
269 | .align 2 | ||
270 | 1: .long schedule | ||
271 | 2: .long do_notify_resume | ||
272 | 3: .long restore_all | ||
273 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
274 | 4: .long trace_hardirqs_on | ||
275 | 5: .long trace_hardirqs_off | ||
276 | #endif | ||
277 | |||
278 | .align 2 | ||
279 | syscall_exit_work: | ||
280 | ! r0: current_thread_info->flags | ||
281 | ! r8: current_thread_info | ||
282 | tst #_TIF_SYSCALL_TRACE, r0 | ||
283 | bt/s work_pending | ||
284 | tst #_TIF_NEED_RESCHED, r0 | ||
285 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
286 | mov.l 5f, r0 | ||
287 | jsr @r0 | ||
288 | nop | ||
289 | #endif | ||
290 | sti | ||
291 | ! XXX setup arguments... | ||
292 | mov.l 4f, r0 ! do_syscall_trace | ||
293 | jsr @r0 | ||
294 | nop | ||
295 | bra resume_userspace | ||
296 | nop | ||
297 | |||
298 | .align 2 | ||
299 | syscall_trace_entry: | ||
300 | ! Yes it is traced. | ||
301 | ! XXX setup arguments... | ||
302 | mov.l 4f, r11 ! Call do_syscall_trace which notifies | ||
303 | jsr @r11 ! superior (will chomp R[0-7]) | ||
304 | nop | ||
305 | ! Reload R0-R4 from kernel stack, where the | ||
306 | ! parent may have modified them using | ||
307 | ! ptrace(POKEUSR). (Note that R0-R2 are | ||
308 | ! used by the system call handler directly | ||
309 | ! from the kernel stack anyway, so don't need | ||
310 | ! to be reloaded here.) This allows the parent | ||
311 | ! to rewrite system calls and args on the fly. | ||
312 | mov.l @(OFF_R4,r15), r4 ! arg0 | ||
313 | mov.l @(OFF_R5,r15), r5 | ||
314 | mov.l @(OFF_R6,r15), r6 | ||
315 | mov.l @(OFF_R7,r15), r7 ! arg3 | ||
316 | mov.l @(OFF_R3,r15), r3 ! syscall_nr | ||
317 | ! | ||
318 | mov.l 2f, r10 ! Number of syscalls | ||
319 | cmp/hs r10, r3 | ||
320 | bf syscall_call | ||
321 | mov #-ENOSYS, r0 | ||
322 | bra syscall_exit | ||
323 | mov.l r0, @(OFF_R0,r15) ! Return value | ||
324 | |||
325 | __restore_all: | ||
326 | mov.l 1f, r0 | ||
327 | jmp @r0 | ||
328 | nop | ||
329 | |||
330 | .align 2 | ||
331 | 1: .long restore_all | ||
332 | |||
333 | .align 2 | ||
334 | not_syscall_tra: | ||
335 | bra debug_trap | ||
336 | nop | ||
337 | |||
338 | .align 2 | ||
339 | syscall_badsys: ! Bad syscall number | ||
340 | mov #-ENOSYS, r0 | ||
341 | bra resume_userspace | ||
342 | mov.l r0, @(OFF_R0,r15) ! Return value | ||
343 | |||
344 | |||
345 | /* | ||
346 | * Syscall interface: | ||
347 | * | ||
348 | * Syscall #: R3 | ||
349 | * Arguments #0 to #3: R4--R7 | ||
350 | * Arguments #4 to #6: R0, R1, R2 | ||
351 | * TRA: (number of arguments + 0x10) x 4 | ||
352 | * | ||
353 | * This code also handles delegating other traps to the BIOS/gdb stub | ||
354 | * according to: | ||
355 | * | ||
356 | * Trap number | ||
357 | * (TRA>>2) Purpose | ||
358 | * -------- ------- | ||
359 | * 0x0-0xf old syscall ABI | ||
360 | * 0x10-0x1f new syscall ABI | ||
361 | * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. | ||
362 | * | ||
363 | * Note: When we're first called, the TRA value must be shifted | ||
364 | * right 2 bits in order to get the value that was used as the "trapa" | ||
365 | * argument. | ||
366 | */ | ||
367 | |||
368 | .align 2 | ||
369 | .globl ret_from_fork | ||
370 | ret_from_fork: | ||
371 | mov.l 1f, r8 | ||
372 | jsr @r8 | ||
373 | mov r0, r4 | ||
374 | bra syscall_exit | ||
375 | nop | ||
376 | .align 2 | ||
377 | 1: .long schedule_tail | ||
378 | ! | ||
379 | ENTRY(system_call) | ||
380 | #if !defined(CONFIG_CPU_SH2) | ||
381 | mov.l 1f, r9 | ||
382 | mov.l @r9, r8 ! Read from TRA (Trap Address) Register | ||
383 | #endif | ||
384 | ! | ||
385 | ! Is the trap argument >= 0x20? (TRA will be >= 0x80) | ||
386 | mov #0x7f, r9 | ||
387 | cmp/hi r9, r8 | ||
388 | bt/s not_syscall_tra | ||
389 | mov #OFF_TRA, r9 | ||
390 | add r15, r9 | ||
391 | mov.l r8, @r9 ! set TRA value to tra | ||
392 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
393 | mov.l 5f, r10 | ||
394 | jsr @r10 | ||
395 | nop | ||
396 | #endif | ||
397 | sti | ||
398 | |||
399 | ! | ||
400 | get_current_thread_info r8, r10 | ||
401 | mov.l @(TI_FLAGS,r8), r8 | ||
402 | mov #_TIF_SYSCALL_TRACE, r10 | ||
403 | tst r10, r8 | ||
404 | bf syscall_trace_entry | ||
405 | ! | ||
406 | mov.l 2f, r8 ! Number of syscalls | ||
407 | cmp/hs r8, r3 | ||
408 | bt syscall_badsys | ||
409 | ! | ||
410 | syscall_call: | ||
411 | shll2 r3 ! x4 | ||
412 | mov.l 3f, r8 ! Load the address of sys_call_table | ||
413 | add r8, r3 | ||
414 | mov.l @r3, r8 | ||
415 | jsr @r8 ! jump to specific syscall handler | ||
416 | nop | ||
417 | mov.l @(OFF_R0,r15), r12 ! save r0 | ||
418 | mov.l r0, @(OFF_R0,r15) ! save the return value | ||
419 | ! | ||
420 | syscall_exit: | ||
421 | cli | ||
422 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
423 | mov.l 6f, r0 | ||
424 | jsr @r0 | ||
425 | nop | ||
426 | #endif | ||
427 | ! | ||
428 | get_current_thread_info r8, r0 | ||
429 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
430 | tst #_TIF_ALLWORK_MASK, r0 | ||
431 | bf syscall_exit_work | ||
432 | bra __restore_all | ||
433 | nop | ||
434 | .align 2 | ||
435 | #if !defined(CONFIG_CPU_SH2) | ||
436 | 1: .long TRA | ||
437 | #endif | ||
438 | 2: .long NR_syscalls | ||
439 | 3: .long sys_call_table | ||
440 | 4: .long do_syscall_trace | ||
441 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
442 | 5: .long trace_hardirqs_on | ||
443 | 6: .long trace_hardirqs_off | ||
444 | #endif | ||
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S index f5f53d14f245..71a3ad7d283e 100644 --- a/arch/sh/kernel/head.S +++ b/arch/sh/kernel/head.S | |||
@@ -33,7 +33,8 @@ ENTRY(empty_zero_page) | |||
33 | .long 0x00360000 /* INITRD_START */ | 33 | .long 0x00360000 /* INITRD_START */ |
34 | .long 0x000a0000 /* INITRD_SIZE */ | 34 | .long 0x000a0000 /* INITRD_SIZE */ |
35 | .long 0 | 35 | .long 0 |
36 | .balign 4096,0,4096 | 36 | 1: |
37 | .skip PAGE_SIZE - empty_zero_page - 1b | ||
37 | 38 | ||
38 | .text | 39 | .text |
39 | /* | 40 | /* |
@@ -53,8 +54,10 @@ ENTRY(_stext) | |||
53 | ldc r0, sr | 54 | ldc r0, sr |
54 | ! Initialize global interrupt mask | 55 | ! Initialize global interrupt mask |
55 | mov #0, r0 | 56 | mov #0, r0 |
57 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
56 | ldc r0, r6_bank | 58 | ldc r0, r6_bank |
57 | 59 | #endif | |
60 | |||
58 | /* | 61 | /* |
59 | * Prefetch if possible to reduce cache miss penalty. | 62 | * Prefetch if possible to reduce cache miss penalty. |
60 | * | 63 | * |
@@ -68,11 +71,14 @@ ENTRY(_stext) | |||
68 | ! | 71 | ! |
69 | mov.l 2f, r0 | 72 | mov.l 2f, r0 |
70 | mov r0, r15 ! Set initial r15 (stack pointer) | 73 | mov r0, r15 ! Set initial r15 (stack pointer) |
71 | mov #(THREAD_SIZE >> 8), r1 | 74 | mov #(THREAD_SIZE >> 10), r1 |
72 | shll8 r1 ! r1 = THREAD_SIZE | 75 | shll8 r1 ! r1 = THREAD_SIZE |
76 | shll2 r1 | ||
73 | sub r1, r0 ! | 77 | sub r1, r0 ! |
78 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
74 | ldc r0, r7_bank ! ... and initial thread_info | 79 | ldc r0, r7_bank ! ... and initial thread_info |
75 | 80 | #endif | |
81 | |||
76 | ! Clear BSS area | 82 | ! Clear BSS area |
77 | mov.l 3f, r1 | 83 | mov.l 3f, r1 |
78 | add #4, r1 | 84 | add #4, r1 |
@@ -95,7 +101,11 @@ ENTRY(_stext) | |||
95 | nop | 101 | nop |
96 | 102 | ||
97 | .balign 4 | 103 | .balign 4 |
104 | #if defined(CONFIG_CPU_SH2) | ||
105 | 1: .long 0x000000F0 ! IMASK=0xF | ||
106 | #else | ||
98 | 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF | 107 | 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF |
108 | #endif | ||
99 | 2: .long init_thread_union+THREAD_SIZE | 109 | 2: .long init_thread_union+THREAD_SIZE |
100 | 3: .long __bss_start | 110 | 3: .long __bss_start |
101 | 4: .long _end | 111 | 4: .long _end |
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index acf2602569c4..67be2b6e8cd1 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/kernel_stat.h> | 12 | #include <linux/kernel_stat.h> |
13 | #include <linux/seq_file.h> | 13 | #include <linux/seq_file.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <asm/irq.h> | 15 | #include <linux/irq.h> |
16 | #include <asm/processor.h> | 16 | #include <asm/processor.h> |
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | #include <asm/thread_info.h> | 18 | #include <asm/thread_info.h> |
@@ -54,7 +54,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
54 | for_each_online_cpu(j) | 54 | for_each_online_cpu(j) |
55 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 55 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); |
56 | seq_printf(p, " %14s", irq_desc[i].chip->name); | 56 | seq_printf(p, " %14s", irq_desc[i].chip->name); |
57 | seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); | 57 | seq_printf(p, "-%-8s", irq_desc[i].name); |
58 | seq_printf(p, " %s", action->name); | 58 | seq_printf(p, " %s", action->name); |
59 | 59 | ||
60 | for (action=action->next; action; action = action->next) | 60 | for (action=action->next; action; action = action->next) |
@@ -78,15 +78,16 @@ union irq_ctx { | |||
78 | u32 stack[THREAD_SIZE/sizeof(u32)]; | 78 | u32 stack[THREAD_SIZE/sizeof(u32)]; |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static union irq_ctx *hardirq_ctx[NR_CPUS]; | 81 | static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; |
82 | static union irq_ctx *softirq_ctx[NR_CPUS]; | 82 | static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; |
83 | #endif | 83 | #endif |
84 | 84 | ||
85 | asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | 85 | asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, |
86 | unsigned long r6, unsigned long r7, | 86 | unsigned long r6, unsigned long r7, |
87 | struct pt_regs regs) | 87 | struct pt_regs __regs) |
88 | { | 88 | { |
89 | struct pt_regs *old_regs = set_irq_regs(®s); | 89 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
90 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
90 | int irq; | 91 | int irq; |
91 | #ifdef CONFIG_4KSTACKS | 92 | #ifdef CONFIG_4KSTACKS |
92 | union irq_ctx *curctx, *irqctx; | 93 | union irq_ctx *curctx, *irqctx; |
@@ -111,7 +112,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | |||
111 | #endif | 112 | #endif |
112 | 113 | ||
113 | #ifdef CONFIG_CPU_HAS_INTEVT | 114 | #ifdef CONFIG_CPU_HAS_INTEVT |
114 | irq = (ctrl_inl(INTEVT) >> 5) - 16; | 115 | irq = evt2irq(ctrl_inl(INTEVT)); |
115 | #else | 116 | #else |
116 | irq = r4; | 117 | irq = r4; |
117 | #endif | 118 | #endif |
@@ -135,17 +136,24 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | |||
135 | irqctx->tinfo.task = curctx->tinfo.task; | 136 | irqctx->tinfo.task = curctx->tinfo.task; |
136 | irqctx->tinfo.previous_sp = current_stack_pointer; | 137 | irqctx->tinfo.previous_sp = current_stack_pointer; |
137 | 138 | ||
139 | /* | ||
140 | * Copy the softirq bits in preempt_count so that the | ||
141 | * softirq checks work in the hardirq context. | ||
142 | */ | ||
143 | irqctx->tinfo.preempt_count = | ||
144 | (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) | | ||
145 | (curctx->tinfo.preempt_count & SOFTIRQ_MASK); | ||
146 | |||
138 | __asm__ __volatile__ ( | 147 | __asm__ __volatile__ ( |
139 | "mov %0, r4 \n" | 148 | "mov %0, r4 \n" |
140 | "mov r15, r9 \n" | 149 | "mov r15, r8 \n" |
141 | "jsr @%1 \n" | 150 | "jsr @%1 \n" |
142 | /* swith to the irq stack */ | 151 | /* swith to the irq stack */ |
143 | " mov %2, r15 \n" | 152 | " mov %2, r15 \n" |
144 | /* restore the stack (ring zero) */ | 153 | /* restore the stack (ring zero) */ |
145 | "mov r9, r15 \n" | 154 | "mov r8, r15 \n" |
146 | : /* no outputs */ | 155 | : /* no outputs */ |
147 | : "r" (irq), "r" (generic_handle_irq), "r" (isp) | 156 | : "r" (irq), "r" (generic_handle_irq), "r" (isp) |
148 | /* XXX: A somewhat excessive clobber list? -PFM */ | ||
149 | : "memory", "r0", "r1", "r2", "r3", "r4", | 157 | : "memory", "r0", "r1", "r2", "r3", "r4", |
150 | "r5", "r6", "r7", "r8", "t", "pr" | 158 | "r5", "r6", "r7", "r8", "t", "pr" |
151 | ); | 159 | ); |
@@ -193,7 +201,7 @@ void irq_ctx_init(int cpu) | |||
193 | irqctx->tinfo.task = NULL; | 201 | irqctx->tinfo.task = NULL; |
194 | irqctx->tinfo.exec_domain = NULL; | 202 | irqctx->tinfo.exec_domain = NULL; |
195 | irqctx->tinfo.cpu = cpu; | 203 | irqctx->tinfo.cpu = cpu; |
196 | irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET; | 204 | irqctx->tinfo.preempt_count = 0; |
197 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); | 205 | irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); |
198 | 206 | ||
199 | softirq_ctx[cpu] = irqctx; | 207 | softirq_ctx[cpu] = irqctx; |
@@ -239,13 +247,38 @@ asmlinkage void do_softirq(void) | |||
239 | "mov r9, r15 \n" | 247 | "mov r9, r15 \n" |
240 | : /* no outputs */ | 248 | : /* no outputs */ |
241 | : "r" (__do_softirq), "r" (isp) | 249 | : "r" (__do_softirq), "r" (isp) |
242 | /* XXX: A somewhat excessive clobber list? -PFM */ | ||
243 | : "memory", "r0", "r1", "r2", "r3", "r4", | 250 | : "memory", "r0", "r1", "r2", "r3", "r4", |
244 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" | 251 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" |
245 | ); | 252 | ); |
253 | |||
254 | /* | ||
255 | * Shouldnt happen, we returned above if in_interrupt(): | ||
256 | */ | ||
257 | WARN_ON_ONCE(softirq_count()); | ||
246 | } | 258 | } |
247 | 259 | ||
248 | local_irq_restore(flags); | 260 | local_irq_restore(flags); |
249 | } | 261 | } |
250 | EXPORT_SYMBOL(do_softirq); | 262 | EXPORT_SYMBOL(do_softirq); |
251 | #endif | 263 | #endif |
264 | |||
265 | void __init init_IRQ(void) | ||
266 | { | ||
267 | #ifdef CONFIG_CPU_HAS_PINT_IRQ | ||
268 | init_IRQ_pint(); | ||
269 | #endif | ||
270 | |||
271 | #ifdef CONFIG_CPU_HAS_INTC2_IRQ | ||
272 | init_IRQ_intc2(); | ||
273 | #endif | ||
274 | |||
275 | #ifdef CONFIG_CPU_HAS_IPR_IRQ | ||
276 | init_IRQ_ipr(); | ||
277 | #endif | ||
278 | |||
279 | /* Perform the machine specific initialisation */ | ||
280 | if (sh_mv.mv_init_irq) | ||
281 | sh_mv.mv_init_irq(); | ||
282 | |||
283 | irq_ctx_init(smp_processor_id()); | ||
284 | } | ||
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 91516dca4a85..486c06e18033 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c | |||
@@ -105,7 +105,7 @@ void show_regs(struct pt_regs * regs) | |||
105 | { | 105 | { |
106 | printk("\n"); | 106 | printk("\n"); |
107 | printk("Pid : %d, Comm: %20s\n", current->pid, current->comm); | 107 | printk("Pid : %d, Comm: %20s\n", current->pid, current->comm); |
108 | print_symbol("PC is at %s\n", regs->pc); | 108 | print_symbol("PC is at %s\n", instruction_pointer(regs)); |
109 | printk("PC : %08lx SP : %08lx SR : %08lx ", | 109 | printk("PC : %08lx SP : %08lx SR : %08lx ", |
110 | regs->pc, regs->regs[15], regs->sr); | 110 | regs->pc, regs->regs[15], regs->sr); |
111 | #ifdef CONFIG_MMU | 111 | #ifdef CONFIG_MMU |
@@ -130,15 +130,7 @@ void show_regs(struct pt_regs * regs) | |||
130 | printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n", | 130 | printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n", |
131 | regs->mach, regs->macl, regs->gbr, regs->pr); | 131 | regs->mach, regs->macl, regs->gbr, regs->pr); |
132 | 132 | ||
133 | /* | 133 | show_trace(NULL, (unsigned long *)regs->regs[15], regs); |
134 | * If we're in kernel mode, dump the stack too.. | ||
135 | */ | ||
136 | if (!user_mode(regs)) { | ||
137 | extern void show_task(unsigned long *sp); | ||
138 | unsigned long sp = regs->regs[15]; | ||
139 | |||
140 | show_task((unsigned long *)sp); | ||
141 | } | ||
142 | } | 134 | } |
143 | 135 | ||
144 | /* | 136 | /* |
@@ -393,10 +385,11 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne | |||
393 | 385 | ||
394 | asmlinkage int sys_fork(unsigned long r4, unsigned long r5, | 386 | asmlinkage int sys_fork(unsigned long r4, unsigned long r5, |
395 | unsigned long r6, unsigned long r7, | 387 | unsigned long r6, unsigned long r7, |
396 | struct pt_regs regs) | 388 | struct pt_regs __regs) |
397 | { | 389 | { |
390 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
398 | #ifdef CONFIG_MMU | 391 | #ifdef CONFIG_MMU |
399 | return do_fork(SIGCHLD, regs.regs[15], ®s, 0, NULL, NULL); | 392 | return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL); |
400 | #else | 393 | #else |
401 | /* fork almost works, enough to trick you into looking elsewhere :-( */ | 394 | /* fork almost works, enough to trick you into looking elsewhere :-( */ |
402 | return -EINVAL; | 395 | return -EINVAL; |
@@ -406,11 +399,12 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5, | |||
406 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | 399 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, |
407 | unsigned long parent_tidptr, | 400 | unsigned long parent_tidptr, |
408 | unsigned long child_tidptr, | 401 | unsigned long child_tidptr, |
409 | struct pt_regs regs) | 402 | struct pt_regs __regs) |
410 | { | 403 | { |
404 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
411 | if (!newsp) | 405 | if (!newsp) |
412 | newsp = regs.regs[15]; | 406 | newsp = regs->regs[15]; |
413 | return do_fork(clone_flags, newsp, ®s, 0, | 407 | return do_fork(clone_flags, newsp, regs, 0, |
414 | (int __user *)parent_tidptr, (int __user *)child_tidptr); | 408 | (int __user *)parent_tidptr, (int __user *)child_tidptr); |
415 | } | 409 | } |
416 | 410 | ||
@@ -426,9 +420,10 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | |||
426 | */ | 420 | */ |
427 | asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, | 421 | asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, |
428 | unsigned long r6, unsigned long r7, | 422 | unsigned long r6, unsigned long r7, |
429 | struct pt_regs regs) | 423 | struct pt_regs __regs) |
430 | { | 424 | { |
431 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], ®s, | 425 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
426 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs, | ||
432 | 0, NULL, NULL); | 427 | 0, NULL, NULL); |
433 | } | 428 | } |
434 | 429 | ||
@@ -437,8 +432,9 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, | |||
437 | */ | 432 | */ |
438 | asmlinkage int sys_execve(char *ufilename, char **uargv, | 433 | asmlinkage int sys_execve(char *ufilename, char **uargv, |
439 | char **uenvp, unsigned long r7, | 434 | char **uenvp, unsigned long r7, |
440 | struct pt_regs regs) | 435 | struct pt_regs __regs) |
441 | { | 436 | { |
437 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
442 | int error; | 438 | int error; |
443 | char *filename; | 439 | char *filename; |
444 | 440 | ||
@@ -450,7 +446,7 @@ asmlinkage int sys_execve(char *ufilename, char **uargv, | |||
450 | error = do_execve(filename, | 446 | error = do_execve(filename, |
451 | (char __user * __user *)uargv, | 447 | (char __user * __user *)uargv, |
452 | (char __user * __user *)uenvp, | 448 | (char __user * __user *)uenvp, |
453 | ®s); | 449 | regs); |
454 | if (error == 0) { | 450 | if (error == 0) { |
455 | task_lock(current); | 451 | task_lock(current); |
456 | current->ptrace &= ~PT_DTRACE; | 452 | current->ptrace &= ~PT_DTRACE; |
@@ -474,15 +470,14 @@ unsigned long get_wchan(struct task_struct *p) | |||
474 | */ | 470 | */ |
475 | pc = thread_saved_pc(p); | 471 | pc = thread_saved_pc(p); |
476 | if (in_sched_functions(pc)) { | 472 | if (in_sched_functions(pc)) { |
477 | schedule_frame = ((unsigned long *)(long)p->thread.sp)[1]; | 473 | schedule_frame = (unsigned long)p->thread.sp; |
478 | return (unsigned long)((unsigned long *)schedule_frame)[1]; | 474 | return ((unsigned long *)schedule_frame)[21]; |
479 | } | 475 | } |
476 | |||
480 | return pc; | 477 | return pc; |
481 | } | 478 | } |
482 | 479 | ||
483 | asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, | 480 | asmlinkage void break_point_trap(void) |
484 | unsigned long r6, unsigned long r7, | ||
485 | struct pt_regs regs) | ||
486 | { | 481 | { |
487 | /* Clear tracing. */ | 482 | /* Clear tracing. */ |
488 | #if defined(CONFIG_CPU_SH4A) | 483 | #if defined(CONFIG_CPU_SH4A) |
@@ -500,8 +495,20 @@ asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, | |||
500 | 495 | ||
501 | asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, | 496 | asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, |
502 | unsigned long r6, unsigned long r7, | 497 | unsigned long r6, unsigned long r7, |
503 | struct pt_regs regs) | 498 | struct pt_regs __regs) |
504 | { | 499 | { |
505 | regs.pc -= 2; | 500 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
501 | |||
502 | /* Rewind */ | ||
503 | regs->pc -= 2; | ||
504 | |||
505 | #ifdef CONFIG_BUG | ||
506 | if (__kernel_text_address(instruction_pointer(regs))) { | ||
507 | u16 insn = *(u16 *)instruction_pointer(regs); | ||
508 | if (insn == TRAPA_BUG_OPCODE) | ||
509 | handle_BUG(regs); | ||
510 | } | ||
511 | #endif | ||
512 | |||
506 | force_sig(SIGTRAP, current); | 513 | force_sig(SIGTRAP, current); |
507 | } | 514 | } |
diff --git a/arch/sh/kernel/relocate_kernel.S b/arch/sh/kernel/relocate_kernel.S index 8221b37c9773..c66cb3209db5 100644 --- a/arch/sh/kernel/relocate_kernel.S +++ b/arch/sh/kernel/relocate_kernel.S | |||
@@ -7,11 +7,9 @@ | |||
7 | * This source code is licensed under the GNU General Public License, | 7 | * This source code is licensed under the GNU General Public License, |
8 | * Version 2. See the file COPYING for more details. | 8 | * Version 2. See the file COPYING for more details. |
9 | */ | 9 | */ |
10 | |||
11 | #include <linux/linkage.h> | 10 | #include <linux/linkage.h> |
12 | 11 | #include <asm/addrspace.h> | |
13 | #define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */ | 12 | #include <asm/page.h> |
14 | |||
15 | 13 | ||
16 | .globl relocate_new_kernel | 14 | .globl relocate_new_kernel |
17 | relocate_new_kernel: | 15 | relocate_new_kernel: |
@@ -20,8 +18,8 @@ relocate_new_kernel: | |||
20 | /* r6 = start_address */ | 18 | /* r6 = start_address */ |
21 | /* r7 = vbr_reg */ | 19 | /* r7 = vbr_reg */ |
22 | 20 | ||
23 | mov.l 10f,r8 /* 4096 */ | 21 | mov.l 10f,r8 /* PAGE_SIZE */ |
24 | mov.l 11f,r9 /* 0xa0000000 */ | 22 | mov.l 11f,r9 /* P2SEG */ |
25 | 23 | ||
26 | /* stack setting */ | 24 | /* stack setting */ |
27 | add r8,r5 | 25 | add r8,r5 |
@@ -32,7 +30,7 @@ relocate_new_kernel: | |||
32 | 0: | 30 | 0: |
33 | mov.l @r4+,r0 /* cmd = *ind++ */ | 31 | mov.l @r4+,r0 /* cmd = *ind++ */ |
34 | 32 | ||
35 | 1: /* addr = (cmd | 0xa0000000) & 0xfffffff0 */ | 33 | 1: /* addr = (cmd | P2SEG) & 0xfffffff0 */ |
36 | mov r0,r2 | 34 | mov r0,r2 |
37 | or r9,r2 | 35 | or r9,r2 |
38 | mov #-16,r1 | 36 | mov #-16,r1 |
@@ -92,7 +90,7 @@ relocate_new_kernel: | |||
92 | 10: | 90 | 10: |
93 | .long PAGE_SIZE | 91 | .long PAGE_SIZE |
94 | 11: | 92 | 11: |
95 | .long 0xa0000000 | 93 | .long P2SEG |
96 | 94 | ||
97 | relocate_new_kernel_end: | 95 | relocate_new_kernel_end: |
98 | 96 | ||
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 36d86f9ac38a..225f9ea5cdd7 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -84,8 +84,7 @@ unsigned long memory_start, memory_end; | |||
84 | 84 | ||
85 | static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE], | 85 | static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE], |
86 | struct sh_machine_vector** mvp, | 86 | struct sh_machine_vector** mvp, |
87 | unsigned long *mv_io_base, | 87 | unsigned long *mv_io_base) |
88 | int *mv_mmio_enable) | ||
89 | { | 88 | { |
90 | char c = ' ', *to = command_line, *from = COMMAND_LINE; | 89 | char c = ' ', *to = command_line, *from = COMMAND_LINE; |
91 | int len = 0; | 90 | int len = 0; |
@@ -112,23 +111,6 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE], | |||
112 | } | 111 | } |
113 | } | 112 | } |
114 | 113 | ||
115 | #ifdef CONFIG_EARLY_PRINTK | ||
116 | if (c == ' ' && !memcmp(from, "earlyprintk=", 12)) { | ||
117 | char *ep_end; | ||
118 | |||
119 | if (to != command_line) | ||
120 | to--; | ||
121 | |||
122 | from += 12; | ||
123 | ep_end = strchr(from, ' '); | ||
124 | |||
125 | setup_early_printk(from); | ||
126 | printk("early console enabled\n"); | ||
127 | |||
128 | from = ep_end; | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | if (c == ' ' && !memcmp(from, "sh_mv=", 6)) { | 114 | if (c == ' ' && !memcmp(from, "sh_mv=", 6)) { |
133 | char* mv_end; | 115 | char* mv_end; |
134 | char* mv_comma; | 116 | char* mv_comma; |
@@ -145,7 +127,6 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE], | |||
145 | int ints[3]; | 127 | int ints[3]; |
146 | get_options(mv_comma+1, ARRAY_SIZE(ints), ints); | 128 | get_options(mv_comma+1, ARRAY_SIZE(ints), ints); |
147 | *mv_io_base = ints[1]; | 129 | *mv_io_base = ints[1]; |
148 | *mv_mmio_enable = ints[2]; | ||
149 | mv_len = mv_comma - from; | 130 | mv_len = mv_comma - from; |
150 | } else { | 131 | } else { |
151 | mv_len = mv_end - from; | 132 | mv_len = mv_end - from; |
@@ -158,6 +139,7 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE], | |||
158 | 139 | ||
159 | *mvp = get_mv_byname(mv_name); | 140 | *mvp = get_mv_byname(mv_name); |
160 | } | 141 | } |
142 | |||
161 | c = *(from++); | 143 | c = *(from++); |
162 | if (!c) | 144 | if (!c) |
163 | break; | 145 | break; |
@@ -177,9 +159,8 @@ static int __init sh_mv_setup(char **cmdline_p) | |||
177 | struct sh_machine_vector *mv = NULL; | 159 | struct sh_machine_vector *mv = NULL; |
178 | char mv_name[MV_NAME_SIZE] = ""; | 160 | char mv_name[MV_NAME_SIZE] = ""; |
179 | unsigned long mv_io_base = 0; | 161 | unsigned long mv_io_base = 0; |
180 | int mv_mmio_enable = 0; | ||
181 | 162 | ||
182 | parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base, &mv_mmio_enable); | 163 | parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base); |
183 | 164 | ||
184 | #ifdef CONFIG_SH_UNKNOWN | 165 | #ifdef CONFIG_SH_UNKNOWN |
185 | if (mv == NULL) { | 166 | if (mv == NULL) { |
@@ -258,6 +239,7 @@ void __init setup_arch(char **cmdline_p) | |||
258 | 239 | ||
259 | sh_mv_setup(cmdline_p); | 240 | sh_mv_setup(cmdline_p); |
260 | 241 | ||
242 | |||
261 | /* | 243 | /* |
262 | * Find the highest page frame number we have available | 244 | * Find the highest page frame number we have available |
263 | */ | 245 | */ |
@@ -305,6 +287,7 @@ void __init setup_arch(char **cmdline_p) | |||
305 | PFN_PHYS(pages)); | 287 | PFN_PHYS(pages)); |
306 | } | 288 | } |
307 | 289 | ||
290 | |||
308 | /* | 291 | /* |
309 | * Reserve the kernel text and | 292 | * Reserve the kernel text and |
310 | * Reserve the bootmem bitmap. We do this in two steps (first step | 293 | * Reserve the bootmem bitmap. We do this in two steps (first step |
@@ -325,15 +308,18 @@ void __init setup_arch(char **cmdline_p) | |||
325 | ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); | 308 | ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); |
326 | if (&__rd_start != &__rd_end) { | 309 | if (&__rd_start != &__rd_end) { |
327 | LOADER_TYPE = 1; | 310 | LOADER_TYPE = 1; |
328 | INITRD_START = PHYSADDR((unsigned long)&__rd_start) - __MEMORY_START; | 311 | INITRD_START = PHYSADDR((unsigned long)&__rd_start) - |
329 | INITRD_SIZE = (unsigned long)&__rd_end - (unsigned long)&__rd_start; | 312 | __MEMORY_START; |
313 | INITRD_SIZE = (unsigned long)&__rd_end - | ||
314 | (unsigned long)&__rd_start; | ||
330 | } | 315 | } |
331 | 316 | ||
332 | if (LOADER_TYPE && INITRD_START) { | 317 | if (LOADER_TYPE && INITRD_START) { |
333 | if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { | 318 | if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { |
334 | reserve_bootmem_node(NODE_DATA(0), INITRD_START+__MEMORY_START, INITRD_SIZE); | 319 | reserve_bootmem_node(NODE_DATA(0), INITRD_START + |
335 | initrd_start = | 320 | __MEMORY_START, INITRD_SIZE); |
336 | INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; | 321 | initrd_start = INITRD_START + PAGE_OFFSET + |
322 | __MEMORY_START; | ||
337 | initrd_end = initrd_start + INITRD_SIZE; | 323 | initrd_end = initrd_start + INITRD_SIZE; |
338 | } else { | 324 | } else { |
339 | printk("initrd extends beyond end of memory " | 325 | printk("initrd extends beyond end of memory " |
@@ -392,6 +378,7 @@ static int __init topology_init(void) | |||
392 | subsys_initcall(topology_init); | 378 | subsys_initcall(topology_init); |
393 | 379 | ||
394 | static const char *cpu_name[] = { | 380 | static const char *cpu_name[] = { |
381 | [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619", | ||
395 | [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300", | 382 | [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300", |
396 | [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", | 383 | [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", |
397 | [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", | 384 | [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", |
@@ -404,6 +391,7 @@ static const char *cpu_name[] = { | |||
404 | [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501", | 391 | [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501", |
405 | [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780", | 392 | [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780", |
406 | [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343", | 393 | [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343", |
394 | [CPU_SH7785] = "SH7785", [CPU_SH7722] = "SH7722", | ||
407 | [CPU_SH_NONE] = "Unknown" | 395 | [CPU_SH_NONE] = "Unknown" |
408 | }; | 396 | }; |
409 | 397 | ||
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index 9daad70bc305..e6106239a0fe 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <asm/delay.h> | 18 | #include <asm/delay.h> |
19 | #include <asm/tlbflush.h> | 19 | #include <asm/tlbflush.h> |
20 | #include <asm/cacheflush.h> | 20 | #include <asm/cacheflush.h> |
21 | #include <asm/checksum.h> | ||
22 | 21 | ||
23 | extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); | 22 | extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); |
24 | extern struct hw_interrupt_type no_irq_type; | 23 | extern struct hw_interrupt_type no_irq_type; |
@@ -71,15 +70,26 @@ DECLARE_EXPORT(__sdivsi3); | |||
71 | DECLARE_EXPORT(__ashrdi3); | 70 | DECLARE_EXPORT(__ashrdi3); |
72 | DECLARE_EXPORT(__ashldi3); | 71 | DECLARE_EXPORT(__ashldi3); |
73 | DECLARE_EXPORT(__lshrdi3); | 72 | DECLARE_EXPORT(__lshrdi3); |
74 | DECLARE_EXPORT(__movstr); | ||
75 | DECLARE_EXPORT(__movstrSI16); | 73 | DECLARE_EXPORT(__movstrSI16); |
76 | 74 | #if __GNUC__ == 4 | |
77 | EXPORT_SYMBOL(strcpy); | 75 | DECLARE_EXPORT(__movmem); |
76 | #else | ||
77 | DECLARE_EXPORT(__movstr); | ||
78 | #endif | ||
78 | 79 | ||
79 | #ifdef CONFIG_CPU_SH4 | 80 | #ifdef CONFIG_CPU_SH4 |
81 | #if __GNUC__ == 4 | ||
82 | DECLARE_EXPORT(__movmem_i4_even); | ||
83 | DECLARE_EXPORT(__movmem_i4_odd); | ||
84 | DECLARE_EXPORT(__movmemSI12_i4); | ||
85 | DECLARE_EXPORT(__sdivsi3_i4i); | ||
86 | DECLARE_EXPORT(__udiv_qrnnd_16); | ||
87 | DECLARE_EXPORT(__udivsi3_i4i); | ||
88 | #else /* GCC 3.x */ | ||
80 | DECLARE_EXPORT(__movstr_i4_even); | 89 | DECLARE_EXPORT(__movstr_i4_even); |
81 | DECLARE_EXPORT(__movstr_i4_odd); | 90 | DECLARE_EXPORT(__movstr_i4_odd); |
82 | DECLARE_EXPORT(__movstrSI12_i4); | 91 | DECLARE_EXPORT(__movstrSI12_i4); |
92 | #endif /* __GNUC__ == 4 */ | ||
83 | #endif | 93 | #endif |
84 | 94 | ||
85 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) | 95 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) |
@@ -102,10 +112,6 @@ EXPORT_SYMBOL(__down_trylock); | |||
102 | EXPORT_SYMBOL(synchronize_irq); | 112 | EXPORT_SYMBOL(synchronize_irq); |
103 | #endif | 113 | #endif |
104 | 114 | ||
105 | #ifdef CONFIG_PM | ||
106 | EXPORT_SYMBOL(pm_suspend); | ||
107 | #endif | ||
108 | |||
109 | EXPORT_SYMBOL(csum_partial); | 115 | EXPORT_SYMBOL(csum_partial); |
110 | #ifdef CONFIG_IPV6 | 116 | #ifdef CONFIG_IPV6 |
111 | EXPORT_SYMBOL(csum_ipv6_magic); | 117 | EXPORT_SYMBOL(csum_ipv6_magic); |
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 5213f5bc6ce0..379c88bf5d9a 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/elf.h> | 23 | #include <linux/elf.h> |
24 | #include <linux/personality.h> | 24 | #include <linux/personality.h> |
25 | #include <linux/binfmts.h> | 25 | #include <linux/binfmts.h> |
26 | #include <linux/freezer.h> | ||
26 | 27 | ||
27 | #include <asm/ucontext.h> | 28 | #include <asm/ucontext.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
@@ -37,7 +38,7 @@ | |||
37 | asmlinkage int | 38 | asmlinkage int |
38 | sys_sigsuspend(old_sigset_t mask, | 39 | sys_sigsuspend(old_sigset_t mask, |
39 | unsigned long r5, unsigned long r6, unsigned long r7, | 40 | unsigned long r5, unsigned long r6, unsigned long r7, |
40 | struct pt_regs regs) | 41 | struct pt_regs __regs) |
41 | { | 42 | { |
42 | mask &= _BLOCKABLE; | 43 | mask &= _BLOCKABLE; |
43 | spin_lock_irq(¤t->sighand->siglock); | 44 | spin_lock_irq(¤t->sighand->siglock); |
@@ -52,7 +53,7 @@ sys_sigsuspend(old_sigset_t mask, | |||
52 | return -ERESTARTNOHAND; | 53 | return -ERESTARTNOHAND; |
53 | } | 54 | } |
54 | 55 | ||
55 | asmlinkage int | 56 | asmlinkage int |
56 | sys_sigaction(int sig, const struct old_sigaction __user *act, | 57 | sys_sigaction(int sig, const struct old_sigaction __user *act, |
57 | struct old_sigaction __user *oact) | 58 | struct old_sigaction __user *oact) |
58 | { | 59 | { |
@@ -87,9 +88,11 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
87 | asmlinkage int | 88 | asmlinkage int |
88 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 89 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
89 | unsigned long r6, unsigned long r7, | 90 | unsigned long r6, unsigned long r7, |
90 | struct pt_regs regs) | 91 | struct pt_regs __regs) |
91 | { | 92 | { |
92 | return do_sigaltstack(uss, uoss, regs.regs[15]); | 93 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
94 | |||
95 | return do_sigaltstack(uss, uoss, regs->regs[15]); | ||
93 | } | 96 | } |
94 | 97 | ||
95 | 98 | ||
@@ -98,7 +101,11 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
98 | */ | 101 | */ |
99 | 102 | ||
100 | #define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ | 103 | #define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ |
101 | #define TRAP16 0xc310 /* Syscall w/no args (NR in R3) */ | 104 | #if defined(CONFIG_CPU_SH2) |
105 | #define TRAP_NOARG 0xc320 /* Syscall w/no args (NR in R3) */ | ||
106 | #else | ||
107 | #define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) */ | ||
108 | #endif | ||
102 | #define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ | 109 | #define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ |
103 | 110 | ||
104 | struct sigframe | 111 | struct sigframe |
@@ -194,9 +201,10 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p | |||
194 | 201 | ||
195 | asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, | 202 | asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, |
196 | unsigned long r6, unsigned long r7, | 203 | unsigned long r6, unsigned long r7, |
197 | struct pt_regs regs) | 204 | struct pt_regs __regs) |
198 | { | 205 | { |
199 | struct sigframe __user *frame = (struct sigframe __user *)regs.regs[15]; | 206 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
207 | struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15]; | ||
200 | sigset_t set; | 208 | sigset_t set; |
201 | int r0; | 209 | int r0; |
202 | 210 | ||
@@ -216,7 +224,7 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, | |||
216 | recalc_sigpending(); | 224 | recalc_sigpending(); |
217 | spin_unlock_irq(¤t->sighand->siglock); | 225 | spin_unlock_irq(¤t->sighand->siglock); |
218 | 226 | ||
219 | if (restore_sigcontext(®s, &frame->sc, &r0)) | 227 | if (restore_sigcontext(regs, &frame->sc, &r0)) |
220 | goto badframe; | 228 | goto badframe; |
221 | return r0; | 229 | return r0; |
222 | 230 | ||
@@ -227,9 +235,10 @@ badframe: | |||
227 | 235 | ||
228 | asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, | 236 | asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, |
229 | unsigned long r6, unsigned long r7, | 237 | unsigned long r6, unsigned long r7, |
230 | struct pt_regs regs) | 238 | struct pt_regs __regs) |
231 | { | 239 | { |
232 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.regs[15]; | 240 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
241 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15]; | ||
233 | sigset_t set; | 242 | sigset_t set; |
234 | stack_t st; | 243 | stack_t st; |
235 | int r0; | 244 | int r0; |
@@ -246,14 +255,14 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, | |||
246 | recalc_sigpending(); | 255 | recalc_sigpending(); |
247 | spin_unlock_irq(¤t->sighand->siglock); | 256 | spin_unlock_irq(¤t->sighand->siglock); |
248 | 257 | ||
249 | if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &r0)) | 258 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) |
250 | goto badframe; | 259 | goto badframe; |
251 | 260 | ||
252 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) | 261 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) |
253 | goto badframe; | 262 | goto badframe; |
254 | /* It is more difficult to avoid calling this function than to | 263 | /* It is more difficult to avoid calling this function than to |
255 | call it and ignore errors. */ | 264 | call it and ignore errors. */ |
256 | do_sigaltstack(&st, NULL, regs.regs[15]); | 265 | do_sigaltstack(&st, NULL, regs->regs[15]); |
257 | 266 | ||
258 | return r0; | 267 | return r0; |
259 | 268 | ||
@@ -350,7 +359,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
350 | } else { | 359 | } else { |
351 | /* Generate return code (system call to sigreturn) */ | 360 | /* Generate return code (system call to sigreturn) */ |
352 | err |= __put_user(MOVW(7), &frame->retcode[0]); | 361 | err |= __put_user(MOVW(7), &frame->retcode[0]); |
353 | err |= __put_user(TRAP16, &frame->retcode[1]); | 362 | err |= __put_user(TRAP_NOARG, &frame->retcode[1]); |
354 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); | 363 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); |
355 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); | 364 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); |
356 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); | 365 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); |
@@ -430,7 +439,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
430 | } else { | 439 | } else { |
431 | /* Generate return code (system call to rt_sigreturn) */ | 440 | /* Generate return code (system call to rt_sigreturn) */ |
432 | err |= __put_user(MOVW(7), &frame->retcode[0]); | 441 | err |= __put_user(MOVW(7), &frame->retcode[0]); |
433 | err |= __put_user(TRAP16, &frame->retcode[1]); | 442 | err |= __put_user(TRAP_NOARG, &frame->retcode[1]); |
434 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); | 443 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); |
435 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); | 444 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); |
436 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); | 445 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); |
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c new file mode 100644 index 000000000000..0d5268afe80f --- /dev/null +++ b/arch/sh/kernel/stacktrace.c | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/stacktrace.c | ||
3 | * | ||
4 | * Stack trace management functions | ||
5 | * | ||
6 | * Copyright (C) 2006 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/stacktrace.h> | ||
14 | #include <linux/thread_info.h> | ||
15 | #include <asm/ptrace.h> | ||
16 | |||
17 | /* | ||
18 | * Save stack-backtrace addresses into a stack_trace buffer. | ||
19 | */ | ||
20 | void save_stack_trace(struct stack_trace *trace, struct task_struct *task) | ||
21 | { | ||
22 | unsigned long *sp; | ||
23 | |||
24 | if (!task) | ||
25 | task = current; | ||
26 | if (task == current) | ||
27 | sp = (unsigned long *)current_stack_pointer; | ||
28 | else | ||
29 | sp = (unsigned long *)task->thread.sp; | ||
30 | |||
31 | while (!kstack_end(sp)) { | ||
32 | unsigned long addr = *sp++; | ||
33 | |||
34 | if (__kernel_text_address(addr)) { | ||
35 | if (trace->skip > 0) | ||
36 | trace->skip--; | ||
37 | else | ||
38 | trace->entries[trace->nr_entries++] = addr; | ||
39 | if (trace->nr_entries >= trace->max_entries) | ||
40 | break; | ||
41 | } | ||
42 | } | ||
43 | } | ||
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 8fde95001c34..e18f183e1035 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c | |||
@@ -33,14 +33,15 @@ | |||
33 | */ | 33 | */ |
34 | asmlinkage int sys_pipe(unsigned long r4, unsigned long r5, | 34 | asmlinkage int sys_pipe(unsigned long r4, unsigned long r5, |
35 | unsigned long r6, unsigned long r7, | 35 | unsigned long r6, unsigned long r7, |
36 | struct pt_regs regs) | 36 | struct pt_regs __regs) |
37 | { | 37 | { |
38 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
38 | int fd[2]; | 39 | int fd[2]; |
39 | int error; | 40 | int error; |
40 | 41 | ||
41 | error = do_pipe(fd); | 42 | error = do_pipe(fd); |
42 | if (!error) { | 43 | if (!error) { |
43 | regs.regs[1] = fd[1]; | 44 | regs->regs[1] = fd[1]; |
44 | return fd[0]; | 45 | return fd[0]; |
45 | } | 46 | } |
46 | return error; | 47 | return error; |
@@ -50,6 +51,7 @@ unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ | |||
50 | 51 | ||
51 | EXPORT_SYMBOL(shm_align_mask); | 52 | EXPORT_SYMBOL(shm_align_mask); |
52 | 53 | ||
54 | #ifdef CONFIG_MMU | ||
53 | /* | 55 | /* |
54 | * To avoid cache aliases, we map the shared page with same color. | 56 | * To avoid cache aliases, we map the shared page with same color. |
55 | */ | 57 | */ |
@@ -135,6 +137,7 @@ full_search: | |||
135 | addr = COLOUR_ALIGN(addr, pgoff); | 137 | addr = COLOUR_ALIGN(addr, pgoff); |
136 | } | 138 | } |
137 | } | 139 | } |
140 | #endif /* CONFIG_MMU */ | ||
138 | 141 | ||
139 | static inline long | 142 | static inline long |
140 | do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, | 143 | do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, |
@@ -311,6 +314,12 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, | |||
311 | #endif | 314 | #endif |
312 | } | 315 | } |
313 | 316 | ||
317 | #if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A) | ||
318 | #define SYSCALL_ARG3 "trapa #0x23" | ||
319 | #else | ||
320 | #define SYSCALL_ARG3 "trapa #0x13" | ||
321 | #endif | ||
322 | |||
314 | /* | 323 | /* |
315 | * Do a system call from kernel instead of calling sys_execve so we | 324 | * Do a system call from kernel instead of calling sys_execve so we |
316 | * end up with proper pt_regs. | 325 | * end up with proper pt_regs. |
@@ -321,7 +330,7 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | |||
321 | register long __sc4 __asm__ ("r4") = (long) filename; | 330 | register long __sc4 __asm__ ("r4") = (long) filename; |
322 | register long __sc5 __asm__ ("r5") = (long) argv; | 331 | register long __sc5 __asm__ ("r5") = (long) argv; |
323 | register long __sc6 __asm__ ("r6") = (long) envp; | 332 | register long __sc6 __asm__ ("r6") = (long) envp; |
324 | __asm__ __volatile__ ("trapa #0x13" : "=z" (__sc0) | 333 | __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0) |
325 | : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) | 334 | : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) |
326 | : "memory"); | 335 | : "memory"); |
327 | return __sc0; | 336 | return __sc0; |
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S index 768334e95075..ca81976e9e34 100644 --- a/arch/sh/kernel/syscalls.S +++ b/arch/sh/kernel/syscalls.S | |||
@@ -351,3 +351,6 @@ ENTRY(sys_call_table) | |||
351 | .long sys_sync_file_range | 351 | .long sys_sync_file_range |
352 | .long sys_tee /* 315 */ | 352 | .long sys_tee /* 315 */ |
353 | .long sys_vmsplice | 353 | .long sys_vmsplice |
354 | .long sys_move_pages | ||
355 | .long sys_getcpu | ||
356 | .long sys_epoll_pwait | ||
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 57e708d7b52d..c206c9504c4b 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/profile.h> | 15 | #include <linux/profile.h> |
16 | #include <linux/timex.h> | ||
17 | #include <linux/sched.h> | ||
16 | #include <asm/clock.h> | 18 | #include <asm/clock.h> |
17 | #include <asm/rtc.h> | 19 | #include <asm/rtc.h> |
18 | #include <asm/timer.h> | 20 | #include <asm/timer.h> |
@@ -50,15 +52,20 @@ unsigned long long __attribute__ ((weak)) sched_clock(void) | |||
50 | #ifndef CONFIG_GENERIC_TIME | 52 | #ifndef CONFIG_GENERIC_TIME |
51 | void do_gettimeofday(struct timeval *tv) | 53 | void do_gettimeofday(struct timeval *tv) |
52 | { | 54 | { |
55 | unsigned long flags; | ||
53 | unsigned long seq; | 56 | unsigned long seq; |
54 | unsigned long usec, sec; | 57 | unsigned long usec, sec; |
55 | 58 | ||
56 | do { | 59 | do { |
57 | seq = read_seqbegin(&xtime_lock); | 60 | /* |
61 | * Turn off IRQs when grabbing xtime_lock, so that | ||
62 | * the sys_timer get_offset code doesn't have to handle it. | ||
63 | */ | ||
64 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | ||
58 | usec = get_timer_offset(); | 65 | usec = get_timer_offset(); |
59 | sec = xtime.tv_sec; | 66 | sec = xtime.tv_sec; |
60 | usec += xtime.tv_nsec / 1000; | 67 | usec += xtime.tv_nsec / NSEC_PER_USEC; |
61 | } while (read_seqretry(&xtime_lock, seq)); | 68 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); |
62 | 69 | ||
63 | while (usec >= 1000000) { | 70 | while (usec >= 1000000) { |
64 | usec -= 1000000; | 71 | usec -= 1000000; |
@@ -85,7 +92,7 @@ int do_settimeofday(struct timespec *tv) | |||
85 | * wall time. Discover what correction gettimeofday() would have | 92 | * wall time. Discover what correction gettimeofday() would have |
86 | * made, and then undo it! | 93 | * made, and then undo it! |
87 | */ | 94 | */ |
88 | nsec -= 1000 * get_timer_offset(); | 95 | nsec -= get_timer_offset() * NSEC_PER_USEC; |
89 | 96 | ||
90 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | 97 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); |
91 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | 98 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); |
@@ -169,6 +176,108 @@ static struct sysdev_class timer_sysclass = { | |||
169 | .resume = timer_resume, | 176 | .resume = timer_resume, |
170 | }; | 177 | }; |
171 | 178 | ||
179 | #ifdef CONFIG_NO_IDLE_HZ | ||
180 | static int timer_dyn_tick_enable(void) | ||
181 | { | ||
182 | struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; | ||
183 | unsigned long flags; | ||
184 | int ret = -ENODEV; | ||
185 | |||
186 | if (dyn_tick) { | ||
187 | spin_lock_irqsave(&dyn_tick->lock, flags); | ||
188 | ret = 0; | ||
189 | if (!(dyn_tick->state & DYN_TICK_ENABLED)) { | ||
190 | ret = dyn_tick->enable(); | ||
191 | |||
192 | if (ret == 0) | ||
193 | dyn_tick->state |= DYN_TICK_ENABLED; | ||
194 | } | ||
195 | spin_unlock_irqrestore(&dyn_tick->lock, flags); | ||
196 | } | ||
197 | |||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | static int timer_dyn_tick_disable(void) | ||
202 | { | ||
203 | struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; | ||
204 | unsigned long flags; | ||
205 | int ret = -ENODEV; | ||
206 | |||
207 | if (dyn_tick) { | ||
208 | spin_lock_irqsave(&dyn_tick->lock, flags); | ||
209 | ret = 0; | ||
210 | if (dyn_tick->state & DYN_TICK_ENABLED) { | ||
211 | ret = dyn_tick->disable(); | ||
212 | |||
213 | if (ret == 0) | ||
214 | dyn_tick->state &= ~DYN_TICK_ENABLED; | ||
215 | } | ||
216 | spin_unlock_irqrestore(&dyn_tick->lock, flags); | ||
217 | } | ||
218 | |||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Reprogram the system timer for at least the calculated time interval. | ||
224 | * This function should be called from the idle thread with IRQs disabled, | ||
225 | * immediately before sleeping. | ||
226 | */ | ||
227 | void timer_dyn_reprogram(void) | ||
228 | { | ||
229 | struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; | ||
230 | unsigned long next, seq, flags; | ||
231 | |||
232 | if (!dyn_tick) | ||
233 | return; | ||
234 | |||
235 | spin_lock_irqsave(&dyn_tick->lock, flags); | ||
236 | if (dyn_tick->state & DYN_TICK_ENABLED) { | ||
237 | next = next_timer_interrupt(); | ||
238 | do { | ||
239 | seq = read_seqbegin(&xtime_lock); | ||
240 | dyn_tick->reprogram(next - jiffies); | ||
241 | } while (read_seqretry(&xtime_lock, seq)); | ||
242 | } | ||
243 | spin_unlock_irqrestore(&dyn_tick->lock, flags); | ||
244 | } | ||
245 | |||
246 | static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf) | ||
247 | { | ||
248 | return sprintf(buf, "%i\n", | ||
249 | (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1); | ||
250 | } | ||
251 | |||
252 | static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf, | ||
253 | size_t count) | ||
254 | { | ||
255 | unsigned int enable = simple_strtoul(buf, NULL, 2); | ||
256 | |||
257 | if (enable) | ||
258 | timer_dyn_tick_enable(); | ||
259 | else | ||
260 | timer_dyn_tick_disable(); | ||
261 | |||
262 | return count; | ||
263 | } | ||
264 | static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick); | ||
265 | |||
266 | /* | ||
267 | * dyntick=enable|disable | ||
268 | */ | ||
269 | static char dyntick_str[4] __initdata = ""; | ||
270 | |||
271 | static int __init dyntick_setup(char *str) | ||
272 | { | ||
273 | if (str) | ||
274 | strlcpy(dyntick_str, str, sizeof(dyntick_str)); | ||
275 | return 1; | ||
276 | } | ||
277 | |||
278 | __setup("dyntick=", dyntick_setup); | ||
279 | #endif | ||
280 | |||
172 | static int __init timer_init_sysfs(void) | 281 | static int __init timer_init_sysfs(void) |
173 | { | 282 | { |
174 | int ret = sysdev_class_register(&timer_sysclass); | 283 | int ret = sysdev_class_register(&timer_sysclass); |
@@ -176,7 +285,22 @@ static int __init timer_init_sysfs(void) | |||
176 | return ret; | 285 | return ret; |
177 | 286 | ||
178 | sys_timer->dev.cls = &timer_sysclass; | 287 | sys_timer->dev.cls = &timer_sysclass; |
179 | return sysdev_register(&sys_timer->dev); | 288 | ret = sysdev_register(&sys_timer->dev); |
289 | |||
290 | #ifdef CONFIG_NO_IDLE_HZ | ||
291 | if (ret == 0 && sys_timer->dyn_tick) { | ||
292 | ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick); | ||
293 | |||
294 | /* | ||
295 | * Turn on dynamic tick after calibrate delay | ||
296 | * for correct bogomips | ||
297 | */ | ||
298 | if (ret == 0 && dyntick_str[0] == 'e') | ||
299 | ret = timer_dyn_tick_enable(); | ||
300 | } | ||
301 | #endif | ||
302 | |||
303 | return ret; | ||
180 | } | 304 | } |
181 | device_initcall(timer_init_sysfs); | 305 | device_initcall(timer_init_sysfs); |
182 | 306 | ||
@@ -200,6 +324,11 @@ void __init time_init(void) | |||
200 | sys_timer = get_sys_timer(); | 324 | sys_timer = get_sys_timer(); |
201 | printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); | 325 | printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); |
202 | 326 | ||
327 | #ifdef CONFIG_NO_IDLE_HZ | ||
328 | if (sys_timer->dyn_tick) | ||
329 | spin_lock_init(&sys_timer->dyn_tick->lock); | ||
330 | #endif | ||
331 | |||
203 | #if defined(CONFIG_SH_KGDB) | 332 | #if defined(CONFIG_SH_KGDB) |
204 | /* | 333 | /* |
205 | * Set up kgdb as requested. We do it here because the serial | 334 | * Set up kgdb as requested. We do it here because the serial |
diff --git a/arch/sh/kernel/timers/Makefile b/arch/sh/kernel/timers/Makefile index 151a6a304cec..bcf244ff6a12 100644 --- a/arch/sh/kernel/timers/Makefile +++ b/arch/sh/kernel/timers/Makefile | |||
@@ -5,4 +5,6 @@ | |||
5 | obj-y := timer.o | 5 | obj-y := timer.o |
6 | 6 | ||
7 | obj-$(CONFIG_SH_TMU) += timer-tmu.o | 7 | obj-$(CONFIG_SH_TMU) += timer-tmu.o |
8 | obj-$(CONFIG_SH_MTU2) += timer-mtu2.o | ||
9 | obj-$(CONFIG_SH_CMT) += timer-cmt.o | ||
8 | 10 | ||
diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c new file mode 100644 index 000000000000..a574b93a4e7b --- /dev/null +++ b/arch/sh/kernel/timers/timer-cmt.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/timers/timer-cmt.c - CMT Timer Support | ||
3 | * | ||
4 | * Copyright (C) 2005 Yoshinori Sato | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/seqlock.h> | ||
15 | #include <asm/timer.h> | ||
16 | #include <asm/rtc.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/clock.h> | ||
20 | |||
21 | #if defined(CONFIG_CPU_SUBTYPE_SH7619) | ||
22 | #define CMT_CMSTR 0xf84a0070 | ||
23 | #define CMT_CMCSR_0 0xf84a0072 | ||
24 | #define CMT_CMCNT_0 0xf84a0074 | ||
25 | #define CMT_CMCOR_0 0xf84a0076 | ||
26 | #define CMT_CMCSR_1 0xf84a0078 | ||
27 | #define CMT_CMCNT_1 0xf84a007a | ||
28 | #define CMT_CMCOR_1 0xf84a007c | ||
29 | |||
30 | #define STBCR3 0xf80a0000 | ||
31 | #define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0) | ||
32 | #define CMT_CMCSR_INIT 0x0040 | ||
33 | #define CMT_CMCSR_CALIB 0x0000 | ||
34 | #elif defined(CONFIG_CPU_SUBTYPE_SH7206) | ||
35 | #define CMT_CMSTR 0xfffec000 | ||
36 | #define CMT_CMCSR_0 0xfffec002 | ||
37 | #define CMT_CMCNT_0 0xfffec004 | ||
38 | #define CMT_CMCOR_0 0xfffec006 | ||
39 | |||
40 | #define STBCR4 0xfffe040c | ||
41 | #define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR4) & ~0x04, STBCR4); } while(0) | ||
42 | #define CMT_CMCSR_INIT 0x0040 | ||
43 | #define CMT_CMCSR_CALIB 0x0000 | ||
44 | #else | ||
45 | #error "Unknown CPU SUBTYPE" | ||
46 | #endif | ||
47 | |||
48 | static unsigned long cmt_timer_get_offset(void) | ||
49 | { | ||
50 | int count; | ||
51 | static unsigned short count_p = 0xffff; /* for the first call after boot */ | ||
52 | static unsigned long jiffies_p = 0; | ||
53 | |||
54 | /* | ||
55 | * cache volatile jiffies temporarily; we have IRQs turned off. | ||
56 | */ | ||
57 | unsigned long jiffies_t; | ||
58 | |||
59 | /* timer count may underflow right here */ | ||
60 | count = ctrl_inw(CMT_CMCOR_0); | ||
61 | count -= ctrl_inw(CMT_CMCNT_0); | ||
62 | |||
63 | jiffies_t = jiffies; | ||
64 | |||
65 | /* | ||
66 | * avoiding timer inconsistencies (they are rare, but they happen)... | ||
67 | * there is one kind of problem that must be avoided here: | ||
68 | * 1. the timer counter underflows | ||
69 | */ | ||
70 | |||
71 | if (jiffies_t == jiffies_p) { | ||
72 | if (count > count_p) { | ||
73 | /* the nutcase */ | ||
74 | if (ctrl_inw(CMT_CMCSR_0) & 0x80) { /* Check CMF bit */ | ||
75 | count -= LATCH; | ||
76 | } else { | ||
77 | printk("%s (): hardware timer problem?\n", | ||
78 | __FUNCTION__); | ||
79 | } | ||
80 | } | ||
81 | } else | ||
82 | jiffies_p = jiffies_t; | ||
83 | |||
84 | count_p = count; | ||
85 | |||
86 | count = ((LATCH-1) - count) * TICK_SIZE; | ||
87 | count = (count + LATCH/2) / LATCH; | ||
88 | |||
89 | return count; | ||
90 | } | ||
91 | |||
92 | static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id) | ||
93 | { | ||
94 | unsigned long timer_status; | ||
95 | |||
96 | /* Clear CMF bit */ | ||
97 | timer_status = ctrl_inw(CMT_CMCSR_0); | ||
98 | timer_status &= ~0x80; | ||
99 | ctrl_outw(timer_status, CMT_CMCSR_0); | ||
100 | |||
101 | /* | ||
102 | * Here we are in the timer irq handler. We just have irqs locally | ||
103 | * disabled but we don't know if the timer_bh is running on the other | ||
104 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
105 | * the irq version of write_lock because as just said we have irq | ||
106 | * locally disabled. -arca | ||
107 | */ | ||
108 | write_seqlock(&xtime_lock); | ||
109 | handle_timer_tick(); | ||
110 | write_sequnlock(&xtime_lock); | ||
111 | |||
112 | return IRQ_HANDLED; | ||
113 | } | ||
114 | |||
115 | static struct irqaction cmt_irq = { | ||
116 | .name = "timer", | ||
117 | .handler = cmt_timer_interrupt, | ||
118 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
119 | .mask = CPU_MASK_NONE, | ||
120 | }; | ||
121 | |||
122 | static void cmt_clk_init(struct clk *clk) | ||
123 | { | ||
124 | u8 divisor = CMT_CMCSR_INIT & 0x3; | ||
125 | ctrl_inw(CMT_CMCSR_0); | ||
126 | ctrl_outw(CMT_CMCSR_INIT, CMT_CMCSR_0); | ||
127 | clk->parent = clk_get(NULL, "module_clk"); | ||
128 | clk->rate = clk->parent->rate / (8 << (divisor << 1)); | ||
129 | } | ||
130 | |||
131 | static void cmt_clk_recalc(struct clk *clk) | ||
132 | { | ||
133 | u8 divisor = ctrl_inw(CMT_CMCSR_0) & 0x3; | ||
134 | clk->rate = clk->parent->rate / (8 << (divisor << 1)); | ||
135 | } | ||
136 | |||
137 | static struct clk_ops cmt_clk_ops = { | ||
138 | .init = cmt_clk_init, | ||
139 | .recalc = cmt_clk_recalc, | ||
140 | }; | ||
141 | |||
142 | static struct clk cmt0_clk = { | ||
143 | .name = "cmt0_clk", | ||
144 | .ops = &cmt_clk_ops, | ||
145 | }; | ||
146 | |||
147 | static int cmt_timer_start(void) | ||
148 | { | ||
149 | ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int cmt_timer_stop(void) | ||
154 | { | ||
155 | ctrl_outw(ctrl_inw(CMT_CMSTR) & ~0x01, CMT_CMSTR); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int cmt_timer_init(void) | ||
160 | { | ||
161 | unsigned long interval; | ||
162 | |||
163 | cmt_clock_enable(); | ||
164 | |||
165 | setup_irq(CONFIG_SH_TIMER_IRQ, &cmt_irq); | ||
166 | |||
167 | cmt0_clk.parent = clk_get(NULL, "module_clk"); | ||
168 | |||
169 | cmt_timer_stop(); | ||
170 | |||
171 | interval = cmt0_clk.parent->rate / 8 / HZ; | ||
172 | printk(KERN_INFO "Interval = %ld\n", interval); | ||
173 | |||
174 | ctrl_outw(interval, CMT_CMCOR_0); | ||
175 | |||
176 | clk_register(&cmt0_clk); | ||
177 | clk_enable(&cmt0_clk); | ||
178 | |||
179 | cmt_timer_start(); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | struct sys_timer_ops cmt_timer_ops = { | ||
185 | .init = cmt_timer_init, | ||
186 | .start = cmt_timer_start, | ||
187 | .stop = cmt_timer_stop, | ||
188 | #ifndef CONFIG_GENERIC_TIME | ||
189 | .get_offset = cmt_timer_get_offset, | ||
190 | #endif | ||
191 | }; | ||
192 | |||
193 | struct sys_timer cmt_timer = { | ||
194 | .name = "cmt", | ||
195 | .ops = &cmt_timer_ops, | ||
196 | }; | ||
diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c new file mode 100644 index 000000000000..fffcd1c09873 --- /dev/null +++ b/arch/sh/kernel/timers/timer-mtu2.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/timers/timer-mtu2.c - MTU2 Timer Support | ||
3 | * | ||
4 | * Copyright (C) 2005 Paul Mundt | ||
5 | * | ||
6 | * Based off of arch/sh/kernel/timers/timer-tmu.c | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/seqlock.h> | ||
16 | #include <asm/timer.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/clock.h> | ||
20 | |||
21 | /* | ||
22 | * We use channel 1 for our lowly system timer. Channel 2 would be the other | ||
23 | * likely candidate, but we leave it alone as it has higher divisors that | ||
24 | * would be of more use to other more interesting applications. | ||
25 | * | ||
26 | * TODO: Presently we only implement a 16-bit single-channel system timer. | ||
27 | * However, we can implement channel cascade if we go the overflow route and | ||
28 | * get away with using 2 MTU2 channels as a 32-bit timer. | ||
29 | */ | ||
30 | #define MTU2_TSTR 0xfffe4280 | ||
31 | #define MTU2_TCR_1 0xfffe4380 | ||
32 | #define MTU2_TMDR_1 0xfffe4381 | ||
33 | #define MTU2_TIOR_1 0xfffe4382 | ||
34 | #define MTU2_TIER_1 0xfffe4384 | ||
35 | #define MTU2_TSR_1 0xfffe4385 | ||
36 | #define MTU2_TCNT_1 0xfffe4386 /* 16-bit counter */ | ||
37 | #define MTU2_TGRA_1 0xfffe438a | ||
38 | |||
39 | #define STBCR3 0xfffe0408 | ||
40 | |||
41 | #define MTU2_TSTR_CST1 (1 << 1) /* Counter Start 1 */ | ||
42 | |||
43 | #define MTU2_TSR_TGFA (1 << 0) /* GRA compare match */ | ||
44 | |||
45 | #define MTU2_TIER_TGIEA (1 << 0) /* GRA compare match interrupt enable */ | ||
46 | |||
47 | #define MTU2_TCR_INIT 0x22 | ||
48 | |||
49 | #define MTU2_TCR_CALIB 0x00 | ||
50 | |||
51 | static unsigned long mtu2_timer_get_offset(void) | ||
52 | { | ||
53 | int count; | ||
54 | static int count_p = 0x7fff; /* for the first call after boot */ | ||
55 | static unsigned long jiffies_p = 0; | ||
56 | |||
57 | /* | ||
58 | * cache volatile jiffies temporarily; we have IRQs turned off. | ||
59 | */ | ||
60 | unsigned long jiffies_t; | ||
61 | |||
62 | /* timer count may underflow right here */ | ||
63 | count = ctrl_inw(MTU2_TCNT_1); /* read the latched count */ | ||
64 | |||
65 | jiffies_t = jiffies; | ||
66 | |||
67 | /* | ||
68 | * avoiding timer inconsistencies (they are rare, but they happen)... | ||
69 | * there is one kind of problem that must be avoided here: | ||
70 | * 1. the timer counter underflows | ||
71 | */ | ||
72 | |||
73 | if (jiffies_t == jiffies_p) { | ||
74 | if (count > count_p) { | ||
75 | if (ctrl_inb(MTU2_TSR_1) & MTU2_TSR_TGFA) { | ||
76 | count -= LATCH; | ||
77 | } else { | ||
78 | printk("%s (): hardware timer problem?\n", | ||
79 | __FUNCTION__); | ||
80 | } | ||
81 | } | ||
82 | } else | ||
83 | jiffies_p = jiffies_t; | ||
84 | |||
85 | count_p = count; | ||
86 | |||
87 | count = ((LATCH-1) - count) * TICK_SIZE; | ||
88 | count = (count + LATCH/2) / LATCH; | ||
89 | |||
90 | return count; | ||
91 | } | ||
92 | |||
93 | static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id) | ||
94 | { | ||
95 | unsigned long timer_status; | ||
96 | |||
97 | /* Clear TGFA bit */ | ||
98 | timer_status = ctrl_inb(MTU2_TSR_1); | ||
99 | timer_status &= ~MTU2_TSR_TGFA; | ||
100 | ctrl_outb(timer_status, MTU2_TSR_1); | ||
101 | |||
102 | /* Do timer tick */ | ||
103 | write_seqlock(&xtime_lock); | ||
104 | handle_timer_tick(); | ||
105 | write_sequnlock(&xtime_lock); | ||
106 | |||
107 | return IRQ_HANDLED; | ||
108 | } | ||
109 | |||
110 | static struct irqaction mtu2_irq = { | ||
111 | .name = "timer", | ||
112 | .handler = mtu2_timer_interrupt, | ||
113 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
114 | .mask = CPU_MASK_NONE, | ||
115 | }; | ||
116 | |||
117 | static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 }; | ||
118 | |||
119 | static void mtu2_clk_init(struct clk *clk) | ||
120 | { | ||
121 | u8 idx = MTU2_TCR_INIT & 0x7; | ||
122 | |||
123 | clk->rate = clk->parent->rate / divisors[idx]; | ||
124 | /* Start TCNT counting */ | ||
125 | ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR); | ||
126 | |||
127 | } | ||
128 | |||
129 | static void mtu2_clk_recalc(struct clk *clk) | ||
130 | { | ||
131 | u8 idx = ctrl_inb(MTU2_TCR_1) & 0x7; | ||
132 | clk->rate = clk->parent->rate / divisors[idx]; | ||
133 | } | ||
134 | |||
135 | static struct clk_ops mtu2_clk_ops = { | ||
136 | .init = mtu2_clk_init, | ||
137 | .recalc = mtu2_clk_recalc, | ||
138 | }; | ||
139 | |||
140 | static struct clk mtu2_clk1 = { | ||
141 | .name = "mtu2_clk1", | ||
142 | .ops = &mtu2_clk_ops, | ||
143 | }; | ||
144 | |||
145 | static int mtu2_timer_start(void) | ||
146 | { | ||
147 | ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR); | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int mtu2_timer_stop(void) | ||
152 | { | ||
153 | ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR); | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int mtu2_timer_init(void) | ||
158 | { | ||
159 | u8 tmp; | ||
160 | unsigned long interval; | ||
161 | |||
162 | setup_irq(CONFIG_SH_TIMER_IRQ, &mtu2_irq); | ||
163 | |||
164 | mtu2_clk1.parent = clk_get(NULL, "module_clk"); | ||
165 | |||
166 | ctrl_outb(ctrl_inb(STBCR3) & (~0x20), STBCR3); | ||
167 | |||
168 | /* Normal operation */ | ||
169 | ctrl_outb(0, MTU2_TMDR_1); | ||
170 | ctrl_outb(MTU2_TCR_INIT, MTU2_TCR_1); | ||
171 | ctrl_outb(0x01, MTU2_TIOR_1); | ||
172 | |||
173 | /* Enable underflow interrupt */ | ||
174 | ctrl_outb(ctrl_inb(MTU2_TIER_1) | MTU2_TIER_TGIEA, MTU2_TIER_1); | ||
175 | |||
176 | interval = CONFIG_SH_PCLK_FREQ / 16 / HZ; | ||
177 | printk(KERN_INFO "Interval = %ld\n", interval); | ||
178 | |||
179 | ctrl_outw(interval, MTU2_TGRA_1); | ||
180 | ctrl_outw(0, MTU2_TCNT_1); | ||
181 | |||
182 | clk_register(&mtu2_clk1); | ||
183 | clk_enable(&mtu2_clk1); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | struct sys_timer_ops mtu2_timer_ops = { | ||
189 | .init = mtu2_timer_init, | ||
190 | .start = mtu2_timer_start, | ||
191 | .stop = mtu2_timer_stop, | ||
192 | #ifndef CONFIG_GENERIC_TIME | ||
193 | .get_offset = mtu2_timer_get_offset, | ||
194 | #endif | ||
195 | }; | ||
196 | |||
197 | struct sys_timer mtu2_timer = { | ||
198 | .name = "mtu2", | ||
199 | .ops = &mtu2_timer_ops, | ||
200 | }; | ||
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c index 24927015dc31..e060e71d0785 100644 --- a/arch/sh/kernel/timers/timer-tmu.c +++ b/arch/sh/kernel/timers/timer-tmu.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/seqlock.h> | 20 | #include <linux/seqlock.h> |
22 | #include <asm/timer.h> | 21 | #include <asm/timer.h> |
23 | #include <asm/rtc.h> | 22 | #include <asm/rtc.h> |
@@ -31,13 +30,9 @@ | |||
31 | 30 | ||
32 | #define TMU0_TCR_CALIB 0x0000 | 31 | #define TMU0_TCR_CALIB 0x0000 |
33 | 32 | ||
34 | static DEFINE_SPINLOCK(tmu0_lock); | ||
35 | |||
36 | static unsigned long tmu_timer_get_offset(void) | 33 | static unsigned long tmu_timer_get_offset(void) |
37 | { | 34 | { |
38 | int count; | 35 | int count; |
39 | unsigned long flags; | ||
40 | |||
41 | static int count_p = 0x7fffffff; /* for the first call after boot */ | 36 | static int count_p = 0x7fffffff; /* for the first call after boot */ |
42 | static unsigned long jiffies_p = 0; | 37 | static unsigned long jiffies_p = 0; |
43 | 38 | ||
@@ -46,7 +41,6 @@ static unsigned long tmu_timer_get_offset(void) | |||
46 | */ | 41 | */ |
47 | unsigned long jiffies_t; | 42 | unsigned long jiffies_t; |
48 | 43 | ||
49 | spin_lock_irqsave(&tmu0_lock, flags); | ||
50 | /* timer count may underflow right here */ | 44 | /* timer count may underflow right here */ |
51 | count = ctrl_inl(TMU0_TCNT); /* read the latched count */ | 45 | count = ctrl_inl(TMU0_TCNT); /* read the latched count */ |
52 | 46 | ||
@@ -72,7 +66,6 @@ static unsigned long tmu_timer_get_offset(void) | |||
72 | jiffies_p = jiffies_t; | 66 | jiffies_p = jiffies_t; |
73 | 67 | ||
74 | count_p = count; | 68 | count_p = count; |
75 | spin_unlock_irqrestore(&tmu0_lock, flags); | ||
76 | 69 | ||
77 | count = ((LATCH-1) - count) * TICK_SIZE; | 70 | count = ((LATCH-1) - count) * TICK_SIZE; |
78 | count = (count + LATCH/2) / LATCH; | 71 | count = (count + LATCH/2) / LATCH; |
@@ -106,7 +99,7 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy) | |||
106 | static struct irqaction tmu_irq = { | 99 | static struct irqaction tmu_irq = { |
107 | .name = "timer", | 100 | .name = "timer", |
108 | .handler = tmu_timer_interrupt, | 101 | .handler = tmu_timer_interrupt, |
109 | .flags = IRQF_DISABLED, | 102 | .flags = IRQF_DISABLED | IRQF_TIMER, |
110 | .mask = CPU_MASK_NONE, | 103 | .mask = CPU_MASK_NONE, |
111 | }; | 104 | }; |
112 | 105 | ||
@@ -149,9 +142,9 @@ static int tmu_timer_init(void) | |||
149 | { | 142 | { |
150 | unsigned long interval; | 143 | unsigned long interval; |
151 | 144 | ||
152 | setup_irq(TIMER_IRQ, &tmu_irq); | 145 | setup_irq(CONFIG_SH_TIMER_IRQ, &tmu_irq); |
153 | 146 | ||
154 | tmu0_clk.parent = clk_get("module_clk"); | 147 | tmu0_clk.parent = clk_get(NULL, "module_clk"); |
155 | 148 | ||
156 | /* Start TMU0 */ | 149 | /* Start TMU0 */ |
157 | tmu_timer_stop(); | 150 | tmu_timer_stop(); |
diff --git a/arch/sh/kernel/timers/timer.c b/arch/sh/kernel/timers/timer.c index dc1f631053a8..a6bcc913d25e 100644 --- a/arch/sh/kernel/timers/timer.c +++ b/arch/sh/kernel/timers/timer.c | |||
@@ -17,6 +17,12 @@ static struct sys_timer *sys_timers[] __initdata = { | |||
17 | #ifdef CONFIG_SH_TMU | 17 | #ifdef CONFIG_SH_TMU |
18 | &tmu_timer, | 18 | &tmu_timer, |
19 | #endif | 19 | #endif |
20 | #ifdef CONFIG_SH_MTU2 | ||
21 | &mtu2_timer, | ||
22 | #endif | ||
23 | #ifdef CONFIG_SH_CMT | ||
24 | &cmt_timer, | ||
25 | #endif | ||
20 | NULL, | 26 | NULL, |
21 | }; | 27 | }; |
22 | 28 | ||
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index c2c597e09482..ec110157992d 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c | |||
@@ -1,43 +1,32 @@ | |||
1 | /* $Id: traps.c,v 1.17 2004/05/02 01:46:30 sugioka Exp $ | 1 | /* |
2 | * | 2 | * 'traps.c' handles hardware traps and faults after we have saved some |
3 | * linux/arch/sh/traps.c | 3 | * state in 'entry.S'. |
4 | * | 4 | * |
5 | * SuperH version: Copyright (C) 1999 Niibe Yutaka | 5 | * SuperH version: Copyright (C) 1999 Niibe Yutaka |
6 | * Copyright (C) 2000 Philipp Rumpf | 6 | * Copyright (C) 2000 Philipp Rumpf |
7 | * Copyright (C) 2000 David Howells | 7 | * Copyright (C) 2000 David Howells |
8 | * Copyright (C) 2002, 2003 Paul Mundt | 8 | * Copyright (C) 2002 - 2006 Paul Mundt |
9 | */ | 9 | * |
10 | 10 | * This file is subject to the terms and conditions of the GNU General Public | |
11 | /* | 11 | * License. See the file "COPYING" in the main directory of this archive |
12 | * 'Traps.c' handles hardware traps and faults after we have saved some | 12 | * for more details. |
13 | * state in 'entry.S'. | ||
14 | */ | 13 | */ |
15 | #include <linux/sched.h> | ||
16 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
17 | #include <linux/string.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/ptrace.h> | 15 | #include <linux/ptrace.h> |
20 | #include <linux/timer.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/smp.h> | ||
23 | #include <linux/smp_lock.h> | ||
24 | #include <linux/init.h> | 16 | #include <linux/init.h> |
25 | #include <linux/delay.h> | ||
26 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
27 | #include <linux/module.h> | 18 | #include <linux/module.h> |
28 | #include <linux/kallsyms.h> | 19 | #include <linux/kallsyms.h> |
29 | 20 | #include <linux/io.h> | |
21 | #include <linux/debug_locks.h> | ||
22 | #include <linux/limits.h> | ||
30 | #include <asm/system.h> | 23 | #include <asm/system.h> |
31 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
32 | #include <asm/io.h> | ||
33 | #include <asm/atomic.h> | ||
34 | #include <asm/processor.h> | ||
35 | #include <asm/sections.h> | ||
36 | 25 | ||
37 | #ifdef CONFIG_SH_KGDB | 26 | #ifdef CONFIG_SH_KGDB |
38 | #include <asm/kgdb.h> | 27 | #include <asm/kgdb.h> |
39 | #define CHK_REMOTE_DEBUG(regs) \ | 28 | #define CHK_REMOTE_DEBUG(regs) \ |
40 | { \ | 29 | { \ |
41 | if (kgdb_debug_hook && !user_mode(regs))\ | 30 | if (kgdb_debug_hook && !user_mode(regs))\ |
42 | (*kgdb_debug_hook)(regs); \ | 31 | (*kgdb_debug_hook)(regs); \ |
43 | } | 32 | } |
@@ -46,20 +35,44 @@ | |||
46 | #endif | 35 | #endif |
47 | 36 | ||
48 | #ifdef CONFIG_CPU_SH2 | 37 | #ifdef CONFIG_CPU_SH2 |
49 | #define TRAP_RESERVED_INST 4 | 38 | # define TRAP_RESERVED_INST 4 |
50 | #define TRAP_ILLEGAL_SLOT_INST 6 | 39 | # define TRAP_ILLEGAL_SLOT_INST 6 |
40 | # define TRAP_ADDRESS_ERROR 9 | ||
41 | # ifdef CONFIG_CPU_SH2A | ||
42 | # define TRAP_DIVZERO_ERROR 17 | ||
43 | # define TRAP_DIVOVF_ERROR 18 | ||
44 | # endif | ||
51 | #else | 45 | #else |
52 | #define TRAP_RESERVED_INST 12 | 46 | #define TRAP_RESERVED_INST 12 |
53 | #define TRAP_ILLEGAL_SLOT_INST 13 | 47 | #define TRAP_ILLEGAL_SLOT_INST 13 |
54 | #endif | 48 | #endif |
55 | 49 | ||
56 | /* | 50 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) |
57 | * These constants are for searching for possible module text | 51 | { |
58 | * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is | 52 | unsigned long p; |
59 | * a guess of how much space is likely to be vmalloced. | 53 | int i; |
60 | */ | 54 | |
61 | #define VMALLOC_OFFSET (8*1024*1024) | 55 | printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); |
62 | #define MODULE_RANGE (8*1024*1024) | 56 | |
57 | for (p = bottom & ~31; p < top; ) { | ||
58 | printk("%04lx: ", p & 0xffff); | ||
59 | |||
60 | for (i = 0; i < 8; i++, p += 4) { | ||
61 | unsigned int val; | ||
62 | |||
63 | if (p < bottom || p >= top) | ||
64 | printk(" "); | ||
65 | else { | ||
66 | if (__get_user(val, (unsigned int __user *)p)) { | ||
67 | printk("\n"); | ||
68 | return; | ||
69 | } | ||
70 | printk("%08x ", val); | ||
71 | } | ||
72 | } | ||
73 | printk("\n"); | ||
74 | } | ||
75 | } | ||
63 | 76 | ||
64 | DEFINE_SPINLOCK(die_lock); | 77 | DEFINE_SPINLOCK(die_lock); |
65 | 78 | ||
@@ -69,21 +82,33 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
69 | 82 | ||
70 | console_verbose(); | 83 | console_verbose(); |
71 | spin_lock_irq(&die_lock); | 84 | spin_lock_irq(&die_lock); |
85 | bust_spinlocks(1); | ||
86 | |||
72 | printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); | 87 | printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); |
88 | |||
73 | CHK_REMOTE_DEBUG(regs); | 89 | CHK_REMOTE_DEBUG(regs); |
90 | print_modules(); | ||
74 | show_regs(regs); | 91 | show_regs(regs); |
92 | |||
93 | printk("Process: %s (pid: %d, stack limit = %p)\n", | ||
94 | current->comm, current->pid, task_stack_page(current) + 1); | ||
95 | |||
96 | if (!user_mode(regs) || in_interrupt()) | ||
97 | dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + | ||
98 | (unsigned long)task_stack_page(current)); | ||
99 | |||
100 | bust_spinlocks(0); | ||
75 | spin_unlock_irq(&die_lock); | 101 | spin_unlock_irq(&die_lock); |
76 | do_exit(SIGSEGV); | 102 | do_exit(SIGSEGV); |
77 | } | 103 | } |
78 | 104 | ||
79 | static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) | 105 | static inline void die_if_kernel(const char *str, struct pt_regs *regs, |
106 | long err) | ||
80 | { | 107 | { |
81 | if (!user_mode(regs)) | 108 | if (!user_mode(regs)) |
82 | die(str, regs, err); | 109 | die(str, regs, err); |
83 | } | 110 | } |
84 | 111 | ||
85 | static int handle_unaligned_notify_count = 10; | ||
86 | |||
87 | /* | 112 | /* |
88 | * try and fix up kernelspace address errors | 113 | * try and fix up kernelspace address errors |
89 | * - userspace errors just cause EFAULT to be returned, resulting in SEGV | 114 | * - userspace errors just cause EFAULT to be returned, resulting in SEGV |
@@ -93,8 +118,7 @@ static int handle_unaligned_notify_count = 10; | |||
93 | */ | 118 | */ |
94 | static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) | 119 | static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) |
95 | { | 120 | { |
96 | if (!user_mode(regs)) | 121 | if (!user_mode(regs)) { |
97 | { | ||
98 | const struct exception_table_entry *fixup; | 122 | const struct exception_table_entry *fixup; |
99 | fixup = search_exception_tables(regs->pc); | 123 | fixup = search_exception_tables(regs->pc); |
100 | if (fixup) { | 124 | if (fixup) { |
@@ -106,6 +130,40 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) | |||
106 | return -EFAULT; | 130 | return -EFAULT; |
107 | } | 131 | } |
108 | 132 | ||
133 | #ifdef CONFIG_BUG | ||
134 | #ifdef CONFIG_DEBUG_BUGVERBOSE | ||
135 | static inline void do_bug_verbose(struct pt_regs *regs) | ||
136 | { | ||
137 | struct bug_frame f; | ||
138 | long len; | ||
139 | |||
140 | if (__copy_from_user(&f, (const void __user *)regs->pc, | ||
141 | sizeof(struct bug_frame))) | ||
142 | return; | ||
143 | |||
144 | len = __strnlen_user(f.file, PATH_MAX) - 1; | ||
145 | if (unlikely(len < 0 || len >= PATH_MAX)) | ||
146 | f.file = "<bad filename>"; | ||
147 | len = __strnlen_user(f.func, PATH_MAX) - 1; | ||
148 | if (unlikely(len < 0 || len >= PATH_MAX)) | ||
149 | f.func = "<bad function>"; | ||
150 | |||
151 | printk(KERN_ALERT "kernel BUG in %s() at %s:%d!\n", | ||
152 | f.func, f.file, f.line); | ||
153 | } | ||
154 | #else | ||
155 | static inline void do_bug_verbose(struct pt_regs *regs) | ||
156 | { | ||
157 | } | ||
158 | #endif /* CONFIG_DEBUG_BUGVERBOSE */ | ||
159 | #endif /* CONFIG_BUG */ | ||
160 | |||
161 | void handle_BUG(struct pt_regs *regs) | ||
162 | { | ||
163 | do_bug_verbose(regs); | ||
164 | die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); | ||
165 | } | ||
166 | |||
109 | /* | 167 | /* |
110 | * handle an instruction that does an unaligned memory access by emulating the | 168 | * handle an instruction that does an unaligned memory access by emulating the |
111 | * desired behaviour | 169 | * desired behaviour |
@@ -179,7 +237,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
179 | if (copy_to_user(dst,src,4)) | 237 | if (copy_to_user(dst,src,4)) |
180 | goto fetch_fault; | 238 | goto fetch_fault; |
181 | ret = 0; | 239 | ret = 0; |
182 | break; | 240 | break; |
183 | 241 | ||
184 | case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ | 242 | case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ |
185 | if (instruction & 4) | 243 | if (instruction & 4) |
@@ -203,7 +261,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
203 | if (copy_from_user(dst,src,4)) | 261 | if (copy_from_user(dst,src,4)) |
204 | goto fetch_fault; | 262 | goto fetch_fault; |
205 | ret = 0; | 263 | ret = 0; |
206 | break; | 264 | break; |
207 | 265 | ||
208 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ | 266 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ |
209 | src = (unsigned char*) *rm; | 267 | src = (unsigned char*) *rm; |
@@ -211,7 +269,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
211 | *rm += count; | 269 | *rm += count; |
212 | dst = (unsigned char*) rn; | 270 | dst = (unsigned char*) rn; |
213 | *(unsigned long*)dst = 0; | 271 | *(unsigned long*)dst = 0; |
214 | 272 | ||
215 | #ifdef __LITTLE_ENDIAN__ | 273 | #ifdef __LITTLE_ENDIAN__ |
216 | if (copy_from_user(dst, src, count)) | 274 | if (copy_from_user(dst, src, count)) |
217 | goto fetch_fault; | 275 | goto fetch_fault; |
@@ -222,7 +280,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
222 | } | 280 | } |
223 | #else | 281 | #else |
224 | dst += 4-count; | 282 | dst += 4-count; |
225 | 283 | ||
226 | if (copy_from_user(dst, src, count)) | 284 | if (copy_from_user(dst, src, count)) |
227 | goto fetch_fault; | 285 | goto fetch_fault; |
228 | 286 | ||
@@ -301,7 +359,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) | |||
301 | return -EFAULT; | 359 | return -EFAULT; |
302 | 360 | ||
303 | /* kernel */ | 361 | /* kernel */ |
304 | die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0); | 362 | die("delay-slot-insn faulting in handle_unaligned_delayslot", |
363 | regs, 0); | ||
305 | } | 364 | } |
306 | 365 | ||
307 | return handle_unaligned_ins(instruction,regs); | 366 | return handle_unaligned_ins(instruction,regs); |
@@ -323,6 +382,13 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) | |||
323 | #define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) | 382 | #define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) |
324 | #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) | 383 | #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) |
325 | 384 | ||
385 | /* | ||
386 | * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit | ||
387 | * opcodes.. | ||
388 | */ | ||
389 | #ifndef CONFIG_CPU_SH2A | ||
390 | static int handle_unaligned_notify_count = 10; | ||
391 | |||
326 | static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | 392 | static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) |
327 | { | 393 | { |
328 | u_int rm; | 394 | u_int rm; |
@@ -335,7 +401,8 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
335 | if (user_mode(regs) && handle_unaligned_notify_count>0) { | 401 | if (user_mode(regs) && handle_unaligned_notify_count>0) { |
336 | handle_unaligned_notify_count--; | 402 | handle_unaligned_notify_count--; |
337 | 403 | ||
338 | printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | 404 | printk(KERN_NOTICE "Fixing up unaligned userspace access " |
405 | "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | ||
339 | current->comm,current->pid,(u16*)regs->pc,instruction); | 406 | current->comm,current->pid,(u16*)regs->pc,instruction); |
340 | } | 407 | } |
341 | 408 | ||
@@ -459,32 +526,58 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
459 | regs->pc += 2; | 526 | regs->pc += 2; |
460 | return ret; | 527 | return ret; |
461 | } | 528 | } |
529 | #endif /* CONFIG_CPU_SH2A */ | ||
530 | |||
531 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
532 | #define lookup_exception_vector(x) \ | ||
533 | __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x))) | ||
534 | #else | ||
535 | #define lookup_exception_vector(x) \ | ||
536 | __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x))) | ||
537 | #endif | ||
462 | 538 | ||
463 | /* | 539 | /* |
464 | * Handle various address error exceptions | 540 | * Handle various address error exceptions: |
541 | * - instruction address error: | ||
542 | * misaligned PC | ||
543 | * PC >= 0x80000000 in user mode | ||
544 | * - data address error (read and write) | ||
545 | * misaligned data access | ||
546 | * access to >= 0x80000000 is user mode | ||
547 | * Unfortuntaly we can't distinguish between instruction address error | ||
548 | * and data address errors caused by read acceses. | ||
465 | */ | 549 | */ |
466 | asmlinkage void do_address_error(struct pt_regs *regs, | 550 | asmlinkage void do_address_error(struct pt_regs *regs, |
467 | unsigned long writeaccess, | 551 | unsigned long writeaccess, |
468 | unsigned long address) | 552 | unsigned long address) |
469 | { | 553 | { |
470 | unsigned long error_code; | 554 | unsigned long error_code = 0; |
471 | mm_segment_t oldfs; | 555 | mm_segment_t oldfs; |
556 | siginfo_t info; | ||
557 | #ifndef CONFIG_CPU_SH2A | ||
472 | u16 instruction; | 558 | u16 instruction; |
473 | int tmp; | 559 | int tmp; |
560 | #endif | ||
474 | 561 | ||
475 | asm volatile("stc r2_bank,%0": "=r" (error_code)); | 562 | /* Intentional ifdef */ |
563 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
564 | lookup_exception_vector(error_code); | ||
565 | #endif | ||
476 | 566 | ||
477 | oldfs = get_fs(); | 567 | oldfs = get_fs(); |
478 | 568 | ||
479 | if (user_mode(regs)) { | 569 | if (user_mode(regs)) { |
570 | int si_code = BUS_ADRERR; | ||
571 | |||
480 | local_irq_enable(); | 572 | local_irq_enable(); |
481 | current->thread.error_code = error_code; | ||
482 | current->thread.trap_no = (writeaccess) ? 8 : 7; | ||
483 | 573 | ||
484 | /* bad PC is not something we can fix */ | 574 | /* bad PC is not something we can fix */ |
485 | if (regs->pc & 1) | 575 | if (regs->pc & 1) { |
576 | si_code = BUS_ADRALN; | ||
486 | goto uspace_segv; | 577 | goto uspace_segv; |
578 | } | ||
487 | 579 | ||
580 | #ifndef CONFIG_CPU_SH2A | ||
488 | set_fs(USER_DS); | 581 | set_fs(USER_DS); |
489 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { | 582 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { |
490 | /* Argh. Fault on the instruction itself. | 583 | /* Argh. Fault on the instruction itself. |
@@ -499,14 +592,23 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
499 | 592 | ||
500 | if (tmp==0) | 593 | if (tmp==0) |
501 | return; /* sorted */ | 594 | return; /* sorted */ |
595 | #endif | ||
502 | 596 | ||
503 | uspace_segv: | 597 | uspace_segv: |
504 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); | 598 | printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " |
505 | force_sig(SIGSEGV, current); | 599 | "access (PC %lx PR %lx)\n", current->comm, regs->pc, |
600 | regs->pr); | ||
601 | |||
602 | info.si_signo = SIGBUS; | ||
603 | info.si_errno = 0; | ||
604 | info.si_code = si_code; | ||
605 | info.si_addr = (void *) address; | ||
606 | force_sig_info(SIGBUS, &info, current); | ||
506 | } else { | 607 | } else { |
507 | if (regs->pc & 1) | 608 | if (regs->pc & 1) |
508 | die("unaligned program counter", regs, error_code); | 609 | die("unaligned program counter", regs, error_code); |
509 | 610 | ||
611 | #ifndef CONFIG_CPU_SH2A | ||
510 | set_fs(KERNEL_DS); | 612 | set_fs(KERNEL_DS); |
511 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { | 613 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { |
512 | /* Argh. Fault on the instruction itself. | 614 | /* Argh. Fault on the instruction itself. |
@@ -518,6 +620,12 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
518 | 620 | ||
519 | handle_unaligned_access(instruction, regs); | 621 | handle_unaligned_access(instruction, regs); |
520 | set_fs(oldfs); | 622 | set_fs(oldfs); |
623 | #else | ||
624 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " | ||
625 | "access\n", current->comm); | ||
626 | |||
627 | force_sig(SIGSEGV, current); | ||
628 | #endif | ||
521 | } | 629 | } |
522 | } | 630 | } |
523 | 631 | ||
@@ -529,7 +637,7 @@ int is_dsp_inst(struct pt_regs *regs) | |||
529 | { | 637 | { |
530 | unsigned short inst; | 638 | unsigned short inst; |
531 | 639 | ||
532 | /* | 640 | /* |
533 | * Safe guard if DSP mode is already enabled or we're lacking | 641 | * Safe guard if DSP mode is already enabled or we're lacking |
534 | * the DSP altogether. | 642 | * the DSP altogether. |
535 | */ | 643 | */ |
@@ -550,24 +658,49 @@ int is_dsp_inst(struct pt_regs *regs) | |||
550 | #define is_dsp_inst(regs) (0) | 658 | #define is_dsp_inst(regs) (0) |
551 | #endif /* CONFIG_SH_DSP */ | 659 | #endif /* CONFIG_SH_DSP */ |
552 | 660 | ||
553 | extern int do_fpu_inst(unsigned short, struct pt_regs*); | 661 | #ifdef CONFIG_CPU_SH2A |
662 | asmlinkage void do_divide_error(unsigned long r4, unsigned long r5, | ||
663 | unsigned long r6, unsigned long r7, | ||
664 | struct pt_regs __regs) | ||
665 | { | ||
666 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
667 | siginfo_t info; | ||
668 | |||
669 | switch (r4) { | ||
670 | case TRAP_DIVZERO_ERROR: | ||
671 | info.si_code = FPE_INTDIV; | ||
672 | break; | ||
673 | case TRAP_DIVOVF_ERROR: | ||
674 | info.si_code = FPE_INTOVF; | ||
675 | break; | ||
676 | } | ||
677 | |||
678 | force_sig_info(SIGFPE, &info, current); | ||
679 | } | ||
680 | #endif | ||
681 | |||
682 | /* arch/sh/kernel/cpu/sh4/fpu.c */ | ||
683 | extern int do_fpu_inst(unsigned short, struct pt_regs *); | ||
684 | extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5, | ||
685 | unsigned long r6, unsigned long r7, struct pt_regs __regs); | ||
554 | 686 | ||
555 | asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, | 687 | asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, |
556 | unsigned long r6, unsigned long r7, | 688 | unsigned long r6, unsigned long r7, |
557 | struct pt_regs regs) | 689 | struct pt_regs __regs) |
558 | { | 690 | { |
691 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
559 | unsigned long error_code; | 692 | unsigned long error_code; |
560 | struct task_struct *tsk = current; | 693 | struct task_struct *tsk = current; |
561 | 694 | ||
562 | #ifdef CONFIG_SH_FPU_EMU | 695 | #ifdef CONFIG_SH_FPU_EMU |
563 | unsigned short inst; | 696 | unsigned short inst = 0; |
564 | int err; | 697 | int err; |
565 | 698 | ||
566 | get_user(inst, (unsigned short*)regs.pc); | 699 | get_user(inst, (unsigned short*)regs->pc); |
567 | 700 | ||
568 | err = do_fpu_inst(inst, ®s); | 701 | err = do_fpu_inst(inst, regs); |
569 | if (!err) { | 702 | if (!err) { |
570 | regs.pc += 2; | 703 | regs->pc += 2; |
571 | return; | 704 | return; |
572 | } | 705 | } |
573 | /* not a FPU inst. */ | 706 | /* not a FPU inst. */ |
@@ -575,20 +708,19 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, | |||
575 | 708 | ||
576 | #ifdef CONFIG_SH_DSP | 709 | #ifdef CONFIG_SH_DSP |
577 | /* Check if it's a DSP instruction */ | 710 | /* Check if it's a DSP instruction */ |
578 | if (is_dsp_inst(®s)) { | 711 | if (is_dsp_inst(regs)) { |
579 | /* Enable DSP mode, and restart instruction. */ | 712 | /* Enable DSP mode, and restart instruction. */ |
580 | regs.sr |= SR_DSP; | 713 | regs->sr |= SR_DSP; |
581 | return; | 714 | return; |
582 | } | 715 | } |
583 | #endif | 716 | #endif |
584 | 717 | ||
585 | asm volatile("stc r2_bank, %0": "=r" (error_code)); | 718 | lookup_exception_vector(error_code); |
719 | |||
586 | local_irq_enable(); | 720 | local_irq_enable(); |
587 | tsk->thread.error_code = error_code; | 721 | CHK_REMOTE_DEBUG(regs); |
588 | tsk->thread.trap_no = TRAP_RESERVED_INST; | ||
589 | CHK_REMOTE_DEBUG(®s); | ||
590 | force_sig(SIGILL, tsk); | 722 | force_sig(SIGILL, tsk); |
591 | die_if_no_fixup("reserved instruction", ®s, error_code); | 723 | die_if_no_fixup("reserved instruction", regs, error_code); |
592 | } | 724 | } |
593 | 725 | ||
594 | #ifdef CONFIG_SH_FPU_EMU | 726 | #ifdef CONFIG_SH_FPU_EMU |
@@ -636,39 +768,41 @@ static int emulate_branch(unsigned short inst, struct pt_regs* regs) | |||
636 | 768 | ||
637 | asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, | 769 | asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, |
638 | unsigned long r6, unsigned long r7, | 770 | unsigned long r6, unsigned long r7, |
639 | struct pt_regs regs) | 771 | struct pt_regs __regs) |
640 | { | 772 | { |
773 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
641 | unsigned long error_code; | 774 | unsigned long error_code; |
642 | struct task_struct *tsk = current; | 775 | struct task_struct *tsk = current; |
643 | #ifdef CONFIG_SH_FPU_EMU | 776 | #ifdef CONFIG_SH_FPU_EMU |
644 | unsigned short inst; | 777 | unsigned short inst = 0; |
645 | 778 | ||
646 | get_user(inst, (unsigned short *)regs.pc + 1); | 779 | get_user(inst, (unsigned short *)regs->pc + 1); |
647 | if (!do_fpu_inst(inst, ®s)) { | 780 | if (!do_fpu_inst(inst, regs)) { |
648 | get_user(inst, (unsigned short *)regs.pc); | 781 | get_user(inst, (unsigned short *)regs->pc); |
649 | if (!emulate_branch(inst, ®s)) | 782 | if (!emulate_branch(inst, regs)) |
650 | return; | 783 | return; |
651 | /* fault in branch.*/ | 784 | /* fault in branch.*/ |
652 | } | 785 | } |
653 | /* not a FPU inst. */ | 786 | /* not a FPU inst. */ |
654 | #endif | 787 | #endif |
655 | 788 | ||
656 | asm volatile("stc r2_bank, %0": "=r" (error_code)); | 789 | lookup_exception_vector(error_code); |
790 | |||
657 | local_irq_enable(); | 791 | local_irq_enable(); |
658 | tsk->thread.error_code = error_code; | 792 | CHK_REMOTE_DEBUG(regs); |
659 | tsk->thread.trap_no = TRAP_RESERVED_INST; | ||
660 | CHK_REMOTE_DEBUG(®s); | ||
661 | force_sig(SIGILL, tsk); | 793 | force_sig(SIGILL, tsk); |
662 | die_if_no_fixup("illegal slot instruction", ®s, error_code); | 794 | die_if_no_fixup("illegal slot instruction", regs, error_code); |
663 | } | 795 | } |
664 | 796 | ||
665 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, | 797 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, |
666 | unsigned long r6, unsigned long r7, | 798 | unsigned long r6, unsigned long r7, |
667 | struct pt_regs regs) | 799 | struct pt_regs __regs) |
668 | { | 800 | { |
801 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
669 | long ex; | 802 | long ex; |
670 | asm volatile("stc r2_bank, %0" : "=r" (ex)); | 803 | |
671 | die_if_kernel("exception", ®s, ex); | 804 | lookup_exception_vector(ex); |
805 | die_if_kernel("exception", regs, ex); | ||
672 | } | 806 | } |
673 | 807 | ||
674 | #if defined(CONFIG_SH_STANDARD_BIOS) | 808 | #if defined(CONFIG_SH_STANDARD_BIOS) |
@@ -709,14 +843,24 @@ void __init per_cpu_trap_init(void) | |||
709 | : "memory"); | 843 | : "memory"); |
710 | } | 844 | } |
711 | 845 | ||
712 | void __init trap_init(void) | 846 | void *set_exception_table_vec(unsigned int vec, void *handler) |
713 | { | 847 | { |
714 | extern void *exception_handling_table[]; | 848 | extern void *exception_handling_table[]; |
849 | void *old_handler; | ||
850 | |||
851 | old_handler = exception_handling_table[vec]; | ||
852 | exception_handling_table[vec] = handler; | ||
853 | return old_handler; | ||
854 | } | ||
715 | 855 | ||
716 | exception_handling_table[TRAP_RESERVED_INST] | 856 | extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5, |
717 | = (void *)do_reserved_inst; | 857 | unsigned long r6, unsigned long r7, |
718 | exception_handling_table[TRAP_ILLEGAL_SLOT_INST] | 858 | struct pt_regs __regs); |
719 | = (void *)do_illegal_slot_inst; | 859 | |
860 | void __init trap_init(void) | ||
861 | { | ||
862 | set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst); | ||
863 | set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst); | ||
720 | 864 | ||
721 | #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \ | 865 | #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \ |
722 | defined(CONFIG_SH_FPU_EMU) | 866 | defined(CONFIG_SH_FPU_EMU) |
@@ -725,61 +869,67 @@ void __init trap_init(void) | |||
725 | * reserved. They'll be handled in the math-emu case, or faulted on | 869 | * reserved. They'll be handled in the math-emu case, or faulted on |
726 | * otherwise. | 870 | * otherwise. |
727 | */ | 871 | */ |
728 | /* entry 64 corresponds to EXPEVT=0x800 */ | 872 | set_exception_table_evt(0x800, do_reserved_inst); |
729 | exception_handling_table[64] = (void *)do_reserved_inst; | 873 | set_exception_table_evt(0x820, do_illegal_slot_inst); |
730 | exception_handling_table[65] = (void *)do_illegal_slot_inst; | 874 | #elif defined(CONFIG_SH_FPU) |
875 | set_exception_table_evt(0x800, do_fpu_state_restore); | ||
876 | set_exception_table_evt(0x820, do_fpu_state_restore); | ||
731 | #endif | 877 | #endif |
732 | 878 | ||
879 | #ifdef CONFIG_CPU_SH2 | ||
880 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler); | ||
881 | #endif | ||
882 | #ifdef CONFIG_CPU_SH2A | ||
883 | set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error); | ||
884 | set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error); | ||
885 | #endif | ||
886 | |||
733 | /* Setup VBR for boot cpu */ | 887 | /* Setup VBR for boot cpu */ |
734 | per_cpu_trap_init(); | 888 | per_cpu_trap_init(); |
735 | } | 889 | } |
736 | 890 | ||
737 | void show_stack(struct task_struct *tsk, unsigned long *sp) | 891 | void show_trace(struct task_struct *tsk, unsigned long *sp, |
892 | struct pt_regs *regs) | ||
738 | { | 893 | { |
739 | unsigned long *stack, addr; | 894 | unsigned long addr; |
740 | unsigned long module_start = VMALLOC_START; | ||
741 | unsigned long module_end = VMALLOC_END; | ||
742 | int i = 1; | ||
743 | 895 | ||
744 | if (!tsk) | 896 | if (regs && user_mode(regs)) |
745 | tsk = current; | 897 | return; |
746 | if (tsk == current) | ||
747 | sp = (unsigned long *)current_stack_pointer; | ||
748 | else | ||
749 | sp = (unsigned long *)tsk->thread.sp; | ||
750 | |||
751 | stack = sp; | ||
752 | 898 | ||
753 | printk("\nCall trace: "); | 899 | printk("\nCall trace: "); |
754 | #ifdef CONFIG_KALLSYMS | 900 | #ifdef CONFIG_KALLSYMS |
755 | printk("\n"); | 901 | printk("\n"); |
756 | #endif | 902 | #endif |
757 | 903 | ||
758 | while (!kstack_end(stack)) { | 904 | while (!kstack_end(sp)) { |
759 | addr = *stack++; | 905 | addr = *sp++; |
760 | if (((addr >= (unsigned long)_text) && | 906 | if (kernel_text_address(addr)) |
761 | (addr <= (unsigned long)_etext)) || | 907 | print_ip_sym(addr); |
762 | ((addr >= module_start) && (addr <= module_end))) { | ||
763 | /* | ||
764 | * For 80-columns display, 6 entry is maximum. | ||
765 | * NOTE: '[<8c00abcd>] ' consumes 13 columns . | ||
766 | */ | ||
767 | #ifndef CONFIG_KALLSYMS | ||
768 | if (i && ((i % 6) == 0)) | ||
769 | printk("\n "); | ||
770 | #endif | ||
771 | printk("[<%08lx>] ", addr); | ||
772 | print_symbol("%s\n", addr); | ||
773 | i++; | ||
774 | } | ||
775 | } | 908 | } |
776 | 909 | ||
777 | printk("\n"); | 910 | printk("\n"); |
911 | |||
912 | if (!tsk) | ||
913 | tsk = current; | ||
914 | |||
915 | debug_show_held_locks(tsk); | ||
778 | } | 916 | } |
779 | 917 | ||
780 | void show_task(unsigned long *sp) | 918 | void show_stack(struct task_struct *tsk, unsigned long *sp) |
781 | { | 919 | { |
782 | show_stack(NULL, sp); | 920 | unsigned long stack; |
921 | |||
922 | if (!tsk) | ||
923 | tsk = current; | ||
924 | if (tsk == current) | ||
925 | sp = (unsigned long *)current_stack_pointer; | ||
926 | else | ||
927 | sp = (unsigned long *)tsk->thread.sp; | ||
928 | |||
929 | stack = (unsigned long)sp; | ||
930 | dump_mem("Stack: ", stack, THREAD_SIZE + | ||
931 | (unsigned long)task_stack_page(tsk)); | ||
932 | show_trace(tsk, sp, NULL); | ||
783 | } | 933 | } |
784 | 934 | ||
785 | void dump_stack(void) | 935 | void dump_stack(void) |
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index 5eb930918186..f34bdcc33a7d 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S | |||
@@ -51,7 +51,7 @@ SECTIONS | |||
51 | } | 51 | } |
52 | 52 | ||
53 | . = ALIGN(PAGE_SIZE); | 53 | . = ALIGN(PAGE_SIZE); |
54 | .data.page_aligned : { *(.data.idt) } | 54 | .data.page_aligned : { *(.data.page_aligned) } |
55 | 55 | ||
56 | . = ALIGN(32); | 56 | . = ALIGN(32); |
57 | __per_cpu_start = .; | 57 | __per_cpu_start = .; |
@@ -76,13 +76,7 @@ SECTIONS | |||
76 | __setup_end = .; | 76 | __setup_end = .; |
77 | __initcall_start = .; | 77 | __initcall_start = .; |
78 | .initcall.init : { | 78 | .initcall.init : { |
79 | *(.initcall1.init) | 79 | INITCALLS |
80 | *(.initcall2.init) | ||
81 | *(.initcall3.init) | ||
82 | *(.initcall4.init) | ||
83 | *(.initcall5.init) | ||
84 | *(.initcall6.init) | ||
85 | *(.initcall7.init) | ||
86 | } | 80 | } |
87 | __initcall_end = .; | 81 | __initcall_end = .; |
88 | __con_initcall_start = .; | 82 | __con_initcall_start = .; |
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c index 075d6cc1a2d7..deb46941f315 100644 --- a/arch/sh/kernel/vsyscall/vsyscall.c +++ b/arch/sh/kernel/vsyscall/vsyscall.c | |||
@@ -97,7 +97,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, | |||
97 | goto up_fail; | 97 | goto up_fail; |
98 | } | 98 | } |
99 | 99 | ||
100 | vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); | 100 | vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); |
101 | if (!vma) { | 101 | if (!vma) { |
102 | ret = -ENOMEM; | 102 | ret = -ENOMEM; |
103 | goto up_fail; | 103 | goto up_fail; |