diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-12-07 15:48:15 -0500 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-12-07 15:48:15 -0500 |
| commit | 34161db6b14d984fb9b06c735b7b42f8803f6851 (patch) | |
| tree | 99656278b6697f1cde5b05894b7c0ee22c63a00e /arch/sh/kernel | |
| parent | 5847e1f4d058677c5e46dc6c3e3c70e8855ea3ba (diff) | |
| parent | 620034c84d1d939717bdfbe02c51a3fee43541c3 (diff) | |
Merge branch 'master' of /home/trondmy/kernel/linux-2.6/ into merge_linus
Conflicts:
include/linux/sunrpc/xprt.h
net/sunrpc/xprtsock.c
Fix up conflicts with the workqueue changes.
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) |
