diff options
Diffstat (limited to 'arch/sh/kernel')
47 files changed, 2406 insertions, 656 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..0582e6712b79 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile | |||
@@ -2,11 +2,12 @@ | |||
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/ | ||
10 | 9 | ||
11 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o | 10 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o |
12 | obj-$(CONFIG_SH_ADC) += adc.o | 11 | obj-$(CONFIG_SH_ADC) += adc.o |
12 | |||
13 | 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 74ca576a7ce5..74defe76a058 100644 --- a/arch/sh/kernel/cpu/irq/intc2.c +++ b/arch/sh/kernel/cpu/irq/intc2.c | |||
@@ -11,22 +11,29 @@ | |||
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/irq.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
16 | #include <asm/system.h> | 16 | |
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 | ||
17 | 26 | ||
18 | static void disable_intc2_irq(unsigned int irq) | 27 | static void disable_intc2_irq(unsigned int irq) |
19 | { | 28 | { |
20 | struct intc2_data *p = get_irq_chip_data(irq); | 29 | struct intc2_data *p = get_irq_chip_data(irq); |
21 | ctrl_outl(1 << p->msk_shift, | 30 | ctrl_outl(1 << p->msk_shift, INTC2_INTMSK + p->msk_offset); |
22 | INTC2_BASE + INTC2_INTMSK_OFFSET + p->msk_offset); | ||
23 | } | 31 | } |
24 | 32 | ||
25 | static void enable_intc2_irq(unsigned int irq) | 33 | static void enable_intc2_irq(unsigned int irq) |
26 | { | 34 | { |
27 | struct intc2_data *p = get_irq_chip_data(irq); | 35 | struct intc2_data *p = get_irq_chip_data(irq); |
28 | ctrl_outl(1 << p->msk_shift, | 36 | ctrl_outl(1 << p->msk_shift, INTC2_INTMSKCLR + p->msk_offset); |
29 | INTC2_BASE + INTC2_INTMSKCLR_OFFSET + p->msk_offset); | ||
30 | } | 37 | } |
31 | 38 | ||
32 | static struct irq_chip intc2_irq_chip = { | 39 | static struct irq_chip intc2_irq_chip = { |
@@ -61,12 +68,10 @@ void make_intc2_irq(struct intc2_data *table, unsigned int nr_irqs) | |||
61 | /* Set the priority level */ | 68 | /* Set the priority level */ |
62 | local_irq_save(flags); | 69 | local_irq_save(flags); |
63 | 70 | ||
64 | ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + | 71 | ipr = ctrl_inl(INTC2_BASE + p->ipr_offset); |
65 | p->ipr_offset); | ||
66 | ipr &= ~(0xf << p->ipr_shift); | 72 | ipr &= ~(0xf << p->ipr_shift); |
67 | ipr |= p->priority << p->ipr_shift; | 73 | ipr |= p->priority << p->ipr_shift; |
68 | ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + | 74 | ctrl_outl(ipr, INTC2_BASE + p->ipr_offset); |
69 | p->ipr_offset); | ||
70 | 75 | ||
71 | local_irq_restore(flags); | 76 | local_irq_restore(flags); |
72 | 77 | ||
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index a0089563cbfc..35eb5751a3aa 100644 --- a/arch/sh/kernel/cpu/irq/ipr.c +++ b/arch/sh/kernel/cpu/irq/ipr.c | |||
@@ -19,25 +19,21 @@ | |||
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 | 24 | ||
27 | static void disable_ipr_irq(unsigned int irq) | 25 | static void disable_ipr_irq(unsigned int irq) |
28 | { | 26 | { |
29 | struct ipr_data *p = get_irq_chip_data(irq); | 27 | struct ipr_data *p = get_irq_chip_data(irq); |
30 | int shift = p->shift*4; | ||
31 | /* Set the priority in IPR to 0 */ | 28 | /* Set the priority in IPR to 0 */ |
32 | ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << shift)), p->addr); | 29 | ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr); |
33 | } | 30 | } |
34 | 31 | ||
35 | static void enable_ipr_irq(unsigned int irq) | 32 | static void enable_ipr_irq(unsigned int irq) |
36 | { | 33 | { |
37 | struct ipr_data *p = get_irq_chip_data(irq); | 34 | struct ipr_data *p = get_irq_chip_data(irq); |
38 | int shift = p->shift*4; | ||
39 | /* Set priority in IPR back to original value */ | 35 | /* Set priority in IPR back to original value */ |
40 | ctrl_outw(ctrl_inw(p->addr) | (p->priority << shift), p->addr); | 36 | ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr); |
41 | } | 37 | } |
42 | 38 | ||
43 | static struct irq_chip ipr_irq_chip = { | 39 | static struct irq_chip ipr_irq_chip = { |
@@ -53,6 +49,10 @@ void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs) | |||
53 | 49 | ||
54 | for (i = 0; i < nr_irqs; i++) { | 50 | for (i = 0; i < nr_irqs; i++) { |
55 | unsigned int irq = table[i].irq; | 51 | unsigned int irq = table[i].irq; |
52 | table[i].addr = map_ipridx_to_addr(table[i].ipr_idx); | ||
53 | /* could the IPR index be mapped, if not we ignore this */ | ||
54 | if (table[i].addr == 0) | ||
55 | continue; | ||
56 | disable_irq_nosync(irq); | 56 | disable_irq_nosync(irq); |
57 | set_irq_chip_and_handler_name(irq, &ipr_irq_chip, | 57 | set_irq_chip_and_handler_name(irq, &ipr_irq_chip, |
58 | handle_level_irq, "level"); | 58 | handle_level_irq, "level"); |
@@ -62,83 +62,6 @@ void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs) | |||
62 | } | 62 | } |
63 | EXPORT_SYMBOL(make_ipr_irq); | 63 | EXPORT_SYMBOL(make_ipr_irq); |
64 | 64 | ||
65 | static struct ipr_data sys_ipr_map[] = { | ||
66 | #ifndef CONFIG_CPU_SUBTYPE_SH7780 | ||
67 | { TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY }, | ||
68 | { TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY }, | ||
69 | #ifdef RTC_IRQ | ||
70 | { RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY }, | ||
71 | #endif | ||
72 | #ifdef SCI_ERI_IRQ | ||
73 | { SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, | ||
74 | { SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, | ||
75 | { SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY }, | ||
76 | #endif | ||
77 | #ifdef SCIF1_ERI_IRQ | ||
78 | { SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, | ||
79 | { SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, | ||
80 | { SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, | ||
81 | { SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, | ||
82 | #endif | ||
83 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
84 | { SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY }, | ||
85 | { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY }, | ||
86 | { DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY }, | ||
87 | { VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY }, | ||
88 | #endif | ||
89 | #ifdef SCIF_ERI_IRQ | ||
90 | { SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, | ||
91 | { SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, | ||
92 | { SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, | ||
93 | { SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY }, | ||
94 | #endif | ||
95 | #ifdef IRDA_ERI_IRQ | ||
96 | { IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, | ||
97 | { IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, | ||
98 | { IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, | ||
99 | { IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY }, | ||
100 | #endif | ||
101 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | ||
102 | defined(CONFIG_CPU_SUBTYPE_SH7706) || \ | ||
103 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) | ||
104 | /* | ||
105 | * Initialize the Interrupt Controller (INTC) | ||
106 | * registers to their power on values | ||
107 | */ | ||
108 | |||
109 | /* | ||
110 | * Enable external irq (INTC IRQ mode). | ||
111 | * You should set corresponding bits of PFC to "00" | ||
112 | * to enable these interrupts. | ||
113 | */ | ||
114 | { IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY }, | ||
115 | { IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY }, | ||
116 | { IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY }, | ||
117 | { IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY }, | ||
118 | { IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY }, | ||
119 | { IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY }, | ||
120 | #endif | ||
121 | #endif | ||
122 | }; | ||
123 | |||
124 | void __init init_IRQ(void) | ||
125 | { | ||
126 | make_ipr_irq(sys_ipr_map, ARRAY_SIZE(sys_ipr_map)); | ||
127 | |||
128 | #ifdef CONFIG_CPU_HAS_PINT_IRQ | ||
129 | init_IRQ_pint(); | ||
130 | #endif | ||
131 | |||
132 | #ifdef CONFIG_CPU_HAS_INTC2_IRQ | ||
133 | init_IRQ_intc2(); | ||
134 | #endif | ||
135 | /* Perform the machine specific initialisation */ | ||
136 | if (sh_mv.mv_init_irq != NULL) | ||
137 | sh_mv.mv_init_irq(); | ||
138 | |||
139 | irq_ctx_init(smp_processor_id()); | ||
140 | } | ||
141 | |||
142 | #if !defined(CONFIG_CPU_HAS_PINT_IRQ) | 65 | #if !defined(CONFIG_CPU_HAS_PINT_IRQ) |
143 | int ipr_irq_demux(int irq) | 66 | int ipr_irq_demux(int irq) |
144 | { | 67 | { |
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..34d51b3745ea --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/entry.S | |||
@@ -0,0 +1,341 @@ | |||
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 | add #-0x10,r9 | ||
182 | shll2 r9 ! TRA | ||
183 | mov #OFF_TRA,r8 | ||
184 | add r15,r8 | ||
185 | mov.l r9,@r8 | ||
186 | mov r9,r8 | ||
187 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
188 | mov.l 5f, r9 | ||
189 | jsr @r9 | ||
190 | nop | ||
191 | #endif | ||
192 | sti | ||
193 | bra system_call | ||
194 | nop | ||
195 | |||
196 | .align 2 | ||
197 | 1: .long syscall_exit | ||
198 | 2: .long break_point_trap_software | ||
199 | 3: .long NR_syscalls | ||
200 | 4: .long sys_call_table | ||
201 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
202 | 5: .long trace_hardirqs_on | ||
203 | #endif | ||
204 | |||
205 | #if defined(CONFIG_SH_STANDARD_BIOS) | ||
206 | /* Unwind the stack and jmp to the debug entry */ | ||
207 | debug_kernel_fw: | ||
208 | mov r15,r0 | ||
209 | add #(22-4)*4-4,r0 | ||
210 | ldc.l @r0+,gbr | ||
211 | lds.l @r0+,mach | ||
212 | lds.l @r0+,macl | ||
213 | mov r15,r0 | ||
214 | mov.l @(OFF_SP,r0),r1 | ||
215 | mov #OFF_SR,r2 | ||
216 | mov.l @(r0,r2),r3 | ||
217 | mov.l r3,@-r1 | ||
218 | mov #OFF_SP,r2 | ||
219 | mov.l @(r0,r2),r3 | ||
220 | mov.l r3,@-r1 | ||
221 | mov r15,r0 | ||
222 | add #(22-4)*4-8,r0 | ||
223 | mov.l 1f,r2 | ||
224 | mov.l @r2,r2 | ||
225 | stc sr,r3 | ||
226 | mov.l r2,@r0 | ||
227 | mov.l r3,@r0 | ||
228 | mov.l r1,@(8,r0) | ||
229 | mov.l @r15+, r0 | ||
230 | mov.l @r15+, r1 | ||
231 | mov.l @r15+, r2 | ||
232 | mov.l @r15+, r3 | ||
233 | mov.l @r15+, r4 | ||
234 | mov.l @r15+, r5 | ||
235 | mov.l @r15+, r6 | ||
236 | mov.l @r15+, r7 | ||
237 | mov.l @r15+, r8 | ||
238 | mov.l @r15+, r9 | ||
239 | mov.l @r15+, r10 | ||
240 | mov.l @r15+, r11 | ||
241 | mov.l @r15+, r12 | ||
242 | mov.l @r15+, r13 | ||
243 | mov.l @r15+, r14 | ||
244 | add #8,r15 | ||
245 | lds.l @r15+, pr | ||
246 | rte | ||
247 | mov.l @r15+,r15 | ||
248 | .align 2 | ||
249 | 1: .long gdb_vbr_vector | ||
250 | #endif /* CONFIG_SH_STANDARD_BIOS */ | ||
251 | |||
252 | ENTRY(address_error_handler) | ||
253 | mov r15,r4 ! regs | ||
254 | add #4,r4 | ||
255 | mov #OFF_PC,r0 | ||
256 | mov.l @(r0,r15),r6 ! pc | ||
257 | mov.l 1f,r0 | ||
258 | jmp @r0 | ||
259 | mov #0,r5 ! writeaccess is unknown | ||
260 | .align 2 | ||
261 | |||
262 | 1: .long do_address_error | ||
263 | |||
264 | restore_all: | ||
265 | cli | ||
266 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
267 | mov.l 3f, r0 | ||
268 | jsr @r0 | ||
269 | nop | ||
270 | #endif | ||
271 | mov r15,r0 | ||
272 | mov.l $cpu_mode,r2 | ||
273 | mov #OFF_SR,r3 | ||
274 | mov.l @(r0,r3),r1 | ||
275 | mov.l r1,@r2 | ||
276 | shll2 r1 ! clear MD bit | ||
277 | shlr2 r1 | ||
278 | mov.l @(OFF_SP,r0),r2 | ||
279 | add #-8,r2 | ||
280 | mov.l r2,@(OFF_SP,r0) ! point exception frame top | ||
281 | mov.l r1,@(4,r2) ! set sr | ||
282 | mov #OFF_PC,r3 | ||
283 | mov.l @(r0,r3),r1 | ||
284 | mov.l r1,@r2 ! set pc | ||
285 | add #4*16+4,r0 | ||
286 | lds.l @r0+,pr | ||
287 | add #4,r0 ! skip sr | ||
288 | ldc.l @r0+,gbr | ||
289 | lds.l @r0+,mach | ||
290 | lds.l @r0+,macl | ||
291 | get_current_thread_info r0, r1 | ||
292 | mov.l $current_thread_info,r1 | ||
293 | mov.l r0,@r1 | ||
294 | mov.l @r15+,r0 | ||
295 | mov.l @r15+,r1 | ||
296 | mov.l @r15+,r2 | ||
297 | mov.l @r15+,r3 | ||
298 | mov.l @r15+,r4 | ||
299 | mov.l @r15+,r5 | ||
300 | mov.l @r15+,r6 | ||
301 | mov.l @r15+,r7 | ||
302 | mov.l @r15+,r8 | ||
303 | mov.l @r15+,r9 | ||
304 | mov.l @r15+,r10 | ||
305 | mov.l @r15+,r11 | ||
306 | mov.l @r15+,r12 | ||
307 | mov.l @r15+,r13 | ||
308 | mov.l @r15+,r14 | ||
309 | mov.l @r15,r15 | ||
310 | rte | ||
311 | nop | ||
312 | 2: | ||
313 | mov.l 1f,r8 | ||
314 | mov.l 2f,r9 | ||
315 | jmp @r9 | ||
316 | lds r8,pr | ||
317 | |||
318 | .align 2 | ||
319 | $current_thread_info: | ||
320 | .long __current_thread_info | ||
321 | $cpu_mode: | ||
322 | .long __cpu_mode | ||
323 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
324 | 3: .long trace_hardirqs_off | ||
325 | #endif | ||
326 | |||
327 | ! common exception handler | ||
328 | #include "../../entry-common.S" | ||
329 | |||
330 | .data | ||
331 | ! cpu operation mode | ||
332 | ! bit30 = MD (compatible SH3/4) | ||
333 | __cpu_mode: | ||
334 | .long 0x40000000 | ||
335 | |||
336 | .section .bss | ||
337 | __current_thread_info: | ||
338 | .long 0 | ||
339 | |||
340 | ENTRY(exception_handling_table) | ||
341 | .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..82c2d905152f --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c | |||
@@ -0,0 +1,53 @@ | |||
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); | ||
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..cdfeef49e62e --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c | |||
@@ -0,0 +1,58 @@ | |||
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 = { 240, 241, 242, 243}, | ||
21 | }, { | ||
22 | .mapbase = 0xfffe8800, | ||
23 | .flags = UPF_BOOT_AUTOCONF, | ||
24 | .type = PORT_SCIF, | ||
25 | .irqs = { 244, 245, 246, 247}, | ||
26 | }, { | ||
27 | .mapbase = 0xfffe9000, | ||
28 | .flags = UPF_BOOT_AUTOCONF, | ||
29 | .type = PORT_SCIF, | ||
30 | .irqs = { 248, 249, 250, 251}, | ||
31 | }, { | ||
32 | .mapbase = 0xfffe9800, | ||
33 | .flags = UPF_BOOT_AUTOCONF, | ||
34 | .type = PORT_SCIF, | ||
35 | .irqs = { 252, 253, 254, 255}, | ||
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); | ||
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/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile index 8dbf3895ece7..6e415baf04b4 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 |
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/clock-sh7780.c b/arch/sh/kernel/cpu/sh4/clock-sh7780.c index 93ad367342c9..9e6a216750c8 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh7780.c +++ b/arch/sh/kernel/cpu/sh4/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/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..afe0f1b1c030 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; |
@@ -126,23 +126,22 @@ int __init detect_cpu_and_cache_system(void) | |||
126 | break; | 126 | break; |
127 | case 0x8000: | 127 | case 0x8000: |
128 | cpu_data->type = CPU_ST40RA; | 128 | cpu_data->type = CPU_ST40RA; |
129 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 129 | cpu_data->flags |= CPU_HAS_FPU; |
130 | break; | 130 | break; |
131 | case 0x8100: | 131 | case 0x8100: |
132 | cpu_data->type = CPU_ST40GX1; | 132 | cpu_data->type = CPU_ST40GX1; |
133 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 133 | cpu_data->flags |= CPU_HAS_FPU; |
134 | break; | 134 | break; |
135 | case 0x700: | 135 | case 0x700: |
136 | cpu_data->type = CPU_SH4_501; | 136 | cpu_data->type = CPU_SH4_501; |
137 | cpu_data->icache.ways = 2; | 137 | cpu_data->icache.ways = 2; |
138 | cpu_data->dcache.ways = 2; | 138 | cpu_data->dcache.ways = 2; |
139 | cpu_data->flags |= CPU_HAS_PTEA; | ||
140 | break; | 139 | break; |
141 | case 0x600: | 140 | case 0x600: |
142 | cpu_data->type = CPU_SH4_202; | 141 | cpu_data->type = CPU_SH4_202; |
143 | cpu_data->icache.ways = 2; | 142 | cpu_data->icache.ways = 2; |
144 | cpu_data->dcache.ways = 2; | 143 | cpu_data->dcache.ways = 2; |
145 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 144 | cpu_data->flags |= CPU_HAS_FPU; |
146 | break; | 145 | break; |
147 | case 0x500 ... 0x501: | 146 | case 0x500 ... 0x501: |
148 | switch (prr) { | 147 | switch (prr) { |
@@ -160,7 +159,7 @@ int __init detect_cpu_and_cache_system(void) | |||
160 | cpu_data->icache.ways = 2; | 159 | cpu_data->icache.ways = 2; |
161 | cpu_data->dcache.ways = 2; | 160 | cpu_data->dcache.ways = 2; |
162 | 161 | ||
163 | cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA; | 162 | cpu_data->flags |= CPU_HAS_FPU; |
164 | 163 | ||
165 | break; | 164 | break; |
166 | default: | 165 | default: |
@@ -173,6 +172,10 @@ int __init detect_cpu_and_cache_system(void) | |||
173 | cpu_data->dcache.ways = 1; | 172 | cpu_data->dcache.ways = 1; |
174 | #endif | 173 | #endif |
175 | 174 | ||
175 | #ifdef CONFIG_CPU_HAS_PTEA | ||
176 | cpu_data->flags |= CPU_HAS_PTEA; | ||
177 | #endif | ||
178 | |||
176 | /* | 179 | /* |
177 | * On anything that's not a direct-mapped cache, look to the CVR | 180 | * On anything that's not a direct-mapped cache, look to the CVR |
178 | * for I/D-cache specifics. | 181 | * 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..bbcb06f18b04 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,6 +11,7 @@ | |||
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 | ||
15 | static struct plat_sci_port sci_platform_data[] = { | 17 | static struct plat_sci_port sci_platform_data[] = { |
@@ -46,3 +48,71 @@ static int __init sh7750_devices_setup(void) | |||
46 | ARRAY_SIZE(sh7750_devices)); | 48 | ARRAY_SIZE(sh7750_devices)); |
47 | } | 49 | } |
48 | __initcall(sh7750_devices_setup); | 50 | __initcall(sh7750_devices_setup); |
51 | |||
52 | static struct ipr_data sh7750_ipr_map[] = { | ||
53 | /* IRQ, IPR-idx, shift, priority */ | ||
54 | { 16, 0, 12, 2 }, /* TMU0 TUNI*/ | ||
55 | { 17, 0, 12, 2 }, /* TMU1 TUNI */ | ||
56 | { 18, 0, 4, 2 }, /* TMU2 TUNI */ | ||
57 | { 19, 0, 4, 2 }, /* TMU2 TIPCI */ | ||
58 | { 27, 1, 12, 2 }, /* WDT ITI */ | ||
59 | { 20, 0, 0, 2 }, /* RTC ATI (alarm) */ | ||
60 | { 21, 0, 0, 2 }, /* RTC PRI (period) */ | ||
61 | { 22, 0, 0, 2 }, /* RTC CUI (carry) */ | ||
62 | { 23, 1, 4, 3 }, /* SCI ERI */ | ||
63 | { 24, 1, 4, 3 }, /* SCI RXI */ | ||
64 | { 25, 1, 4, 3 }, /* SCI TXI */ | ||
65 | { 40, 2, 4, 3 }, /* SCIF ERI */ | ||
66 | { 41, 2, 4, 3 }, /* SCIF RXI */ | ||
67 | { 42, 2, 4, 3 }, /* SCIF BRI */ | ||
68 | { 43, 2, 4, 3 }, /* SCIF TXI */ | ||
69 | { 34, 2, 8, 7 }, /* DMAC DMTE0 */ | ||
70 | { 35, 2, 8, 7 }, /* DMAC DMTE1 */ | ||
71 | { 36, 2, 8, 7 }, /* DMAC DMTE2 */ | ||
72 | { 37, 2, 8, 7 }, /* DMAC DMTE3 */ | ||
73 | { 28, 2, 8, 7 }, /* DMAC DMAE */ | ||
74 | }; | ||
75 | |||
76 | static struct ipr_data sh7751_ipr_map[] = { | ||
77 | { 44, 2, 8, 7 }, /* DMAC DMTE4 */ | ||
78 | { 45, 2, 8, 7 }, /* DMAC DMTE5 */ | ||
79 | { 46, 2, 8, 7 }, /* DMAC DMTE6 */ | ||
80 | { 47, 2, 8, 7 }, /* DMAC DMTE7 */ | ||
81 | /* The following use INTC_INPRI00 for masking, which is a 32-bit | ||
82 | register, not a 16-bit register like the IPRx registers, so it | ||
83 | would need special support */ | ||
84 | /*{ 72, INTPRI00, 8, ? },*/ /* TMU3 TUNI */ | ||
85 | /*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */ | ||
86 | }; | ||
87 | |||
88 | static unsigned long ipr_offsets[] = { | ||
89 | 0xffd00004UL, /* 0: IPRA */ | ||
90 | 0xffd00008UL, /* 1: IPRB */ | ||
91 | 0xffd0000cUL, /* 2: IPRC */ | ||
92 | 0xffd00010UL, /* 3: IPRD */ | ||
93 | }; | ||
94 | |||
95 | /* given the IPR index return the address of the IPR register */ | ||
96 | unsigned int map_ipridx_to_addr(int idx) | ||
97 | { | ||
98 | if (idx >= ARRAY_SIZE(ipr_offsets)) | ||
99 | return 0; | ||
100 | return ipr_offsets[idx]; | ||
101 | } | ||
102 | |||
103 | #define INTC_ICR 0xffd00000UL | ||
104 | #define INTC_ICR_IRLM (1<<7) | ||
105 | |||
106 | /* enable individual interrupt mode for external interupts */ | ||
107 | void ipr_irq_enable_irlm(void) | ||
108 | { | ||
109 | ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR); | ||
110 | } | ||
111 | |||
112 | void __init init_IRQ_ipr() | ||
113 | { | ||
114 | make_ipr_irq(sh7750_ipr_map, ARRAY_SIZE(sh7750_ipr_map)); | ||
115 | #ifdef CONFIG_CPU_SUBTYPE_SH7751 | ||
116 | make_ipr_irq(sh7751_ipr_map, ARRAY_SIZE(sh7751_ipr_map)); | ||
117 | #endif | ||
118 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7780.c b/arch/sh/kernel/cpu/sh4/setup-sh7780.c index 814ddb226531..9aeaa2ddaa28 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7780.c | |||
@@ -79,25 +79,27 @@ static int __init sh7780_devices_setup(void) | |||
79 | __initcall(sh7780_devices_setup); | 79 | __initcall(sh7780_devices_setup); |
80 | 80 | ||
81 | static struct intc2_data intc2_irq_table[] = { | 81 | static struct intc2_data intc2_irq_table[] = { |
82 | { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2 }, | 82 | { 28, 0, 24, 0, 0, 2 }, /* TMU0 */ |
83 | { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY }, | ||
84 | { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY }, | ||
85 | { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY }, | ||
86 | { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, | ||
87 | { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, | ||
88 | { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, | ||
89 | { SCIF0_TXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, | ||
90 | 83 | ||
91 | { SCIF1_ERI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, | 84 | { 21, 1, 0, 0, 2, 2 }, |
92 | { SCIF1_RXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, | 85 | { 22, 1, 1, 0, 2, 2 }, |
93 | { SCIF1_BRI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, | 86 | { 23, 1, 2, 0, 2, 2 }, |
94 | { SCIF1_TXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY }, | ||
95 | 87 | ||
96 | { PCIC0_IRQ, 0x10, 8, 0, INTC_PCIC0_MSK, PCIC0_PRIORITY }, | 88 | { 40, 8, 24, 0, 3, 3 }, /* SCIF0 ERI */ |
97 | { PCIC1_IRQ, 0x10, 0, 0, INTC_PCIC1_MSK, PCIC1_PRIORITY }, | 89 | { 41, 8, 24, 0, 3, 3 }, /* SCIF0 RXI */ |
98 | { PCIC2_IRQ, 0x14, 24, 0, INTC_PCIC2_MSK, PCIC2_PRIORITY }, | 90 | { 42, 8, 24, 0, 3, 3 }, /* SCIF0 BRI */ |
99 | { PCIC3_IRQ, 0x14, 16, 0, INTC_PCIC3_MSK, PCIC3_PRIORITY }, | 91 | { 43, 8, 24, 0, 3, 3 }, /* SCIF0 TXI */ |
100 | { PCIC4_IRQ, 0x14, 8, 0, INTC_PCIC4_MSK, PCIC4_PRIORITY }, | 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 */ | ||
101 | }; | 103 | }; |
102 | 104 | ||
103 | void __init init_IRQ_intc2(void) | 105 | void __init init_IRQ_intc2(void) |
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 7bcc73f9b8df..55f43506995a 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> |
@@ -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 | { |
@@ -166,7 +167,7 @@ unsigned long sq_remap(unsigned long phys, unsigned int size, | |||
166 | map->size = size; | 167 | map->size = size; |
167 | map->name = name; | 168 | map->name = name; |
168 | 169 | ||
169 | page = bitmap_find_free_region(sq_bitmap, 0x04000000, | 170 | page = bitmap_find_free_region(sq_bitmap, 0x04000000 >> PAGE_SHIFT, |
170 | get_order(map->size)); | 171 | get_order(map->size)); |
171 | if (unlikely(page < 0)) { | 172 | if (unlikely(page < 0)) { |
172 | ret = -ENOSPC; | 173 | ret = -ENOSPC; |
@@ -193,6 +194,7 @@ out: | |||
193 | kmem_cache_free(sq_cache, map); | 194 | kmem_cache_free(sq_cache, map); |
194 | return ret; | 195 | return ret; |
195 | } | 196 | } |
197 | EXPORT_SYMBOL(sq_remap); | ||
196 | 198 | ||
197 | /** | 199 | /** |
198 | * sq_unmap - Unmap a Store Queue allocation | 200 | * sq_unmap - Unmap a Store Queue allocation |
@@ -234,6 +236,7 @@ void sq_unmap(unsigned long vaddr) | |||
234 | 236 | ||
235 | kmem_cache_free(sq_cache, map); | 237 | kmem_cache_free(sq_cache, map); |
236 | } | 238 | } |
239 | EXPORT_SYMBOL(sq_unmap); | ||
237 | 240 | ||
238 | /* | 241 | /* |
239 | * Needlessly complex sysfs interface. Unfortunately it doesn't seem like | 242 | * Needlessly complex sysfs interface. Unfortunately it doesn't seem like |
@@ -402,7 +405,3 @@ module_exit(sq_api_exit); | |||
402 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); | 405 | 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"); | 406 | MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); |
404 | MODULE_LICENSE("GPL"); | 407 | 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/early_printk.c b/arch/sh/kernel/early_printk.c index a00022722e9e..60340823798a 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 |
@@ -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 | } |
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S new file mode 100644 index 000000000000..29136a35d7c7 --- /dev/null +++ b/arch/sh/kernel/entry-common.S | |||
@@ -0,0 +1,433 @@ | |||
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 | |||
83 | #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ | ||
84 | |||
85 | |||
86 | .align 2 | ||
87 | debug_trap: | ||
88 | #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) | ||
89 | mov #OFF_SR, r0 | ||
90 | mov.l @(r0,r15), r0 ! get status register | ||
91 | shll r0 | ||
92 | shll r0 ! kernel space? | ||
93 | bt/s debug_kernel | ||
94 | #endif | ||
95 | mov.l @r15, r0 ! Restore R0 value | ||
96 | mov.l 1f, r8 | ||
97 | jmp @r8 | ||
98 | nop | ||
99 | |||
100 | .align 2 | ||
101 | ENTRY(exception_error) | ||
102 | ! | ||
103 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
104 | mov.l 3f, r0 | ||
105 | jsr @r0 | ||
106 | nop | ||
107 | #endif | ||
108 | sti | ||
109 | mov.l 2f, r0 | ||
110 | jmp @r0 | ||
111 | nop | ||
112 | |||
113 | ! | ||
114 | .align 2 | ||
115 | 1: .long break_point_trap_software | ||
116 | 2: .long do_exception_error | ||
117 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
118 | 3: .long trace_hardirqs_on | ||
119 | #endif | ||
120 | |||
121 | .align 2 | ||
122 | ret_from_exception: | ||
123 | preempt_stop() | ||
124 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
125 | mov.l 4f, r0 | ||
126 | jsr @r0 | ||
127 | nop | ||
128 | #endif | ||
129 | ENTRY(ret_from_irq) | ||
130 | ! | ||
131 | mov #OFF_SR, r0 | ||
132 | mov.l @(r0,r15), r0 ! get status register | ||
133 | shll r0 | ||
134 | shll r0 ! kernel space? | ||
135 | get_current_thread_info r8, r0 | ||
136 | bt resume_kernel ! Yes, it's from kernel, go back soon | ||
137 | |||
138 | #ifdef CONFIG_PREEMPT | ||
139 | bra resume_userspace | ||
140 | nop | ||
141 | ENTRY(resume_kernel) | ||
142 | mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count | ||
143 | tst r0, r0 | ||
144 | bf noresched | ||
145 | need_resched: | ||
146 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
147 | tst #_TIF_NEED_RESCHED, r0 ! need_resched set? | ||
148 | bt noresched | ||
149 | |||
150 | mov #OFF_SR, r0 | ||
151 | mov.l @(r0,r15), r0 ! get status register | ||
152 | and #0xf0, r0 ! interrupts off (exception path)? | ||
153 | cmp/eq #0xf0, r0 | ||
154 | bt noresched | ||
155 | |||
156 | mov.l 1f, r0 | ||
157 | mov.l r0, @(TI_PRE_COUNT,r8) | ||
158 | |||
159 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
160 | mov.l 3f, r0 | ||
161 | jsr @r0 | ||
162 | nop | ||
163 | #endif | ||
164 | sti | ||
165 | mov.l 2f, r0 | ||
166 | jsr @r0 | ||
167 | nop | ||
168 | mov #0, r0 | ||
169 | mov.l r0, @(TI_PRE_COUNT,r8) | ||
170 | cli | ||
171 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
172 | mov.l 4f, r0 | ||
173 | jsr @r0 | ||
174 | nop | ||
175 | #endif | ||
176 | |||
177 | bra need_resched | ||
178 | nop | ||
179 | |||
180 | noresched: | ||
181 | bra __restore_all | ||
182 | nop | ||
183 | |||
184 | .align 2 | ||
185 | 1: .long PREEMPT_ACTIVE | ||
186 | 2: .long schedule | ||
187 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
188 | 3: .long trace_hardirqs_on | ||
189 | 4: .long trace_hardirqs_off | ||
190 | #endif | ||
191 | #endif | ||
192 | |||
193 | ENTRY(resume_userspace) | ||
194 | ! r8: current_thread_info | ||
195 | cli | ||
196 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
197 | mov.l 5f, r0 | ||
198 | jsr @r0 | ||
199 | nop | ||
200 | #endif | ||
201 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
202 | tst #_TIF_WORK_MASK, r0 | ||
203 | bt/s __restore_all | ||
204 | tst #_TIF_NEED_RESCHED, r0 | ||
205 | |||
206 | .align 2 | ||
207 | work_pending: | ||
208 | ! r0: current_thread_info->flags | ||
209 | ! r8: current_thread_info | ||
210 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" | ||
211 | bf/s work_resched | ||
212 | tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0 | ||
213 | work_notifysig: | ||
214 | bt/s __restore_all | ||
215 | mov r15, r4 | ||
216 | mov r12, r5 ! set arg1(save_r0) | ||
217 | mov r0, r6 | ||
218 | mov.l 2f, r1 | ||
219 | mov.l 3f, r0 | ||
220 | jmp @r1 | ||
221 | lds r0, pr | ||
222 | work_resched: | ||
223 | #ifndef CONFIG_PREEMPT | ||
224 | ! gUSA handling | ||
225 | mov.l @(OFF_SP,r15), r0 ! get user space stack pointer | ||
226 | mov r0, r1 | ||
227 | shll r0 | ||
228 | bf/s 1f | ||
229 | shll r0 | ||
230 | bf/s 1f | ||
231 | mov #OFF_PC, r0 | ||
232 | ! SP >= 0xc0000000 : gUSA mark | ||
233 | mov.l @(r0,r15), r2 ! get user space PC (program counter) | ||
234 | mov.l @(OFF_R0,r15), r3 ! end point | ||
235 | cmp/hs r3, r2 ! r2 >= r3? | ||
236 | bt 1f | ||
237 | add r3, r1 ! rewind point #2 | ||
238 | mov.l r1, @(r0,r15) ! reset PC to rewind point #2 | ||
239 | ! | ||
240 | 1: | ||
241 | #endif | ||
242 | mov.l 1f, r1 | ||
243 | jsr @r1 ! schedule | ||
244 | nop | ||
245 | cli | ||
246 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
247 | mov.l 5f, r0 | ||
248 | jsr @r0 | ||
249 | nop | ||
250 | #endif | ||
251 | ! | ||
252 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
253 | tst #_TIF_WORK_MASK, r0 | ||
254 | bt __restore_all | ||
255 | bra work_pending | ||
256 | tst #_TIF_NEED_RESCHED, r0 | ||
257 | |||
258 | .align 2 | ||
259 | 1: .long schedule | ||
260 | 2: .long do_notify_resume | ||
261 | 3: .long restore_all | ||
262 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
263 | 4: .long trace_hardirqs_on | ||
264 | 5: .long trace_hardirqs_off | ||
265 | #endif | ||
266 | |||
267 | .align 2 | ||
268 | syscall_exit_work: | ||
269 | ! r0: current_thread_info->flags | ||
270 | ! r8: current_thread_info | ||
271 | tst #_TIF_SYSCALL_TRACE, r0 | ||
272 | bt/s work_pending | ||
273 | tst #_TIF_NEED_RESCHED, r0 | ||
274 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
275 | mov.l 5f, r0 | ||
276 | jsr @r0 | ||
277 | nop | ||
278 | #endif | ||
279 | sti | ||
280 | ! XXX setup arguments... | ||
281 | mov.l 4f, r0 ! do_syscall_trace | ||
282 | jsr @r0 | ||
283 | nop | ||
284 | bra resume_userspace | ||
285 | nop | ||
286 | |||
287 | .align 2 | ||
288 | syscall_trace_entry: | ||
289 | ! Yes it is traced. | ||
290 | ! XXX setup arguments... | ||
291 | mov.l 4f, r11 ! Call do_syscall_trace which notifies | ||
292 | jsr @r11 ! superior (will chomp R[0-7]) | ||
293 | nop | ||
294 | ! Reload R0-R4 from kernel stack, where the | ||
295 | ! parent may have modified them using | ||
296 | ! ptrace(POKEUSR). (Note that R0-R2 are | ||
297 | ! used by the system call handler directly | ||
298 | ! from the kernel stack anyway, so don't need | ||
299 | ! to be reloaded here.) This allows the parent | ||
300 | ! to rewrite system calls and args on the fly. | ||
301 | mov.l @(OFF_R4,r15), r4 ! arg0 | ||
302 | mov.l @(OFF_R5,r15), r5 | ||
303 | mov.l @(OFF_R6,r15), r6 | ||
304 | mov.l @(OFF_R7,r15), r7 ! arg3 | ||
305 | mov.l @(OFF_R3,r15), r3 ! syscall_nr | ||
306 | ! | ||
307 | mov.l 2f, r10 ! Number of syscalls | ||
308 | cmp/hs r10, r3 | ||
309 | bf syscall_call | ||
310 | mov #-ENOSYS, r0 | ||
311 | bra syscall_exit | ||
312 | mov.l r0, @(OFF_R0,r15) ! Return value | ||
313 | |||
314 | __restore_all: | ||
315 | mov.l 1f, r0 | ||
316 | jmp @r0 | ||
317 | nop | ||
318 | |||
319 | .align 2 | ||
320 | 1: .long restore_all | ||
321 | |||
322 | .align 2 | ||
323 | not_syscall_tra: | ||
324 | bra debug_trap | ||
325 | nop | ||
326 | |||
327 | .align 2 | ||
328 | syscall_badsys: ! Bad syscall number | ||
329 | mov #-ENOSYS, r0 | ||
330 | bra resume_userspace | ||
331 | mov.l r0, @(OFF_R0,r15) ! Return value | ||
332 | |||
333 | |||
334 | /* | ||
335 | * Syscall interface: | ||
336 | * | ||
337 | * Syscall #: R3 | ||
338 | * Arguments #0 to #3: R4--R7 | ||
339 | * Arguments #4 to #6: R0, R1, R2 | ||
340 | * TRA: (number of arguments + 0x10) x 4 | ||
341 | * | ||
342 | * This code also handles delegating other traps to the BIOS/gdb stub | ||
343 | * according to: | ||
344 | * | ||
345 | * Trap number | ||
346 | * (TRA>>2) Purpose | ||
347 | * -------- ------- | ||
348 | * 0x0-0xf old syscall ABI | ||
349 | * 0x10-0x1f new syscall ABI | ||
350 | * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. | ||
351 | * | ||
352 | * Note: When we're first called, the TRA value must be shifted | ||
353 | * right 2 bits in order to get the value that was used as the "trapa" | ||
354 | * argument. | ||
355 | */ | ||
356 | |||
357 | .align 2 | ||
358 | .globl ret_from_fork | ||
359 | ret_from_fork: | ||
360 | mov.l 1f, r8 | ||
361 | jsr @r8 | ||
362 | mov r0, r4 | ||
363 | bra syscall_exit | ||
364 | nop | ||
365 | .align 2 | ||
366 | 1: .long schedule_tail | ||
367 | ! | ||
368 | ENTRY(system_call) | ||
369 | #if !defined(CONFIG_CPU_SH2) | ||
370 | mov.l 1f, r9 | ||
371 | mov.l @r9, r8 ! Read from TRA (Trap Address) Register | ||
372 | #endif | ||
373 | ! | ||
374 | ! Is the trap argument >= 0x20? (TRA will be >= 0x80) | ||
375 | mov #0x7f, r9 | ||
376 | cmp/hi r9, r8 | ||
377 | bt/s not_syscall_tra | ||
378 | mov #OFF_TRA, r9 | ||
379 | add r15, r9 | ||
380 | mov.l r8, @r9 ! set TRA value to tra | ||
381 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
382 | mov.l 5f, r10 | ||
383 | jsr @r10 | ||
384 | nop | ||
385 | #endif | ||
386 | sti | ||
387 | |||
388 | ! | ||
389 | get_current_thread_info r8, r10 | ||
390 | mov.l @(TI_FLAGS,r8), r8 | ||
391 | mov #_TIF_SYSCALL_TRACE, r10 | ||
392 | tst r10, r8 | ||
393 | bf syscall_trace_entry | ||
394 | ! | ||
395 | mov.l 2f, r8 ! Number of syscalls | ||
396 | cmp/hs r8, r3 | ||
397 | bt syscall_badsys | ||
398 | ! | ||
399 | syscall_call: | ||
400 | shll2 r3 ! x4 | ||
401 | mov.l 3f, r8 ! Load the address of sys_call_table | ||
402 | add r8, r3 | ||
403 | mov.l @r3, r8 | ||
404 | jsr @r8 ! jump to specific syscall handler | ||
405 | nop | ||
406 | mov.l @(OFF_R0,r15), r12 ! save r0 | ||
407 | mov.l r0, @(OFF_R0,r15) ! save the return value | ||
408 | ! | ||
409 | syscall_exit: | ||
410 | cli | ||
411 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
412 | mov.l 6f, r0 | ||
413 | jsr @r0 | ||
414 | nop | ||
415 | #endif | ||
416 | ! | ||
417 | get_current_thread_info r8, r0 | ||
418 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | ||
419 | tst #_TIF_ALLWORK_MASK, r0 | ||
420 | bf syscall_exit_work | ||
421 | bra __restore_all | ||
422 | nop | ||
423 | .align 2 | ||
424 | #if !defined(CONFIG_CPU_SH2) | ||
425 | 1: .long TRA | ||
426 | #endif | ||
427 | 2: .long NR_syscalls | ||
428 | 3: .long sys_call_table | ||
429 | 4: .long do_syscall_trace | ||
430 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
431 | 5: .long trace_hardirqs_on | ||
432 | 6: .long trace_hardirqs_off | ||
433 | #endif | ||
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S index f5f53d14f245..6aca4bc6ec5d 100644 --- a/arch/sh/kernel/head.S +++ b/arch/sh/kernel/head.S | |||
@@ -33,7 +33,7 @@ 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 | .balign PAGE_SIZE,0,PAGE_SIZE |
37 | 37 | ||
38 | .text | 38 | .text |
39 | /* | 39 | /* |
@@ -53,8 +53,10 @@ ENTRY(_stext) | |||
53 | ldc r0, sr | 53 | ldc r0, sr |
54 | ! Initialize global interrupt mask | 54 | ! Initialize global interrupt mask |
55 | mov #0, r0 | 55 | mov #0, r0 |
56 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
56 | ldc r0, r6_bank | 57 | ldc r0, r6_bank |
57 | 58 | #endif | |
59 | |||
58 | /* | 60 | /* |
59 | * Prefetch if possible to reduce cache miss penalty. | 61 | * Prefetch if possible to reduce cache miss penalty. |
60 | * | 62 | * |
@@ -68,11 +70,14 @@ ENTRY(_stext) | |||
68 | ! | 70 | ! |
69 | mov.l 2f, r0 | 71 | mov.l 2f, r0 |
70 | mov r0, r15 ! Set initial r15 (stack pointer) | 72 | mov r0, r15 ! Set initial r15 (stack pointer) |
71 | mov #(THREAD_SIZE >> 8), r1 | 73 | mov #(THREAD_SIZE >> 10), r1 |
72 | shll8 r1 ! r1 = THREAD_SIZE | 74 | shll8 r1 ! r1 = THREAD_SIZE |
75 | shll2 r1 | ||
73 | sub r1, r0 ! | 76 | sub r1, r0 ! |
77 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
74 | ldc r0, r7_bank ! ... and initial thread_info | 78 | ldc r0, r7_bank ! ... and initial thread_info |
75 | 79 | #endif | |
80 | |||
76 | ! Clear BSS area | 81 | ! Clear BSS area |
77 | mov.l 3f, r1 | 82 | mov.l 3f, r1 |
78 | add #4, r1 | 83 | add #4, r1 |
@@ -95,7 +100,11 @@ ENTRY(_stext) | |||
95 | nop | 100 | nop |
96 | 101 | ||
97 | .balign 4 | 102 | .balign 4 |
103 | #if defined(CONFIG_CPU_SH2) | ||
104 | 1: .long 0x000000F0 ! IMASK=0xF | ||
105 | #else | ||
98 | 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF | 106 | 1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF |
107 | #endif | ||
99 | 2: .long init_thread_union+THREAD_SIZE | 108 | 2: .long init_thread_union+THREAD_SIZE |
100 | 3: .long __bss_start | 109 | 3: .long __bss_start |
101 | 4: .long _end | 110 | 4: .long _end |
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 944128ce9706..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> |
@@ -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 a52b13ac6b7f..f3e2631be144 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c | |||
@@ -385,10 +385,11 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne | |||
385 | 385 | ||
386 | asmlinkage int sys_fork(unsigned long r4, unsigned long r5, | 386 | asmlinkage int sys_fork(unsigned long r4, unsigned long r5, |
387 | unsigned long r6, unsigned long r7, | 387 | unsigned long r6, unsigned long r7, |
388 | struct pt_regs regs) | 388 | struct pt_regs __regs) |
389 | { | 389 | { |
390 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
390 | #ifdef CONFIG_MMU | 391 | #ifdef CONFIG_MMU |
391 | return do_fork(SIGCHLD, regs.regs[15], ®s, 0, NULL, NULL); | 392 | return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL); |
392 | #else | 393 | #else |
393 | /* fork almost works, enough to trick you into looking elsewhere :-( */ | 394 | /* fork almost works, enough to trick you into looking elsewhere :-( */ |
394 | return -EINVAL; | 395 | return -EINVAL; |
@@ -398,11 +399,12 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5, | |||
398 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | 399 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, |
399 | unsigned long parent_tidptr, | 400 | unsigned long parent_tidptr, |
400 | unsigned long child_tidptr, | 401 | unsigned long child_tidptr, |
401 | struct pt_regs regs) | 402 | struct pt_regs __regs) |
402 | { | 403 | { |
404 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
403 | if (!newsp) | 405 | if (!newsp) |
404 | newsp = regs.regs[15]; | 406 | newsp = regs->regs[15]; |
405 | return do_fork(clone_flags, newsp, ®s, 0, | 407 | return do_fork(clone_flags, newsp, regs, 0, |
406 | (int __user *)parent_tidptr, (int __user *)child_tidptr); | 408 | (int __user *)parent_tidptr, (int __user *)child_tidptr); |
407 | } | 409 | } |
408 | 410 | ||
@@ -418,9 +420,10 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | |||
418 | */ | 420 | */ |
419 | asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, | 421 | asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, |
420 | unsigned long r6, unsigned long r7, | 422 | unsigned long r6, unsigned long r7, |
421 | struct pt_regs regs) | 423 | struct pt_regs __regs) |
422 | { | 424 | { |
423 | 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, | ||
424 | 0, NULL, NULL); | 427 | 0, NULL, NULL); |
425 | } | 428 | } |
426 | 429 | ||
@@ -429,8 +432,9 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, | |||
429 | */ | 432 | */ |
430 | asmlinkage int sys_execve(char *ufilename, char **uargv, | 433 | asmlinkage int sys_execve(char *ufilename, char **uargv, |
431 | char **uenvp, unsigned long r7, | 434 | char **uenvp, unsigned long r7, |
432 | struct pt_regs regs) | 435 | struct pt_regs __regs) |
433 | { | 436 | { |
437 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
434 | int error; | 438 | int error; |
435 | char *filename; | 439 | char *filename; |
436 | 440 | ||
@@ -442,7 +446,7 @@ asmlinkage int sys_execve(char *ufilename, char **uargv, | |||
442 | error = do_execve(filename, | 446 | error = do_execve(filename, |
443 | (char __user * __user *)uargv, | 447 | (char __user * __user *)uargv, |
444 | (char __user * __user *)uenvp, | 448 | (char __user * __user *)uenvp, |
445 | ®s); | 449 | regs); |
446 | if (error == 0) { | 450 | if (error == 0) { |
447 | task_lock(current); | 451 | task_lock(current); |
448 | current->ptrace &= ~PT_DTRACE; | 452 | current->ptrace &= ~PT_DTRACE; |
@@ -472,9 +476,7 @@ unsigned long get_wchan(struct task_struct *p) | |||
472 | return pc; | 476 | return pc; |
473 | } | 477 | } |
474 | 478 | ||
475 | asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, | 479 | asmlinkage void break_point_trap(void) |
476 | unsigned long r6, unsigned long r7, | ||
477 | struct pt_regs regs) | ||
478 | { | 480 | { |
479 | /* Clear tracing. */ | 481 | /* Clear tracing. */ |
480 | #if defined(CONFIG_CPU_SH4A) | 482 | #if defined(CONFIG_CPU_SH4A) |
@@ -492,8 +494,10 @@ asmlinkage void break_point_trap(unsigned long r4, unsigned long r5, | |||
492 | 494 | ||
493 | asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, | 495 | asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, |
494 | unsigned long r6, unsigned long r7, | 496 | unsigned long r6, unsigned long r7, |
495 | struct pt_regs regs) | 497 | struct pt_regs __regs) |
496 | { | 498 | { |
497 | regs.pc -= 2; | 499 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
500 | |||
501 | regs->pc -= 2; | ||
498 | force_sig(SIGTRAP, current); | 502 | force_sig(SIGTRAP, current); |
499 | } | 503 | } |
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..696ca75752d9 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -392,6 +392,7 @@ static int __init topology_init(void) | |||
392 | subsys_initcall(topology_init); | 392 | subsys_initcall(topology_init); |
393 | 393 | ||
394 | static const char *cpu_name[] = { | 394 | static const char *cpu_name[] = { |
395 | [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619", | ||
395 | [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300", | 396 | [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300", |
396 | [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", | 397 | [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", |
397 | [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", | 398 | [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", |
@@ -404,6 +405,7 @@ static const char *cpu_name[] = { | |||
404 | [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501", | 405 | [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501", |
405 | [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780", | 406 | [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780", |
406 | [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343", | 407 | [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343", |
408 | [CPU_SH7785] = "SH7785", | ||
407 | [CPU_SH_NONE] = "Unknown" | 409 | [CPU_SH_NONE] = "Unknown" |
408 | }; | 410 | }; |
409 | 411 | ||
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index 8a2fd19dc9eb..c706f3bfd897 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c | |||
@@ -73,8 +73,6 @@ DECLARE_EXPORT(__lshrdi3); | |||
73 | DECLARE_EXPORT(__movstr); | 73 | DECLARE_EXPORT(__movstr); |
74 | DECLARE_EXPORT(__movstrSI16); | 74 | DECLARE_EXPORT(__movstrSI16); |
75 | 75 | ||
76 | EXPORT_SYMBOL(strcpy); | ||
77 | |||
78 | #ifdef CONFIG_CPU_SH4 | 76 | #ifdef CONFIG_CPU_SH4 |
79 | DECLARE_EXPORT(__movstr_i4_even); | 77 | DECLARE_EXPORT(__movstr_i4_even); |
80 | DECLARE_EXPORT(__movstr_i4_odd); | 78 | DECLARE_EXPORT(__movstr_i4_odd); |
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 5213f5bc6ce0..50d7c4993bef 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c | |||
@@ -37,7 +37,7 @@ | |||
37 | asmlinkage int | 37 | asmlinkage int |
38 | sys_sigsuspend(old_sigset_t mask, | 38 | sys_sigsuspend(old_sigset_t mask, |
39 | unsigned long r5, unsigned long r6, unsigned long r7, | 39 | unsigned long r5, unsigned long r6, unsigned long r7, |
40 | struct pt_regs regs) | 40 | struct pt_regs __regs) |
41 | { | 41 | { |
42 | mask &= _BLOCKABLE; | 42 | mask &= _BLOCKABLE; |
43 | spin_lock_irq(¤t->sighand->siglock); | 43 | spin_lock_irq(¤t->sighand->siglock); |
@@ -52,7 +52,7 @@ sys_sigsuspend(old_sigset_t mask, | |||
52 | return -ERESTARTNOHAND; | 52 | return -ERESTARTNOHAND; |
53 | } | 53 | } |
54 | 54 | ||
55 | asmlinkage int | 55 | asmlinkage int |
56 | sys_sigaction(int sig, const struct old_sigaction __user *act, | 56 | sys_sigaction(int sig, const struct old_sigaction __user *act, |
57 | struct old_sigaction __user *oact) | 57 | struct old_sigaction __user *oact) |
58 | { | 58 | { |
@@ -87,9 +87,11 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
87 | asmlinkage int | 87 | asmlinkage int |
88 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 88 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
89 | unsigned long r6, unsigned long r7, | 89 | unsigned long r6, unsigned long r7, |
90 | struct pt_regs regs) | 90 | struct pt_regs __regs) |
91 | { | 91 | { |
92 | return do_sigaltstack(uss, uoss, regs.regs[15]); | 92 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
93 | |||
94 | return do_sigaltstack(uss, uoss, regs->regs[15]); | ||
93 | } | 95 | } |
94 | 96 | ||
95 | 97 | ||
@@ -98,7 +100,11 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
98 | */ | 100 | */ |
99 | 101 | ||
100 | #define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ | 102 | #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) */ | 103 | #if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A) |
104 | #define TRAP_NOARG 0xc320 /* Syscall w/no args (NR in R3) */ | ||
105 | #else | ||
106 | #define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) */ | ||
107 | #endif | ||
102 | #define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ | 108 | #define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ |
103 | 109 | ||
104 | struct sigframe | 110 | struct sigframe |
@@ -194,9 +200,10 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p | |||
194 | 200 | ||
195 | asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, | 201 | asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, |
196 | unsigned long r6, unsigned long r7, | 202 | unsigned long r6, unsigned long r7, |
197 | struct pt_regs regs) | 203 | struct pt_regs __regs) |
198 | { | 204 | { |
199 | struct sigframe __user *frame = (struct sigframe __user *)regs.regs[15]; | 205 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
206 | struct sigframe __user *frame = (struct sigframe __user *)regs->regs[15]; | ||
200 | sigset_t set; | 207 | sigset_t set; |
201 | int r0; | 208 | int r0; |
202 | 209 | ||
@@ -216,7 +223,7 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, | |||
216 | recalc_sigpending(); | 223 | recalc_sigpending(); |
217 | spin_unlock_irq(¤t->sighand->siglock); | 224 | spin_unlock_irq(¤t->sighand->siglock); |
218 | 225 | ||
219 | if (restore_sigcontext(®s, &frame->sc, &r0)) | 226 | if (restore_sigcontext(regs, &frame->sc, &r0)) |
220 | goto badframe; | 227 | goto badframe; |
221 | return r0; | 228 | return r0; |
222 | 229 | ||
@@ -227,9 +234,10 @@ badframe: | |||
227 | 234 | ||
228 | asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, | 235 | asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, |
229 | unsigned long r6, unsigned long r7, | 236 | unsigned long r6, unsigned long r7, |
230 | struct pt_regs regs) | 237 | struct pt_regs __regs) |
231 | { | 238 | { |
232 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.regs[15]; | 239 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
240 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15]; | ||
233 | sigset_t set; | 241 | sigset_t set; |
234 | stack_t st; | 242 | stack_t st; |
235 | int r0; | 243 | int r0; |
@@ -246,14 +254,14 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, | |||
246 | recalc_sigpending(); | 254 | recalc_sigpending(); |
247 | spin_unlock_irq(¤t->sighand->siglock); | 255 | spin_unlock_irq(¤t->sighand->siglock); |
248 | 256 | ||
249 | if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &r0)) | 257 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) |
250 | goto badframe; | 258 | goto badframe; |
251 | 259 | ||
252 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) | 260 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) |
253 | goto badframe; | 261 | goto badframe; |
254 | /* It is more difficult to avoid calling this function than to | 262 | /* It is more difficult to avoid calling this function than to |
255 | call it and ignore errors. */ | 263 | call it and ignore errors. */ |
256 | do_sigaltstack(&st, NULL, regs.regs[15]); | 264 | do_sigaltstack(&st, NULL, regs->regs[15]); |
257 | 265 | ||
258 | return r0; | 266 | return r0; |
259 | 267 | ||
@@ -350,7 +358,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
350 | } else { | 358 | } else { |
351 | /* Generate return code (system call to sigreturn) */ | 359 | /* Generate return code (system call to sigreturn) */ |
352 | err |= __put_user(MOVW(7), &frame->retcode[0]); | 360 | err |= __put_user(MOVW(7), &frame->retcode[0]); |
353 | err |= __put_user(TRAP16, &frame->retcode[1]); | 361 | err |= __put_user(TRAP_NOARG, &frame->retcode[1]); |
354 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); | 362 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); |
355 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); | 363 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); |
356 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); | 364 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); |
@@ -430,7 +438,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
430 | } else { | 438 | } else { |
431 | /* Generate return code (system call to rt_sigreturn) */ | 439 | /* Generate return code (system call to rt_sigreturn) */ |
432 | err |= __put_user(MOVW(7), &frame->retcode[0]); | 440 | err |= __put_user(MOVW(7), &frame->retcode[0]); |
433 | err |= __put_user(TRAP16, &frame->retcode[1]); | 441 | err |= __put_user(TRAP_NOARG, &frame->retcode[1]); |
434 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); | 442 | err |= __put_user(OR_R0_R0, &frame->retcode[2]); |
435 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); | 443 | err |= __put_user(OR_R0_R0, &frame->retcode[3]); |
436 | err |= __put_user(OR_R0_R0, &frame->retcode[4]); | 444 | 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..5083b6ed4b39 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, |
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 53dfa55f3156..3762d9dc2046 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c | |||
@@ -18,13 +18,14 @@ | |||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/kallsyms.h> | 19 | #include <linux/kallsyms.h> |
20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
21 | #include <linux/debug_locks.h> | ||
21 | #include <asm/system.h> | 22 | #include <asm/system.h> |
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | 24 | ||
24 | #ifdef CONFIG_SH_KGDB | 25 | #ifdef CONFIG_SH_KGDB |
25 | #include <asm/kgdb.h> | 26 | #include <asm/kgdb.h> |
26 | #define CHK_REMOTE_DEBUG(regs) \ | 27 | #define CHK_REMOTE_DEBUG(regs) \ |
27 | { \ | 28 | { \ |
28 | if (kgdb_debug_hook && !user_mode(regs))\ | 29 | if (kgdb_debug_hook && !user_mode(regs))\ |
29 | (*kgdb_debug_hook)(regs); \ | 30 | (*kgdb_debug_hook)(regs); \ |
30 | } | 31 | } |
@@ -33,8 +34,13 @@ | |||
33 | #endif | 34 | #endif |
34 | 35 | ||
35 | #ifdef CONFIG_CPU_SH2 | 36 | #ifdef CONFIG_CPU_SH2 |
36 | #define TRAP_RESERVED_INST 4 | 37 | # define TRAP_RESERVED_INST 4 |
37 | #define TRAP_ILLEGAL_SLOT_INST 6 | 38 | # define TRAP_ILLEGAL_SLOT_INST 6 |
39 | # define TRAP_ADDRESS_ERROR 9 | ||
40 | # ifdef CONFIG_CPU_SH2A | ||
41 | # define TRAP_DIVZERO_ERROR 17 | ||
42 | # define TRAP_DIVOVF_ERROR 18 | ||
43 | # endif | ||
38 | #else | 44 | #else |
39 | #define TRAP_RESERVED_INST 12 | 45 | #define TRAP_RESERVED_INST 12 |
40 | #define TRAP_ILLEGAL_SLOT_INST 13 | 46 | #define TRAP_ILLEGAL_SLOT_INST 13 |
@@ -88,7 +94,7 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
88 | 94 | ||
89 | if (!user_mode(regs) || in_interrupt()) | 95 | if (!user_mode(regs) || in_interrupt()) |
90 | dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + | 96 | dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + |
91 | (unsigned long)task_stack_page(current)); | 97 | (unsigned long)task_stack_page(current)); |
92 | 98 | ||
93 | bust_spinlocks(0); | 99 | bust_spinlocks(0); |
94 | spin_unlock_irq(&die_lock); | 100 | spin_unlock_irq(&die_lock); |
@@ -102,8 +108,6 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs, | |||
102 | die(str, regs, err); | 108 | die(str, regs, err); |
103 | } | 109 | } |
104 | 110 | ||
105 | static int handle_unaligned_notify_count = 10; | ||
106 | |||
107 | /* | 111 | /* |
108 | * try and fix up kernelspace address errors | 112 | * try and fix up kernelspace address errors |
109 | * - userspace errors just cause EFAULT to be returned, resulting in SEGV | 113 | * - userspace errors just cause EFAULT to be returned, resulting in SEGV |
@@ -198,7 +202,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
198 | if (copy_to_user(dst,src,4)) | 202 | if (copy_to_user(dst,src,4)) |
199 | goto fetch_fault; | 203 | goto fetch_fault; |
200 | ret = 0; | 204 | ret = 0; |
201 | break; | 205 | break; |
202 | 206 | ||
203 | case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ | 207 | case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ |
204 | if (instruction & 4) | 208 | if (instruction & 4) |
@@ -222,7 +226,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
222 | if (copy_from_user(dst,src,4)) | 226 | if (copy_from_user(dst,src,4)) |
223 | goto fetch_fault; | 227 | goto fetch_fault; |
224 | ret = 0; | 228 | ret = 0; |
225 | break; | 229 | break; |
226 | 230 | ||
227 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ | 231 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ |
228 | src = (unsigned char*) *rm; | 232 | src = (unsigned char*) *rm; |
@@ -230,7 +234,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
230 | *rm += count; | 234 | *rm += count; |
231 | dst = (unsigned char*) rn; | 235 | dst = (unsigned char*) rn; |
232 | *(unsigned long*)dst = 0; | 236 | *(unsigned long*)dst = 0; |
233 | 237 | ||
234 | #ifdef __LITTLE_ENDIAN__ | 238 | #ifdef __LITTLE_ENDIAN__ |
235 | if (copy_from_user(dst, src, count)) | 239 | if (copy_from_user(dst, src, count)) |
236 | goto fetch_fault; | 240 | goto fetch_fault; |
@@ -241,7 +245,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
241 | } | 245 | } |
242 | #else | 246 | #else |
243 | dst += 4-count; | 247 | dst += 4-count; |
244 | 248 | ||
245 | if (copy_from_user(dst, src, count)) | 249 | if (copy_from_user(dst, src, count)) |
246 | goto fetch_fault; | 250 | goto fetch_fault; |
247 | 251 | ||
@@ -320,7 +324,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) | |||
320 | return -EFAULT; | 324 | return -EFAULT; |
321 | 325 | ||
322 | /* kernel */ | 326 | /* kernel */ |
323 | die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0); | 327 | die("delay-slot-insn faulting in handle_unaligned_delayslot", |
328 | regs, 0); | ||
324 | } | 329 | } |
325 | 330 | ||
326 | return handle_unaligned_ins(instruction,regs); | 331 | return handle_unaligned_ins(instruction,regs); |
@@ -342,6 +347,13 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) | |||
342 | #define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) | 347 | #define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) |
343 | #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) | 348 | #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) |
344 | 349 | ||
350 | /* | ||
351 | * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit | ||
352 | * opcodes.. | ||
353 | */ | ||
354 | #ifndef CONFIG_CPU_SH2A | ||
355 | static int handle_unaligned_notify_count = 10; | ||
356 | |||
345 | static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | 357 | static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) |
346 | { | 358 | { |
347 | u_int rm; | 359 | u_int rm; |
@@ -354,7 +366,8 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
354 | if (user_mode(regs) && handle_unaligned_notify_count>0) { | 366 | if (user_mode(regs) && handle_unaligned_notify_count>0) { |
355 | handle_unaligned_notify_count--; | 367 | handle_unaligned_notify_count--; |
356 | 368 | ||
357 | printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | 369 | printk(KERN_NOTICE "Fixing up unaligned userspace access " |
370 | "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | ||
358 | current->comm,current->pid,(u16*)regs->pc,instruction); | 371 | current->comm,current->pid,(u16*)regs->pc,instruction); |
359 | } | 372 | } |
360 | 373 | ||
@@ -478,32 +491,58 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
478 | regs->pc += 2; | 491 | regs->pc += 2; |
479 | return ret; | 492 | return ret; |
480 | } | 493 | } |
494 | #endif /* CONFIG_CPU_SH2A */ | ||
495 | |||
496 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
497 | #define lookup_exception_vector(x) \ | ||
498 | __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x))) | ||
499 | #else | ||
500 | #define lookup_exception_vector(x) \ | ||
501 | __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x))) | ||
502 | #endif | ||
481 | 503 | ||
482 | /* | 504 | /* |
483 | * Handle various address error exceptions | 505 | * Handle various address error exceptions: |
506 | * - instruction address error: | ||
507 | * misaligned PC | ||
508 | * PC >= 0x80000000 in user mode | ||
509 | * - data address error (read and write) | ||
510 | * misaligned data access | ||
511 | * access to >= 0x80000000 is user mode | ||
512 | * Unfortuntaly we can't distinguish between instruction address error | ||
513 | * and data address errors caused by read acceses. | ||
484 | */ | 514 | */ |
485 | asmlinkage void do_address_error(struct pt_regs *regs, | 515 | asmlinkage void do_address_error(struct pt_regs *regs, |
486 | unsigned long writeaccess, | 516 | unsigned long writeaccess, |
487 | unsigned long address) | 517 | unsigned long address) |
488 | { | 518 | { |
489 | unsigned long error_code; | 519 | unsigned long error_code = 0; |
490 | mm_segment_t oldfs; | 520 | mm_segment_t oldfs; |
521 | siginfo_t info; | ||
522 | #ifndef CONFIG_CPU_SH2A | ||
491 | u16 instruction; | 523 | u16 instruction; |
492 | int tmp; | 524 | int tmp; |
525 | #endif | ||
493 | 526 | ||
494 | asm volatile("stc r2_bank,%0": "=r" (error_code)); | 527 | /* Intentional ifdef */ |
528 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
529 | lookup_exception_vector(error_code); | ||
530 | #endif | ||
495 | 531 | ||
496 | oldfs = get_fs(); | 532 | oldfs = get_fs(); |
497 | 533 | ||
498 | if (user_mode(regs)) { | 534 | if (user_mode(regs)) { |
535 | int si_code = BUS_ADRERR; | ||
536 | |||
499 | local_irq_enable(); | 537 | local_irq_enable(); |
500 | current->thread.error_code = error_code; | ||
501 | current->thread.trap_no = (writeaccess) ? 8 : 7; | ||
502 | 538 | ||
503 | /* bad PC is not something we can fix */ | 539 | /* bad PC is not something we can fix */ |
504 | if (regs->pc & 1) | 540 | if (regs->pc & 1) { |
541 | si_code = BUS_ADRALN; | ||
505 | goto uspace_segv; | 542 | goto uspace_segv; |
543 | } | ||
506 | 544 | ||
545 | #ifndef CONFIG_CPU_SH2A | ||
507 | set_fs(USER_DS); | 546 | set_fs(USER_DS); |
508 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { | 547 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { |
509 | /* Argh. Fault on the instruction itself. | 548 | /* Argh. Fault on the instruction itself. |
@@ -518,14 +557,23 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
518 | 557 | ||
519 | if (tmp==0) | 558 | if (tmp==0) |
520 | return; /* sorted */ | 559 | return; /* sorted */ |
560 | #endif | ||
521 | 561 | ||
522 | uspace_segv: | 562 | uspace_segv: |
523 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); | 563 | printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " |
524 | force_sig(SIGSEGV, current); | 564 | "access (PC %lx PR %lx)\n", current->comm, regs->pc, |
565 | regs->pr); | ||
566 | |||
567 | info.si_signo = SIGBUS; | ||
568 | info.si_errno = 0; | ||
569 | info.si_code = si_code; | ||
570 | info.si_addr = (void *) address; | ||
571 | force_sig_info(SIGBUS, &info, current); | ||
525 | } else { | 572 | } else { |
526 | if (regs->pc & 1) | 573 | if (regs->pc & 1) |
527 | die("unaligned program counter", regs, error_code); | 574 | die("unaligned program counter", regs, error_code); |
528 | 575 | ||
576 | #ifndef CONFIG_CPU_SH2A | ||
529 | set_fs(KERNEL_DS); | 577 | set_fs(KERNEL_DS); |
530 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { | 578 | if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { |
531 | /* Argh. Fault on the instruction itself. | 579 | /* Argh. Fault on the instruction itself. |
@@ -537,6 +585,12 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
537 | 585 | ||
538 | handle_unaligned_access(instruction, regs); | 586 | handle_unaligned_access(instruction, regs); |
539 | set_fs(oldfs); | 587 | set_fs(oldfs); |
588 | #else | ||
589 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " | ||
590 | "access\n", current->comm); | ||
591 | |||
592 | force_sig(SIGSEGV, current); | ||
593 | #endif | ||
540 | } | 594 | } |
541 | } | 595 | } |
542 | 596 | ||
@@ -548,7 +602,7 @@ int is_dsp_inst(struct pt_regs *regs) | |||
548 | { | 602 | { |
549 | unsigned short inst; | 603 | unsigned short inst; |
550 | 604 | ||
551 | /* | 605 | /* |
552 | * Safe guard if DSP mode is already enabled or we're lacking | 606 | * Safe guard if DSP mode is already enabled or we're lacking |
553 | * the DSP altogether. | 607 | * the DSP altogether. |
554 | */ | 608 | */ |
@@ -569,27 +623,49 @@ int is_dsp_inst(struct pt_regs *regs) | |||
569 | #define is_dsp_inst(regs) (0) | 623 | #define is_dsp_inst(regs) (0) |
570 | #endif /* CONFIG_SH_DSP */ | 624 | #endif /* CONFIG_SH_DSP */ |
571 | 625 | ||
626 | #ifdef CONFIG_CPU_SH2A | ||
627 | asmlinkage void do_divide_error(unsigned long r4, unsigned long r5, | ||
628 | unsigned long r6, unsigned long r7, | ||
629 | struct pt_regs __regs) | ||
630 | { | ||
631 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
632 | siginfo_t info; | ||
633 | |||
634 | switch (r4) { | ||
635 | case TRAP_DIVZERO_ERROR: | ||
636 | info.si_code = FPE_INTDIV; | ||
637 | break; | ||
638 | case TRAP_DIVOVF_ERROR: | ||
639 | info.si_code = FPE_INTOVF; | ||
640 | break; | ||
641 | } | ||
642 | |||
643 | force_sig_info(SIGFPE, &info, current); | ||
644 | } | ||
645 | #endif | ||
646 | |||
572 | /* arch/sh/kernel/cpu/sh4/fpu.c */ | 647 | /* arch/sh/kernel/cpu/sh4/fpu.c */ |
573 | extern int do_fpu_inst(unsigned short, struct pt_regs *); | 648 | extern int do_fpu_inst(unsigned short, struct pt_regs *); |
574 | extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5, | 649 | extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5, |
575 | unsigned long r6, unsigned long r7, struct pt_regs regs); | 650 | unsigned long r6, unsigned long r7, struct pt_regs __regs); |
576 | 651 | ||
577 | asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, | 652 | asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, |
578 | unsigned long r6, unsigned long r7, | 653 | unsigned long r6, unsigned long r7, |
579 | struct pt_regs regs) | 654 | struct pt_regs __regs) |
580 | { | 655 | { |
656 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
581 | unsigned long error_code; | 657 | unsigned long error_code; |
582 | struct task_struct *tsk = current; | 658 | struct task_struct *tsk = current; |
583 | 659 | ||
584 | #ifdef CONFIG_SH_FPU_EMU | 660 | #ifdef CONFIG_SH_FPU_EMU |
585 | unsigned short inst; | 661 | unsigned short inst = 0; |
586 | int err; | 662 | int err; |
587 | 663 | ||
588 | get_user(inst, (unsigned short*)regs.pc); | 664 | get_user(inst, (unsigned short*)regs->pc); |
589 | 665 | ||
590 | err = do_fpu_inst(inst, ®s); | 666 | err = do_fpu_inst(inst, regs); |
591 | if (!err) { | 667 | if (!err) { |
592 | regs.pc += 2; | 668 | regs->pc += 2; |
593 | return; | 669 | return; |
594 | } | 670 | } |
595 | /* not a FPU inst. */ | 671 | /* not a FPU inst. */ |
@@ -597,20 +673,19 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, | |||
597 | 673 | ||
598 | #ifdef CONFIG_SH_DSP | 674 | #ifdef CONFIG_SH_DSP |
599 | /* Check if it's a DSP instruction */ | 675 | /* Check if it's a DSP instruction */ |
600 | if (is_dsp_inst(®s)) { | 676 | if (is_dsp_inst(regs)) { |
601 | /* Enable DSP mode, and restart instruction. */ | 677 | /* Enable DSP mode, and restart instruction. */ |
602 | regs.sr |= SR_DSP; | 678 | regs->sr |= SR_DSP; |
603 | return; | 679 | return; |
604 | } | 680 | } |
605 | #endif | 681 | #endif |
606 | 682 | ||
607 | asm volatile("stc r2_bank, %0": "=r" (error_code)); | 683 | lookup_exception_vector(error_code); |
684 | |||
608 | local_irq_enable(); | 685 | local_irq_enable(); |
609 | tsk->thread.error_code = error_code; | 686 | CHK_REMOTE_DEBUG(regs); |
610 | tsk->thread.trap_no = TRAP_RESERVED_INST; | ||
611 | CHK_REMOTE_DEBUG(®s); | ||
612 | force_sig(SIGILL, tsk); | 687 | force_sig(SIGILL, tsk); |
613 | die_if_no_fixup("reserved instruction", ®s, error_code); | 688 | die_if_no_fixup("reserved instruction", regs, error_code); |
614 | } | 689 | } |
615 | 690 | ||
616 | #ifdef CONFIG_SH_FPU_EMU | 691 | #ifdef CONFIG_SH_FPU_EMU |
@@ -658,39 +733,41 @@ static int emulate_branch(unsigned short inst, struct pt_regs* regs) | |||
658 | 733 | ||
659 | asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, | 734 | asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, |
660 | unsigned long r6, unsigned long r7, | 735 | unsigned long r6, unsigned long r7, |
661 | struct pt_regs regs) | 736 | struct pt_regs __regs) |
662 | { | 737 | { |
738 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
663 | unsigned long error_code; | 739 | unsigned long error_code; |
664 | struct task_struct *tsk = current; | 740 | struct task_struct *tsk = current; |
665 | #ifdef CONFIG_SH_FPU_EMU | 741 | #ifdef CONFIG_SH_FPU_EMU |
666 | unsigned short inst; | 742 | unsigned short inst = 0; |
667 | 743 | ||
668 | get_user(inst, (unsigned short *)regs.pc + 1); | 744 | get_user(inst, (unsigned short *)regs->pc + 1); |
669 | if (!do_fpu_inst(inst, ®s)) { | 745 | if (!do_fpu_inst(inst, regs)) { |
670 | get_user(inst, (unsigned short *)regs.pc); | 746 | get_user(inst, (unsigned short *)regs->pc); |
671 | if (!emulate_branch(inst, ®s)) | 747 | if (!emulate_branch(inst, regs)) |
672 | return; | 748 | return; |
673 | /* fault in branch.*/ | 749 | /* fault in branch.*/ |
674 | } | 750 | } |
675 | /* not a FPU inst. */ | 751 | /* not a FPU inst. */ |
676 | #endif | 752 | #endif |
677 | 753 | ||
678 | asm volatile("stc r2_bank, %0": "=r" (error_code)); | 754 | lookup_exception_vector(error_code); |
755 | |||
679 | local_irq_enable(); | 756 | local_irq_enable(); |
680 | tsk->thread.error_code = error_code; | 757 | CHK_REMOTE_DEBUG(regs); |
681 | tsk->thread.trap_no = TRAP_RESERVED_INST; | ||
682 | CHK_REMOTE_DEBUG(®s); | ||
683 | force_sig(SIGILL, tsk); | 758 | force_sig(SIGILL, tsk); |
684 | die_if_no_fixup("illegal slot instruction", ®s, error_code); | 759 | die_if_no_fixup("illegal slot instruction", regs, error_code); |
685 | } | 760 | } |
686 | 761 | ||
687 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, | 762 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, |
688 | unsigned long r6, unsigned long r7, | 763 | unsigned long r6, unsigned long r7, |
689 | struct pt_regs regs) | 764 | struct pt_regs __regs) |
690 | { | 765 | { |
766 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
691 | long ex; | 767 | long ex; |
692 | asm volatile("stc r2_bank, %0" : "=r" (ex)); | 768 | |
693 | die_if_kernel("exception", ®s, ex); | 769 | lookup_exception_vector(ex); |
770 | die_if_kernel("exception", regs, ex); | ||
694 | } | 771 | } |
695 | 772 | ||
696 | #if defined(CONFIG_SH_STANDARD_BIOS) | 773 | #if defined(CONFIG_SH_STANDARD_BIOS) |
@@ -735,12 +812,16 @@ void *set_exception_table_vec(unsigned int vec, void *handler) | |||
735 | { | 812 | { |
736 | extern void *exception_handling_table[]; | 813 | extern void *exception_handling_table[]; |
737 | void *old_handler; | 814 | void *old_handler; |
738 | 815 | ||
739 | old_handler = exception_handling_table[vec]; | 816 | old_handler = exception_handling_table[vec]; |
740 | exception_handling_table[vec] = handler; | 817 | exception_handling_table[vec] = handler; |
741 | return old_handler; | 818 | return old_handler; |
742 | } | 819 | } |
743 | 820 | ||
821 | extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5, | ||
822 | unsigned long r6, unsigned long r7, | ||
823 | struct pt_regs __regs); | ||
824 | |||
744 | void __init trap_init(void) | 825 | void __init trap_init(void) |
745 | { | 826 | { |
746 | set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst); | 827 | set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst); |
@@ -759,7 +840,15 @@ void __init trap_init(void) | |||
759 | set_exception_table_evt(0x800, do_fpu_state_restore); | 840 | set_exception_table_evt(0x800, do_fpu_state_restore); |
760 | set_exception_table_evt(0x820, do_fpu_state_restore); | 841 | set_exception_table_evt(0x820, do_fpu_state_restore); |
761 | #endif | 842 | #endif |
762 | 843 | ||
844 | #ifdef CONFIG_CPU_SH2 | ||
845 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler); | ||
846 | #endif | ||
847 | #ifdef CONFIG_CPU_SH2A | ||
848 | set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error); | ||
849 | set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error); | ||
850 | #endif | ||
851 | |||
763 | /* Setup VBR for boot cpu */ | 852 | /* Setup VBR for boot cpu */ |
764 | per_cpu_trap_init(); | 853 | per_cpu_trap_init(); |
765 | } | 854 | } |
@@ -784,6 +873,11 @@ void show_trace(struct task_struct *tsk, unsigned long *sp, | |||
784 | } | 873 | } |
785 | 874 | ||
786 | printk("\n"); | 875 | printk("\n"); |
876 | |||
877 | if (!tsk) | ||
878 | tsk = current; | ||
879 | |||
880 | debug_show_held_locks(tsk); | ||
787 | } | 881 | } |
788 | 882 | ||
789 | void show_stack(struct task_struct *tsk, unsigned long *sp) | 883 | void show_stack(struct task_struct *tsk, unsigned long *sp) |